diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index a32537357f..b7708453ff 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -1402,6 +1402,7 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("screenTex"); mReservedUniforms.push_back("screenDepth"); mReservedUniforms.push_back("refTex"); + mReservedUniforms.push_back("exclusionTex"); mReservedUniforms.push_back("eyeVec"); mReservedUniforms.push_back("time"); mReservedUniforms.push_back("waveDir1"); diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index e672b07068..356b075026 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -36,6 +36,8 @@ public: LLShaderMgr(); virtual ~LLShaderMgr(); + // Note: although you can use statically hashed strings to just bind a random uniform, it's generally preferably that you use this. + // Always document what the actual shader uniform is next to the shader uniform in this struct. // clang-format off typedef enum { // Shader uniform name, set in LLShaderMgr::initAttribsAndUniforms() @@ -238,6 +240,7 @@ public: WATER_SCREENTEX, // "screenTex" WATER_SCREENDEPTH, // "screenDepth" WATER_REFTEX, // "refTex" + WATER_EXCLUSIONTEX, // "exclusionTex" WATER_EYEVEC, // "eyeVec" WATER_TIME, // "time" WATER_WAVE_DIR1, // "waveDir1" diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 73c491fe4b..d76ea0ffeb 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -28,6 +28,7 @@ #include "llfolderview.h" #include "llfolderviewmodel.h" +#include "llcallbacklist.h" #include "llclipboard.h" // *TODO: remove this once hack below gone. #include "llkeyboard.h" #include "lllineeditor.h" @@ -278,7 +279,11 @@ LLFolderView::~LLFolderView( void ) mRenamer = NULL; mStatusTextBox = NULL; - if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die(); + if (mPopupMenuHandle.get()) + { + mPopupMenuHandle.get()->die(); + gIdleCallbacks.deleteFunction(onIdleUpdateMenu, this); + } mPopupMenuHandle.markDead(); mAutoOpenItems.removeAllNodes(); @@ -1132,7 +1137,10 @@ bool LLFolderView::handleKeyHere( KEY key, MASK mask ) LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); if (menu && menu->isOpen()) { - LLMenuGL::sMenuContainer->hideMenus(); + if (LLMenuGL::sMenuContainer->hideMenus()) + { + gIdleCallbacks.deleteFunction(onIdleUpdateMenu, this); + } } switch( key ) @@ -1417,7 +1425,10 @@ bool LLFolderView::handleUnicodeCharHere(llwchar uni_char) LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); if (menu && menu->isOpen()) { - LLMenuGL::sMenuContainer->hideMenus(); + if (LLMenuGL::sMenuContainer->hideMenus()) + { + gIdleCallbacks.deleteFunction(onIdleUpdateMenu, this); + } } //do text search @@ -1706,7 +1717,11 @@ void LLFolderView::deleteAllChildren() { LLUI::getInstance()->removePopup(mRenamer); } - if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die(); + if (mPopupMenuHandle.get()) + { + mPopupMenuHandle.get()->die(); + gIdleCallbacks.deleteFunction(onIdleUpdateMenu, this); + } mPopupMenuHandle.markDead(); mScrollContainer = NULL; mRenameItem = NULL; @@ -2073,9 +2088,24 @@ void LLFolderView::updateMenu() LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); if (menu && menu->getVisible()) { - updateMenuOptions(menu); + // When fetching folders in bulk or in parts, each callback + // cause updateMenu individually, so make sure it gets called + // only once per frame, after callbacks are done. + // gIdleCallbacks has built in dupplicate protection. + gIdleCallbacks.addFunction(onIdleUpdateMenu, this); + } +} + +void LLFolderView::onIdleUpdateMenu(void* user_data) +{ + LLFolderView* self = (LLFolderView*)user_data; + LLMenuGL* menu = (LLMenuGL*)self->mPopupMenuHandle.get(); + if (menu) + { + self->updateMenuOptions(menu); menu->needsArrange(); // update menu height if needed } + gIdleCallbacks.deleteFunction(onIdleUpdateMenu, NULL); } bool LLFolderView::isFolderSelected() diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h index 7d989260c1..371caa2850 100644 --- a/indra/llui/llfolderview.h +++ b/indra/llui/llfolderview.h @@ -271,6 +271,7 @@ public: private: void updateMenuOptions(LLMenuGL* menu); void updateRenamerPosition(); + static void onIdleUpdateMenu(void* user_data); protected: LLScrollContainer* mScrollContainer; // NULL if this is not a child of a scroll container. diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index d2a0bb629b..a4ab4a66a7 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -273,6 +273,7 @@ set(viewer_SOURCE_FILES lldrawpooltree.cpp lldrawpoolwater.cpp lldrawpoolwlsky.cpp + lldrawpoolwaterexclusion.cpp lldynamictexture.cpp llemote.cpp llenvironment.cpp @@ -1088,6 +1089,7 @@ set(viewer_HEADER_FILES lldrawpooltree.h lldrawpoolwater.h lldrawpoolwlsky.h + lldrawpoolwaterexclusion.h lldynamictexture.h llemote.h llenvironment.h diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleColorF.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleColorF.glsl new file mode 100644 index 0000000000..dea76da5a5 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/objects/simpleColorF.glsl @@ -0,0 +1,57 @@ +/** + * @file simpleColorF.glsl + * + * $LicenseInfo:firstyear=2025&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +out vec4 frag_color; + +in vec4 vertex_color; +in vec4 vertex_position; + +uniform vec4 waterPlane; +uniform float waterSign; + +void waterClip(vec3 pos) +{ + // TODO: make this less branchy + if (waterSign > 0) + { + if ((dot(pos.xyz, waterPlane.xyz) + waterPlane.w) < 0.0) + { + discard; + } + } + else + { + if ((dot(pos.xyz, waterPlane.xyz) + waterPlane.w) > 0.0) + { + discard; + } + } +} + +void main() +{ + + frag_color = vertex_color; +} diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleNoAtmosV.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleNoAtmosV.glsl new file mode 100644 index 0000000000..4564e56313 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/objects/simpleNoAtmosV.glsl @@ -0,0 +1,43 @@ +/** + * @file simpleNoAtmosV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +uniform mat4 modelview_matrix; +uniform mat4 modelview_projection_matrix; + +uniform vec4 color; + +in vec3 position; + +out vec4 vertex_color; +out vec4 vertex_position; + +void main() +{ + //transform vertex + vec4 pos = (modelview_matrix * vec4(position.xyz, 1.0)); + vertex_position = modelview_projection_matrix * vec4(position.xyz, 1.0); + gl_Position = vertex_position; + vertex_color = color; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl index a975b1f121..136b3dd966 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl @@ -789,9 +789,6 @@ void sampleReflectionProbesWater(inout vec3 ambenv, inout vec3 glossenv, probeIndex[probeInfluences++] = 0; doProbeSample(ambenv, glossenv, tc, pos, norm, glossiness, false, amblit); - - // fudge factor to get PBR water at a similar luminance ot legacy water - glossenv *= 0.4; } void debugTapRefMap(vec3 pos, vec3 dir, float depth, int i, inout vec4 col) diff --git a/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl index ee49b4baae..091c25d15e 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl @@ -35,13 +35,25 @@ vec4 getWaterFogView(vec3 pos); uniform int above_water; +uniform sampler2D exclusionTex; + void main() { vec2 tc = vary_fragcoord.xy/vary_fragcoord.w*0.5+0.5; float depth = getDepth(tc.xy); + float mask = texture(exclusionTex, tc.xy).r; if (above_water > 0) { + // Just discard if we're in the exclusion mask. + // The previous invisiprim hack we're replacing would also crank up water fog desntiy. + // But doing that makes exclusion surfaces very slow as we'd need to render even more into the mask. + // - Geenz 2025-02-06 + if (mask < 1) + { + discard; + } + // we want to depth test when the camera is above water, but some GPUs have a hard time // with depth testing against render targets that are bound for sampling in the same shader // so we do it manually here @@ -51,12 +63,14 @@ void main() { discard; } + } vec4 pos = getPositionWithDepth(tc, depth); vec4 fogged = getWaterFogView(pos.xyz); fogged.a = max(pow(fogged.a, 1.7), 0); + frag_color = max(fogged, vec4(0)); //output linear since local lights will be added to this shader's results } diff --git a/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl b/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl index 1c02dc764d..fa410e9f11 100644 --- a/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl +++ b/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl @@ -26,6 +26,7 @@ out vec4 frag_color; uniform sampler2D bumpMap; +uniform sampler2D exclusionTex; #ifdef TRANSPARENT_WATER uniform sampler2D screenTex; @@ -59,6 +60,9 @@ void mirrorClip(vec3 position); void main() { mirrorClip(vary_position); + vec2 screen_tc = (refCoord.xy/refCoord.z) * 0.5 + 0.5; + float water_mask = texture(exclusionTex, screen_tc).r; + vec4 color; //get detail normals @@ -68,8 +72,8 @@ void main() vec3 wavef = normalize(wave1+wave2+wave3); //figure out distortion vector (ripply) - vec2 distort = (refCoord.xy/refCoord.z) * 0.5 + 0.5; - distort = distort+wavef.xy*refScale; + vec2 distort = screen_tc; + distort = mix(distort, distort+wavef.xy*refScale, water_mask); #ifdef TRANSPARENT_WATER vec4 fb = texture(screenTex, distort); diff --git a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl index f9e300070d..7027e3796e 100644 --- a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl +++ b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl @@ -25,6 +25,8 @@ // class3/environment/waterF.glsl +#define WATER_MINIMAL 1 + out vec4 frag_color; #ifdef HAS_SUN_SHADOW @@ -86,7 +88,7 @@ uniform sampler2D screenTex; uniform sampler2D depthMap; #endif -uniform sampler2D refTex; +uniform sampler2D exclusionTex; uniform float sunAngle; uniform float sunAngle2; @@ -122,6 +124,9 @@ vec3 BlendNormal(vec3 bump1, vec3 bump2) vec3 srgb_to_linear(vec3 col); vec3 linear_to_srgb(vec3 col); +vec3 atmosLighting(vec3 light); +vec3 scaleSoftClip(vec3 light); + vec3 vN, vT, vB; vec3 transform_normal(vec3 vNt) @@ -148,7 +153,7 @@ void generateWaveNormals(out vec3 wave1, out vec3 wave2, out vec3 wave3) vec2 bigwave = vec2(refCoord.w, view.w); - vec3 wave1_a = texture(bumpMap, bigwave, -2).xyz * 2.0 - 1.0; + vec3 wave1_a = texture(bumpMap, bigwave).xyz * 2.0 - 1.0; vec3 wave2_a = texture(bumpMap, littleWave.xy).xyz * 2.0 - 1.0; vec3 wave3_a = texture(bumpMap, littleWave.zw).xyz * 2.0 - 1.0; @@ -183,6 +188,7 @@ void calculateFresnelFactors(out vec3 df3, out vec2 df2, vec3 viewVec, vec3 wave void main() { mirrorClip(vary_position); + vN = vary_normal; vT = vary_tangent; vB = cross(vN, vT); @@ -202,6 +208,7 @@ void main() generateWaveNormals(wave1, wave2, wave3); + float dmod = sqrt(dist); vec2 distort = (refCoord.xy/refCoord.z) * 0.5 + 0.5; vec3 wavef = (wave1 + wave2 * 0.4 + wave3 * 0.6) * 0.5; @@ -216,7 +223,7 @@ void main() vec3 up = transform_normal(vec3(0,0,1)); float vdu = -dot(viewVec, up)*2; - vec3 wave_ibl = wavef; + vec3 wave_ibl = wavef * normScale; wave_ibl.z *= 2.0; wave_ibl = transform_normal(normalize(wave_ibl)); @@ -233,8 +240,6 @@ void main() float dist2 = dist; dist = max(dist, 5.0); - float dmod = sqrt(dist); - //figure out distortion vector (ripply) vec2 distort2 = distort + waver.xy * refScale / max(dmod, 1.0) * 2; @@ -247,6 +252,8 @@ void main() float shadow = 1.0f; + float water_mask = texture(exclusionTex, distort).r; + #ifdef HAS_SUN_SHADOW shadow = sampleDirectionalShadow(pos.xyz, norm.xyz, distort); #endif @@ -254,23 +261,31 @@ void main() calcAtmosphericVarsLinear(pos.xyz, wavef, vary_light_dir, sunlit, amblit, additive, atten); vec3 sunlit_linear = srgb_to_linear(sunlit); - + float fade = 0; #ifdef TRANSPARENT_WATER - float depth = texture(depthMap, distort2).r; - vec4 fb = texture(screenTex, distort2); - vec3 refPos = getPositionWithNDC(vec3(distort2*2.0-vec2(1.0), depth*2.0-1.0)); + float depth = texture(depthMap, distort).r; - if (refPos.z > pos.z-0.05) + vec3 refPos = getPositionWithNDC(vec3(distort*2.0-vec2(1.0), depth*2.0-1.0)); + + // Calculate some distance fade in the water to better assist with refraction blending and reducing the refraction texture's "disconnect". + fade = max(0,min(1, (pos.z - refPos.z) / 10)) * water_mask; + distort2 = mix(distort, distort2, min(1, fade * 10)); + depth = texture(depthMap, distort2).r; + + refPos = getPositionWithNDC(vec3(distort2 * 2.0 - vec2(1.0), depth * 2.0 - 1.0)); + + if (pos.z < refPos.z - 0.05) { - //we sampled an above water sample, don't distort distort2 = distort; - fb = texture(screenTex, distort2); - depth = texture(depthMap, distort2).r; - refPos = getPositionWithNDC(vec3(distort2 * 2.0 - vec2(1.0), depth * 2.0 - 1.0)); } + vec4 fb = texture(screenTex, distort2); + #else vec4 fb = applyWaterFogViewLinear(viewVec*2048.0, vec4(1.0)); + + if (water_mask < 1) + discard; #endif float metallic = 1.0; @@ -280,13 +295,18 @@ void main() vec3 irradiance = vec3(0); vec3 radiance = vec3(0); vec3 legacyenv = vec3(0); + + // TODO: Make this an option. +#ifdef WATER_MINIMAL sampleReflectionProbesWater(irradiance, radiance, distort2, pos.xyz, wave_ibl.xyz, gloss, amblit); - //sampleReflectionProbes(irradiance, radiance, distort2, pos.xyz, wave_ibl.xyz, 1, true, amblit); - //sampleReflectionProbesLegacy(irradiance, radiance, legacyenv, distort2, pos.xyz, wave_ibl.xyz, gloss, 1, false, amblit); +#elif WATER_MINIMAL_PLUS + sampleReflectionProbes(irradiance, radiance, distort2, pos.xyz, wave_ibl.xyz, 1, false, amblit); +#endif vec3 diffuseColor = vec3(0); vec3 specularColor = vec3(0); - calcDiffuseSpecular(vec3(1), metallic, diffuseColor, specularColor); + vec3 specular_linear = srgb_to_linear(specular); + calcDiffuseSpecular(specular_linear, metallic, diffuseColor, specularColor); vec3 v = -normalize(pos.xyz); @@ -302,14 +322,22 @@ void main() pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, normalize(wavef+up*max(dist, 32.0)/32.0*(1.0-vdu)), v, normalize(light_dir), nl, diffPunc, specPunc); - vec3 punctual = clamp(nl * (diffPunc + specPunc), vec3(0), vec3(10)) * sunlit_linear * 2.75 * shadow; + vec3 punctual = clamp(nl * (diffPunc + specPunc), vec3(0), vec3(10)) * sunlit_linear * shadow; vec3 color = vec3(0); + color = mix(fb.rgb, radiance * df2.y, df2.x * 0.99999) + punctual.rgb; - color = mix(fb.rgb, radiance * df2.x, df2.x * 0.99999) + punctual.rgb; + // This looks super janky, but we do this to restore water haze in the distance. + // These values were finagled in to try and bring back some of the distant brightening on legacy water. Also works reasonably well on PBR skies such as PBR midday. + color += color * min(vec3(4),pow(1 - atten, vec3(1.35)) * 16 * fade); + + // We shorten the fade here at the shoreline so it doesn't appear too soft from a distance. + fade *= 60; + fade = min(1, fade); + color = mix(fb.rgb, color, fade); float spec = min(max(max(punctual.r, punctual.g), punctual.b), 0.05); - frag_color = max(vec4(color.rgb, spec), vec4(0)); + frag_color = min(vec4(1),max(vec4(color.rgb, spec * water_mask), vec4(0))); } diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp index 40be824fe9..5cf712074e 100644 --- a/indra/newview/llconversationmodel.cpp +++ b/indra/newview/llconversationmodel.cpp @@ -359,8 +359,9 @@ void LLConversationItemSession::clearParticipants() void LLConversationItemSession::clearAndDeparentModels() { - for (LLFolderViewModelItem* child : mChildren) + for (child_list_t::iterator it = mChildren.begin(); it != mChildren.end();) { + LLFolderViewModelItem* child = *it; if (child->getNumRefs() == 0) { // LLConversationItemParticipant can be created but not assigned to any view, @@ -372,8 +373,8 @@ void LLConversationItemSession::clearAndDeparentModels() // Model is still assigned to some view/widget child->setParent(NULL); } + it = mChildren.erase(it); } - mChildren.clear(); } LLConversationItemParticipant* LLConversationItemSession::findParticipant(const LLUUID& participant_id) diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index e5038dfd13..2f29ac61db 100644 --- a/indra/newview/lldrawpool.cpp +++ b/indra/newview/lldrawpool.cpp @@ -42,6 +42,7 @@ #include "lldrawpooltree.h" #include "lldrawpoolterrain.h" #include "lldrawpoolwater.h" +#include "lldrawpoolwaterexclusion.h" #include "llface.h" #include "llviewerobjectlist.h" // For debug listing. #include "pipeline.h" @@ -119,6 +120,9 @@ LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerTexture *tex0) case POOL_GLTF_PBR_ALPHA_MASK: poolp = new LLDrawPoolGLTFPBR(LLDrawPool::POOL_GLTF_PBR_ALPHA_MASK); break; + case POOL_WATEREXCLUSION: + poolp = new LLDrawPoolWaterExclusion(); + break; default: LL_ERRS() << "Unknown draw pool type!" << LL_ENDL; return NULL; diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h index bc412214c7..1c8864a9df 100644 --- a/indra/newview/lldrawpool.h +++ b/indra/newview/lldrawpool.h @@ -55,6 +55,7 @@ public: // based on fill rate and likelihood to occlude future passes (faster, large occluders first). // POOL_SKY = 1, + POOL_WATEREXCLUSION, POOL_WL_SKY, POOL_SIMPLE, POOL_FULLBRIGHT, @@ -140,7 +141,7 @@ public: PASS_GRASS, PASS_FULLBRIGHT, PASS_FULLBRIGHT_RIGGED, - PASS_INVISIBLE, + PASS_INVISIBLE, // Formerly, invisiprims. Now, water exclusion surfaces. PASS_INVISIBLE_RIGGED, PASS_INVISI_SHINY, PASS_INVISI_SHINY_RIGGED, diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp index 0507568d0d..158e940f1c 100644 --- a/indra/newview/lldrawpoolwater.cpp +++ b/indra/newview/lldrawpoolwater.cpp @@ -249,6 +249,8 @@ void LLDrawPoolWater::renderPostDeferred(S32 pass) gGL.getTexUnit(bumpTex2)->bind(tex_b); } + shader->bindTexture(LLShaderMgr::WATER_EXCLUSIONTEX, &gPipeline.mWaterExclusionMask); + // bind reflection texture from RenderTarget S32 screentex = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX); @@ -320,30 +322,11 @@ void LLDrawPoolWater::renderPostDeferred(S32 pass) LLGLDisable cullface(GL_CULL_FACE); - LLVOWater* water = nullptr; - for (LLFace* const& face : mDrawFace) - { - if (!face) continue; - water = static_cast(face->getViewerObject()); - if (!water) continue; - - if ((bool)edge == (bool)water->getIsEdgePatch()) - { - face->renderIndexed(); - - // Note non-void water being drawn, updates required - if (!edge) // SL-16461 remove !LLPipeline::sUseOcclusion check - { - sNeedsReflectionUpdate = true; - sNeedsDistortionUpdate = true; - } - } - } + pushWaterPlanes(edge); shader->disableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); shader->disableTexture(LLShaderMgr::WATER_SCREENTEX); shader->disableTexture(LLShaderMgr::BUMP_MAP); - shader->disableTexture(LLShaderMgr::WATER_REFTEX); // clean up gPipeline.unbindDeferredShader(*shader); @@ -358,6 +341,31 @@ void LLDrawPoolWater::renderPostDeferred(S32 pass) gGL.setColorMask(true, false); } +void LLDrawPoolWater::pushWaterPlanes(int pass) +{ + LLVOWater* water = nullptr; + for (LLFace* const& face : mDrawFace) + { + if (!face) + continue; + water = static_cast(face->getViewerObject()); + if (!water) + continue; + + if ((bool)pass == (bool)water->getIsEdgePatch()) + { + face->renderIndexed(); + + // Note non-void water being drawn, updates required + if (!pass) // SL-16461 remove !LLPipeline::sUseOcclusion check + { + sNeedsReflectionUpdate = true; + sNeedsDistortionUpdate = true; + } + } + } +} + LLViewerTexture *LLDrawPoolWater::getDebugTexture() { return LLViewerTextureManager::getFetchedTexture(IMG_SMOKE); diff --git a/indra/newview/lldrawpoolwater.h b/indra/newview/lldrawpoolwater.h index 25934070af..bf9b667fba 100644 --- a/indra/newview/lldrawpoolwater.h +++ b/indra/newview/lldrawpoolwater.h @@ -74,6 +74,8 @@ public: void setOpaqueTexture(const LLUUID& opaqueTextureId); void setNormalMaps(const LLUUID& normalMapId, const LLUUID& nextNormalMapId); + void pushWaterPlanes(int pass); + protected: void renderOpaqueLegacyWater(); diff --git a/indra/newview/lldrawpoolwaterexclusion.cpp b/indra/newview/lldrawpoolwaterexclusion.cpp new file mode 100644 index 0000000000..d796bf39bf --- /dev/null +++ b/indra/newview/lldrawpoolwaterexclusion.cpp @@ -0,0 +1,79 @@ +/** + * @file lldrawpool.cpp + * @brief LLDrawPoolMaterials class implementation + * @author Jonathan "Geenz" Goodman + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "lldrawpoolwaterexclusion.h" +#include "llviewershadermgr.h" +#include "pipeline.h" +#include "llglcommonfunc.h" +#include "llvoavatar.h" +#include "lldrawpoolwater.h" + +LLDrawPoolWaterExclusion::LLDrawPoolWaterExclusion() : LLRenderPass(LLDrawPool::POOL_WATEREXCLUSION) +{ + LL_INFOS("DPInvisible") << "Creating water exclusion draw pool" << LL_ENDL; +} + + +void LLDrawPoolWaterExclusion::render(S32 pass) +{ // render invisiprims + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; // LL_RECORD_BLOCK_TIME(FTM_RENDER_INVISIBLE); + + if (gPipeline.shadersLoaded()) + { + gDrawColorProgram.bind(); + } + + + LLGLDepthTest depth(GL_TRUE); + gDrawColorProgram.uniform4f(LLShaderMgr::DIFFUSE_COLOR, 1, 1, 1, 1); + + LLDrawPoolWater* pwaterpool = (LLDrawPoolWater*)gPipeline.getPool(LLDrawPool::POOL_WATER); + if (pwaterpool) + { + // Just treat our water planes as double sided for the purposes of generating the exclusion mask. + LLGLDisable cullface(GL_CULL_FACE); + pwaterpool->pushWaterPlanes(0); + + // Take care of the edge water tiles. + pwaterpool->pushWaterPlanes(1); + } + + gDrawColorProgram.uniform4f(LLShaderMgr::DIFFUSE_COLOR, 0, 0, 0, 1); + + static LLStaticHashedString waterSign("waterSign"); + gDrawColorProgram.uniform1f(waterSign, 1.f); + + pushBatches(LLRenderPass::PASS_INVISIBLE, false, false); + + + if (gPipeline.shadersLoaded()) + { + gDrawColorProgram.unbind(); + } +} diff --git a/indra/newview/lldrawpoolwaterexclusion.h b/indra/newview/lldrawpoolwaterexclusion.h new file mode 100644 index 0000000000..e95721a443 --- /dev/null +++ b/indra/newview/lldrawpoolwaterexclusion.h @@ -0,0 +1,61 @@ +/** + * @file lldrawpoolwaterexclusion.h + * @brief LLDrawPoolWaterExclusion class definition + * @author Jonathan "Geenz" Goodman + * + * $LicenseInfo:firstyear=2025&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLDRAWPOOLWATEREXCLUSION_H +#define LL_LLDRAWPOOLWATEREXCLUSION_H + +#include "v4coloru.h" +#include "v2math.h" +#include "v3math.h" +#include "llvertexbuffer.h" +#include "lldrawpool.h" + +class LLViewerTexture; +class LLDrawInfo; +class LLGLSLShader; + +class LLDrawPoolWaterExclusion : public LLRenderPass +{ +public: + LLDrawPoolWaterExclusion(); + + enum + { + VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX + }; + + virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; } + + virtual void prerender() {} + + virtual void render(S32 pass = 0); + virtual void beginRenderPass(S32 pass) {} + virtual void endRenderPass(S32 pass) {} + virtual S32 getNumPasses() { return 1; } +}; + +#endif // LL_LLDRAWPOOLWATEREXCLUSION_H diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index 8a5c2a343d..3cb4aea523 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -4638,14 +4638,9 @@ void LLFolderBridge::staticFolderOptionsMenu() bool LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& is_type) { - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - model->collectDescendentsIf(mUUID, - cat_array, - item_array, + return model->hasMatchingDescendents(mUUID, LLInventoryModel::EXCLUDE_TRASH, is_type); - return !item_array.empty(); } void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items, menuentry_vec_t& disabled_items) @@ -4866,21 +4861,26 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items //Added by aura to force inventory pull on right-click to display folder options correctly. 07-17-06 mCallingCards = mWearables = false; - LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD); - if (checkFolderForContentsOfType(model, is_callingcard)) + if (gInventory.getRootFolderID() != mUUID) { - mCallingCards=true; + LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD); + if (checkFolderForContentsOfType(model, is_callingcard)) + { + mCallingCards = true; + } + + const std::vector types = { LLAssetType::AT_CLOTHING, LLAssetType::AT_BODYPART, LLAssetType::AT_OBJECT, LLAssetType::AT_GESTURE }; + LLIsOneOfTypes is_wearable(types); + + if (checkFolderForContentsOfType(model, is_wearable)) + { + mWearables = true; + } } - - LLFindWearables is_wearable; - LLIsType is_object( LLAssetType::AT_OBJECT ); - LLIsType is_gesture( LLAssetType::AT_GESTURE ); - - if (checkFolderForContentsOfType(model, is_wearable) || - checkFolderForContentsOfType(model, is_object) || - checkFolderForContentsOfType(model, is_gesture) ) + else { - mWearables=true; + // Assume that there are wearables in the root folder + mWearables = true; } } // [SL:KB] - Patch: Inventory-Misc | Checked: 2011-05-28 (Catznip-2.6.0a) | Added: Catznip-2.6.0a @@ -4901,13 +4901,10 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items LLFolderType::EType type = category->getPreferredType(); const bool is_system_folder = LLFolderType::lookupIsProtectedType(type); - LLFindWearables is_wearable; - LLIsType is_object(LLAssetType::AT_OBJECT); - LLIsType is_gesture(LLAssetType::AT_GESTURE); + const std::vector types = { LLAssetType::AT_CLOTHING, LLAssetType::AT_BODYPART, LLAssetType::AT_OBJECT, LLAssetType::AT_GESTURE }; + LLIsOneOfTypes is_wearable(types); - if (checkFolderForContentsOfType(model, is_wearable) || - checkFolderForContentsOfType(model, is_object) || - checkFolderForContentsOfType(model, is_gesture)) + if (checkFolderForContentsOfType(model, is_wearable)) { mWearables = true; } @@ -5071,14 +5068,11 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t& // wearables related functionality for folders. //is_wearable - LLFindWearables is_wearable; - LLIsType is_object( LLAssetType::AT_OBJECT ); - LLIsType is_gesture( LLAssetType::AT_GESTURE ); + const std::vector types = { LLAssetType::AT_CLOTHING, LLAssetType::AT_BODYPART, LLAssetType::AT_OBJECT, LLAssetType::AT_GESTURE }; + LLIsOneOfTypes is_wearable(types); if (mWearables || - checkFolderForContentsOfType(model, is_wearable) || - checkFolderForContentsOfType(model, is_object) || - checkFolderForContentsOfType(model, is_gesture) ) + checkFolderForContentsOfType(model, is_wearable)) { // Only enable add/replace outfit for non-system folders. if (!is_system_folder) diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 1722a40691..e6c88399a9 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2795,6 +2795,22 @@ bool LLIsType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) return false; } +bool LLIsOneOfTypes::operator()(LLInventoryCategory* cat, LLInventoryItem* item) +{ + for (LLAssetType::EType &type : mTypes) + { + if (type == LLAssetType::AT_CATEGORY) + { + if (cat) return true; + } + if (item) + { + if (item->getType() == type) return true; + } + } + return false; +} + bool LLIsNotType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { if(mType == LLAssetType::AT_CATEGORY) diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 72bcef5730..97f7649aff 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -252,6 +252,24 @@ protected: LLAssetType::EType mType; }; +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLIsOneOfTypes +// +// Implementation of a LLInventoryCollectFunctor which returns true if +// the type is one of the types passed in during construction. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLIsOneOfTypes : public LLInventoryCollectFunctor +{ +public: + LLIsOneOfTypes(const std::vector &types) : mTypes(types) {} + virtual ~LLIsOneOfTypes() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); +protected: + std::vector mTypes; +}; + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLIsNotType // diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index e047721c23..278705f3f1 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1438,6 +1438,47 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, // [/RLVa:KB] } +bool LLInventoryModel::hasMatchingDescendents(const LLUUID& id, + bool include_trash, + LLInventoryCollectFunctor& matches) +{ + if (!include_trash) + { + const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); + if (trash_id.notNull() && (trash_id == id)) + return false; + } + cat_array_t* cat_array = get_ptr_in_map(mParentChildCategoryTree, id); + if (cat_array) + { + for (auto& cat : *cat_array) + { + if (matches(cat, NULL)) + { + return true; + } + if (hasMatchingDescendents(cat->getUUID(), include_trash, matches)) + { + return true; + } + } + } + + item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id); + + if (item_array) + { + for (auto& item : *item_array) + { + if (matches(NULL, item)) + { + return true; + } + } + } + return false; +} + void LLInventoryModel::addChangedMaskForLinks(const LLUUID& object_id, U32 mask) { const LLInventoryObject *obj = getObject(object_id); diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 31184e663f..2696e0cc93 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -306,6 +306,9 @@ public: // item_array_t& items, // bool include_trash, // LLInventoryCollectFunctor& add); + bool hasMatchingDescendents(const LLUUID& id, + bool include_trash, + LLInventoryCollectFunctor& add); // Collect all items in inventory that are linked to item_id. // Assumes item_id is itself not a linked item. diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index be1cf93823..5d03b7b87f 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -1424,6 +1424,8 @@ void LLInventoryPanel::openStartFolderOrMyInventory() LLFolderViewFolder *fchild = dynamic_cast(child); if (fchild && fchild->getViewModelItem() + // Is this right? Name might be localized, + // use FT_ROOT_INVENTORY or gInventory.getRootFolderID()? && fchild->getViewModelItem()->getName() == "My Inventory") { fchild->setOpen(true); diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 983ae58df1..39cc2a1714 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -101,6 +101,7 @@ LLGLSLShader gReflectionProbeDisplayProgram; LLGLSLShader gCopyProgram; LLGLSLShader gCopyDepthProgram; LLGLSLShader gPBRTerrainBakeProgram; +LLGLSLShader gDrawColorProgram; //object shaders LLGLSLShader gObjectPreviewProgram; @@ -3402,6 +3403,17 @@ bool LLViewerShaderMgr::loadShadersInterface() success = gCopyDepthProgram.createShader(); } + if (success) + { + gDrawColorProgram.mName = "Draw Color Shader"; + gDrawColorProgram.mShaderFiles.clear(); + gDrawColorProgram.mShaderFiles.push_back(make_pair("objects/simpleNoAtmosV.glsl", GL_VERTEX_SHADER)); + gDrawColorProgram.mShaderFiles.push_back(make_pair("objects/simpleColorF.glsl", GL_FRAGMENT_SHADER)); + gDrawColorProgram.clearPermutations(); + gDrawColorProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; + success = gDrawColorProgram.createShader(); + } + if (gSavedSettings.getBOOL("LocalTerrainPaintEnabled")) { if (success) diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index f10fd9b3c1..1f1524f55a 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -175,6 +175,7 @@ extern LLGLSLShader gReflectionProbeDisplayProgram; extern LLGLSLShader gCopyProgram; extern LLGLSLShader gCopyDepthProgram; extern LLGLSLShader gPBRTerrainBakeProgram; +extern LLGLSLShader gDrawColorProgram; //output tex0[tc0] - tex1[tc1] extern LLGLSLShader gTwoTextureCompareProgram; diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index efbbd4d2a7..58daf580bc 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -3661,18 +3661,7 @@ void LLViewerMediaTexture::setPlaying(bool playing) for(std::list< LLFace* >::iterator iter = mMediaFaceList.begin(); iter!= mMediaFaceList.end(); ++iter) { LLFace* facep = *iter; - const LLTextureEntry* te = facep->getTextureEntry(); - if (te && te->getGLTFMaterial()) - { - // PBR material, switch emissive and basecolor - switchTexture(LLRender::EMISSIVE_MAP, *iter); - switchTexture(LLRender::BASECOLOR_MAP, *iter); - } - else - { - // blinn-phong material, switch diffuse map only - switchTexture(LLRender::DIFFUSE_MAP, *iter); - } + switchTexture(LLRender::DIFFUSE_MAP, facep); } } else //stop playing this media diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 70c1fbd5a8..e0e5221e78 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -293,6 +293,7 @@ void LLVoiceClient::setNonSpatialVoiceModule(const std::string &voice_server_typ void LLVoiceClient::setHidden(bool hidden) { + LL_INFOS("Voice") << "( " << (hidden ? "true" : "false") << " )" << LL_ENDL; #ifdef OPENSIM LLWebRTCVoiceClient::getInstance()->setHidden(hidden && LLGridManager::getInstance()->isInSecondLife()); LLVivoxVoiceClient::getInstance()->setHidden(hidden && LLGridManager::getInstance()->isInSecondLife()); diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index 46f9cbff22..0fd9b378c1 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -345,6 +345,8 @@ void LLWebRTCVoiceClient::updateSettings() static LLCachedControl sOutputDevice(gSavedSettings, "VoiceOutputAudioDevice"); setRenderDevice(sOutputDevice); + LL_INFOS("Voice") << "Input device: " << std::quoted(sInputDevice()) << ", output device: " << std::quoted(sOutputDevice()) << LL_ENDL; + static LLCachedControl sMicLevel(gSavedSettings, "AudioLevelMic"); setMicGain(sMicLevel); @@ -896,7 +898,7 @@ void LLWebRTCVoiceClient::OnConnectionShutDown(const std::string &channelID, con { if (mSession && mSession->mChannelID == channelID) { - LL_DEBUGS("Voice") << "Main WebRTC Connection Shut Down." << LL_ENDL; + LL_INFOS("Voice") << "Main WebRTC Connection Shut Down." << LL_ENDL; } } mSession->removeAllParticipants(regionID); @@ -1504,6 +1506,11 @@ bool LLWebRTCVoiceClient::compareChannels(const LLSD &channelInfo1, const LLSD & // we're muting the mic, so tell each session such void LLWebRTCVoiceClient::setMuteMic(bool muted) { + if (mMuteMic != muted) + { + LL_INFOS("Voice") << "( " << (muted ? "true" : "false") << " )" << LL_ENDL; + } + mMuteMic = muted; // when you're hidden, your mic is always muted. if (!mHidden) @@ -1552,14 +1559,10 @@ void LLWebRTCVoiceClient::setVoiceEnabled(bool enabled) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE; - LL_DEBUGS("Voice") - << "( " << (enabled ? "enabled" : "disabled") << " )" - << " was "<< (mVoiceEnabled ? "enabled" : "disabled") - << " coro "<< (mIsCoroutineActive ? "active" : "inactive") - << LL_ENDL; - if (enabled != mVoiceEnabled) { + LL_INFOS("Voice") << "( " << (enabled ? "enabled" : "disabled") << " )" + << ", coro: " << (mIsCoroutineActive ? "active" : "inactive") << LL_ENDL; // TODO: Refactor this so we don't call into LLVoiceChannel, but simply // use the status observer mVoiceEnabled = enabled; @@ -2485,7 +2488,7 @@ void LLVoiceWebRTCConnection::breakVoiceConnectionCoro(connectionPtr_t connectio { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE; - LL_DEBUGS("Voice") << "Disconnecting voice." << LL_ENDL; + LL_INFOS("Voice") << "Disconnecting voice." << LL_ENDL; if (connection->mWebRTCDataInterface) { connection->mWebRTCDataInterface->unsetDataObserver(connection.get()); @@ -2593,6 +2596,7 @@ void LLVoiceWebRTCSpatialConnection::requestVoiceConnection() LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + LL_INFOS("Voice") << "Voice connection request: " << (status ? "Success" : status.toString()) << LL_ENDL; if (status) { OnVoiceConnectionRequestSuccess(result); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index dfa40f240c..5fc7fffb38 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -6078,7 +6078,12 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) if (is_pbr) { // tell texture streaming system to ignore blinn-phong textures - facep->setTexture(LLRender::DIFFUSE_MAP, nullptr); + // except the special case of the diffuse map containing a + // media texture that will be reused for swapping on to the pbr face + if (!facep->hasMedia()) + { + facep->setTexture(LLRender::DIFFUSE_MAP, nullptr); + } facep->setTexture(LLRender::NORMAL_MAP, nullptr); facep->setTexture(LLRender::SPECULAR_MAP, nullptr); @@ -7073,8 +7078,11 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace { //shiny if (tex && tex->getPrimaryFormat() == GL_ALPHA) // [FIRE-34534] guard additional cases of tex == null { //invisiprim+shiny - registerFace(group, facep, LLRenderPass::PASS_INVISI_SHINY); - registerFace(group, facep, LLRenderPass::PASS_INVISIBLE); + if (!facep->getViewerObject()->isAttachment() && !facep->getViewerObject()->isRiggedMesh()) + { + registerFace(group, facep, LLRenderPass::PASS_INVISI_SHINY); + registerFace(group, facep, LLRenderPass::PASS_INVISIBLE); + } } else if (!hud_group) { //deferred rendering @@ -7110,7 +7118,10 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace { //not alpha and not shiny if (!is_alpha && tex && tex->getPrimaryFormat() == GL_ALPHA) // FIRE-34540 bugsplat crash caused by tex==nullptr. This stops the crash, but should we continue and leave the face unregistered instead of falling through? { //invisiprim - registerFace(group, facep, LLRenderPass::PASS_INVISIBLE); + if (!facep->getViewerObject()->isAttachment() && !facep->getViewerObject()->isRiggedMesh()) + { + registerFace(group, facep, LLRenderPass::PASS_INVISIBLE); + } } else if (fullbright || bake_sunlight) { //fullbright diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 1b938944b4..04fe231275 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -473,6 +473,7 @@ void LLPipeline::init() stop_glerror(); //create render pass pools + getPool(LLDrawPool::POOL_WATEREXCLUSION); getPool(LLDrawPool::POOL_ALPHA_PRE_WATER); getPool(LLDrawPool::POOL_ALPHA_POST_WATER); getPool(LLDrawPool::POOL_SIMPLE); @@ -732,6 +733,8 @@ void LLPipeline::cleanup() // don't delete wl sky pool it was handled above in the for loop //delete mWLSkyPool; mWLSkyPool = NULL; + delete mWaterExclusionPool; + mWaterExclusionPool = nullptr; releaseGLBuffers(); @@ -1013,6 +1016,15 @@ bool LLPipeline::allocateScreenBufferInternal(U32 resX, U32 resY) {LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("mPostMapBuffer"); // improve Tracy scoping mPostMap.allocate(resX, resY, screenFormat); } // improve Tracy scoping + // The water exclusion mask needs its own depth buffer so we can take care of the problem of multiple water planes. + // Should we ever make water not just a plane, it also aids with that as well as the water planes will be rendered into the mask. + // Why do we do this? Because it saves us some janky logic in the exclusion shader when we generate the mask. + // Regardless, this should always only be an R8 texture unless we choose to start having multiple kinds of exclusion that 8 bits can't handle. + // - Geenz 2025-02-06 + bool success = mWaterExclusionMask.allocate(resX, resY, GL_R8, true); + + assert(success); + // used to scale down textures // See LLViwerTextureList::updateImagesCreateTextures and LLImageGL::scaleDown {LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("DownResBuffer");// create an independent preview screen target @@ -1294,6 +1306,8 @@ void LLPipeline::releaseGLBuffers() mSceneMap.release(); + mWaterExclusionMask.release(); + mPostMap.release(); mFXAAMap.release(); @@ -1806,6 +1820,10 @@ LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerTexture *tex0) poolp = mPBRAlphaMaskPool; break; + case LLDrawPool::POOL_WATEREXCLUSION: + poolp = mWaterExclusionPool; + break; + default: llassert(0); LL_ERRS() << "Invalid Pool Type in LLPipeline::findPool() type=" << type << LL_ENDL; @@ -4238,6 +4256,8 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera, bool do_occlusion) } } +// Render all of our geometry that's required after our deferred pass. +// This is gonna be stuff like alpha, water, etc. void LLPipeline::renderGeomPostDeferred(LLCamera& camera) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; @@ -4254,6 +4274,10 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera) bool done_atmospherics = LLPipeline::sRenderingHUDs; //skip atmospherics on huds bool done_water_haze = done_atmospherics; + bool done_water_exclusion = false; + + // do water exclusion just before water pass. + U32 water_exclusion_pass = LLDrawPool::POOL_WATEREXCLUSION; // do atmospheric haze just before post water alpha U32 atmospherics_pass = LLDrawPool::POOL_ALPHA_POST_WATER; @@ -4292,6 +4316,12 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera) cur_type = poolp->getType(); + if (cur_type >= water_exclusion_pass && !done_water_exclusion) + { // do water exclusion against depth buffer before rendering alpha + doWaterExclusionMask(); + done_water_exclusion = true; + } + if (cur_type >= atmospherics_pass && !done_atmospherics) { // do atmospherics against depth buffer before rendering alpha doAtmospherics(); @@ -5371,6 +5401,17 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp ) } break; + case LLDrawPool::POOL_WATEREXCLUSION: + if (mWaterExclusionPool) + { + llassert(0); + LL_WARNS() << "LLPipeline::addPool(): Ignoring duplicate Water Exclusion Pool" << LL_ENDL; + } + else + { + mWaterExclusionPool = new_poolp; + } + break; default: llassert(0); @@ -5493,6 +5534,11 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp ) mPBRAlphaMaskPool = NULL; break; + case LLDrawPool::POOL_WATEREXCLUSION: + llassert(poolp == mWaterExclusionPool); + mWaterExclusionPool = nullptr; + break; + default: llassert(0); LL_WARNS() << "Invalid Pool Type in LLPipeline::removeFromQuickLookup() type=" << poolp->getType() << LL_ENDL; @@ -7991,7 +8037,7 @@ bool LLPipeline::renderSnapshotFrame(LLRenderTarget* src, LLRenderTarget* dst) { float frame_width = w; float frame_height = frame_width / snapshot_aspect; - // Centre this box in [0..1]×[0..1] + // Centre this box in [0..1]×[0..1] float y_offset = 0.5f * (h - frame_height); left = 0.f; top = y_offset / h; @@ -8002,7 +8048,7 @@ bool LLPipeline::renderSnapshotFrame(LLRenderTarget* src, LLRenderTarget* dst) { float frame_height = h; float frame_width = h * snapshot_aspect; - // Centre this box in [0..1]×[0..1] + // Centre this box in [0..1]×[0..1] float x_offset = 0.5f * (w - frame_width); left = x_offset / w; top = 0.f; @@ -9258,6 +9304,7 @@ void LLPipeline::renderDeferredLighting() LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK, LLPipeline::RENDER_TYPE_TERRAIN, LLPipeline::RENDER_TYPE_WATER, + LLPipeline::RENDER_TYPE_WATEREXCLUSION, END_RENDER_TYPES); renderGeomPostDeferred(*LLViewerCamera::getInstance()); @@ -9396,6 +9443,8 @@ void LLPipeline::doWaterHaze() static LLStaticHashedString above_water_str("above_water"); haze_shader.uniform1i(above_water_str, sUnderWaterRender ? -1 : 1); + haze_shader.bindTexture(LLShaderMgr::WATER_EXCLUSIONTEX, &mWaterExclusionMask); + if (LLPipeline::sUnderWaterRender) { LLGLDepthTest depth(GL_FALSE); @@ -9426,6 +9475,17 @@ void LLPipeline::doWaterHaze() } } +void LLPipeline::doWaterExclusionMask() +{ + mWaterExclusionMask.bindTarget(); + glClearColor(1, 1, 1, 1); + mWaterExclusionMask.clear(); + mWaterExclusionPool->render(); + + mWaterExclusionMask.flush(); + glClearColor(0, 0, 0, 0); +} + void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep) { //construct frustum diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 5343dccfba..e70737926b 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -337,6 +337,9 @@ public: // should be called just before rendering pre-water alpha objects void doWaterHaze(); + // Generate the water exclusion surface mask. + void doWaterExclusionMask(); + void postDeferredGammaCorrect(LLRenderTarget* screen_target); void generateSunShadow(LLCamera& camera); @@ -506,6 +509,7 @@ public: RENDER_TYPE_AVATAR = LLDrawPool::POOL_AVATAR, RENDER_TYPE_CONTROL_AV = LLDrawPool::POOL_CONTROL_AV, // Animesh RENDER_TYPE_TREE = LLDrawPool::POOL_TREE, + RENDER_TYPE_WATEREXCLUSION = LLDrawPool::POOL_WATEREXCLUSION, RENDER_TYPE_VOIDWATER = LLDrawPool::POOL_VOIDWATER, RENDER_TYPE_WATER = LLDrawPool::POOL_WATER, RENDER_TYPE_GLTF_PBR = LLDrawPool::POOL_GLTF_PBR, @@ -733,6 +737,7 @@ public: LLRenderTarget mSpotShadow[2]; LLRenderTarget mPbrBrdfLut; + LLRenderTarget mWaterExclusionMask; // copy of the color/depth buffer just before gamma correction // for use by SSR @@ -979,6 +984,7 @@ protected: LLDrawPool* mWLSkyPool = nullptr; LLDrawPool* mPBROpaquePool = nullptr; LLDrawPool* mPBRAlphaMaskPool = nullptr; + LLDrawPool* mWaterExclusionPool = nullptr; // Note: no need to keep an quick-lookup to avatar pools, since there's only one per avatar