diff options
-rw-r--r-- | doc/testplans/material_preview.md | 81 | ||||
-rw-r--r-- | indra/llrender/llrendertarget.cpp | 27 | ||||
-rw-r--r-- | indra/llrender/llrendertarget.h | 3 | ||||
-rw-r--r-- | indra/newview/app_settings/shaders/class1/deferred/exposureF.glsl | 6 | ||||
-rw-r--r-- | indra/newview/lldynamictexture.cpp | 3 | ||||
-rw-r--r-- | indra/newview/llgltfmaterialpreviewmgr.cpp | 28 | ||||
-rw-r--r-- | indra/newview/llgltfmaterialpreviewmgr.h | 8 | ||||
-rw-r--r-- | indra/newview/lltexturectrl.cpp | 15 | ||||
-rw-r--r-- | indra/newview/lltexturectrl.h | 42 | ||||
-rw-r--r-- | indra/newview/llviewershadermgr.cpp | 17 | ||||
-rw-r--r-- | indra/newview/llviewershadermgr.h | 1 | ||||
-rw-r--r-- | indra/newview/pipeline.cpp | 71 | ||||
-rw-r--r-- | indra/newview/pipeline.h | 2 |
13 files changed, 246 insertions, 58 deletions
diff --git a/doc/testplans/material_preview.md b/doc/testplans/material_preview.md new file mode 100644 index 0000000000..d653fc45ca --- /dev/null +++ b/doc/testplans/material_preview.md @@ -0,0 +1,81 @@ +# Material Preview + +## Overview + +Material preview is a UI feature which displays a lit spherical preview of a PBR material. It can be found in the following UIs: + +- The material picker swatch + - In the build floater, in the Texture tab, when applying a PBR material + - (If the feature is enabled) In the Region/Estate floater, in the Terrain tab, when applying PBR materials to terrain +- In the floater to select a material from inventory, which can be opened by clicking the material picker swatch + +## Known Issues + +These are known issues that the current implementation of this feature does not address: + +- Material swatch preview is a preview of the base material ID only, and ignores other properties on the prim face like material overrides +- Alpha mask previews as alpha blend +- Double-sided previews as single-sided +- Material swatch preview inherits some of its lighting from the current environment, and reflections from the default reflection probe + +## General Regression Testing + +- Check that the material preview swatch looks OK with different materials selected +- Check that the material preview swatch runs reasonably well on different systems, especially when the select material from inventory floater is also open + - In particular: AMD, MacOS, minimum spec machines +- Watch out for regressions in rendering caused by opening a floater with a material preview swatch + +## Bug Fixes + +### Disappearing Objects Fix Test + +This test is recommended for verifying that secondlife/viewer-issues#72 is fixed. + +#### Symptoms + +The following types of objects could randomly disappear until relog in the main view when the bug occured: + +- Objects +- Water level in current region +- Adjacent region/void water + +Note: Disappearing objects in reflections have a different root cause and are not covered by the fix. + +#### Bug Reproduction Steps + +Verify the disappearing objects bug does not reproduce, given the following steps: + +- Runtime prerequisites: Material preview swatch is enabled ("UIPreviewMaterial") by visiting a test region with the feature enabled, or by manually enabling "UIPreviewMaterial" in the advanced settings for the current session +- Region prerequisites: Unknown, but a region with lots of stuff in it (like Rumpus Room 2048 on Aditi) seems to increase repro rate +- Right click an object and select, "Edit item" +- Go to texture tab, select PBR Metallic Roughness from dropdown, and click the button to select material from inventory +- Ensure "Apply now" is checked in the inventory selection floater +- Alternate between different materials from the inventory selection floater +- Look around the world and check for permanently disappeared objects. + +### Dynamic Exposure Influence Fix Test + +This test is recommended for verifying that secondlife/viewer-issues#72 is fixed. + +#### Symptoms + +Dynamic exposure in the world could be influenced by the material preview being displayed. If a material preview was being generated in a given frame, then, depending on the current environment, the user would observe an unpleasant flashing effect in the environment: + +- The world view could suddenly get darker and then fade back to normal exposure levels +- The world view could suddenly get brighter and then fade back to normal exposure levels + +#### Bug Reproduction Steps + +Verify the dynamic exposure influence bug does not reproduce. Test using a few environment presets such as Default Midday, Sunset, and Midnight. + +- Right click an object and select, "Edit item" +- Go to texture tab, select PBR Metallic Roughness from dropdown, and click the button to select material from inventory +- Alternate between different materials from the inventory selection floater + +#### Regression Testing + +Dynamic exposure in the world should continue to work correctly. In particular: + +- Exposure should fade gradually from high exposure to low exposure and back as needed +- Exposure should decrease in brighter environments +- Exposure should increase in darker environments diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp index 88c48e5166..9cd7527d3e 100644 --- a/indra/llrender/llrendertarget.cpp +++ b/indra/llrender/llrendertarget.cpp @@ -567,4 +567,31 @@ bool LLRenderTarget::isBoundInStack() const return cur == this; } +void LLRenderTarget::swapFBORefs(LLRenderTarget& other) +{ + // Must be initialized + llassert(mFBO); + llassert(other.mFBO); + // Must be unbound + // *NOTE: mPreviousRT can be non-null even if this target is unbound - presumably for debugging purposes? + llassert(sCurFBO != mFBO); + llassert(sCurFBO != other.mFBO); + llassert(!isBoundInStack()); + llassert(!other.isBoundInStack()); + + // Must be same type + llassert(sUseFBO == other.sUseFBO); + llassert(mResX == other.mResX); + llassert(mResY == other.mResY); + llassert(mInternalFormat == other.mInternalFormat); + llassert(mTex.size() == other.mTex.size()); + llassert(mDepth == other.mDepth); + llassert(mUseDepth == other.mUseDepth); + llassert(mGenerateMipMaps == other.mGenerateMipMaps); + llassert(mMipLevels == other.mMipLevels); + llassert(mUsage == other.mUsage); + + std::swap(mFBO, other.mFBO); + std::swap(mTex, other.mTex); +} diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h index 9fcea35e3d..da401572d1 100644 --- a/indra/llrender/llrendertarget.h +++ b/indra/llrender/llrendertarget.h @@ -169,6 +169,9 @@ public: static LLRenderTarget* getCurrentBoundTarget() { return sBoundTarget; } + // *HACK + void swapFBORefs(LLRenderTarget& other); + protected: U32 mResX; U32 mResY; diff --git a/indra/newview/app_settings/shaders/class1/deferred/exposureF.glsl b/indra/newview/app_settings/shaders/class1/deferred/exposureF.glsl index 9ac4ceb37e..eff7221ae7 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/exposureF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/exposureF.glsl @@ -28,7 +28,9 @@ out vec4 frag_color; uniform sampler2D emissiveRect; +#ifdef USE_LAST_EXPOSURE uniform sampler2D exposureMap; +#endif uniform float dt; uniform vec2 noiseVec; @@ -51,10 +53,12 @@ void main() L /= max_L; L = pow(L, 2.0); float s = mix(dynamic_exposure_params.z, dynamic_exposure_params.y, L); - + +#ifdef USE_LAST_EXPOSURE float prev = texture(exposureMap, vec2(0.5,0.5)).r; s = mix(prev, s, min(dt*2.0*abs(prev-s), 0.04)); +#endif frag_color = max(vec4(s, s, s, dt), vec4(0.0)); } diff --git a/indra/newview/lldynamictexture.cpp b/indra/newview/lldynamictexture.cpp index a66c3876fc..24818241ab 100644 --- a/indra/newview/lldynamictexture.cpp +++ b/indra/newview/lldynamictexture.cpp @@ -118,6 +118,8 @@ BOOL LLViewerDynamicTexture::render() //----------------------------------------------------------------------------- void LLViewerDynamicTexture::preRender(BOOL clear_depth) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; + //use the bottom left corner mOrigin.set(0, 0); @@ -219,7 +221,6 @@ BOOL LLViewerDynamicTexture::updateAllInstances() llassert(dynamicTexture->getFullHeight() <= LLPipeline::MAX_BAKE_WIDTH); glClear(GL_DEPTH_BUFFER_BIT); - gDepthDirty = TRUE; gGL.color4f(1,1,1,1); dynamicTexture->setBoundTarget(&bake_target); diff --git a/indra/newview/llgltfmaterialpreviewmgr.cpp b/indra/newview/llgltfmaterialpreviewmgr.cpp index 901db87eed..1c39f1ae7d 100644 --- a/indra/newview/llgltfmaterialpreviewmgr.cpp +++ b/indra/newview/llgltfmaterialpreviewmgr.cpp @@ -58,6 +58,15 @@ LLGLTFPreviewTexture::MaterialLoadLevels::MaterialLoadLevels() } } +bool LLGLTFPreviewTexture::MaterialLoadLevels::isFullyLoaded() +{ + for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i) + { + if (levels[i] != FULLY_LOADED) { return false; } + } + return true; +} + S32& LLGLTFPreviewTexture::MaterialLoadLevels::operator[](size_t i) { llassert(i >= 0 && i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT); @@ -187,17 +196,26 @@ LLPointer<LLGLTFPreviewTexture> LLGLTFPreviewTexture::create(LLPointer<LLFetched return new LLGLTFPreviewTexture(material, LLPipeline::MAX_BAKE_WIDTH); } -void LLGLTFPreviewTexture::preRender(BOOL clear_depth) +BOOL LLGLTFPreviewTexture::needsRender() { LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; + if (!mShouldRender && mBestLoad.isFullyLoaded()) { return false; } MaterialLoadLevels current_load = get_material_load_levels(*mGLTFMaterial.get()); if (current_load < mBestLoad) { mShouldRender = true; mBestLoad = current_load; + return true; } + return false; +} +void LLGLTFPreviewTexture::preRender(BOOL clear_depth) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; + + llassert(mShouldRender); if (!mShouldRender) { return; } LLViewerDynamicTexture::preRender(clear_depth); @@ -499,9 +517,12 @@ BOOL LLGLTFPreviewTexture::render() screen.flush(); } + // *HACK: Hide mExposureMap from generateExposure + gPipeline.mExposureMap.swapFBORefs(gPipeline.mLastExposure); + gPipeline.copyScreenSpaceReflections(&screen, &gPipeline.mSceneMap); gPipeline.generateLuminance(&screen, &gPipeline.mLuminanceMap); - gPipeline.generateExposure(&gPipeline.mLuminanceMap, &gPipeline.mExposureMap); + gPipeline.generateExposure(&gPipeline.mLuminanceMap, &gPipeline.mExposureMap, /*use_history = */ false); gPipeline.gammaCorrect(&screen, &gPipeline.mPostMap); LLVertexBuffer::unbind(); gPipeline.generateGlow(&gPipeline.mPostMap); @@ -509,6 +530,9 @@ BOOL LLGLTFPreviewTexture::render() gPipeline.renderDoF(&screen, &gPipeline.mPostMap); gPipeline.applyFXAA(&gPipeline.mPostMap, &screen); + // *HACK: Restore mExposureMap (it will be consumed by generateExposure next frame) + gPipeline.mExposureMap.swapFBORefs(gPipeline.mLastExposure); + // Final render gDeferredPostNoDoFProgram.bind(); diff --git a/indra/newview/llgltfmaterialpreviewmgr.h b/indra/newview/llgltfmaterialpreviewmgr.h index cc40a6f2e2..981c8b0592 100644 --- a/indra/newview/llgltfmaterialpreviewmgr.h +++ b/indra/newview/llgltfmaterialpreviewmgr.h @@ -40,7 +40,7 @@ public: // Width scales with size of material's textures static LLPointer<LLGLTFPreviewTexture> create(LLPointer<LLFetchedGLTFMaterial> material); - BOOL needsRender() override { return mNeedsRender; } + BOOL needsRender() override; void preRender(BOOL clear_depth = TRUE) override; BOOL render() override; void postRender(BOOL success) override; @@ -50,15 +50,12 @@ public: S32 levels[LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT]; MaterialLoadLevels(); - + bool isFullyLoaded(); S32& operator[](size_t i); - const S32& operator[](size_t i) const; - // Less is better // Returns false if lhs is not strictly less or equal for all levels bool operator<(const MaterialLoadLevels& other) const; - // Less is better // Returns false if lhs is not strictly greater or equal for all levels bool operator>(const MaterialLoadLevels& other) const; @@ -66,7 +63,6 @@ public: private: LLPointer<LLFetchedGLTFMaterial> mGLTFMaterial; - bool mNeedsRender = true; bool mShouldRender = true; MaterialLoadLevels mBestLoad; }; diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp index 5415f9bd9a..d9001bc16a 100644 --- a/indra/newview/lltexturectrl.cpp +++ b/indra/newview/lltexturectrl.cpp @@ -538,6 +538,8 @@ void LLFloaterTexturePicker::onClose(bool app_quitting) } stopUsingPipette(); sLastPickerMode = mModeSelector->getValue().asInteger(); + // *NOTE: Vertex buffer for sphere preview is still cached + mGLTFPreview = nullptr; } // virtual @@ -1760,6 +1762,19 @@ void LLTextureCtrl::setFilterPermissionMasks(PermissionMask mask) setDnDFilterPermMask(mask); } +void LLTextureCtrl::onVisibilityChange(BOOL new_visibility) +{ + if (!new_visibility) + { + // *NOTE: Vertex buffer for sphere preview is still cached + mGLTFPreview = nullptr; + } + else + { + llassert(!mGLTFPreview); + } +} + void LLTextureCtrl::setVisible( BOOL visible ) { if( !visible ) diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h index 05ea185b1b..f193b0c083 100644 --- a/indra/newview/lltexturectrl.h +++ b/indra/newview/lltexturectrl.h @@ -148,26 +148,28 @@ public: // LLView interface - virtual BOOL handleMouseDown(S32 x, S32 y, MASK mask); - virtual BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, - BOOL drop, EDragAndDropType cargo_type, void *cargo_data, - EAcceptance *accept, - std::string& tooltip_msg); - virtual BOOL handleHover(S32 x, S32 y, MASK mask); - virtual BOOL handleUnicodeCharHere(llwchar uni_char); - - virtual void draw(); - virtual void setVisible( BOOL visible ); - virtual void setEnabled( BOOL enabled ); - - void setValid(BOOL valid); - - // LLUICtrl interface - virtual void clear(); - - // Takes a UUID, wraps get/setImageAssetID - virtual void setValue(const LLSD& value); - virtual LLSD getValue() const; + BOOL handleMouseDown(S32 x, S32 y, MASK mask) override; + BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, + BOOL drop, EDragAndDropType cargo_type, void *cargo_data, + EAcceptance *accept, + std::string& tooltip_msg) override; + BOOL handleHover(S32 x, S32 y, MASK mask) override; + BOOL handleUnicodeCharHere(llwchar uni_char) override; + + void draw() override; + void setVisible( BOOL visible ) override; + void setEnabled( BOOL enabled ) override; + + void onVisibilityChange(BOOL new_visibility) override; + + void setValid(BOOL valid); + + // LLUICtrl interface + void clear() override; + + // Takes a UUID, wraps get/setImageAssetID + void setValue(const LLSD& value) override; + LLSD getValue() const override; // LLTextureCtrl interface void showPicker(BOOL take_focus); diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 4eb934114d..354cc79036 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -196,6 +196,7 @@ LLGLSLShader gDeferredPostGammaCorrectProgram; LLGLSLShader gNoPostGammaCorrectProgram; LLGLSLShader gLegacyPostGammaCorrectProgram; LLGLSLShader gExposureProgram; +LLGLSLShader gExposureProgramNoFade; LLGLSLShader gLuminanceProgram; LLGLSLShader gFXAAProgram; LLGLSLShader gDeferredPostNoDoFProgram; @@ -980,6 +981,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredCoFProgram.unload(); gDeferredDoFCombineProgram.unload(); gExposureProgram.unload(); + gExposureProgramNoFade.unload(); gLuminanceProgram.unload(); gDeferredPostGammaCorrectProgram.unload(); gNoPostGammaCorrectProgram.unload(); @@ -2127,6 +2129,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gExposureProgram.mFeatures.isDeferred = true; gExposureProgram.mShaderFiles.clear(); gExposureProgram.clearPermutations(); + gExposureProgram.addPermutation("USE_LAST_EXPOSURE", "1"); gExposureProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER)); gExposureProgram.mShaderFiles.push_back(make_pair("deferred/exposureF.glsl", GL_FRAGMENT_SHADER)); gExposureProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; @@ -2136,6 +2139,20 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() if (success) { + gExposureProgramNoFade.mName = "Exposure (no fade)"; + gExposureProgramNoFade.mFeatures.hasSrgb = true; + gExposureProgramNoFade.mFeatures.isDeferred = true; + gExposureProgramNoFade.mShaderFiles.clear(); + gExposureProgramNoFade.clearPermutations(); + gExposureProgramNoFade.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER)); + gExposureProgramNoFade.mShaderFiles.push_back(make_pair("deferred/exposureF.glsl", GL_FRAGMENT_SHADER)); + gExposureProgramNoFade.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + success = gExposureProgramNoFade.createShader(NULL, NULL); + llassert(success); + } + + if (success) + { gLuminanceProgram.mName = "Luminance"; gLuminanceProgram.mShaderFiles.clear(); gLuminanceProgram.clearPermutations(); diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index 57fc66ce0d..2502be6bb1 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -249,6 +249,7 @@ extern LLGLSLShader gDeferredPostGammaCorrectProgram; extern LLGLSLShader gNoPostGammaCorrectProgram; extern LLGLSLShader gLegacyPostGammaCorrectProgram; extern LLGLSLShader gExposureProgram; +extern LLGLSLShader gExposureProgramNoFade; extern LLGLSLShader gLuminanceProgram; extern LLGLSLShader gDeferredAvatarShadowProgram; extern LLGLSLShader gDeferredAvatarAlphaShadowProgram; diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 9d90002eb9..6ceaca731b 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -6772,11 +6772,12 @@ void LLPipeline::generateLuminance(LLRenderTarget* src, LLRenderTarget* dst) } } -void LLPipeline::generateExposure(LLRenderTarget* src, LLRenderTarget* dst) { +void LLPipeline::generateExposure(LLRenderTarget* src, LLRenderTarget* dst, bool use_history) { // exposure sample { LL_PROFILE_GPU_ZONE("exposure sample"); + if (use_history) { // copy last frame's exposure into mLastExposure mLastExposure.bindTarget(); @@ -6793,51 +6794,67 @@ void LLPipeline::generateExposure(LLRenderTarget* src, LLRenderTarget* dst) { LLGLDepthTest depth(GL_FALSE, GL_FALSE); - gExposureProgram.bind(); + LLGLSLShader* shader; + if (use_history) + { + shader = &gExposureProgram; + } + else + { + shader = &gExposureProgramNoFade; + } + + shader->bind(); - S32 channel = gExposureProgram.enableTexture(LLShaderMgr::DEFERRED_EMISSIVE); + S32 channel = shader->enableTexture(LLShaderMgr::DEFERRED_EMISSIVE); if (channel > -1) { - mLuminanceMap.bindTexture(0, channel, LLTexUnit::TFO_TRILINEAR); + src->bindTexture(0, channel, LLTexUnit::TFO_TRILINEAR); } - channel = gExposureProgram.enableTexture(LLShaderMgr::EXPOSURE_MAP); - if (channel > -1) + if (use_history) { - mLastExposure.bindTexture(0, channel); + channel = shader->enableTexture(LLShaderMgr::EXPOSURE_MAP); + if (channel > -1) + { + mLastExposure.bindTexture(0, channel); + } } static LLStaticHashedString dt("dt"); static LLStaticHashedString noiseVec("noiseVec"); static LLStaticHashedString dynamic_exposure_params("dynamic_exposure_params"); static LLCachedControl<F32> dynamic_exposure_coefficient(gSavedSettings, "RenderDynamicExposureCoefficient", 0.175f); - static LLCachedControl<bool> should_auto_adjust(gSavedSettings, "RenderSkyAutoAdjustLegacy", true); + static LLCachedControl<bool> should_auto_adjust(gSavedSettings, "RenderSkyAutoAdjustLegacy", true); - LLSettingsSky::ptr_t sky = LLEnvironment::instance().getCurrentSky(); + LLSettingsSky::ptr_t sky = LLEnvironment::instance().getCurrentSky(); - F32 probe_ambiance = LLEnvironment::instance().getCurrentSky()->getReflectionProbeAmbiance(should_auto_adjust); - F32 exp_min = 1.f; - F32 exp_max = 1.f; - - if (probe_ambiance > 0.f) - { - F32 hdr_scale = sqrtf(LLEnvironment::instance().getCurrentSky()->getGamma())*2.f; + F32 probe_ambiance = LLEnvironment::instance().getCurrentSky()->getReflectionProbeAmbiance(should_auto_adjust); + F32 exp_min = 1.f; + F32 exp_max = 1.f; - if (hdr_scale > 1.f) - { - exp_min = 1.f / hdr_scale; - exp_max = hdr_scale; - } - } - gExposureProgram.uniform1f(dt, gFrameIntervalSeconds); - gExposureProgram.uniform2f(noiseVec, ll_frand() * 2.0 - 1.0, ll_frand() * 2.0 - 1.0); - gExposureProgram.uniform3f(dynamic_exposure_params, dynamic_exposure_coefficient, exp_min, exp_max); + if (probe_ambiance > 0.f) + { + F32 hdr_scale = sqrtf(LLEnvironment::instance().getCurrentSky()->getGamma()) * 2.f; + + if (hdr_scale > 1.f) + { + exp_min = 1.f / hdr_scale; + exp_max = hdr_scale; + } + } + shader->uniform1f(dt, gFrameIntervalSeconds); + shader->uniform2f(noiseVec, ll_frand() * 2.0 - 1.0, ll_frand() * 2.0 - 1.0); + shader->uniform3f(dynamic_exposure_params, dynamic_exposure_coefficient, exp_min, exp_max); mScreenTriangleVB->setBuffer(); mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); - gGL.getTexUnit(channel)->unbind(mLastExposure.getUsage()); - gExposureProgram.unbind(); + if (use_history) + { + gGL.getTexUnit(channel)->unbind(mLastExposure.getUsage()); + } + shader->unbind(); dst->flush(); } } diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index e8c6da1473..259dc3f9d0 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -154,7 +154,7 @@ public: void renderFinalize(); void copyScreenSpaceReflections(LLRenderTarget* src, LLRenderTarget* dst); void generateLuminance(LLRenderTarget* src, LLRenderTarget* dst); - void generateExposure(LLRenderTarget* src, LLRenderTarget* dst); + void generateExposure(LLRenderTarget* src, LLRenderTarget* dst, bool use_history = true); void gammaCorrect(LLRenderTarget* src, LLRenderTarget* dst); void generateGlow(LLRenderTarget* src); void applyFXAA(LLRenderTarget* src, LLRenderTarget* dst); |