Merge branch 'release/2024.12-ForeverFPS' of https://github.com/secondlife/viewer

# Conflicts:
#	indra/newview/llinventorymodel.h
#	indra/newview/llviewertexturelist.cpp
#	indra/newview/llvoiceclient.cpp
#	indra/newview/pipeline.cpp
master
Ansariel 2025-02-07 19:38:29 +01:00
commit 7e7e19ee35
32 changed files with 603 additions and 109 deletions

View File

@ -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");

View File

@ -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"

View File

@ -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()

View File

@ -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.

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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)

View File

@ -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
}

View File

@ -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);

View File

@ -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)));
}

View File

@ -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)

View File

@ -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;

View File

@ -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,

View File

@ -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<LLVOWater*>(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<LLVOWater*>(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);

View File

@ -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();

View File

@ -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();
}
}

View File

@ -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

View File

@ -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<LLAssetType::EType> 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<LLAssetType::EType> 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<LLAssetType::EType> 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)

View File

@ -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)

View File

@ -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<LLAssetType::EType> &types) : mTypes(types) {}
virtual ~LLIsOneOfTypes() {}
virtual bool operator()(LLInventoryCategory* cat,
LLInventoryItem* item);
protected:
std::vector <LLAssetType::EType> mTypes;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Class LLIsNotType
//

View File

@ -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);

View File

@ -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.

View File

@ -1424,6 +1424,8 @@ void LLInventoryPanel::openStartFolderOrMyInventory()
LLFolderViewFolder *fchild = dynamic_cast<LLFolderViewFolder*>(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);

View File

@ -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)

View File

@ -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;

View File

@ -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

View File

@ -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());

View File

@ -345,6 +345,8 @@ void LLWebRTCVoiceClient::updateSettings()
static LLCachedControl<std::string> sOutputDevice(gSavedSettings, "VoiceOutputAudioDevice");
setRenderDevice(sOutputDevice);
LL_INFOS("Voice") << "Input device: " << std::quoted(sInputDevice()) << ", output device: " << std::quoted(sOutputDevice()) << LL_ENDL;
static LLCachedControl<F32> 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);

View File

@ -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) // <FS:Beq/> [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) // <FS:Beq/> 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

View File

@ -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"); // <FS:Beq/> improve Tracy scoping
mPostMap.allocate(resX, resY, screenFormat);
} // <FS:Beq/> 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");// <FS:Beq/> 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

View File

@ -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