From 003e34190f314cd159f8ec227ef32c2400e90f48 Mon Sep 17 00:00:00 2001 From: "Jonathan \"Geenz\" Goodman" Date: Mon, 2 Jan 2023 05:38:29 -0800 Subject: Refactor post processing a smidge Fixes SL-18484. --- .../shaders/class1/interface/glowcombineV.glsl | 4 +- indra/newview/llviewerdisplay.cpp | 7 +- indra/newview/pipeline.cpp | 955 +++++++++++---------- indra/newview/pipeline.h | 2 + 4 files changed, 524 insertions(+), 444 deletions(-) (limited to 'indra') diff --git a/indra/newview/app_settings/shaders/class1/interface/glowcombineV.glsl b/indra/newview/app_settings/shaders/class1/interface/glowcombineV.glsl index e08284f762..71fa095505 100644 --- a/indra/newview/app_settings/shaders/class1/interface/glowcombineV.glsl +++ b/indra/newview/app_settings/shaders/class1/interface/glowcombineV.glsl @@ -35,7 +35,7 @@ VARYING vec2 vary_texcoord1; void main() { gl_Position = vec4(position.xyz, 1.0); - vary_texcoord0 = texcoord0; - vary_texcoord1 = texcoord1; + vary_texcoord0 = position.xy * 0.5 + 0.5; + vary_texcoord1 = vary_texcoord0; } diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 1b2f07515a..58b1716caa 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -1348,9 +1348,12 @@ void render_ui(F32 zoom_factor, int subfield) } { + // Render our post process prior to the HUD, UI, etc. + gPipeline.renderPostProcess(); + // draw hud and 3D ui elements into screen render target so they'll be able to use // the depth buffer (avoids extra copy of depth buffer per frame) - gPipeline.mRT->screen.bindTarget(); + gPipeline.screenTarget()->bindTarget(); // SL-15709 // NOTE: Tracy only allows one ZoneScoped per function. // Solutions are: @@ -1384,7 +1387,7 @@ void render_ui(F32 zoom_factor, int subfield) } } - gPipeline.mRT->screen.flush(); + gPipeline.screenTarget()->flush(); // apply gamma correction and post effects before rendering 2D UI gPipeline.renderFinalize(); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 744d21b2c9..4edc092271 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -880,7 +880,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples) if (shadow_detail > 0 || ssao || RenderDepthOfField || samples > 0) { //only need mRT->deferredLight for shadows OR ssao OR dof OR fxaa - if (!mRT->deferredLight.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE)) return false; + if (!mRT->deferredLight.allocate(resX, resY, GL_RGBA16, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE)) return false; } else { @@ -7530,500 +7530,541 @@ void LLPipeline::bindScreenToTexture() static LLTrace::BlockTimerStatHandle FTM_RENDER_BLOOM("Bloom"); -void LLPipeline::renderFinalize() +void LLPipeline::renderPostProcess() { - LLVertexBuffer::unbind(); - LLGLState::checkStates(); - LLGLState::checkTextureChannels(); + LLVertexBuffer::unbind(); + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); - assertInitialized(); + assertInitialized(); - LLVector2 tc1(0, 0); - LLVector2 tc2((F32) mRT->screen.getWidth() * 2, (F32) mRT->screen.getHeight() * 2); + LLVector2 tc1(0, 0); + LLVector2 tc2((F32)mRT->screen.getWidth() * 2, (F32)mRT->screen.getHeight() * 2); - LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM); - LL_PROFILE_GPU_ZONE("renderFinalize"); + LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM); + LL_PROFILE_GPU_ZONE("renderPostProcess"); - gGL.color4f(1, 1, 1, 1); - LLGLDepthTest depth(GL_FALSE); - LLGLDisable blend(GL_BLEND); - LLGLDisable cull(GL_CULL_FACE); + gGL.color4f(1, 1, 1, 1); + LLGLDepthTest depth(GL_FALSE); + LLGLDisable blend(GL_BLEND); + LLGLDisable cull(GL_CULL_FACE); - enableLightsFullbright(); + enableLightsFullbright(); - LLGLDisable test(GL_ALPHA_TEST); + LLGLDisable test(GL_ALPHA_TEST); - gGL.setColorMask(true, true); - glClearColor(0, 0, 0, 0); + gGL.setColorMask(true, true); + glClearColor(0, 0, 0, 0); - if (!gCubeSnapshot) - { - LLRenderTarget* screen_target = &mRT->screen; - screen_target->bindTarget(); + if (sRenderGlow) + { + LL_PROFILE_GPU_ZONE("glow"); + mGlow[2].bindTarget(); + mGlow[2].clear(); - if (RenderScreenSpaceReflections) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - screen space reflections"); - LL_PROFILE_GPU_ZONE("screen space reflections"); + gGlowExtractProgram.bind(); + F32 minLum = llmax((F32)RenderGlowMinLuminance, 0.0f); + F32 maxAlpha = RenderGlowMaxExtractAlpha; + F32 warmthAmount = RenderGlowWarmthAmount; + LLVector3 lumWeights = RenderGlowLumWeights; + LLVector3 warmthWeights = RenderGlowWarmthWeights; - bindDeferredShader(gPostScreenSpaceReflectionProgram, NULL); - mScreenTriangleVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_MIN_LUMINANCE, minLum); + gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_MAX_EXTRACT_ALPHA, maxAlpha); + gGlowExtractProgram.uniform3f(LLShaderMgr::GLOW_LUM_WEIGHTS, lumWeights.mV[0], lumWeights.mV[1], + lumWeights.mV[2]); + gGlowExtractProgram.uniform3f(LLShaderMgr::GLOW_WARMTH_WEIGHTS, warmthWeights.mV[0], warmthWeights.mV[1], + warmthWeights.mV[2]); + gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_WARMTH_AMOUNT, warmthAmount); - set_camera_projection_matrix(gPostScreenSpaceReflectionProgram); + { + LLGLEnable blend_on(GL_BLEND); + LLGLEnable test(GL_ALPHA_TEST); - // We need linear depth. - static LLStaticHashedString zfar("zFar"); - static LLStaticHashedString znear("zNear"); - float nearClip = LLViewerCamera::getInstance()->getNear(); - float farClip = LLViewerCamera::getInstance()->getFar(); - gPostScreenSpaceReflectionProgram.uniform1f(zfar, farClip); - gPostScreenSpaceReflectionProgram.uniform1f(znear, nearClip); + gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); - S32 channel = gPostScreenSpaceReflectionProgram.enableTexture(LLShaderMgr::DIFFUSE_MAP, screen_target->getUsage()); - if (channel > -1) - { - screen_target->bindTexture(0, channel, LLTexUnit::TFO_POINT); - } + mRT->screen.bindTexture(0, 0, LLTexUnit::TFO_POINT); - { - LLGLDisable blend(GL_BLEND); - LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); + gGL.color4f(1, 1, 1, 1); + gPipeline.enableLightsFullbright(); + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1, -1); - stop_glerror(); - mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); - stop_glerror(); - } + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1, 3); - unbindDeferredShader(gPostScreenSpaceReflectionProgram); - } + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3, -1); - // gamma correct lighting - { - LL_PROFILE_GPU_ZONE("gamma correct"); + gGL.end(); - LLGLDepthTest depth(GL_FALSE, GL_FALSE); + gGL.getTexUnit(0)->unbind(mRT->screen.getUsage()); - LLVector2 tc1(0, 0); - LLVector2 tc2((F32)screen_target->getWidth() * 2, (F32)screen_target->getHeight() * 2); + mGlow[2].flush(); - // Apply gamma correction to the frame here. - gDeferredPostGammaCorrectProgram.bind(); - // mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); - S32 channel = 0; - channel = gDeferredPostGammaCorrectProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, screen_target->getUsage()); - if (channel > -1) - { - screen_target->bindTexture(0, channel, LLTexUnit::TFO_POINT); - } + tc1.setVec(0, 0); + tc2.setVec(2, 2); + } - gDeferredPostGammaCorrectProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, screen_target->getWidth(), screen_target->getHeight()); + // power of two between 1 and 1024 + U32 glowResPow = RenderGlowResolutionPow; + const U32 glow_res = llmax(1, llmin(1024, 1 << glowResPow)); - F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma"); + S32 kernel = RenderGlowIterations * 2; + F32 delta = RenderGlowWidth / glow_res; + // Use half the glow width if we have the res set to less than 9 so that it looks + // almost the same in either case. + if (glowResPow < 9) + { + delta *= 0.5f; + } + F32 strength = RenderGlowStrength; - gDeferredPostGammaCorrectProgram.uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f / 2.2f)); + gGlowProgram.bind(); + gGlowProgram.uniform1f(LLShaderMgr::GLOW_STRENGTH, strength); - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1, -1); + for (S32 i = 0; i < kernel; i++) + { + mGlow[i % 2].bindTarget(); + mGlow[i % 2].clear(); - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1, 3); + if (i == 0) + { + gGL.getTexUnit(0)->bind(&mGlow[2]); + } + else + { + gGL.getTexUnit(0)->bind(&mGlow[(i - 1) % 2]); + } - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3, -1); + if (i % 2 == 0) + { + gGlowProgram.uniform2f(LLShaderMgr::GLOW_DELTA, delta, 0); + } + else + { + gGlowProgram.uniform2f(LLShaderMgr::GLOW_DELTA, 0, delta); + } - gGL.end(); + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1, -1); - gGL.getTexUnit(channel)->unbind(screen_target->getUsage()); - gDeferredPostGammaCorrectProgram.unbind(); - } + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1, 3); - screen_target->flush(); + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3, -1); - LLVertexBuffer::unbind(); - } + gGL.end(); - if (sRenderGlow) - { - LL_PROFILE_GPU_ZONE("glow"); - mGlow[2].bindTarget(); - mGlow[2].clear(); - - gGlowExtractProgram.bind(); - F32 minLum = llmax((F32) RenderGlowMinLuminance, 0.0f); - F32 maxAlpha = RenderGlowMaxExtractAlpha; - F32 warmthAmount = RenderGlowWarmthAmount; - LLVector3 lumWeights = RenderGlowLumWeights; - LLVector3 warmthWeights = RenderGlowWarmthWeights; - - gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_MIN_LUMINANCE, minLum); - gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_MAX_EXTRACT_ALPHA, maxAlpha); - gGlowExtractProgram.uniform3f(LLShaderMgr::GLOW_LUM_WEIGHTS, lumWeights.mV[0], lumWeights.mV[1], - lumWeights.mV[2]); - gGlowExtractProgram.uniform3f(LLShaderMgr::GLOW_WARMTH_WEIGHTS, warmthWeights.mV[0], warmthWeights.mV[1], - warmthWeights.mV[2]); - gGlowExtractProgram.uniform1f(LLShaderMgr::GLOW_WARMTH_AMOUNT, warmthAmount); - - { - LLGLEnable blend_on(GL_BLEND); - LLGLEnable test(GL_ALPHA_TEST); + mGlow[i % 2].flush(); + } - gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA); + gGlowProgram.unbind(); + } + else // !sRenderGlow, skip the glow ping-pong and just clear the result target + { + mGlow[1].bindTarget(); + mGlow[1].clear(); + mGlow[1].flush(); + } - mRT->screen.bindTexture(0, 0, LLTexUnit::TFO_POINT); + gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; + gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; + gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth(); + gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); + glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); - gGL.color4f(1, 1, 1, 1); - gPipeline.enableLightsFullbright(); - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1, -1); + tc2.setVec((F32)mRT->screen.getWidth(), (F32)mRT->screen.getHeight()); - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1, 3); + gGL.flush(); - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3, -1); + LLVertexBuffer::unbind(); - gGL.end(); + if (LLPipeline::sRenderDeferred) + { + bool dof_enabled = !LLViewerCamera::getInstance()->cameraUnderWater() && + (RenderDepthOfFieldInEditMode || !LLToolMgr::getInstance()->inBuildMode()) && + RenderDepthOfField && + !gCubeSnapshot; - gGL.getTexUnit(0)->unbind(mRT->screen.getUsage()); + bool multisample = RenderFSAASamples > 1 && mRT->fxaaBuffer.isComplete() && !gCubeSnapshot; - mGlow[2].flush(); + gViewerWindow->setup3DViewport(); - tc1.setVec(0, 0); - tc2.setVec(2, 2); - } + if (dof_enabled) + { + LL_PROFILE_GPU_ZONE("dof"); + LLGLSLShader* shader = &gDeferredPostProgram; + LLGLDisable blend(GL_BLEND); - // power of two between 1 and 1024 - U32 glowResPow = RenderGlowResolutionPow; - const U32 glow_res = llmax(1, llmin(1024, 1 << glowResPow)); + // depth of field focal plane calculations + static F32 current_distance = 16.f; + static F32 start_distance = 16.f; + static F32 transition_time = 1.f; - S32 kernel = RenderGlowIterations * 2; - F32 delta = RenderGlowWidth / glow_res; - // Use half the glow width if we have the res set to less than 9 so that it looks - // almost the same in either case. - if (glowResPow < 9) - { - delta *= 0.5f; - } - F32 strength = RenderGlowStrength; + LLVector3 focus_point; - gGlowProgram.bind(); - gGlowProgram.uniform1f(LLShaderMgr::GLOW_STRENGTH, strength); + LLViewerObject* obj = LLViewerMediaFocus::getInstance()->getFocusedObject(); + if (obj && obj->mDrawable && obj->isSelected()) + { // focus on selected media object + S32 face_idx = LLViewerMediaFocus::getInstance()->getFocusedFace(); + if (obj && obj->mDrawable) + { + LLFace* face = obj->mDrawable->getFace(face_idx); + if (face) + { + focus_point = face->getPositionAgent(); + } + } + } - for (S32 i = 0; i < kernel; i++) - { - mGlow[i % 2].bindTarget(); - mGlow[i % 2].clear(); + if (focus_point.isExactlyZero()) + { + if (LLViewerJoystick::getInstance()->getOverrideCamera()) + { // focus on point under cursor + focus_point.set(gDebugRaycastIntersection.getF32ptr()); + } + else if (gAgentCamera.cameraMouselook()) + { // focus on point under mouselook crosshairs + LLVector4a result; + result.clear(); - if (i == 0) - { - gGL.getTexUnit(0)->bind(&mGlow[2]); - } - else - { - gGL.getTexUnit(0)->bind(&mGlow[(i - 1) % 2]); - } + gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, FALSE, TRUE, NULL, &result); - if (i % 2 == 0) - { - gGlowProgram.uniform2f(LLShaderMgr::GLOW_DELTA, delta, 0); - } - else - { - gGlowProgram.uniform2f(LLShaderMgr::GLOW_DELTA, 0, delta); - } + focus_point.set(result.getF32ptr()); + } + else + { + // focus on alt-zoom target + LLViewerRegion* region = gAgent.getRegion(); + if (region) + { + focus_point = LLVector3(gAgentCamera.getFocusGlobal() - region->getOriginGlobal()); + } + } + } - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1, -1); + LLVector3 eye = LLViewerCamera::getInstance()->getOrigin(); + F32 target_distance = 16.f; + if (!focus_point.isExactlyZero()) + { + target_distance = LLViewerCamera::getInstance()->getAtAxis() * (focus_point - eye); + } - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1, 3); + if (transition_time >= 1.f && fabsf(current_distance - target_distance) / current_distance > 0.01f) + { // large shift happened, interpolate smoothly to new target distance + transition_time = 0.f; + start_distance = current_distance; + } + else if (transition_time < 1.f) + { // currently in a transition, continue interpolating + transition_time += 1.f / CameraFocusTransitionTime * gFrameIntervalSeconds.value(); + transition_time = llmin(transition_time, 1.f); - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3, -1); + F32 t = cosf(transition_time * F_PI + F_PI) * 0.5f + 0.5f; + current_distance = start_distance + (target_distance - start_distance) * t; + } + else + { // small or no change, just snap to target distance + current_distance = target_distance; + } - gGL.end(); + // convert to mm + F32 subject_distance = current_distance * 1000.f; + F32 fnumber = CameraFNumber; + F32 default_focal_length = CameraFocalLength; - mGlow[i % 2].flush(); - } + F32 fov = LLViewerCamera::getInstance()->getView(); - gGlowProgram.unbind(); - } - else // !sRenderGlow, skip the glow ping-pong and just clear the result target - { - mGlow[1].bindTarget(); - mGlow[1].clear(); - mGlow[1].flush(); - } + const F32 default_fov = CameraFieldOfView * F_PI / 180.f; - gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; - gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; - gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth(); - gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); - glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); + // F32 aspect_ratio = (F32) mRT->screen.getWidth()/(F32)mRT->screen.getHeight(); - tc2.setVec((F32) mRT->screen.getWidth(), (F32) mRT->screen.getHeight()); + F32 dv = 2.f * default_focal_length * tanf(default_fov / 2.f); - gGL.flush(); + F32 focal_length = dv / (2 * tanf(fov / 2.f)); - LLVertexBuffer::unbind(); + // F32 tan_pixel_angle = tanf(LLDrawable::sCurPixelAngle); - if (LLPipeline::sRenderDeferred) - { - bool dof_enabled = !LLViewerCamera::getInstance()->cameraUnderWater() && - (RenderDepthOfFieldInEditMode || !LLToolMgr::getInstance()->inBuildMode()) && - RenderDepthOfField && - !gCubeSnapshot; + // from wikipedia -- c = |s2-s1|/s2 * f^2/(N(S1-f)) + // where N = fnumber + // s2 = dot distance + // s1 = subject distance + // f = focal length + // - bool multisample = RenderFSAASamples > 1 && mRT->fxaaBuffer.isComplete() && !gCubeSnapshot; + F32 blur_constant = focal_length * focal_length / (fnumber * (subject_distance - focal_length)); + blur_constant /= 1000.f; // convert to meters for shader + F32 magnification = focal_length / (subject_distance - focal_length); - gViewerWindow->setup3DViewport(); + { // build diffuse+bloom+CoF + mRT->deferredLight.bindTarget(); + shader = &gDeferredCoFProgram; - if (dof_enabled) - { - LL_PROFILE_GPU_ZONE("dof"); - LLGLSLShader *shader = &gDeferredPostProgram; - LLGLDisable blend(GL_BLEND); + bindDeferredShader(*shader); - // depth of field focal plane calculations - static F32 current_distance = 16.f; - static F32 start_distance = 16.f; - static F32 transition_time = 1.f; + S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->screen.getUsage()); + if (channel > -1) + { + mRT->screen.bindTexture(0, channel); + } - LLVector3 focus_point; + shader->uniform1f(LLShaderMgr::DOF_FOCAL_DISTANCE, -subject_distance / 1000.f); + shader->uniform1f(LLShaderMgr::DOF_BLUR_CONSTANT, blur_constant); + shader->uniform1f(LLShaderMgr::DOF_TAN_PIXEL_ANGLE, tanf(1.f / LLDrawable::sCurPixelAngle)); + shader->uniform1f(LLShaderMgr::DOF_MAGNIFICATION, magnification); + shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF); + shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale); - LLViewerObject *obj = LLViewerMediaFocus::getInstance()->getFocusedObject(); - if (obj && obj->mDrawable && obj->isSelected()) - { // focus on selected media object - S32 face_idx = LLViewerMediaFocus::getInstance()->getFocusedFace(); - if (obj && obj->mDrawable) - { - LLFace *face = obj->mDrawable->getFace(face_idx); - if (face) - { - focus_point = face->getPositionAgent(); - } - } - } + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1, -1); - if (focus_point.isExactlyZero()) - { - if (LLViewerJoystick::getInstance()->getOverrideCamera()) - { // focus on point under cursor - focus_point.set(gDebugRaycastIntersection.getF32ptr()); - } - else if (gAgentCamera.cameraMouselook()) - { // focus on point under mouselook crosshairs - LLVector4a result; - result.clear(); + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1, 3); - gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE, FALSE, TRUE, NULL, &result); + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3, -1); - focus_point.set(result.getF32ptr()); - } - else - { - // focus on alt-zoom target - LLViewerRegion *region = gAgent.getRegion(); - if (region) - { - focus_point = LLVector3(gAgentCamera.getFocusGlobal() - region->getOriginGlobal()); - } - } - } + gGL.end(); - LLVector3 eye = LLViewerCamera::getInstance()->getOrigin(); - F32 target_distance = 16.f; - if (!focus_point.isExactlyZero()) - { - target_distance = LLViewerCamera::getInstance()->getAtAxis() * (focus_point - eye); - } + unbindDeferredShader(*shader); + mRT->deferredLight.flush(); + } - if (transition_time >= 1.f && fabsf(current_distance - target_distance) / current_distance > 0.01f) - { // large shift happened, interpolate smoothly to new target distance - transition_time = 0.f; - start_distance = current_distance; - } - else if (transition_time < 1.f) - { // currently in a transition, continue interpolating - transition_time += 1.f / CameraFocusTransitionTime * gFrameIntervalSeconds.value(); - transition_time = llmin(transition_time, 1.f); + U32 dof_width = (U32)(mRT->screen.getWidth() * CameraDoFResScale); + U32 dof_height = (U32)(mRT->screen.getHeight() * CameraDoFResScale); - F32 t = cosf(transition_time * F_PI + F_PI) * 0.5f + 0.5f; - current_distance = start_distance + (target_distance - start_distance) * t; - } - else - { // small or no change, just snap to target distance - current_distance = target_distance; - } + { // perform DoF sampling at half-res (preserve alpha channel) + mRT->screen.bindTarget(); + glViewport(0, 0, dof_width, dof_height); + gGL.setColorMask(true, false); - // convert to mm - F32 subject_distance = current_distance * 1000.f; - F32 fnumber = CameraFNumber; - F32 default_focal_length = CameraFocalLength; + shader = &gDeferredPostProgram; + bindDeferredShader(*shader); + S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->deferredLight.getUsage()); + if (channel > -1) + { + mRT->deferredLight.bindTexture(0, channel); + } - F32 fov = LLViewerCamera::getInstance()->getView(); + shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF); + shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale); - const F32 default_fov = CameraFieldOfView * F_PI / 180.f; + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1, -1); - // F32 aspect_ratio = (F32) mRT->screen.getWidth()/(F32)mRT->screen.getHeight(); + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1, 3); - F32 dv = 2.f * default_focal_length * tanf(default_fov / 2.f); + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3, -1); - F32 focal_length = dv / (2 * tanf(fov / 2.f)); + gGL.end(); - // F32 tan_pixel_angle = tanf(LLDrawable::sCurPixelAngle); + unbindDeferredShader(*shader); + mRT->screen.flush(); + gGL.setColorMask(true, true); + } - // from wikipedia -- c = |s2-s1|/s2 * f^2/(N(S1-f)) - // where N = fnumber - // s2 = dot distance - // s1 = subject distance - // f = focal length - // + { // combine result based on alpha + if (multisample) + { + mRT->deferredLight.bindTarget(); + glViewport(0, 0, mRT->deferredScreen.getWidth(), mRT->deferredScreen.getHeight()); + } + else + { + gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; + gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; + gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth(); + gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); + glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); + } - F32 blur_constant = focal_length * focal_length / (fnumber * (subject_distance - focal_length)); - blur_constant /= 1000.f; // convert to meters for shader - F32 magnification = focal_length / (subject_distance - focal_length); + shader = &gDeferredDoFCombineProgram; + bindDeferredShader(*shader); - { // build diffuse+bloom+CoF - mRT->deferredLight.bindTarget(); - shader = &gDeferredCoFProgram; + S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->screen.getUsage()); + if (channel > -1) + { + mRT->screen.bindTexture(0, channel); + } - bindDeferredShader(*shader); + shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF); + shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale); + shader->uniform1f(LLShaderMgr::DOF_WIDTH, (dof_width - 1) / (F32)mRT->screen.getWidth()); + shader->uniform1f(LLShaderMgr::DOF_HEIGHT, (dof_height - 1) / (F32)mRT->screen.getHeight()); - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->screen.getUsage()); - if (channel > -1) - { - mRT->screen.bindTexture(0, channel); - } + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1, -1); - shader->uniform1f(LLShaderMgr::DOF_FOCAL_DISTANCE, -subject_distance / 1000.f); - shader->uniform1f(LLShaderMgr::DOF_BLUR_CONSTANT, blur_constant); - shader->uniform1f(LLShaderMgr::DOF_TAN_PIXEL_ANGLE, tanf(1.f / LLDrawable::sCurPixelAngle)); - shader->uniform1f(LLShaderMgr::DOF_MAGNIFICATION, magnification); - shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF); - shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale); + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1, 3); - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1, -1); + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3, -1); - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1, 3); + gGL.end(); - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3, -1); + unbindDeferredShader(*shader); - gGL.end(); + if (multisample) + { + mRT->deferredLight.flush(); + } + } + } + else + { + LL_PROFILE_GPU_ZONE("no dof"); + if (multisample) + { + mRT->deferredLight.bindTarget(); + } + LLGLSLShader* shader = &gDeferredPostNoDoFProgram; - unbindDeferredShader(*shader); - mRT->deferredLight.flush(); - } + bindDeferredShader(*shader); - U32 dof_width = (U32)(mRT->screen.getWidth() * CameraDoFResScale); - U32 dof_height = (U32)(mRT->screen.getHeight() * CameraDoFResScale); + S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->screen.getUsage()); + if (channel > -1) + { + mRT->screen.bindTexture(0, channel); + } - { // perform DoF sampling at half-res (preserve alpha channel) - mRT->screen.bindTarget(); - glViewport(0, 0, dof_width, dof_height); - gGL.setColorMask(true, false); + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); + gGL.vertex2f(-1, -1); - shader = &gDeferredPostProgram; - bindDeferredShader(*shader); - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->deferredLight.getUsage()); - if (channel > -1) - { - mRT->deferredLight.bindTexture(0, channel); - } + gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); + gGL.vertex2f(-1, 3); - shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF); - shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale); + gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); + gGL.vertex2f(3, -1); - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1, -1); + gGL.end(); - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1, 3); + unbindDeferredShader(*shader); - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3, -1); + if (multisample) + { + mRT->deferredLight.flush(); + } + } + } +} - gGL.end(); +LLRenderTarget* LLPipeline::screenTarget() { - unbindDeferredShader(*shader); - mRT->screen.flush(); - gGL.setColorMask(true, true); - } + bool dof_enabled = !LLViewerCamera::getInstance()->cameraUnderWater() && + (RenderDepthOfFieldInEditMode || !LLToolMgr::getInstance()->inBuildMode()) && + RenderDepthOfField && + !gCubeSnapshot; - { // combine result based on alpha - if (multisample) - { - mRT->deferredLight.bindTarget(); - glViewport(0, 0, mRT->deferredScreen.getWidth(), mRT->deferredScreen.getHeight()); - } - else - { - gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; - gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; - gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth(); - gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); - glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); - } + bool multisample = RenderFSAASamples > 1 && mRT->fxaaBuffer.isComplete() && !gCubeSnapshot; - shader = &gDeferredDoFCombineProgram; - bindDeferredShader(*shader); + if (multisample || dof_enabled) + return &mRT->deferredLight; + + return &mRT->screen; +} - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->screen.getUsage()); - if (channel > -1) - { - mRT->screen.bindTexture(0, channel); - } +void LLPipeline::renderFinalize() +{ + LLVertexBuffer::unbind(); + LLGLState::checkStates(); + LLGLState::checkTextureChannels(); + + assertInitialized(); + + LLVector2 tc1(0, 0); + LLVector2 tc2((F32) mRT->screen.getWidth() * 2, (F32) mRT->screen.getHeight() * 2); - shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF); - shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale); - shader->uniform1f(LLShaderMgr::DOF_WIDTH, (dof_width - 1) / (F32)mRT->screen.getWidth()); - shader->uniform1f(LLShaderMgr::DOF_HEIGHT, (dof_height - 1) / (F32)mRT->screen.getHeight()); + LL_RECORD_BLOCK_TIME(FTM_RENDER_BLOOM); + LL_PROFILE_GPU_ZONE("renderFinalize"); - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); - gGL.vertex2f(-1, -1); + gGL.color4f(1, 1, 1, 1); + LLGLDepthTest depth(GL_FALSE); + LLGLDisable blend(GL_BLEND); + LLGLDisable cull(GL_CULL_FACE); - gGL.texCoord2f(tc1.mV[0], tc2.mV[1]); - gGL.vertex2f(-1, 3); + enableLightsFullbright(); - gGL.texCoord2f(tc2.mV[0], tc1.mV[1]); - gGL.vertex2f(3, -1); + LLGLDisable test(GL_ALPHA_TEST); - gGL.end(); + gGL.setColorMask(true, true); + glClearColor(0, 0, 0, 0); - unbindDeferredShader(*shader); + if (!gCubeSnapshot) + { + screenTarget()->bindTarget(); - if (multisample) - { - mRT->deferredLight.flush(); - } - } - } - else + if (RenderScreenSpaceReflections) { - LL_PROFILE_GPU_ZONE("no dof"); - if (multisample) + LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("renderDeferredLighting - screen space reflections"); + LL_PROFILE_GPU_ZONE("screen space reflections"); + + bindDeferredShader(gPostScreenSpaceReflectionProgram, NULL); + mScreenTriangleVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + + set_camera_projection_matrix(gPostScreenSpaceReflectionProgram); + + // We need linear depth. + static LLStaticHashedString zfar("zFar"); + static LLStaticHashedString znear("zNear"); + float nearClip = LLViewerCamera::getInstance()->getNear(); + float farClip = LLViewerCamera::getInstance()->getFar(); + gPostScreenSpaceReflectionProgram.uniform1f(zfar, farClip); + gPostScreenSpaceReflectionProgram.uniform1f(znear, nearClip); + + S32 channel = gPostScreenSpaceReflectionProgram.enableTexture(LLShaderMgr::DIFFUSE_MAP, screenTarget()->getUsage()); + if (channel > -1) { - mRT->deferredLight.bindTarget(); + screenTarget()->bindTexture(0, channel, LLTexUnit::TFO_POINT); } - LLGLSLShader *shader = &gDeferredPostNoDoFProgram; - bindDeferredShader(*shader); + { + LLGLDisable blend(GL_BLEND); + LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS); + + stop_glerror(); + mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); + stop_glerror(); + } - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->screen.getUsage()); + unbindDeferredShader(gPostScreenSpaceReflectionProgram); + } + + // gamma correct lighting + { + LL_PROFILE_GPU_ZONE("gamma correct"); + + LLGLDepthTest depth(GL_FALSE, GL_FALSE); + + LLVector2 tc1(0, 0); + LLVector2 tc2((F32)screenTarget()->getWidth() * 2, (F32)screenTarget()->getHeight() * 2); + + // Apply gamma correction to the frame here. + gDeferredPostGammaCorrectProgram.bind(); + // mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX); + S32 channel = 0; + channel = gDeferredPostGammaCorrectProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, screenTarget()->getUsage()); if (channel > -1) { - mRT->screen.bindTexture(0, channel); + screenTarget()->bindTexture(0, channel, LLTexUnit::TFO_POINT); } + gDeferredPostGammaCorrectProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, screenTarget()->getWidth(), screenTarget()->getHeight()); + + F32 gamma = gSavedSettings.getF32("RenderDeferredDisplayGamma"); + + gDeferredPostGammaCorrectProgram.uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f / 2.2f)); + gGL.begin(LLRender::TRIANGLE_STRIP); gGL.texCoord2f(tc1.mV[0], tc1.mV[1]); gGL.vertex2f(-1, -1); @@ -8036,82 +8077,116 @@ void LLPipeline::renderFinalize() gGL.end(); - unbindDeferredShader(*shader); - - if (multisample) - { - mRT->deferredLight.flush(); - } + gGL.getTexUnit(channel)->unbind(screenTarget()->getUsage()); + gDeferredPostGammaCorrectProgram.unbind(); } - if (multisample) - { - LL_PROFILE_GPU_ZONE("aa"); - // bake out texture2D with RGBL for FXAA shader - mRT->fxaaBuffer.bindTarget(); + screenTarget()->flush(); - S32 width = mRT->screen.getWidth(); - S32 height = mRT->screen.getHeight(); - glViewport(0, 0, width, height); + LLVertexBuffer::unbind(); + } - LLGLSLShader *shader = &gGlowCombineFXAAProgram; + if (RenderDeferred) + { + bool multisample = RenderFSAASamples > 1 && mRT->fxaaBuffer.isComplete() && !gCubeSnapshot; + LLGLSLShader* shader = &gGlowCombineProgram; - shader->bind(); - shader->uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, width, height); + S32 width = mRT->screen.getWidth(); + S32 height = mRT->screen.getHeight(); - S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->deferredLight.getUsage()); - if (channel > -1) - { - mRT->deferredLight.bindTexture(0, channel); - } + S32 channel = -1; - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex2f(-1, -1); - gGL.vertex2f(-1, 3); - gGL.vertex2f(3, -1); - gGL.end(); + // Present everything. + if (multisample) + { + LL_PROFILE_GPU_ZONE("aa"); + // bake out texture2D with RGBL for FXAA shader + mRT->fxaaBuffer.bindTarget(); - gGL.flush(); + glViewport(0, 0, width, height); - shader->disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->deferredLight.getUsage()); - shader->unbind(); + shader = &gGlowCombineFXAAProgram; - mRT->fxaaBuffer.flush(); + shader->bind(); + shader->uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, width, height); - shader = &gFXAAProgram; - shader->bind(); + channel = shader->enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->deferredLight.getUsage()); + if (channel > -1) + { + mRT->deferredLight.bindTexture(0, channel); + } - channel = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP, mRT->fxaaBuffer.getUsage()); - if (channel > -1) - { - mRT->fxaaBuffer.bindTexture(0, channel, LLTexUnit::TFO_BILINEAR); - } + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.vertex2f(-1, -1); + gGL.vertex2f(-1, 3); + gGL.vertex2f(3, -1); + gGL.end(); - gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; - gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; - gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth(); - gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); - glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); - - F32 scale_x = (F32) width / mRT->fxaaBuffer.getWidth(); - F32 scale_y = (F32) height / mRT->fxaaBuffer.getHeight(); - shader->uniform2f(LLShaderMgr::FXAA_TC_SCALE, scale_x, scale_y); - shader->uniform2f(LLShaderMgr::FXAA_RCP_SCREEN_RES, 1.f / width * scale_x, 1.f / height * scale_y); - shader->uniform4f(LLShaderMgr::FXAA_RCP_FRAME_OPT, -0.5f / width * scale_x, -0.5f / height * scale_y, - 0.5f / width * scale_x, 0.5f / height * scale_y); - shader->uniform4f(LLShaderMgr::FXAA_RCP_FRAME_OPT2, -2.f / width * scale_x, -2.f / height * scale_y, - 2.f / width * scale_x, 2.f / height * scale_y); + gGL.flush(); - gGL.begin(LLRender::TRIANGLE_STRIP); - gGL.vertex2f(-1, -1); - gGL.vertex2f(-1, 3); - gGL.vertex2f(3, -1); - gGL.end(); + shader->disableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mRT->deferredLight.getUsage()); + shader->unbind(); - gGL.flush(); - shader->unbind(); - } - } + mRT->fxaaBuffer.flush(); + + shader = &gFXAAProgram; + shader->bind(); + + channel = shader->enableTexture(LLShaderMgr::DIFFUSE_MAP, mRT->fxaaBuffer.getUsage()); + if (channel > -1) + { + mRT->fxaaBuffer.bindTexture(0, channel, LLTexUnit::TFO_BILINEAR); + } + + gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; + gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; + gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth(); + gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); + glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); + + F32 scale_x = (F32)width / mRT->fxaaBuffer.getWidth(); + F32 scale_y = (F32)height / mRT->fxaaBuffer.getHeight(); + shader->uniform2f(LLShaderMgr::FXAA_TC_SCALE, scale_x, scale_y); + shader->uniform2f(LLShaderMgr::FXAA_RCP_SCREEN_RES, 1.f / width * scale_x, 1.f / height * scale_y); + shader->uniform4f(LLShaderMgr::FXAA_RCP_FRAME_OPT, -0.5f / width * scale_x, -0.5f / height * scale_y, + 0.5f / width * scale_x, 0.5f / height * scale_y); + shader->uniform4f(LLShaderMgr::FXAA_RCP_FRAME_OPT2, -2.f / width * scale_x, -2.f / height * scale_y, + 2.f / width * scale_x, 2.f / height * scale_y); + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.vertex2f(-1, -1); + gGL.vertex2f(-1, 3); + gGL.vertex2f(3, -1); + gGL.end(); + + gGL.flush(); + shader->unbind(); + } + else + { + shader->bind(); + + + gGL.getTexUnit(0)->bind(&mGlow[1]); + gGL.getTexUnit(1)->bind(screenTarget()); + + gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; + gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; + gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth(); + gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight(); + glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]); + + gGL.begin(LLRender::TRIANGLE_STRIP); + gGL.vertex2f(-1, -1); + gGL.vertex2f(-1, 3); + gGL.vertex2f(3, -1); + gGL.end(); + + gGL.flush(); + shader->unbind(); + } + } + #if 0 // DEPRECATED else // not deferred { diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 0097b863ab..bac68cfff0 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -137,6 +137,8 @@ public: void generateImpostor(LLVOAvatar* avatar, bool preview_avatar = false); void bindScreenToTexture(); void renderFinalize(); + void renderPostProcess(); + LLRenderTarget* screenTarget(); void init(); void cleanup(); -- cgit v1.2.3