diff options
Diffstat (limited to 'indra/newview')
105 files changed, 7125 insertions, 1846 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 3bc636bac4..c6d82ea260 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -257,10 +257,12 @@ set(viewer_SOURCE_FILES llfloaterpathfindinglinksets.cpp llfloaterpathfindingobjects.cpp llfloaterpay.cpp + llfloaterperformance.cpp llfloaterperms.cpp llfloaterpostprocess.cpp llfloaterprofile.cpp llfloaterpreference.cpp + llfloaterpreferencesgraphicsadvanced.cpp llfloaterpreferenceviewadvanced.cpp llfloaterpreviewtrash.cpp llfloaterprofiletexture.cpp @@ -904,10 +906,12 @@ set(viewer_HEADER_FILES llfloaterpathfindinglinksets.h llfloaterpathfindingobjects.h llfloaterpay.h + llfloaterperformance.h llfloaterperms.h llfloaterpostprocess.h llfloaterprofile.h llfloaterpreference.h + llfloaterpreferencesgraphicsadvanced.h llfloaterpreferenceviewadvanced.h llfloaterpreviewtrash.h llfloaterprofiletexture.h @@ -1350,6 +1354,9 @@ set(viewer_HEADER_FILES VorbisFramework.h ) + list(APPEND viewer_SOURCE_FILES llperfstats.cpp) + list(APPEND viewer_HEADER_FILES llperfstats.h) + source_group("CMake Rules" FILES ViewerInstall.cmake) #build_data.json creation moved to viewer_manifest.py MAINT-6413 diff --git a/indra/newview/app_settings/commands.xml b/indra/newview/app_settings/commands.xml index 2644f5f449..4a3dfffde1 100644 --- a/indra/newview/app_settings/commands.xml +++ b/indra/newview/app_settings/commands.xml @@ -285,4 +285,14 @@ is_running_function="Floater.IsOpen" is_running_parameters="360capture" /> + <command name="performance" + available_in_toybox="true" + icon="Command_Performance_Icon" + label_ref="Command_Performance_Label" + tooltip_ref="Command_Performance_Tooltip" + execute_function="Floater.ToggleOrBringToFront" + execute_parameters="performance" + is_running_function="Floater.IsOpen" + is_running_parameters="performance" + /> </commands> diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 998d139bf1..df36c51f55 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -1426,7 +1426,7 @@ <key>Type</key> <string>U32</string> <key>Value</key> - <integer>1024</integer> + <integer>4096</integer> </map> <key>CacheValidateCounter</key> <map> @@ -8828,6 +8828,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>RenderClass1MemoryBandwidth</key> + <map> + <key>Comment</key> + <string>Memory bandwidth at which to default to Class 1 in gigabytes per second. Used as basis for higher classes.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>32.0</real> + </map> <key>RenderCloudShadowAmbianceFactor</key> <map> <key>Comment</key> @@ -8839,6 +8850,17 @@ <key>Value</key> <real>0.1</real> </map> + <key>RenderCPUBasis</key> + <map> + <key>Comment</key> + <string>Reference CPU clockspeed to use to bias GPU class (in MHz).</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>3000.0</real> + </map> <key>RenderComplexityColorMin</key> <map> <key>Comment</key> @@ -9061,6 +9083,17 @@ <key>Value</key> <real>0.5</real> </map> + <key>RenderShadowSplits</key> + <map> + <key>Comment</key> + <string>Amount of shadow map splits to render (0 - 3).</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>S32</string> + <key>Value</key> + <integer>3</integer> + </map> <key>RenderSSAOScale</key> <map> <key>Comment</key> @@ -9252,6 +9285,17 @@ <key>Value</key> <integer>0</integer> </map> + <key>RenderDisablePostProcessing</key> + <map> + <key>Comment</key> + <string>Disable tone mapping and exposure correction when build floater is open (for artists developing materials)</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> <key>RenderMaxOpenGLVersion</key> <map> <key>Comment</key> @@ -16887,6 +16931,149 @@ <key>Value</key> <integer>0</integer> </map> + <key>TargetFPS</key> + <map> + <key>Comment</key> + <string>Desired minimum FPS</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>15</integer> + </map> + <key>AutoTuneFPS</key> + <map> + <key>Comment</key> + <string>Allow the viewer to adjust your settings to achieve target FPS</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>AutoTuneLock</key> + <map> + <key>Comment</key> + <string>When enabled the viewer will dynamically change settings until auto tune is explicitly turned off.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>KeepAutoTuneLock</key> + <map> + <key>Comment</key> + <string>When enabled the AutoTuneLock will be maintainted all following sessions.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>AllowSelfImpostor</key> + <map> + <key>Comment</key> + <string>Allow own render time to impostor your avatar.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>ShowTunedART</key> + <map> + <key>Comment</key> + <string>Show the current render time not the pre-tuning render time in the avatar display.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>RenderAvatarMaxART</key> + <map> + <key>Comment</key> + <string>Render Time Limit in microseconds (0.0 = no limit)</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>4.699</real> + </map> + <key>AutoTuneRenderFarClipMin</key> + <map> + <key>Comment</key> + <string>The lowest draw distance that auto tune is allowed to use</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>32.0</real> + </map> + <key>AutoTuneRenderFarClipTarget</key> + <map> + <key>Comment</key> + <string>The draw distance that auto tune will try to achieve</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>256.0</real> + </map> + <key>PerfStatsCaptureEnabled</key> + <map> + <key>Comment</key> + <string>Enable/disable render time data to support autotune.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>1</integer> + </map> + <key>AutoTuneImpostorByDistEnabled</key> + <map> + <key>Comment</key> + <string>Enable/disable using MaxNonImpostor to limit avatar rendering by distance.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>Boolean</string> + <key>Value</key> + <integer>0</integer> + </map> + <key>AutoTuneImpostorFarAwayDistance</key> + <map> + <key>Comment</key> + <string>Avatars beyond this range will automatically be optimized</string> + <key>Persist</key> + <integer>0</integer> + <key>Type</key> + <string>F32</string> + <key>Value</key> + <real>64.0</real> + </map> + <key>TuningFPSStrategy</key> + <map> + <key>Comment</key> + <string>Strategy to use when tuning FPS. 0=Tune avatar rendering only, 1=Tune both avatar and global scene settings, 2=Tune only global scene.</string> + <key>Persist</key> + <integer>1</integer> + <key>Type</key> + <string>U32</string> + <key>Value</key> + <integer>1</integer> + </map> <key>CameraOpacity</key> <map> <key>Comment</key> diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrShadowAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrShadowAlphaMaskF.glsl new file mode 100644 index 0000000000..5ef9bb6805 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/pbrShadowAlphaMaskF.glsl @@ -0,0 +1,50 @@ +/** + * @file pbrShadowAlphaMaskF.glsl + * + * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2023, 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$ + */ + +#ifdef DEFINE_GL_FRAGCOLOR +out vec4 frag_color; +#else +#define frag_color gl_FragColor +#endif + +uniform sampler2D diffuseMap; + +in vec4 post_pos; +in float target_pos_x; +in vec4 vertex_color; +in vec2 vary_texcoord0; +uniform float minimum_alpha; + +void main() +{ + float alpha = diffuseLookup(vary_texcoord0.xy).a; + + if (alpha < minimum_alpha) + { + discard; + } + + frag_color = vec4(1,1,1,1); +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/pbrShadowAlphaMaskV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pbrShadowAlphaMaskV.glsl new file mode 100644 index 0000000000..4fb5fbcf06 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/pbrShadowAlphaMaskV.glsl @@ -0,0 +1,75 @@ +/** + * @file pbrShadowAlphaMaskV.glsl + * + * $LicenseInfo:firstyear=2023&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2023, 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 texture_matrix0; +#if defined(HAS_SKIN) +uniform mat4 modelview_matrix; +uniform mat4 projection_matrix; +mat4 getObjectSkinnedTransform(); +#else +uniform mat4 modelview_projection_matrix; +#endif + +uniform vec4[2] texture_base_color_transform; +vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); + +uniform float shadow_target_width; + +in vec3 position; +in vec4 diffuse_color; +in vec2 texcoord0; + +out vec4 post_pos; +out float target_pos_x; +out vec4 vertex_color; +out vec2 vary_texcoord0; + +void passTextureIndex(); + +void main() +{ + //transform vertex +#if defined(HAS_SKIN) + vec4 pre_pos = vec4(position.xyz, 1.0); + mat4 mat = getObjectSkinnedTransform(); + mat = modelview_matrix * mat; + vec4 pos = mat * pre_pos; + pos = projection_matrix * pos; +#else + vec4 pre_pos = vec4(position.xyz, 1.0); + vec4 pos = modelview_projection_matrix * pre_pos; +#endif + + target_pos_x = 0.5 * (shadow_target_width - 1.0) * pos.x; + + post_pos = pos; + + gl_Position = pos; + + passTextureIndex(); + + vary_texcoord0 = texture_transform(texcoord0, texture_base_color_transform, texture_matrix0); + vertex_color = diffuse_color; +} diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl index 82d7bb9835..80816912da 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl @@ -104,20 +104,20 @@ vec3 toneMapACES_Hill(vec3 color) uniform float exposure; uniform float gamma; -vec3 legacy_adjust_post(vec3 c); - -vec3 toneMap(vec3 color, float gs) +vec3 toneMap(vec3 color) { +#ifndef NO_POST float exp_scale = texture(exposureMap, vec2(0.5,0.5)).r; - color *= exposure * exp_scale * gs; + color *= exposure * exp_scale; color = toneMapACES_Hill(color); +#else + color *= 0.6; +#endif color = linear_to_srgb(color); - color = legacy_adjust_post(color); - return color; } @@ -170,22 +170,19 @@ vec3 legacyGamma(vec3 color) return color; } -float legacyGammaApprox() -{ - //TODO -- figure out how to plumb this in as a uniform - float c = 0.5; - float gc = 1.0-pow(c, gamma); - - return gc/c * gamma; -} - void main() { //this is the one of the rare spots where diffuseRect contains linear color values (not sRGB) vec4 diff = texture2D(diffuseRect, vary_fragcoord); - diff.rgb = toneMap(diff.rgb, legacyGammaApprox()); - + diff.rgb = toneMap(diff.rgb); + +#ifdef LEGACY_GAMMA +#ifndef NO_POST + diff.rgb = legacyGamma(diff.rgb); +#endif +#endif + vec2 tc = vary_fragcoord.xy*screen_res*4.0; vec3 seed = (diff.rgb+vec3(1.0))*vec3(tc.xy, tc.x+tc.y); vec3 nz = vec3(noise(seed.rg), noise(seed.gb), noise(seed.rb)); diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskF.glsl index eb2ba68415..8c9b6f8190 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskF.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskF.glsl @@ -48,8 +48,6 @@ void main() discard; } -#if !defined(GLTF) - #if !defined(IS_FULLBRIGHT) alpha *= vertex_color.a; #endif @@ -66,7 +64,6 @@ void main() discard; } } -#endif frag_color = vec4(1,1,1,1); } diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskV.glsl index 72a07fa3d0..26db1a5d4d 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskV.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskV.glsl @@ -32,9 +32,6 @@ mat4 getObjectSkinnedTransform(); uniform mat4 modelview_projection_matrix; #endif -uniform vec4[2] texture_base_color_transform; -vec2 texture_transform(vec2 vertex_texcoord, vec4[2] khr_gltf_transform, mat4 sl_animation_transform); - uniform float shadow_target_width; in vec3 position; @@ -70,6 +67,6 @@ void main() passTextureIndex(); - vary_texcoord0 = texture_transform(texcoord0, texture_base_color_transform, texture_matrix0); + vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy; vertex_color = diffuse_color; } diff --git a/indra/newview/app_settings/shaders/class1/environment/srgbF.glsl b/indra/newview/app_settings/shaders/class1/environment/srgbF.glsl index 35f2395ef1..3817633df0 100644 --- a/indra/newview/app_settings/shaders/class1/environment/srgbF.glsl +++ b/indra/newview/app_settings/shaders/class1/environment/srgbF.glsl @@ -128,8 +128,3 @@ vec3 legacy_adjust_fullbright(vec3 c) return c / exp_scale * 1.34; } - -vec3 legacy_adjust_post(vec3 c) -{ - return c; -} diff --git a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl index 35563713f5..53e15bd1a1 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl @@ -47,7 +47,11 @@ layout (std140) uniform ReflectionProbes mat4 refBox[MAX_REFMAP_COUNT]; // list of bounding spheres for reflection probes sorted by distance to camera (closest first) vec4 refSphere[MAX_REFMAP_COUNT]; - // extra parameters (currently only .x used for probe ambiance) + // extra parameters + // x - irradiance scale + // y - radiance scale + // z - fade in + // w - znear vec4 refParams[MAX_REFMAP_COUNT]; // index of cube map in reflectionProbes for a corresponding reflection probe // e.g. cube map channel of refSphere[2] is stored in refIndex[2] @@ -60,6 +64,8 @@ layout (std140) uniform ReflectionProbes // neighbor list data (refSphere indices, not cubemap array layer) ivec4 refNeighbor[1024]; + ivec4 refBucket[256]; + // number of reflection probes present in refSphere int refmapCount; }; @@ -118,13 +124,26 @@ bool shouldSampleProbe(int i, vec3 pos) return true; } +int getStartIndex(vec3 pos) +{ +#if 1 + int idx = clamp(int(floor(-pos.z)), 0, 255); + return clamp(refBucket[idx].x, 1, refmapCount+1); +#else + return 1; +#endif +} + // call before sampleRef // populate "probeIndex" with N probe indices that influence pos where N is REF_SAMPLE_COUNT void preProbeSample(vec3 pos) { #if REFMAP_LEVEL > 0 + + int start = getStartIndex(pos); + // TODO: make some sort of structure that reduces the number of distance checks - for (int i = 1; i < refmapCount; ++i) + for (int i = start; i < refmapCount; ++i) { // found an influencing probe if (shouldSampleProbe(i, pos)) @@ -142,6 +161,7 @@ void preProbeSample(vec3 pos) { // check up to REF_SAMPLE_COUNT-1 neighbors (neighborIdx is ivec4 index) + // sample refNeighbor[neighborIdx].x int idx = refNeighbor[neighborIdx].x; if (shouldSampleProbe(idx, pos)) { @@ -157,6 +177,7 @@ void preProbeSample(vec3 pos) break; } + // sample refNeighbor[neighborIdx].y idx = refNeighbor[neighborIdx].y; if (shouldSampleProbe(idx, pos)) { @@ -172,6 +193,7 @@ void preProbeSample(vec3 pos) break; } + // sample refNeighbor[neighborIdx].z idx = refNeighbor[neighborIdx].z; if (shouldSampleProbe(idx, pos)) { @@ -187,6 +209,7 @@ void preProbeSample(vec3 pos) break; } + // sample refNeighbor[neighborIdx].w idx = refNeighbor[neighborIdx].w; if (shouldSampleProbe(idx, pos)) { @@ -197,11 +220,7 @@ void preProbeSample(vec3 pos) } } count++; - if (count == neighborCount) - { - break; - } - + ++neighborIdx; } @@ -735,6 +754,14 @@ vec4 sampleReflectionProbesDebug(vec3 pos) debugTapRefMap(pos, dir, d, i, col); } +#if 0 //debug getStartIndex + col.g = float(getStartIndex(pos)); + + col.g /= 255.0; + col.rb = vec2(0); + col.a = 1.0; +#endif + return col; } diff --git a/indra/newview/app_settings/toolbars.xml b/indra/newview/app_settings/toolbars.xml index f3a23edc58..a1c9d6d9ee 100644 --- a/indra/newview/app_settings/toolbars.xml +++ b/indra/newview/app_settings/toolbars.xml @@ -22,6 +22,7 @@ <command name="voice"/> <command name="minimap"/> <command name="snapshot"/> + <command name="performance"/> </left_toolbar> <right_toolbar button_display_mode="icons_only"> diff --git a/indra/newview/featuretable.txt b/indra/newview/featuretable.txt index 78c2578cec..79d92adcc2 100644 --- a/indra/newview/featuretable.txt +++ b/indra/newview/featuretable.txt @@ -113,9 +113,9 @@ RenderReflectionProbeLevel 1 0 list LowMid RenderAnisotropic 1 0 RenderAvatarLODFactor 1 0.5 -RenderAvatarMaxNonImpostors 1 5 RenderAvatarMaxComplexity 1 100000 RenderAvatarPhysicsLODFactor 1 0.75 +RenderAvatarMaxNonImpostors 1 5 RenderFarClip 1 96 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 8 @@ -143,9 +143,9 @@ RenderReflectionProbeLevel 1 1 list Mid RenderAnisotropic 1 1 RenderAvatarLODFactor 1 1.0 -RenderAvatarMaxNonImpostors 1 7 RenderAvatarMaxComplexity 1 200000 RenderAvatarPhysicsLODFactor 1 1.0 +RenderAvatarMaxNonImpostors 1 7 RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 @@ -173,9 +173,9 @@ RenderReflectionProbeLevel 1 2 list MidHigh RenderAnisotropic 1 1 RenderAvatarLODFactor 1 1.0 -RenderAvatarMaxNonImpostors 1 9 RenderAvatarMaxComplexity 1 250000 RenderAvatarPhysicsLODFactor 1 1.0 +RenderAvatarMaxNonImpostors 1 9 RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 @@ -203,9 +203,9 @@ RenderReflectionProbeLevel 1 2 list High RenderAnisotropic 1 1 RenderAvatarLODFactor 1 1.0 -RenderAvatarMaxNonImpostors 1 11 RenderAvatarMaxComplexity 1 300000 RenderAvatarPhysicsLODFactor 1 1.0 +RenderAvatarMaxNonImpostors 1 11 RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 @@ -233,9 +233,9 @@ RenderReflectionProbeLevel 1 3 list HighUltra RenderAnisotropic 1 1 RenderAvatarLODFactor 1 1.0 -RenderAvatarMaxNonImpostors 1 16 RenderAvatarMaxComplexity 1 350000 RenderAvatarPhysicsLODFactor 1 1.0 +RenderAvatarMaxNonImpostors 1 16 RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 diff --git a/indra/newview/featuretable_linux.txt b/indra/newview/featuretable_linux.txt index 66197e6484..4bcefc1546 100644 --- a/indra/newview/featuretable_linux.txt +++ b/indra/newview/featuretable_linux.txt @@ -59,7 +59,6 @@ WindLightUseAtmosShaders 1 1 WLSkyDetail 1 128 Disregard128DefaultDrawDistance 1 1 Disregard96DefaultDrawDistance 1 1 -RenderTextureMemoryMultiple 1 1.0 RenderCompressTextures 1 1 RenderShaderLightingMaxLevel 1 3 RenderDeferred 1 1 diff --git a/indra/newview/featuretable_mac.txt b/indra/newview/featuretable_mac.txt index 1d407b52d8..72deabd9f1 100644 --- a/indra/newview/featuretable_mac.txt +++ b/indra/newview/featuretable_mac.txt @@ -93,7 +93,7 @@ RenderTerrainDetail 1 0 RenderTerrainLODFactor 1 1 RenderTransparentWater 1 0 RenderTreeLODFactor 1 0 -RenderVolumeLODFactor 1 0.5 +RenderVolumeLODFactor 1 1.125 RenderDeferredSSAO 1 0 RenderUseAdvancedAtmospherics 1 0 RenderShadowDetail 1 0 @@ -111,9 +111,9 @@ RenderReflectionProbeLevel 1 0 list LowMid RenderAnisotropic 1 0 RenderAvatarLODFactor 1 0.5 -RenderAvatarMaxNonImpostors 1 5 RenderAvatarMaxComplexity 1 100000 RenderAvatarPhysicsLODFactor 1 0.75 +RenderAvatarMaxNonImpostors 1 5 RenderFarClip 1 96 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 8 @@ -141,9 +141,9 @@ RenderReflectionProbeLevel 1 1 list Mid RenderAnisotropic 1 1 RenderAvatarLODFactor 1 1.0 -RenderAvatarMaxNonImpostors 1 7 RenderAvatarMaxComplexity 1 200000 RenderAvatarPhysicsLODFactor 1 1.0 +RenderAvatarMaxNonImpostors 1 7 RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 @@ -171,9 +171,9 @@ RenderReflectionProbeLevel 1 2 list MidHigh RenderAnisotropic 1 1 RenderAvatarLODFactor 1 1.0 -RenderAvatarMaxNonImpostors 1 9 RenderAvatarMaxComplexity 1 250000 RenderAvatarPhysicsLODFactor 1 1.0 +RenderAvatarMaxNonImpostors 1 9 RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 @@ -201,9 +201,9 @@ RenderReflectionProbeLevel 1 2 list High RenderAnisotropic 1 1 RenderAvatarLODFactor 1 1.0 -RenderAvatarMaxNonImpostors 1 11 RenderAvatarMaxComplexity 1 300000 RenderAvatarPhysicsLODFactor 1 1.0 +RenderAvatarMaxNonImpostors 1 11 RenderFarClip 1 128 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 @@ -261,8 +261,8 @@ RenderReflectionProbeLevel 1 3 list Ultra RenderAnisotropic 1 1 RenderAvatarLODFactor 1 1.0 -RenderAvatarMaxNonImpostors 1 16 RenderAvatarPhysicsLODFactor 1 1.0 +RenderAvatarMaxNonImpostors 1 16 RenderFarClip 1 256 RenderFlexTimeFactor 1 1.0 RenderGlowResolutionPow 1 9 diff --git a/indra/newview/groupchatlistener.cpp b/indra/newview/groupchatlistener.cpp index ef015a950d..a05caa961b 100644 --- a/indra/newview/groupchatlistener.cpp +++ b/indra/newview/groupchatlistener.cpp @@ -64,11 +64,11 @@ GroupChatListener::GroupChatListener(): "Leave a group chat in group with UUID [\"id\"]\n" "Assumes a prior successful startIM request.", &LLGroupActions::endIM, - LLSDArray("id")); - add("sendIM", - "send a groupchat IM", - &send_message_wrapper, - LLSDArray("text")("session_id")("group_id")); + llsd::array("id")); + add("sendIM", + "send a groupchat IM", + &send_message_wrapper, + llsd::array("text", "session_id", "group_id")); } /* static void sendMessage(const std::string& utf8_text, const LLUUID& im_session_id, diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index a68dba98bb..4c3891f302 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -63,6 +63,7 @@ #include "llnotificationsutil.h" #include "llpaneltopinfobar.h" #include "llparcel.h" +#include "llperfstats.h" #include "llrendersphere.h" #include "llscriptruntimeperms.h" #include "llsdutil.h" @@ -4094,6 +4095,7 @@ void LLAgent::handleTeleportFinished() mRegionp->setCapabilitiesReceivedCallback(boost::bind(&LLAgent::onCapabilitiesReceivedAfterTeleport)); } } + LLPerfStats::tunables.autoTuneTimeout = true; } void LLAgent::handleTeleportFailed() @@ -4125,6 +4127,8 @@ void LLAgent::handleTeleportFailed() } mTPNeedsNeabyChatSeparator = false; + + LLPerfStats::tunables.autoTuneTimeout = true; } /*static*/ diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index b17c78abac..c9fc0e2cc8 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -107,6 +107,7 @@ #include "llscenemonitor.h" #include "llavatarrenderinfoaccountant.h" #include "lllocalbitmaps.h" +#include "llperfstats.h" #include "llgltfmateriallist.h" // Linden library includes @@ -1358,82 +1359,93 @@ bool LLAppViewer::frame() bool LLAppViewer::doFrame() { - LL_RECORD_BLOCK_TIME(FTM_FRAME); + LL_RECORD_BLOCK_TIME(FTM_FRAME); + { + // and now adjust the visuals from previous frame. + if(LLPerfStats::tunables.userAutoTuneEnabled && LLPerfStats::tunables.tuningFlag != LLPerfStats::Tunables::Nothing) + { + LLPerfStats::tunables.applyUpdates(); + } + LLPerfStats::RecordSceneTime T (LLPerfStats::StatType_t::RENDER_FRAME); if (!LLWorld::instanceExists()) { LLWorld::createInstance(); } - LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop")); - LLSD newFrame; - - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df LLTrace"); - if (LLFloaterReg::instanceVisible("block_timers")) + LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop")); + LLSD newFrame; + { + LLPerfStats::RecordSceneTime T (LLPerfStats::StatType_t::RENDER_IDLE); // perf stats { - LLTrace::BlockTimer::processTimes(); - } - - LLTrace::get_frame_recording().nextPeriod(); - LLTrace::BlockTimer::logStats(); - } + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df LLTrace"); + if (LLFloaterReg::instanceVisible("block_timers")) + { + LLTrace::BlockTimer::processTimes(); + } - LLTrace::get_thread_recorder()->pullFromChildren(); + LLTrace::get_frame_recording().nextPeriod(); + LLTrace::BlockTimer::logStats(); + } - //clear call stack records - LL_CLEAR_CALLSTACKS(); + LLTrace::get_thread_recorder()->pullFromChildren(); - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df processMiscNativeEvents" ) - pingMainloopTimeout("Main:MiscNativeWindowEvents"); + //clear call stack records + LL_CLEAR_CALLSTACKS(); + } + { + { + LLPerfStats::RecordSceneTime T(LLPerfStats::StatType_t::RENDER_IDLE); // ensure we have the entire top scope of frame covered (input event and coro) + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df processMiscNativeEvents") + pingMainloopTimeout("Main:MiscNativeWindowEvents"); - if (gViewerWindow) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP("System Messages"); - gViewerWindow->getWindow()->processMiscNativeEvents(); - } + if (gViewerWindow) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("System Messages"); + gViewerWindow->getWindow()->processMiscNativeEvents(); + } - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df gatherInput" ) - pingMainloopTimeout("Main:GatherInput"); - } + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df gatherInput") + pingMainloopTimeout("Main:GatherInput"); + } - if (gViewerWindow) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP("System Messages"); - if (!restoreErrorTrap()) - { - LL_WARNS() << " Someone took over my signal/exception handler (post messagehandling)!" << LL_ENDL; - } + if (gViewerWindow) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("System Messages"); + if (!restoreErrorTrap()) + { + LL_WARNS() << " Someone took over my signal/exception handler (post messagehandling)!" << LL_ENDL; + } - gViewerWindow->getWindow()->gatherInput(); - } + gViewerWindow->getWindow()->gatherInput(); + } - //memory leaking simulation - if (gSimulateMemLeak) - { - LLFloaterMemLeak* mem_leak_instance = - LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking"); - if (mem_leak_instance) - { - mem_leak_instance->idle(); - } - } + //memory leaking simulation + if (gSimulateMemLeak) + { + LLFloaterMemLeak* mem_leak_instance = + LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking"); + if (mem_leak_instance) + { + mem_leak_instance->idle(); + } + } - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df mainloop" ) - // canonical per-frame event - mainloop.post(newFrame); - } + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df mainloop") + // canonical per-frame event + mainloop.post(newFrame); + } - { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP( "df suspend" ) - // give listeners a chance to run - llcoro::suspend(); - // if one of our coroutines threw an uncaught exception, rethrow it now - LLCoros::instance().rethrow(); - } + { + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df suspend") + // give listeners a chance to run + llcoro::suspend(); + // if one of our coroutines threw an uncaught exception, rethrow it now + LLCoros::instance().rethrow(); + } + } if (!LLApp::isExiting()) { @@ -1451,6 +1463,7 @@ bool LLAppViewer::doFrame() && (gHeadlessClient || !gViewerWindow->getShowProgress()) && !gFocusMgr.focusLocked()) { + LLPerfStats::RecordSceneTime T (LLPerfStats::StatType_t::RENDER_IDLE); joystick->scanJoystick(); gKeyboard->scanKeyboard(); gViewerInput.scanMouse(); @@ -1464,7 +1477,8 @@ bool LLAppViewer::doFrame() } { - LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df idle"); + LLPerfStats::RecordSceneTime T (LLPerfStats::StatType_t::RENDER_IDLE); + LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df idle"); idle(); } @@ -1499,6 +1513,7 @@ bool LLAppViewer::doFrame() display(); { + LLPerfStats::RecordSceneTime T(LLPerfStats::StatType_t::RENDER_IDLE); LL_PROFILE_ZONE_NAMED_CATEGORY_APP("df Snapshot"); pingMainloopTimeout("Main:Snapshot"); gPipeline.mReflectionMapManager.update(); @@ -1550,7 +1565,8 @@ bool LLAppViewer::doFrame() // of equal priority on Windows if (milliseconds_to_sleep > 0) { - ms_sleep(milliseconds_to_sleep); + LLPerfStats::RecordSceneTime T ( LLPerfStats::StatType_t::RENDER_SLEEP ); + ms_sleep(milliseconds_to_sleep); // also pause worker threads during this wait period LLAppViewer::getTextureCache()->pause(); } @@ -1637,7 +1653,7 @@ bool LLAppViewer::doFrame() LL_INFOS() << "Exiting main_loop" << LL_ENDL; } - + }LLPerfStats::StatsRecorder::endFrame(); LL_PROFILER_FRAME_END return ! LLApp::isRunning(); @@ -2996,15 +3012,9 @@ void LLAppViewer::initStrings() } } -// -// This function decides whether the client machine meets the minimum requirements to -// run in a maximized window, per the consensus of davep, boa and nyx on 3/30/2011. -// bool LLAppViewer::meetsRequirementsForMaximizedStart() { - bool maximizedOk = (LLFeatureManager::getInstance()->getGPUClass() >= GPU_CLASS_2); - - maximizedOk &= (gSysMemory.getPhysicalMemoryKB() >= U32Gigabytes(1)); + bool maximizedOk = (gSysMemory.getPhysicalMemoryKB() >= U32Gigabytes(1)); return maximizedOk; } @@ -3181,15 +3191,16 @@ LLSD LLAppViewer::getViewerInfo() const // LLFloaterAbout. LLSD info; auto& versionInfo(LLVersionInfo::instance()); - info["VIEWER_VERSION"] = LLSDArray(versionInfo.getMajor())(versionInfo.getMinor())(versionInfo.getPatch())(versionInfo.getBuild()); + info["VIEWER_VERSION"] = llsd::array(versionInfo.getMajor(), versionInfo.getMinor(), + versionInfo.getPatch(), versionInfo.getBuild()); info["VIEWER_VERSION_STR"] = versionInfo.getVersion(); info["CHANNEL"] = versionInfo.getChannel(); - info["ADDRESS_SIZE"] = ADDRESS_SIZE; - std::string build_config = versionInfo.getBuildConfig(); - if (build_config != "Release") - { - info["BUILD_CONFIG"] = build_config; - } + info["ADDRESS_SIZE"] = ADDRESS_SIZE; + std::string build_config = versionInfo.getBuildConfig(); + if (build_config != "Release") + { + info["BUILD_CONFIG"] = build_config; + } // return a URL to the release notes for this viewer, such as: // https://releasenotes.secondlife.com/viewer/2.1.0.123456.html @@ -4687,6 +4698,8 @@ void LLAppViewer::idle() LLFrameTimer::updateFrameTime(); LLFrameTimer::updateFrameCount(); LLEventTimer::updateClass(); + LLPerfStats::updateClass(); + // LLApp::stepFrame() performs the above three calls plus mRunner.run(). // Not sure why we don't call stepFrame() here, except that LLRunner seems // completely redundant with LLEventTimer. diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index 6457c13ef3..31c5d2a16f 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -656,16 +656,18 @@ bool LLAppViewerWin32::init() LL_VIEWER_VERSION_PATCH << '.' << LL_VIEWER_VERSION_BUILD)); - DWORD dwFlags = MDSF_NONINTERACTIVE | // automatically submit report without prompting - MDSF_PREVENTHIJACKING; // disallow swiping Exception filter - - bool needs_log_file = !isSecondInstance() && debugLoggingEnabled("BUGSPLAT"); - if (needs_log_file) - { - // Startup only! - LL_INFOS("BUGSPLAT") << "Engaged BugSplat logging to bugsplat.log" << LL_ENDL; - dwFlags |= MDSF_LOGFILE | MDSF_LOG_VERBOSE; - } + DWORD dwFlags = MDSF_NONINTERACTIVE | // automatically submit report without prompting + MDSF_PREVENTHIJACKING; // disallow swiping Exception filter + + bool needs_log_file = !isSecondInstance(); + LL_DEBUGS("BUGSPLAT"); + if (needs_log_file) + { + // Startup only! + LL_INFOS("BUGSPLAT") << "Engaged BugSplat logging to bugsplat.log" << LL_ENDL; + dwFlags |= MDSF_LOGFILE | MDSF_LOG_VERBOSE; + } + LL_ENDL; // have to convert normal wide strings to strings of __wchar_t sBugSplatSender = new MiniDmpSender( @@ -676,12 +678,14 @@ bool LLAppViewerWin32::init() dwFlags); sBugSplatSender->setCallback(bugsplatSendLog); - if (needs_log_file) - { - // Log file will be created in %TEMP%, but it will be moved into logs folder in case of crash - std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "bugsplat.log"); - sBugSplatSender->setLogFilePath(WCSTR(log_file)); - } + LL_DEBUGS("BUGSPLAT"); + if (needs_log_file) + { + // Log file will be created in %TEMP%, but it will be moved into logs folder in case of crash + std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "bugsplat.log"); + sBugSplatSender->setLogFilePath(WCSTR(log_file)); + } + LL_ENDL; // engage stringize() overload that converts from wstring LL_INFOS("BUGSPLAT") << "Engaged BugSplat(" << LL_TO_STRING(LL_VIEWER_CHANNEL) diff --git a/indra/newview/llavatarrendernotifier.cpp b/indra/newview/llavatarrendernotifier.cpp index 94584a623b..8b09f7903d 100644 --- a/indra/newview/llavatarrendernotifier.cpp +++ b/indra/newview/llavatarrendernotifier.cpp @@ -235,6 +235,12 @@ void LLAvatarRenderNotifier::updateNotificationAgent(U32 agentComplexity) // save the value for use in following messages mLatestAgentComplexity = agentComplexity; + static LLCachedControl<U32> show_my_complexity_changes(gSavedSettings, "ShowMyComplexityChanges", 20); + if (!show_my_complexity_changes) + { + return; + } + if (!isAgentAvatarValid() || !gAgentWearables.areWearablesLoaded()) { // data not ready, nothing to show. @@ -282,7 +288,8 @@ static const char* e_hud_messages[] = }; LLHUDRenderNotifier::LLHUDRenderNotifier() : -mReportedHUDWarning(WARN_NONE) +mReportedHUDWarning(WARN_NONE), +mHUDsCount(0) { } @@ -298,6 +305,15 @@ void LLHUDRenderNotifier::updateNotificationHUD(hud_complexity_list_t complexity return; } + mHUDComplexityList = complexity; + mHUDsCount = mHUDComplexityList.size(); + + static LLCachedControl<U32> show_my_complexity_changes(gSavedSettings, "ShowMyComplexityChanges", 20); + if (!show_my_complexity_changes) + { + return; + } + // TODO: // Find a way to show message with list of issues, but without making it too large // and intrusive. diff --git a/indra/newview/llavatarrendernotifier.h b/indra/newview/llavatarrendernotifier.h index ec17b3d9e6..37130bfcf6 100644 --- a/indra/newview/llavatarrendernotifier.h +++ b/indra/newview/llavatarrendernotifier.h @@ -63,6 +63,25 @@ struct LLHUDComplexity typedef std::list<LLHUDComplexity> hud_complexity_list_t; +struct LLObjectComplexity +{ + LLObjectComplexity() + { + reset(); + } + void reset() + { + objectId = LLUUID::null; + objectName = ""; + objectCost = 0; + } + LLUUID objectId; + std::string objectName; + U32 objectCost; +}; + +typedef std::list<LLObjectComplexity> object_complexity_list_t; + // Class to notify user about drastic changes in agent's render weights or if other agents // reported that user's agent is too 'heavy' for their settings class LLAvatarRenderNotifier : public LLSingleton<LLAvatarRenderNotifier> @@ -77,6 +96,9 @@ public: void updateNotificationState(); void updateNotificationAgent(U32 agentComplexity); + void setObjectComplexityList(object_complexity_list_t object_list) { mObjectComplexityList = object_list; } + object_complexity_list_t getObjectComplexityList() { return mObjectComplexityList; } + private: LLNotificationPtr mNotificationPtr; @@ -109,6 +131,8 @@ private: // Used to detect changes in voavatar's rezzed status. // If value decreases - there were changes in outfit. S32 mLastOutfitRezStatus; + + object_complexity_list_t mObjectComplexityList; }; // Class to notify user about heavy set of HUD @@ -121,6 +145,9 @@ public: void updateNotificationHUD(hud_complexity_list_t complexity); bool isNotificationVisible(); + hud_complexity_list_t getHUDComplexityList() { return mHUDComplexityList; } + S32 getHUDsCount() { return mHUDsCount; } + private: enum EWarnLevel { @@ -141,6 +168,8 @@ private: EWarnLevel mReportedHUDWarning; LLHUDComplexity mLatestHUDComplexity; LLFrameTimer mHUDPopUpDelayTimer; + hud_complexity_list_t mHUDComplexityList; + S32 mHUDsCount; }; #endif /* ! defined(LL_llavatarrendernotifier_H) */ diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp index 04b6ebd14c..ea59a413fa 100644 --- a/indra/newview/lldrawable.cpp +++ b/indra/newview/lldrawable.cpp @@ -908,12 +908,6 @@ void LLDrawable::updateDistance(LLCamera& camera, bool force_update) LLVector3 cam_pos_from_agent = LLViewerCamera::getInstance()->getOrigin(); LLVector3 cam_to_box_offset = point_to_box_offset(cam_pos_from_agent, av_box); mDistanceWRTCamera = llmax(0.01f, ll_round(cam_to_box_offset.magVec(), 0.01f)); - LL_DEBUGS("DynamicBox") << volume->getAvatar()->getFullname() - << " pos (ignored) " << pos - << " cam pos " << cam_pos_from_agent - << " box " << av_box[0] << "," << av_box[1] - << " -> dist " << mDistanceWRTCamera - << LL_ENDL; mVObjp->updateLOD(); return; } diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index 3de0e8a7c4..187e290066 100644 --- a/indra/newview/lldrawpool.cpp +++ b/indra/newview/lldrawpool.cpp @@ -53,7 +53,6 @@ #include "llvoavatar.h" #include "llviewershadermgr.h" - S32 LLDrawPool::sNumDrawPools = 0; //============================= @@ -385,13 +384,13 @@ void LLRenderPass::renderGroup(LLSpatialGroup* group, U32 type, bool texture) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type]; - + for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo *pparams = *k; if (pparams) { - pushBatch(*pparams, texture); + pushBatch(*pparams, texture); } } } @@ -420,91 +419,7 @@ void LLRenderPass::renderRiggedGroup(LLSpatialGroup* group, U32 type, bool textu } } -void setup_texture_matrix(LLDrawInfo& params) -{ - if (params.mTextureMatrix) - { //special case implementation of texture animation here because of special handling of textures for PBR batches - gGL.getTexUnit(0)->activate(); - gGL.matrixMode(LLRender::MM_TEXTURE); - gGL.loadMatrix((GLfloat*)params.mTextureMatrix->mMatrix); - gPipeline.mTextureMatrixOps++; - } -} - -void teardown_texture_matrix(LLDrawInfo& params) -{ - if (params.mTextureMatrix) - { - gGL.matrixMode(LLRender::MM_TEXTURE0); - gGL.loadIdentity(); - gGL.matrixMode(LLRender::MM_MODELVIEW); - } -} - -void LLRenderPass::pushGLTFBatches(U32 type) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; - auto* begin = gPipeline.beginRenderMap(type); - auto* end = gPipeline.endRenderMap(type); - for (LLCullResult::drawinfo_iterator i = begin; i != end; ) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("pushGLTFBatch"); - LLDrawInfo& params = **i; - LLCullResult::increment_iterator(i, end); - - pushGLTFBatch(params); - } -} - -void LLRenderPass::pushGLTFBatch(LLDrawInfo& params) -{ - auto& mat = params.mGLTFMaterial; - - mat->bind(params.mTexture); - - LLGLDisable cull_face(mat->mDoubleSided ? GL_CULL_FACE : 0); - - setup_texture_matrix(params); - - applyModelMatrix(params); - - params.mVertexBuffer->setBuffer(); - params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset); - - teardown_texture_matrix(params); -} - -void LLRenderPass::pushRiggedGLTFBatches(U32 type) -{ - LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; - LLVOAvatar* lastAvatar = nullptr; - U64 lastMeshId = 0; - - auto* begin = gPipeline.beginRenderMap(type); - auto* end = gPipeline.endRenderMap(type); - for (LLCullResult::drawinfo_iterator i = begin; i != end; ) - { - LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("pushRiggedGLTFBatch"); - LLDrawInfo& params = **i; - LLCullResult::increment_iterator(i, end); - - pushRiggedGLTFBatch(params, lastAvatar, lastMeshId); - } -} - -void LLRenderPass::pushRiggedGLTFBatch(LLDrawInfo& params, LLVOAvatar*& lastAvatar, U64& lastMeshId) -{ - if (params.mAvatar.notNull() && (lastAvatar != params.mAvatar || lastMeshId != params.mSkinInfo->mHash)) - { - uploadMatrixPalette(params); - lastAvatar = params.mAvatar; - lastMeshId = params.mSkinInfo->mHash; - } - - pushGLTFBatch(params); -} - -void LLRenderPass::pushBatches(U32 type, bool texture, bool batch_textures, bool reset_gltf) +void LLRenderPass::pushBatches(U32 type, bool texture, bool batch_textures) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; auto* begin = gPipeline.beginRenderMap(type); @@ -514,12 +429,11 @@ void LLRenderPass::pushBatches(U32 type, bool texture, bool batch_textures, bool LLDrawInfo* pparams = *i; LLCullResult::increment_iterator(i, end); - pushBatch(*pparams, texture, batch_textures, reset_gltf); - reset_gltf = false; + pushBatch(*pparams, texture, batch_textures); } } -void LLRenderPass::pushRiggedBatches(U32 type, bool texture, bool batch_textures, bool reset_gltf) +void LLRenderPass::pushRiggedBatches(U32 type, bool texture, bool batch_textures) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; LLVOAvatar* lastAvatar = nullptr; @@ -538,12 +452,11 @@ void LLRenderPass::pushRiggedBatches(U32 type, bool texture, bool batch_textures lastMeshId = pparams->mSkinInfo->mHash; } - pushBatch(*pparams, texture, batch_textures, reset_gltf); - reset_gltf = false; + pushBatch(*pparams, texture, batch_textures); } } -void LLRenderPass::pushMaskBatches(U32 type, bool texture, bool batch_textures, bool reset_gltf) +void LLRenderPass::pushMaskBatches(U32 type, bool texture, bool batch_textures) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; auto* begin = gPipeline.beginRenderMap(type); @@ -553,12 +466,11 @@ void LLRenderPass::pushMaskBatches(U32 type, bool texture, bool batch_textures, LLDrawInfo* pparams = *i; LLCullResult::increment_iterator(i, end); LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(pparams->mAlphaMaskCutoff); - pushBatch(*pparams, texture, batch_textures, reset_gltf); - reset_gltf = false; + pushBatch(*pparams, texture, batch_textures); } } -void LLRenderPass::pushRiggedMaskBatches(U32 type, bool texture, bool batch_textures, bool reset_gltf) +void LLRenderPass::pushRiggedMaskBatches(U32 type, bool texture, bool batch_textures) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; LLVOAvatar* lastAvatar = nullptr; @@ -571,6 +483,8 @@ void LLRenderPass::pushRiggedMaskBatches(U32 type, bool texture, bool batch_text LLCullResult::increment_iterator(i, end); + llassert(pparams); + if (LLGLSLShader::sCurBoundShaderPtr) { LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(pparams->mAlphaMaskCutoff); @@ -587,8 +501,7 @@ void LLRenderPass::pushRiggedMaskBatches(U32 type, bool texture, bool batch_text lastMeshId = pparams->mSkinInfo->mHash; } - pushBatch(*pparams, texture, batch_textures, reset_gltf); - reset_gltf = false; + pushBatch(*pparams, texture, batch_textures); } } @@ -607,14 +520,7 @@ void LLRenderPass::applyModelMatrix(const LLDrawInfo& params) } } -void LLRenderPass::resetGLTFTextureTransform() -{ - F32 ignore_gltf_transform[8]; - LLGLTFMaterial::sDefault.mTextureTransform[LLGLTFMaterial::GLTF_TEXTURE_INFO_BASE_COLOR].getPacked(ignore_gltf_transform); - LLGLSLShader::sCurBoundShaderPtr->uniform4fv(LLShaderMgr::TEXTURE_BASE_COLOR_TRANSFORM, 2, (F32*)ignore_gltf_transform); -} - -void LLRenderPass::pushBatch(LLDrawInfo& params, bool texture, bool batch_textures, bool reset_gltf) +void LLRenderPass::pushBatch(LLDrawInfo& params, bool texture, bool batch_textures) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; if (!params.mCount) @@ -623,7 +529,6 @@ void LLRenderPass::pushBatch(LLDrawInfo& params, bool texture, bool batch_textur } applyModelMatrix(params); - if (reset_gltf) { resetGLTFTextureTransform(); } bool tex_setup = false; @@ -702,3 +607,87 @@ bool LLRenderPass::uploadMatrixPalette(LLVOAvatar* avatar, LLMeshSkinInfo* skinI return true; } +void setup_texture_matrix(LLDrawInfo& params) +{ + if (params.mTextureMatrix) + { //special case implementation of texture animation here because of special handling of textures for PBR batches + gGL.getTexUnit(0)->activate(); + gGL.matrixMode(LLRender::MM_TEXTURE); + gGL.loadMatrix((GLfloat*)params.mTextureMatrix->mMatrix); + gPipeline.mTextureMatrixOps++; + } +} + +void teardown_texture_matrix(LLDrawInfo& params) +{ + if (params.mTextureMatrix) + { + gGL.matrixMode(LLRender::MM_TEXTURE0); + gGL.loadIdentity(); + gGL.matrixMode(LLRender::MM_MODELVIEW); + } +} + +void LLRenderPass::pushGLTFBatches(U32 type) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + auto* begin = gPipeline.beginRenderMap(type); + auto* end = gPipeline.endRenderMap(type); + for (LLCullResult::drawinfo_iterator i = begin; i != end; ) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("pushGLTFBatch"); + LLDrawInfo& params = **i; + LLCullResult::increment_iterator(i, end); + + pushGLTFBatch(params); + } +} + +void LLRenderPass::pushGLTFBatch(LLDrawInfo& params) +{ + auto& mat = params.mGLTFMaterial; + + mat->bind(params.mTexture); + + LLGLDisable cull_face(mat->mDoubleSided ? GL_CULL_FACE : 0); + + setup_texture_matrix(params); + + applyModelMatrix(params); + + params.mVertexBuffer->setBuffer(); + params.mVertexBuffer->drawRange(LLRender::TRIANGLES, params.mStart, params.mEnd, params.mCount, params.mOffset); + + teardown_texture_matrix(params); +} + +void LLRenderPass::pushRiggedGLTFBatches(U32 type) +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; + LLVOAvatar* lastAvatar = nullptr; + U64 lastMeshId = 0; + + auto* begin = gPipeline.beginRenderMap(type); + auto* end = gPipeline.endRenderMap(type); + for (LLCullResult::drawinfo_iterator i = begin; i != end; ) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("pushRiggedGLTFBatch"); + LLDrawInfo& params = **i; + LLCullResult::increment_iterator(i, end); + + pushRiggedGLTFBatch(params, lastAvatar, lastMeshId); + } +} + +void LLRenderPass::pushRiggedGLTFBatch(LLDrawInfo& params, LLVOAvatar*& lastAvatar, U64& lastMeshId) +{ + if (params.mAvatar.notNull() && (lastAvatar != params.mAvatar || lastMeshId != params.mSkinInfo->mHash)) + { + uploadMatrixPalette(params); + lastAvatar = params.mAvatar; + lastMeshId = params.mSkinInfo->mHash; + } + + pushGLTFBatch(params); +} + diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h index 8704f2e340..eef19199b9 100644 --- a/indra/newview/lldrawpool.h +++ b/indra/newview/lldrawpool.h @@ -349,17 +349,18 @@ public: void resetDrawOrders() { } static void applyModelMatrix(const LLDrawInfo& params); + // Use before a non-GLTF batch if it is interleaved with GLTF batches that share the same shader static void resetGLTFTextureTransform(); - virtual void pushBatches(U32 type, bool texture = true, bool batch_textures = false, bool reset_gltf = false); - virtual void pushRiggedBatches(U32 type, bool texture = true, bool batch_textures = false, bool reset_gltf = false); + void pushBatches(U32 type, bool texture = true, bool batch_textures = false); + void pushRiggedBatches(U32 type, bool texture = true, bool batch_textures = false); void pushGLTFBatches(U32 type); void pushGLTFBatch(LLDrawInfo& params); void pushRiggedGLTFBatches(U32 type); void pushRiggedGLTFBatch(LLDrawInfo& params, LLVOAvatar*& lastAvatar, U64& lastMeshId); - virtual void pushMaskBatches(U32 type, bool texture = true, bool batch_textures = false, bool reset_gltf = false); - virtual void pushRiggedMaskBatches(U32 type, bool texture = true, bool batch_textures = false, bool reset_gltf = false); - // reset_gltf: batch is interleaved with GLTF batches that share the same shader - virtual void pushBatch(LLDrawInfo& params, bool texture, bool batch_textures = false, bool reset_gltf = false); + void pushMaskBatches(U32 type, bool texture = true, bool batch_textures = false); + void pushRiggedMaskBatches(U32 type, bool texture = true, bool batch_textures = false); + void pushBatch(LLDrawInfo& params, bool texture, bool batch_textures = false); + void pushBumpBatch(LLDrawInfo& params, bool texture, bool batch_textures = false); static bool uploadMatrixPalette(LLDrawInfo& params); static bool uploadMatrixPalette(LLVOAvatar* avatar, LLMeshSkinInfo* skinInfo); virtual void renderGroup(LLSpatialGroup* group, U32 type, bool texture = true); diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp index 280be162bc..f8d2a9e942 100644 --- a/indra/newview/lldrawpoolalpha.cpp +++ b/indra/newview/lldrawpoolalpha.cpp @@ -107,12 +107,10 @@ static void prepare_alpha_shader(LLGLSLShader* shader, bool textureGamma, bool d // i.e. shaders\class1\deferred\alphaF.glsl if (deferredEnvironment) { - gPipeline.bindDeferredShader( *shader ); - } - else - { - shader->bind(); + shader->mCanBindFast = false; } + + shader->bind(); shader->uniform1f(LLShaderMgr::DISPLAY_GAMMA, (gamma > 0.1f) ? 1.0f / gamma : (1.0f / 2.2f)); if (LLPipeline::sRenderingHUDs) @@ -159,7 +157,7 @@ void LLDrawPoolAlpha::renderPostDeferred(S32 pass) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; - if ((!LLPipeline::sRenderTransparentWater || gCubeSnapshot) && getType() == LLDrawPool::POOL_ALPHA_PRE_WATER) + if (LLPipeline::isWaterClip() && getType() == LLDrawPool::POOL_ALPHA_PRE_WATER) { // don't render alpha objects on the other side of the water plane if water is opaque return; } @@ -537,6 +535,8 @@ void LLDrawPoolAlpha::renderRiggedEmissives(std::vector<LLDrawInfo*>& emissives) for (LLDrawInfo* draw : emissives) { + LL_PROFILE_ZONE_NAMED_CATEGORY_DRAWPOOL("Emissives"); + bool tex_setup = TexSetup(draw, false); if (lastAvatar != draw->mAvatar || lastMeshId != draw->mSkinInfo->mHash) { @@ -664,7 +664,7 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask, bool depth_only, bool rigged) LLSpatialGroup::drawmap_elem_t& draw_info = rigged ? group->mDrawMap[LLRenderPass::PASS_ALPHA_RIGGED] : group->mDrawMap[LLRenderPass::PASS_ALPHA]; - for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) + for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo& params = **k; if ((bool)params.mAvatar != rigged) diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 9820202f9b..19b23609a6 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -369,9 +369,11 @@ void LLDrawPoolAvatar::renderShadow(S32 pass) { return; } - LLVOAvatar::AvatarOverallAppearance oa = avatarp->getOverallAppearance(); + + LLVOAvatar::AvatarOverallAppearance oa = avatarp->getOverallAppearance(); BOOL impostor = !LLPipeline::sImpostorRender && avatarp->isImpostor(); - if (impostor || (oa == LLVOAvatar::AOA_INVISIBLE)) + // no shadows if the shadows are causing this avatar to breach the limit. + if (avatarp->isTooSlow() || impostor || (oa == LLVOAvatar::AOA_INVISIBLE)) { // No shadows for impostored (including jellydolled) or invisible avs. return; diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp index 35265b6df0..38768a19c8 100644 --- a/indra/newview/lldrawpoolbump.cpp +++ b/indra/newview/lldrawpoolbump.cpp @@ -77,6 +77,7 @@ static LLGLSLShader* shader = NULL; static S32 cube_channel = -1; static S32 diffuse_channel = -1; static S32 bump_channel = -1; +static BOOL shiny = FALSE; // Enabled after changing LLViewerTexture::mNeedsCreateTexture to an // LLAtomicBool; this should work just fine, now. HB @@ -197,7 +198,7 @@ void LLStandardBumpmap::destroyGL() LLDrawPoolBump::LLDrawPoolBump() : LLRenderPass(LLDrawPool::POOL_BUMP) { - mShiny = FALSE; + shiny = FALSE; } @@ -346,7 +347,7 @@ void LLDrawPoolBump::beginFullbrightShiny() diffuse_channel = 0; } - mShiny = TRUE; + shiny = TRUE; } void LLDrawPoolBump::renderFullbrightShiny() @@ -398,14 +399,14 @@ void LLDrawPoolBump::endFullbrightShiny() diffuse_channel = -1; cube_channel = 0; - mShiny = FALSE; + shiny = FALSE; } void LLDrawPoolBump::renderGroup(LLSpatialGroup* group, U32 type, bool texture = true) { LLSpatialGroup::drawmap_elem_t& draw_info = group->mDrawMap[type]; - for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) + for (LLSpatialGroup::drawmap_elem_t::iterator k = draw_info.begin(); k != draw_info.end(); ++k) { LLDrawInfo& params = **k; @@ -541,7 +542,7 @@ void LLDrawPoolBump::renderDeferred(S32 pass) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; //LL_RECORD_BLOCK_TIME(FTM_RENDER_BUMP); - mShiny = TRUE; + shiny = TRUE; for (int i = 0; i < 2; ++i) { bool rigged = i == 1; @@ -575,11 +576,11 @@ void LLDrawPoolBump::renderDeferred(S32 pass) avatar = params.mAvatar; skin = params.mSkinInfo->mHash; } - pushBatch(params, true, false); + pushBumpBatch(params, true, false); } else { - pushBatch(params, true, false); + pushBumpBatch(params, true, false); } } @@ -589,7 +590,7 @@ void LLDrawPoolBump::renderDeferred(S32 pass) gGL.getTexUnit(0)->activate(); } - mShiny = FALSE; + shiny = FALSE; } @@ -1213,20 +1214,18 @@ void LLDrawPoolBump::pushBumpBatches(U32 type) } } } - pushBatch(params, false); + pushBumpBatch(params, false); } } } -void LLDrawPoolBump::pushBatch(LLDrawInfo& params, bool texture, bool batch_textures, bool reset_gltf) +void LLRenderPass::pushBumpBatch(LLDrawInfo& params, bool texture, bool batch_textures) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; applyModelMatrix(params); bool tex_setup = false; - if (reset_gltf) { LLRenderPass::resetGLTFTextureTransform(); } - if (batch_textures && params.mTextureList.size() > 1) { for (U32 i = 0; i < params.mTextureList.size(); ++i) @@ -1241,7 +1240,7 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, bool texture, bool batch_text { //not batching textures or batch has only 1 texture -- might need a texture matrix if (params.mTextureMatrix) { - if (mShiny) + if (shiny) { gGL.getTexUnit(0)->activate(); gGL.matrixMode(LLRender::MM_TEXTURE); @@ -1260,7 +1259,7 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, bool texture, bool batch_text tex_setup = true; } - if (mShiny && mShaderLevel > 1 && texture) + if (shiny && mShaderLevel > 1 && texture) { if (params.mTexture.notNull()) { @@ -1278,7 +1277,7 @@ void LLDrawPoolBump::pushBatch(LLDrawInfo& params, bool texture, bool batch_text if (tex_setup) { - if (mShiny) + if (shiny) { gGL.getTexUnit(0)->activate(); } diff --git a/indra/newview/lldrawpoolbump.h b/indra/newview/lldrawpoolbump.h index 41c4879ded..b1fe454c72 100644 --- a/indra/newview/lldrawpoolbump.h +++ b/indra/newview/lldrawpoolbump.h @@ -53,7 +53,6 @@ public: LLDrawPoolBump(); /*virtual*/ void prerender() override; - void pushBatch(LLDrawInfo& params, bool texture, bool batch_textures = false, bool reset_gltf = false) override; void pushBumpBatches(U32 type); void renderGroup(LLSpatialGroup* group, U32 type, bool texture) override; diff --git a/indra/newview/llfeaturemanager.cpp b/indra/newview/llfeaturemanager.cpp index 0974ae0742..a2aae91ae1 100644 --- a/indra/newview/llfeaturemanager.cpp +++ b/indra/newview/llfeaturemanager.cpp @@ -408,6 +408,7 @@ bool LLFeatureManager::loadGPUClass() { if (!gSavedSettings.getBOOL("SkipBenchmark")) { + F32 class1_gbps = gSavedSettings.getF32("RenderClass1MemoryBandwidth"); //get memory bandwidth from benchmark F32 gbps; try @@ -424,6 +425,14 @@ bool LLFeatureManager::loadGPUClass() LL_WARNS("RenderInit") << "GPU benchmark failed: " << e.what() << LL_ENDL; } + mGPUMemoryBandwidth = gbps; + + // bias by CPU speed + F32 cpu_basis_mhz = gSavedSettings.getF32("RenderCPUBasis"); + F32 cpu_mhz = (F32) gSysCPU.getMHz(); + F32 cpu_bias = llclamp(cpu_mhz / cpu_basis_mhz, 0.5f, 1.f); + gbps *= cpu_bias; + if (gbps < 0.f) { //couldn't bench, default to Low #if LL_DARWIN @@ -434,19 +443,19 @@ bool LLFeatureManager::loadGPUClass() mGPUClass = GPU_CLASS_0; #endif } - else if (gbps <= 32.0f) + else if (gbps <= class1_gbps) { mGPUClass = GPU_CLASS_1; } - else if (gbps <= 64.0f) + else if (gbps <= class1_gbps *2.f) { mGPUClass = GPU_CLASS_2; } - else if (gbps <= 128.0f) + else if (gbps <= class1_gbps*4.f) { mGPUClass = GPU_CLASS_3; } - else if (gbps <= 256.0f) + else if (gbps <= class1_gbps*8.f) { mGPUClass = GPU_CLASS_4; } diff --git a/indra/newview/llfeaturemanager.h b/indra/newview/llfeaturemanager.h index 42a226cd18..651404d890 100644 --- a/indra/newview/llfeaturemanager.h +++ b/indra/newview/llfeaturemanager.h @@ -111,6 +111,10 @@ public: EGPUClass getGPUClass() { return mGPUClass; } std::string& getGPUString() { return mGPUString; } + + // get the measured GPU memory bandwidth in GB/sec + // may return 0 of benchmark has not been run or failed to run + F32 getGPUMemoryBandwidth() { return mGPUMemoryBandwidth; } BOOL isGPUSupported() { return mGPUSupported; } F32 getExpectedGLVersion() { return mExpectedGLVersion; } @@ -162,6 +166,7 @@ protected: S32 mTableVersion; BOOL mSafe; // Reinitialize everything to the "safe" mask EGPUClass mGPUClass; + F32 mGPUMemoryBandwidth = 0.f; // measured memory bandwidth of GPU in GB/second F32 mExpectedGLVersion; //expected GL version according to gpu table std::string mGPUString; BOOL mGPUSupported; diff --git a/indra/newview/llfloater360capture.cpp b/indra/newview/llfloater360capture.cpp index 542a1ea39b..23f86e2361 100644 --- a/indra/newview/llfloater360capture.cpp +++ b/indra/newview/llfloater360capture.cpp @@ -319,13 +319,7 @@ const std::string LLFloater360Capture::getHTMLBaseFolder() // triggered when the 'capture' button in the UI is pressed void LLFloater360Capture::onCapture360ImagesBtn() { - // launch the main capture code in a coroutine so we can - // yield/suspend at some points to give the main UI - // thread a look-in occasionally. - LLCoros::instance().launch("capture360cap", [this]() - { - capture360Images(); - }); + capture360Images(); } // Gets the full path name for a given JavaScript file in the HTML folder. We @@ -686,9 +680,6 @@ void LLFloater360Capture::capture360Images() mCaptureBtn->setEnabled(true); mSaveLocalBtn->setEnabled(true); - // allow the UI to update by suspending and waiting for the - // main render loop to update the UI - suspendForAFrame(); } // once the request is made to navigate to the web page containing the code diff --git a/indra/newview/llfloateravatarrendersettings.cpp b/indra/newview/llfloateravatarrendersettings.cpp index 8b28f6941e..7d098e6c88 100644 --- a/indra/newview/llfloateravatarrendersettings.cpp +++ b/indra/newview/llfloateravatarrendersettings.cpp @@ -89,8 +89,6 @@ BOOL LLFloaterAvatarRenderSettings::postBuild() LLFloater::postBuild(); mAvatarSettingsList = getChild<LLNameListCtrl>("render_settings_list"); mAvatarSettingsList->setRightMouseDownCallback(boost::bind(&LLFloaterAvatarRenderSettings::onAvatarListRightClick, this, _1, _2, _3)); - mAvatarSettingsList->setAlternateSort(); - getChild<LLFilterEditor>("people_filter_input")->setCommitCallback(boost::bind(&LLFloaterAvatarRenderSettings::onFilterEdit, this, _2)); return TRUE; } @@ -134,37 +132,13 @@ void LLFloaterAvatarRenderSettings::updateList() { item_params.value = iter->first; LLAvatarNameCache::get(iter->first, &av_name); - if(!isHiddenRow(av_name.getCompleteName())) - { - item_params.columns.add().value(av_name.getCompleteName()).column("name"); - std::string setting = getString(iter->second == 1 ? "av_never_render" : "av_always_render"); - item_params.columns.add().value(setting).column("setting"); - S32 mute_date = LLRenderMuteList::getInstance()->getVisualMuteDate(iter->first); - item_params.columns.add().value(createTimestamp(mute_date)).column("timestamp").alt_value(std::to_string(mute_date)); - mAvatarSettingsList->addNameItemRow(item_params); - } + item_params.columns.add().value(av_name.getCompleteName()).column("name"); + std::string setting = getString(iter->second == 1 ? "av_never_render" : "av_always_render"); + item_params.columns.add().value(setting).column("setting"); + mAvatarSettingsList->addNameItemRow(item_params); } } -void LLFloaterAvatarRenderSettings::onFilterEdit(const std::string& search_string) -{ - std::string filter_upper = search_string; - LLStringUtil::toUpper(filter_upper); - if (mNameFilter != filter_upper) - { - mNameFilter = filter_upper; - mNeedsUpdate = true; - } -} - -bool LLFloaterAvatarRenderSettings::isHiddenRow(const std::string& av_name) -{ - if (mNameFilter.empty()) return false; - std::string upper_name = av_name; - LLStringUtil::toUpper(upper_name); - return std::string::npos == upper_name.find(mNameFilter); -} - static LLVOAvatar* find_avatar(const LLUUID& id) { LLViewerObject *obj = gObjectList.findObject(id); @@ -215,6 +189,10 @@ bool LLFloaterAvatarRenderSettings::isActionChecked(const LLSD& userdata, const { return (visual_setting == S32(LLVOAvatar::AV_RENDER_NORMALLY)); } + else if ("non_default" == command_name) + { + return (visual_setting != S32(LLVOAvatar::AV_RENDER_NORMALLY)); + } else if ("never" == command_name) { return (visual_setting == S32(LLVOAvatar::AV_DO_NOT_RENDER)); diff --git a/indra/newview/llfloateravatarrendersettings.h b/indra/newview/llfloateravatarrendersettings.h index 00ee074f17..2e0a844afd 100644 --- a/indra/newview/llfloateravatarrendersettings.h +++ b/indra/newview/llfloateravatarrendersettings.h @@ -48,7 +48,6 @@ public: void onAvatarListRightClick(LLUICtrl* ctrl, S32 x, S32 y); void updateList(); - void onFilterEdit(const std::string& search_string); void onCustomAction (const LLSD& userdata, const LLUUID& av_id); bool isActionChecked(const LLSD& userdata, const LLUUID& av_id); void onClickAdd(const LLSD& userdata); @@ -59,15 +58,12 @@ public: static void setNeedsUpdate(); private: - bool isHiddenRow(const std::string& av_name); void callbackAvatarPicked(const uuid_vec_t& ids, S32 visual_setting); void removePicker(); bool mNeedsUpdate; LLListContextMenu* mContextMenu; LLNameListCtrl* mAvatarSettingsList; - - std::string mNameFilter; }; diff --git a/indra/newview/llfloatereditsky.cpp b/indra/newview/llfloatereditsky.cpp index 6bdc5ee823..2d5e86869d 100644 --- a/indra/newview/llfloatereditsky.cpp +++ b/indra/newview/llfloatereditsky.cpp @@ -523,7 +523,7 @@ void LLFloaterEditSky::refreshSkyPresetsList() for (LLEnvironment::list_name_id_t::iterator it = list.begin(); it != list.end(); ++it) { - mSkyPresetCombo->add((*it).first, LLSDArray((*it).first)((*it).second)); + mSkyPresetCombo->add((*it).first, llsd::array((*it).first, (*it).second)); } mSkyPresetCombo->setLabel(getString("combo_label")); diff --git a/indra/newview/llfloatereditwater.cpp b/indra/newview/llfloatereditwater.cpp index 6e7b777e70..c44ae7faca 100644 --- a/indra/newview/llfloatereditwater.cpp +++ b/indra/newview/llfloatereditwater.cpp @@ -335,7 +335,7 @@ void LLFloaterEditWater::refreshWaterPresetsList() for (LLEnvironment::list_name_id_t::iterator it = list.begin(); it != list.end(); ++it) { - mWaterPresetCombo->add((*it).first, LLSDArray((*it).first)((*it).second)); + mWaterPresetCombo->add((*it).first, llsd::array((*it).first, (*it).second)); } mWaterPresetCombo->setLabel(getString("combo_label")); diff --git a/indra/newview/llfloaterperformance.cpp b/indra/newview/llfloaterperformance.cpp new file mode 100644 index 0000000000..19fc3e673e --- /dev/null +++ b/indra/newview/llfloaterperformance.cpp @@ -0,0 +1,748 @@ +/** + * @file llfloaterperformance.cpp + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, 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 "llfloaterperformance.h" + +#include "llagent.h" +#include "llagentcamera.h" +#include "llappearancemgr.h" +#include "llavataractions.h" +#include "llavatarrendernotifier.h" +#include "llcheckboxctrl.h" +#include "llcombobox.h" +#include "llfeaturemanager.h" +#include "llfloaterpreference.h" // LLAvatarComplexityControls +#include "llfloaterreg.h" +#include "llnamelistctrl.h" +#include "llnotificationsutil.h" +#include "llperfstats.h" +#include "llpresetsmanager.h" +#include "llradiogroup.h" +#include "llsliderctrl.h" +#include "lltextbox.h" +#include "lltrans.h" +#include "llviewerobjectlist.h" +#include "llviewerwindow.h" +#include "llvoavatar.h" +#include "llvoavatarself.h" +#include "llworld.h" +#include "pipeline.h" + +const F32 REFRESH_INTERVAL = 1.0f; +const S32 BAR_LEFT_PAD = 2; +const S32 BAR_RIGHT_PAD = 5; +const S32 BAR_BOTTOM_PAD = 9; + +class LLExceptionsContextMenu : public LLListContextMenu +{ +public: + LLExceptionsContextMenu(LLFloaterPerformance* floater_settings) + : mFloaterPerformance(floater_settings) + {} +protected: + LLContextMenu* createMenu() + { + LLUICtrl::CommitCallbackRegistry::ScopedRegistrar registrar; + LLUICtrl::EnableCallbackRegistry::ScopedRegistrar enable_registrar; + registrar.add("Settings.SetRendering", boost::bind(&LLFloaterPerformance::onCustomAction, mFloaterPerformance, _2, mUUIDs.front())); + enable_registrar.add("Settings.IsSelected", boost::bind(&LLFloaterPerformance::isActionChecked, mFloaterPerformance, _2, mUUIDs.front())); + LLContextMenu* menu = createFromFile("menu_avatar_rendering_settings.xml"); + + return menu; + } + + LLFloaterPerformance* mFloaterPerformance; +}; + +LLFloaterPerformance::LLFloaterPerformance(const LLSD& key) +: LLFloater(key), + mUpdateTimer(new LLTimer()) +{ + mContextMenu = new LLExceptionsContextMenu(this); +} + +LLFloaterPerformance::~LLFloaterPerformance() +{ + mMaxARTChangedSignal.disconnect(); + delete mContextMenu; + delete mUpdateTimer; +} + +BOOL LLFloaterPerformance::postBuild() +{ + mMainPanel = getChild<LLPanel>("panel_performance_main"); + mNearbyPanel = getChild<LLPanel>("panel_performance_nearby"); + mComplexityPanel = getChild<LLPanel>("panel_performance_complexity"); + mSettingsPanel = getChild<LLPanel>("panel_performance_preferences"); + mHUDsPanel = getChild<LLPanel>("panel_performance_huds"); + mAutoadjustmentsPanel = getChild<LLPanel>("panel_performance_autoadjustments"); + + getChild<LLPanel>("nearby_subpanel")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mNearbyPanel)); + getChild<LLPanel>("complexity_subpanel")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mComplexityPanel)); + getChild<LLPanel>("settings_subpanel")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mSettingsPanel)); + getChild<LLPanel>("huds_subpanel")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mHUDsPanel)); + getChild<LLPanel>("autoadjustments_subpanel")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::showSelectedPanel, this, mAutoadjustmentsPanel)); + + initBackBtn(mNearbyPanel); + initBackBtn(mComplexityPanel); + initBackBtn(mSettingsPanel); + initBackBtn(mHUDsPanel); + initBackBtn(mAutoadjustmentsPanel); + + mHUDList = mHUDsPanel->getChild<LLNameListCtrl>("hud_list"); + mHUDList->setNameListType(LLNameListCtrl::SPECIAL); + mHUDList->setHoverIconName("StopReload_Off"); + mHUDList->setIconClickedCallback(boost::bind(&LLFloaterPerformance::detachItem, this, _1)); + + mObjectList = mComplexityPanel->getChild<LLNameListCtrl>("obj_list"); + mObjectList->setNameListType(LLNameListCtrl::SPECIAL); + mObjectList->setHoverIconName("StopReload_Off"); + mObjectList->setIconClickedCallback(boost::bind(&LLFloaterPerformance::detachItem, this, _1)); + + mSettingsPanel->getChild<LLButton>("advanced_btn")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickAdvanced, this)); + mSettingsPanel->getChild<LLButton>("defaults_btn")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickDefaults, this)); + mSettingsPanel->getChild<LLRadioGroup>("graphics_quality")->setCommitCallback(boost::bind(&LLFloaterPerformance::onChangeQuality, this, _2)); + mSettingsPanel->getChild<LLCheckBoxCtrl>("advanced_lighting_model")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::onClickAdvancedLighting, this)); + mSettingsPanel->getChild<LLComboBox>("ShadowDetail")->setMouseDownCallback(boost::bind(&LLFloaterPerformance::onClickShadows, this)); + + mNearbyPanel->getChild<LLButton>("exceptions_btn")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickExceptions, this)); + mNearbyPanel->getChild<LLCheckBoxCtrl>("hide_avatars")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickHideAvatars, this)); + mNearbyPanel->getChild<LLCheckBoxCtrl>("hide_avatars")->set(!LLPipeline::hasRenderTypeControl(LLPipeline::RENDER_TYPE_AVATAR)); + mNearbyList = mNearbyPanel->getChild<LLNameListCtrl>("nearby_list"); + mNearbyList->setRightMouseDownCallback(boost::bind(&LLFloaterPerformance::onAvatarListRightClick, this, _1, _2, _3)); + + mMaxARTChangedSignal = gSavedSettings.getControl("RenderAvatarMaxART")->getCommitSignal()->connect(boost::bind(&LLFloaterPerformance::updateMaxRenderTime, this)); + mNearbyPanel->getChild<LLSliderCtrl>("RenderAvatarMaxART")->setCommitCallback(boost::bind(&LLFloaterPerformance::updateMaxRenderTime, this)); + + if(!LLPerfStats::tunables.userAutoTuneEnabled) + { + gSavedSettings.setF32("AutoTuneRenderFarClipTarget", LLPipeline::RenderFarClip); + } + + LLStringExplicit fps_limit(llformat("%d", gViewerWindow->getWindow()->getRefreshRate())); + mAutoadjustmentsPanel->getChild<LLTextBox>("vsync_desc_limit")->setTextArg("[FPS_LIMIT]", fps_limit); + mAutoadjustmentsPanel->getChild<LLTextBox>("display_desc")->setTextArg("[FPS_LIMIT]", fps_limit); + mAutoadjustmentsPanel->getChild<LLButton>("defaults_btn")->setCommitCallback(boost::bind(&LLFloaterPerformance::onClickDefaults, this)); + + mStartAutotuneBtn = mAutoadjustmentsPanel->getChild<LLButton>("start_autotune"); + mStopAutotuneBtn = mAutoadjustmentsPanel->getChild<LLButton>("stop_autotune"); + mStartAutotuneBtn->setCommitCallback(boost::bind(&LLFloaterPerformance::startAutotune, this)); + mStopAutotuneBtn->setCommitCallback(boost::bind(&LLFloaterPerformance::stopAutotune, this)); + + gSavedPerAccountSettings.declareBOOL("HadEnabledAutoFPS", FALSE, "User had enabled AutoFPS at least once", LLControlVariable::PERSIST_ALWAYS); + + return TRUE; +} + +void LLFloaterPerformance::showSelectedPanel(LLPanel* selected_panel) +{ + hidePanels(); + mMainPanel->setVisible(FALSE); + selected_panel->setVisible(TRUE); + + if (mHUDsPanel == selected_panel) + { + populateHUDList(); + } + else if (mNearbyPanel == selected_panel) + { + populateNearbyList(); + } + else if (mComplexityPanel == selected_panel) + { + populateObjectList(); + } +} + +void LLFloaterPerformance::showAutoadjustmentsPanel() +{ + showSelectedPanel(mAutoadjustmentsPanel); +} + +void LLFloaterPerformance::draw() +{ + enableAutotuneWarning(); + + if (mUpdateTimer->hasExpired() && + !LLFloaterReg::instanceVisible("save_pref_preset", PRESETS_GRAPHIC)) // give user a chance to save the graphics settings before updating them + { + setFPSText(); + if (mHUDsPanel->getVisible()) + { + populateHUDList(); + } + else if (mNearbyPanel->getVisible()) + { + populateNearbyList(); + mNearbyPanel->getChild<LLCheckBoxCtrl>("hide_avatars")->set(!LLPipeline::hasRenderTypeControl(LLPipeline::RENDER_TYPE_AVATAR)); + } + else if (mComplexityPanel->getVisible()) + { + populateObjectList(); + } + + mUpdateTimer->setTimerExpirySec(REFRESH_INTERVAL); + } + updateAutotuneCtrls(LLPerfStats::tunables.userAutoTuneEnabled); + + LLFloater::draw(); +} + +void LLFloaterPerformance::showMainPanel() +{ + hidePanels(); + mMainPanel->setVisible(TRUE); +} + +void LLFloaterPerformance::hidePanels() +{ + mNearbyPanel->setVisible(FALSE); + mComplexityPanel->setVisible(FALSE); + mHUDsPanel->setVisible(FALSE); + mSettingsPanel->setVisible(FALSE); + mAutoadjustmentsPanel->setVisible(FALSE); +} + +void LLFloaterPerformance::initBackBtn(LLPanel* panel) +{ + panel->getChild<LLButton>("back_btn")->setCommitCallback(boost::bind(&LLFloaterPerformance::showMainPanel, this)); + + panel->getChild<LLTextBox>("back_lbl")->setShowCursorHand(false); + panel->getChild<LLTextBox>("back_lbl")->setSoundFlags(LLView::MOUSE_UP); + panel->getChild<LLTextBox>("back_lbl")->setClickedCallback(boost::bind(&LLFloaterPerformance::showMainPanel, this)); +} + +void LLFloaterPerformance::populateHUDList() +{ + S32 prev_pos = mHUDList->getScrollPos(); + LLUUID prev_selected_id = mHUDList->getSelectedSpecialId(); + mHUDList->clearRows(); + mHUDList->updateColumns(true); + + LLVOAvatar* avatar = gAgentAvatarp; + + gPipeline.profileAvatar(avatar, true); + + LLVOAvatar::attachment_map_t::iterator iter; + LLVOAvatar::attachment_map_t::iterator begin = avatar->mAttachmentPoints.begin(); + LLVOAvatar::attachment_map_t::iterator end = avatar->mAttachmentPoints.end(); + + // get max gpu render time of all attachments + F32 max_gpu_time = -1.f; + + for (iter = begin; iter != end; ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + LLViewerObject* attached_object = attachment_iter->get(); + if (attached_object && attached_object->isHUDAttachment()) + { + max_gpu_time = llmax(max_gpu_time, attached_object->mGPURenderTime); + } + } + } + + + for (iter = begin; iter != end; ++iter) + { + if (!iter->second) + { + continue; + } + + LLViewerJointAttachment* attachment = iter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + LLViewerObject* attached_object = attachment_iter->get(); + if (attached_object && attached_object->isHUDAttachment()) + { + F32 gpu_time = attached_object->mGPURenderTime; + + LLSD item; + item["special_id"] = attached_object->getID(); + item["target"] = LLNameListCtrl::SPECIAL; + LLSD& row = item["columns"]; + row[0]["column"] = "complex_visual"; + row[0]["type"] = "bar"; + LLSD& value = row[0]["value"]; + value["ratio"] = gpu_time / max_gpu_time; + value["bottom"] = BAR_BOTTOM_PAD; + value["left_pad"] = BAR_LEFT_PAD; + value["right_pad"] = BAR_RIGHT_PAD; + + row[1]["column"] = "complex_value"; + row[1]["type"] = "text"; + // show gpu time in us + row[1]["value"] = llformat("%.f", gpu_time * 1000.f); + row[1]["font"]["name"] = "SANSSERIF"; + + row[2]["column"] = "name"; + row[2]["type"] = "text"; + row[2]["value"] = attached_object->getAttachmentItemName(); + row[2]["font"]["name"] = "SANSSERIF"; + + LLScrollListItem* obj = mHUDList->addElement(item); + if (obj) + { + LLScrollListText* value_text = dynamic_cast<LLScrollListText*>(obj->getColumn(1)); + if (value_text) + { + value_text->setAlignment(LLFontGL::HCENTER); + } + } + } + } + } + mHUDList->sortByColumnIndex(1, FALSE); + mHUDList->setScrollPos(prev_pos); + mHUDList->selectItemBySpecialId(prev_selected_id); +} + +void LLFloaterPerformance::populateObjectList() +{ + S32 prev_pos = mObjectList->getScrollPos(); + LLUUID prev_selected_id = mObjectList->getSelectedSpecialId(); + mObjectList->clearRows(); + mObjectList->updateColumns(true); + + LLVOAvatar* avatar = gAgentAvatarp; + + gPipeline.profileAvatar(avatar, true); + + LLVOAvatar::attachment_map_t::iterator iter; + LLVOAvatar::attachment_map_t::iterator begin = avatar->mAttachmentPoints.begin(); + LLVOAvatar::attachment_map_t::iterator end = avatar->mAttachmentPoints.end(); + + // get max gpu render time of all attachments + F32 max_gpu_time = -1.f; + + for (iter = begin; iter != end; ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + LLViewerObject* attached_object = attachment_iter->get(); + if (attached_object && !attached_object->isHUDAttachment()) + { + max_gpu_time = llmax(max_gpu_time, attached_object->mGPURenderTime); + } + } + } + + { + for (iter = begin; iter != end; ++iter) + { + if (!iter->second) + { + continue; + } + + LLViewerJointAttachment* attachment = iter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + LLViewerObject* attached_object = attachment_iter->get(); + if (attached_object && !attached_object->isHUDAttachment()) + { + F32 gpu_time = attached_object->mGPURenderTime; + + LLSD item; + item["special_id"] = attached_object->getID(); + item["target"] = LLNameListCtrl::SPECIAL; + LLSD& row = item["columns"]; + row[0]["column"] = "complex_visual"; + row[0]["type"] = "bar"; + LLSD& value = row[0]["value"]; + value["ratio"] = gpu_time / max_gpu_time; + value["bottom"] = BAR_BOTTOM_PAD; + value["left_pad"] = BAR_LEFT_PAD; + value["right_pad"] = BAR_RIGHT_PAD; + + row[1]["column"] = "complex_value"; + row[1]["type"] = "text"; + // show gpu time in us + row[1]["value"] = llformat("%.f", gpu_time * 1000.f); + row[1]["font"]["name"] = "SANSSERIF"; + + row[2]["column"] = "name"; + row[2]["type"] = "text"; + row[2]["value"] = attached_object->getAttachmentItemName(); + row[2]["font"]["name"] = "SANSSERIF"; + + LLScrollListItem* obj = mObjectList->addElement(item); + if (obj) + { + LLScrollListText* value_text = dynamic_cast<LLScrollListText*>(obj->getColumn(1)); + if (value_text) + { + value_text->setAlignment(LLFontGL::HCENTER); + } + } + } + } + } + } + mObjectList->sortByColumnIndex(1, FALSE); + mObjectList->setScrollPos(prev_pos); + mObjectList->selectItemBySpecialId(prev_selected_id); +} + +void LLFloaterPerformance::populateNearbyList() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_APP; + static LLCachedControl<bool> showTunedART(gSavedSettings, "ShowTunedART"); + S32 prev_pos = mNearbyList->getScrollPos(); + LLUUID prev_selected_id = mNearbyList->getStringUUIDSelectedItem(); + mNearbyList->clearRows(); + mNearbyList->updateColumns(true); + + static LLCachedControl<U32> max_render_cost(gSavedSettings, "RenderAvatarMaxComplexity", 0); + std::vector<LLCharacter*> valid_nearby_avs; + mNearbyMaxGPUTime = LLWorld::getInstance()->getNearbyAvatarsAndMaxGPUTime(valid_nearby_avs); + + std::vector<LLCharacter*>::iterator char_iter = valid_nearby_avs.begin(); + + while (char_iter != valid_nearby_avs.end()) + { + LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(*char_iter); + if (avatar && (LLVOAvatar::AOA_INVISIBLE != avatar->getOverallAppearance())) + { + F32 render_av_gpu_ms = avatar->getGPURenderTime(); + + auto is_slow = avatar->isTooSlow(); + LLSD item; + item["id"] = avatar->getID(); + LLSD& row = item["columns"]; + row[0]["column"] = "complex_visual"; + row[0]["type"] = "bar"; + LLSD& value = row[0]["value"]; + // The ratio used in the bar is the current cost, as soon as we take action this changes so we keep the + // pre-tune value for the numerical column and sorting. + value["ratio"] = render_av_gpu_ms / mNearbyMaxGPUTime; + value["bottom"] = BAR_BOTTOM_PAD; + value["left_pad"] = BAR_LEFT_PAD; + value["right_pad"] = BAR_RIGHT_PAD; + + row[1]["column"] = "complex_value"; + row[1]["type"] = "text"; + // use GPU time in us + row[1]["value"] = llformat( "%.f", render_av_gpu_ms * 1000.f); + row[1]["font"]["name"] = "SANSSERIF"; + + row[3]["column"] = "name"; + row[3]["type"] = "text"; + row[3]["value"] = avatar->getFullname(); + row[3]["font"]["name"] = "SANSSERIF"; + + LLScrollListItem* av_item = mNearbyList->addElement(item); + if(av_item) + { + LLScrollListText* value_text = dynamic_cast<LLScrollListText*>(av_item->getColumn(1)); + if (value_text) + { + value_text->setAlignment(LLFontGL::HCENTER); + } + LLScrollListText* name_text = dynamic_cast<LLScrollListText*>(av_item->getColumn(2)); + if (name_text) + { + if (avatar->isSelf()) + { + name_text->setColor(LLUIColorTable::instance().getColor("DrYellow")); + } + else + { + std::string color = "white"; + if (is_slow || LLVOAvatar::AOA_JELLYDOLL == avatar->getOverallAppearance()) + { + color = "LabelDisabledColor"; + LLScrollListBar* bar = dynamic_cast<LLScrollListBar*>(av_item->getColumn(0)); + if (bar) + { + bar->setColor(LLUIColorTable::instance().getColor(color)); + } + } + else if (LLVOAvatar::AOA_NORMAL == avatar->getOverallAppearance()) + { + color = LLAvatarActions::isFriend(avatar->getID()) ? "ConversationFriendColor" : "white"; + } + name_text->setColor(LLUIColorTable::instance().getColor(color)); + } + } + } + } + char_iter++; + } + mNearbyList->sortByColumnIndex(1, FALSE); + mNearbyList->setScrollPos(prev_pos); + mNearbyList->selectByID(prev_selected_id); +} + +void LLFloaterPerformance::setFPSText() +{ + const S32 NUM_PERIODS = 50; + S32 current_fps = (S32)llround(LLTrace::get_frame_recording().getPeriodMedianPerSec(LLStatViewer::FPS, NUM_PERIODS)); + getChild<LLTextBox>("fps_value")->setValue(current_fps); + + std::string fps_text = getString("fps_text"); + static LLCachedControl<bool> vsync_enabled(gSavedSettings, "RenderVSyncEnable", true); + S32 refresh_rate = gViewerWindow->getWindow()->getRefreshRate(); + if (vsync_enabled && (refresh_rate > 0) && (current_fps >= refresh_rate)) + { + fps_text += getString("max_text"); + } + getChild<LLTextBox>("fps_lbl")->setValue(fps_text); +} + +void LLFloaterPerformance::detachItem(const LLUUID& item_id) +{ + LLAppearanceMgr::instance().removeItemFromAvatar(item_id); +} + +void LLFloaterPerformance::onClickAdvanced() +{ + LLFloaterPreference* instance = LLFloaterReg::getTypedInstance<LLFloaterPreference>("preferences"); + if (instance) + { + instance->saveSettings(); + } + LLFloaterReg::showInstance("prefs_graphics_advanced"); +} + +void LLFloaterPerformance::onClickDefaults() +{ + LLFloaterPreference* instance = LLFloaterReg::getTypedInstance<LLFloaterPreference>("preferences"); + if (instance) + { + instance->setRecommendedSettings(); + } +} + +void LLFloaterPerformance::onChangeQuality(const LLSD& data) +{ + LLFloaterPreference* instance = LLFloaterReg::getTypedInstance<LLFloaterPreference>("preferences"); + if (instance) + { + instance->onChangeQuality(data); + } +} + +void LLFloaterPerformance::onClickHideAvatars() +{ + LLPipeline::toggleRenderTypeControl(LLPipeline::RENDER_TYPE_AVATAR); +} + +void LLFloaterPerformance::onClickExceptions() +{ + LLFloaterReg::showInstance("avatar_render_settings"); +} + +void LLFloaterPerformance::updateMaxRenderTime() +{ + LLAvatarComplexityControls::updateMaxRenderTime( + mNearbyPanel->getChild<LLSliderCtrl>("RenderAvatarMaxART"), + mNearbyPanel->getChild<LLTextBox>("RenderAvatarMaxARTText"), + true); +} + +static LLVOAvatar* find_avatar(const LLUUID& id) +{ + LLViewerObject *obj = gObjectList.findObject(id); + while (obj && obj->isAttachment()) + { + obj = (LLViewerObject *)obj->getParent(); + } + + if (obj && obj->isAvatar()) + { + return (LLVOAvatar*)obj; + } + else + { + return NULL; + } +} + +void LLFloaterPerformance::onCustomAction(const LLSD& userdata, const LLUUID& av_id) +{ + const std::string command_name = userdata.asString(); + + S32 new_setting = 0; + if ("default" == command_name) + { + new_setting = S32(LLVOAvatar::AV_RENDER_NORMALLY); + } + else if ("never" == command_name) + { + new_setting = S32(LLVOAvatar::AV_DO_NOT_RENDER); + } + else if ("always" == command_name) + { + new_setting = S32(LLVOAvatar::AV_ALWAYS_RENDER); + } + + LLVOAvatar *avatarp = find_avatar(av_id); + if (avatarp) + { + avatarp->setVisualMuteSettings(LLVOAvatar::VisualMuteSettings(new_setting)); + } + else + { + LLRenderMuteList::getInstance()->saveVisualMuteSetting(av_id, new_setting); + } +} + + +bool LLFloaterPerformance::isActionChecked(const LLSD& userdata, const LLUUID& av_id) +{ + const std::string command_name = userdata.asString(); + + S32 visual_setting = LLRenderMuteList::getInstance()->getSavedVisualMuteSetting(av_id); + if ("default" == command_name) + { + return (visual_setting == S32(LLVOAvatar::AV_RENDER_NORMALLY)); + } + else if ("non_default" == command_name) + { + return (visual_setting != S32(LLVOAvatar::AV_RENDER_NORMALLY)); + } + else if ("never" == command_name) + { + return (visual_setting == S32(LLVOAvatar::AV_DO_NOT_RENDER)); + } + else if ("always" == command_name) + { + return (visual_setting == S32(LLVOAvatar::AV_ALWAYS_RENDER)); + } + return false; +} + +void LLFloaterPerformance::onAvatarListRightClick(LLUICtrl* ctrl, S32 x, S32 y) +{ + LLNameListCtrl* list = dynamic_cast<LLNameListCtrl*>(ctrl); + if (!list) return; + list->selectItemAt(x, y, MASK_NONE); + uuid_vec_t selected_uuids; + + if((list->getCurrentID().notNull()) && (list->getCurrentID() != gAgentID)) + { + selected_uuids.push_back(list->getCurrentID()); + mContextMenu->show(ctrl, selected_uuids, x, y); + } +} + +const U32 RENDER_QUALITY_LEVEL = 3; +void LLFloaterPerformance::changeQualityLevel(const std::string& notif) +{ + LLNotificationsUtil::add(notif, LLSD(), LLSD(), + [](const LLSD¬if, const LLSD&resp) + { + S32 opt = LLNotificationsUtil::getSelectedOption(notif, resp); + if (opt == 0) + { + LLFloaterPreference* instance = LLFloaterReg::getTypedInstance<LLFloaterPreference>("preferences"); + if (instance) + { + gSavedSettings.setU32("RenderQualityPerformance", RENDER_QUALITY_LEVEL); + instance->onChangeQuality(LLSD((S32)RENDER_QUALITY_LEVEL)); + } + } + }); +} + +bool is_ALM_available() +{ + bool bumpshiny = LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump") && gSavedSettings.getBOOL("RenderObjectBump"); + bool shaders = gSavedSettings.getBOOL("WindLightUseAtmosShaders"); + + return LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && + bumpshiny && + shaders; +} + +void LLFloaterPerformance::onClickAdvancedLighting() +{ + if (!is_ALM_available()) + { + changeQualityLevel("AdvancedLightingConfirm"); + } +} + +void LLFloaterPerformance::onClickShadows() +{ + if (!is_ALM_available() || !gSavedSettings.getBOOL("RenderDeferred")) + { + changeQualityLevel("ShadowsConfirm"); + } + +} + +void LLFloaterPerformance::startAutotune() +{ + LLPerfStats::tunables.userAutoTuneEnabled = true; +} + +void LLFloaterPerformance::stopAutotune() +{ + LLPerfStats::tunables.userAutoTuneEnabled = false; +} + +void LLFloaterPerformance::updateAutotuneCtrls(bool autotune_enabled) +{ + static LLCachedControl<bool> auto_tune_locked(gSavedSettings, "AutoTuneLock"); + mStartAutotuneBtn->setEnabled(!autotune_enabled && !auto_tune_locked); + mStopAutotuneBtn->setEnabled(autotune_enabled && !auto_tune_locked); + getChild<LLCheckBoxCtrl>("AutoTuneContinuous")->setEnabled(!autotune_enabled || (autotune_enabled && auto_tune_locked)); + + getChild<LLTextBox>("wip_desc")->setVisible(autotune_enabled && !auto_tune_locked); + getChild<LLTextBox>("display_desc")->setVisible(LLPerfStats::tunables.vsyncEnabled); +} + +void LLFloaterPerformance::enableAutotuneWarning() +{ + if (!gSavedPerAccountSettings.getBOOL("HadEnabledAutoFPS") && LLPerfStats::tunables.userAutoTuneEnabled) + { + gSavedPerAccountSettings.setBOOL("HadEnabledAutoFPS", TRUE); + + LLNotificationsUtil::add("EnableAutoFPSWarning", LLSD(), LLSD(), + [](const LLSD& notif, const LLSD& resp) + { + S32 opt = LLNotificationsUtil::getSelectedOption(notif, resp); + if (opt == 0) + { // offer user to save current graphics settings as a preset + LLFloaterReg::showInstance("save_pref_preset", PRESETS_GRAPHIC); + } + }); + } +} +// EOF diff --git a/indra/newview/llfloaterperformance.h b/indra/newview/llfloaterperformance.h new file mode 100644 index 0000000000..620dbac5bb --- /dev/null +++ b/indra/newview/llfloaterperformance.h @@ -0,0 +1,104 @@ +/** + * @file llfloaterperformance.h + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, 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_LLFLOATERPERFORMANCE_H +#define LL_LLFLOATERPERFORMANCE_H + +#include "llfloater.h" +#include "lllistcontextmenu.h" + +class LLCharacter; +class LLNameListCtrl; + +class LLFloaterPerformance : public LLFloater +{ +public: + LLFloaterPerformance(const LLSD& key); + virtual ~LLFloaterPerformance(); + + /*virtual*/ BOOL postBuild(); + /*virtual*/ void draw(); + + void showSelectedPanel(LLPanel* selected_panel); + void showMainPanel(); + void hidePanels(); + void showAutoadjustmentsPanel(); + + void detachItem(const LLUUID& item_id); + + void onAvatarListRightClick(LLUICtrl* ctrl, S32 x, S32 y); + + void onCustomAction (const LLSD& userdata, const LLUUID& av_id); + bool isActionChecked(const LLSD& userdata, const LLUUID& av_id); + +private: + void initBackBtn(LLPanel* panel); + void populateHUDList(); + void populateObjectList(); + void populateNearbyList(); + void setFPSText(); + + void onClickAdvanced(); + void onClickDefaults(); + void onChangeQuality(const LLSD& data); + void onClickHideAvatars(); + void onClickExceptions(); + void onClickShadows(); + void onClickAdvancedLighting(); + + void startAutotune(); + void stopAutotune(); + void updateAutotuneCtrls(bool autotune_enabled); + void enableAutotuneWarning(); + + void updateMaxRenderTime(); + + static void changeQualityLevel(const std::string& notif); + + LLPanel* mMainPanel; + LLPanel* mNearbyPanel; + LLPanel* mComplexityPanel; + LLPanel* mHUDsPanel; + LLPanel* mSettingsPanel; + LLPanel* mAutoadjustmentsPanel; + LLNameListCtrl* mHUDList; + LLNameListCtrl* mObjectList; + LLNameListCtrl* mNearbyList; + + LLButton* mStartAutotuneBtn; + LLButton* mStopAutotuneBtn; + + LLListContextMenu* mContextMenu; + + LLTimer* mUpdateTimer; + + // maximum GPU time of nearby avatars in ms according to LLWorld::getNearbyAvatarsAndMaxGPUTime + // -1.f if no profile has happened yet + F32 mNearbyMaxGPUTime = -1.f; + + boost::signals2::connection mMaxARTChangedSignal; +}; + +#endif // LL_LLFLOATERPERFORMANCE_H diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp index 7487c1c9f9..d4e40ff103 100644 --- a/indra/newview/llfloaterpreference.cpp +++ b/indra/newview/llfloaterpreference.cpp @@ -50,6 +50,8 @@ #include "llfloaterreg.h" #include "llfloaterabout.h" #include "llfavoritesbar.h" +#include "llfloaterpreferencesgraphicsadvanced.h" +#include "llfloaterperformance.h" #include "llfloatersidepanelcontainer.h" #include "llfloaterimsession.h" #include "llkeyboard.h" @@ -74,7 +76,6 @@ #include "llviewereventrecorder.h" #include "llviewermessage.h" #include "llviewerwindow.h" -#include "llviewershadermgr.h" #include "llviewerthrottle.h" #include "llvoavatarself.h" #include "llvotree.h" @@ -97,11 +98,9 @@ #include "lltextbox.h" #include "llui.h" #include "llviewerobjectlist.h" -#include "llvoavatar.h" #include "llvovolume.h" #include "llwindow.h" #include "llworld.h" -#include "pipeline.h" #include "lluictrlfactory.h" #include "llviewermedia.h" #include "llpluginclassmedia.h" @@ -114,10 +113,9 @@ #include "llpresetsmanager.h" #include "llviewercontrol.h" #include "llpresetsmanager.h" -#include "llfeaturemanager.h" -#include "llviewertexturelist.h" #include "llsearchableui.h" +#include "llperfstats.h" const F32 BANDWIDTH_UPDATER_TIMEOUT = 0.5f; char const* const VISIBILITY_DEFAULT = "default"; @@ -289,6 +287,7 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) mCommitCallbackRegistrar.add("Pref.ClickDisablePopup", boost::bind(&LLFloaterPreference::onClickDisablePopup, this)); mCommitCallbackRegistrar.add("Pref.LogPath", boost::bind(&LLFloaterPreference::onClickLogPath, this)); mCommitCallbackRegistrar.add("Pref.RenderExceptions", boost::bind(&LLFloaterPreference::onClickRenderExceptions, this)); + mCommitCallbackRegistrar.add("Pref.AutoAdjustments", boost::bind(&LLFloaterPreference::onClickAutoAdjustments, this)); mCommitCallbackRegistrar.add("Pref.HardwareDefaults", boost::bind(&LLFloaterPreference::setHardwareDefaults, this)); mCommitCallbackRegistrar.add("Pref.AvatarImpostorsEnable", boost::bind(&LLFloaterPreference::onAvatarImpostorsEnable, this)); mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity", boost::bind(&LLFloaterPreference::updateMaxComplexity, this)); @@ -317,9 +316,12 @@ LLFloaterPreference::LLFloaterPreference(const LLSD& key) gSavedSettings.getControl("UseDisplayNames")->getCommitSignal()->connect(boost::bind(&handleDisplayNamesOptionChanged, _2)); gSavedSettings.getControl("AppearanceCameraMovement")->getCommitSignal()->connect(boost::bind(&handleAppearanceCameraMovementChanged, _2)); + gSavedSettings.getControl("WindLightUseAtmosShaders")->getCommitSignal()->connect(boost::bind(&LLFloaterPreference::onAtmosShaderChange, this)); LLAvatarPropertiesProcessor::getInstance()->addObserver( gAgent.getID(), this ); + mComplexityChangedSignal = gSavedSettings.getControl("RenderAvatarMaxComplexity")->getCommitSignal()->connect(boost::bind(&LLFloaterPreference::updateComplexityText, this)); + mCommitCallbackRegistrar.add("Pref.ClearLog", boost::bind(&LLConversationLog::onClearLog, &LLConversationLog::instance())); mCommitCallbackRegistrar.add("Pref.DeleteTranscripts", boost::bind(&LLFloaterPreference::onDeleteTranscripts, this)); mCommitCallbackRegistrar.add("UpdateFilter", boost::bind(&LLFloaterPreference::onUpdateFilterTerm, this, false)); // <FS:ND/> Hook up for filtering @@ -487,6 +489,7 @@ void LLFloaterPreference::onDoNotDisturbResponseChanged() LLFloaterPreference::~LLFloaterPreference() { LLConversationLog::instance().removeObserver(this); + mComplexityChangedSignal.disconnect(); } void LLFloaterPreference::draw() @@ -730,13 +733,15 @@ void LLFloaterPreference::onOpen(const LLSD& key) LLButton* save_btn = findChild<LLButton>("PrefSaveButton"); LLButton* delete_btn = findChild<LLButton>("PrefDeleteButton"); LLButton* exceptions_btn = findChild<LLButton>("RenderExceptionsButton"); + LLButton* auto_adjustments_btn = findChild<LLButton>("AutoAdjustmentsButton"); - if (load_btn && save_btn && delete_btn && exceptions_btn) + if (load_btn && save_btn && delete_btn && exceptions_btn && auto_adjustments_btn) { load_btn->setEnabled(started); save_btn->setEnabled(started); delete_btn->setEnabled(started); exceptions_btn->setEnabled(started); + auto_adjustments_btn->setEnabled(started); } collectSearchableItems(); @@ -752,33 +757,6 @@ void LLFloaterPreference::onRenderOptionEnable() refreshEnabledGraphics(); } -void LLFloaterPreferenceGraphicsAdvanced::onRenderOptionEnable() -{ - LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); - if (instance) - { - instance->refresh(); - } - - refreshEnabledGraphics(); -} - -void LLFloaterPreferenceGraphicsAdvanced::onAdvancedAtmosphericsEnable() -{ - LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); - if (instance) - { - instance->refresh(); - } - - refreshEnabledGraphics(); -} - -void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledGraphics() -{ - refreshEnabledState(); -} - void LLFloaterPreference::onAvatarImpostorsEnable() { refreshEnabledGraphics(); @@ -812,6 +790,13 @@ void LLFloaterPreference::setHardwareDefaults() saveGraphicsPreset(preset_graphic_active); saveSettings(); // save here to be able to return to the previous preset by Cancel } + setRecommendedSettings(); +} + +void LLFloaterPreference::setRecommendedSettings() +{ + resetAutotuneSettings(); + gSavedSettings.getControl("RenderVSyncEnable")->resetToDefault(true); LLFeatureManager::getInstance()->applyRecommendedSettings(); @@ -836,6 +821,28 @@ void LLFloaterPreference::setHardwareDefaults() } } +void LLFloaterPreference::resetAutotuneSettings() +{ + gSavedSettings.setBOOL("AutoTuneFPS", FALSE); + + const std::string autotune_settings[] = { + "AutoTuneLock", + "KeepAutoTuneLock", + "TargetFPS", + "TuningFPSStrategy", + "AutoTuneImpostorByDistEnabled", + "AutoTuneImpostorFarAwayDistance" , + "AutoTuneRenderFarClipMin", + "AutoTuneRenderFarClipTarget", + "RenderAvatarMaxART" + }; + + for (auto it : autotune_settings) + { + gSavedSettings.getControl(it)->resetToDefault(true); + } +} + void LLFloaterPreference::getControlNames(std::vector<std::string>& names) { LLView* view = findChild<LLView>("display"); @@ -1194,62 +1201,6 @@ void LLFloaterPreference::refreshEnabledState() getChildView("block_list")->setEnabled(LLLoginInstance::getInstance()->authSuccess()); } -void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState() -{ - // WindLight - LLSliderCtrl* sky = getChild<LLSliderCtrl>("SkyMeshDetail"); - LLTextBox* sky_text = getChild<LLTextBox>("SkyMeshDetailText"); - sky->setEnabled(TRUE); - sky_text->setEnabled(TRUE); - - LLCheckBoxCtrl* ctrl_ssao = getChild<LLCheckBoxCtrl>("UseSSAO"); - LLCheckBoxCtrl* ctrl_dof = getChild<LLCheckBoxCtrl>("UseDoF"); - LLComboBox* ctrl_shadow = getChild<LLComboBox>("ShadowDetail"); - LLTextBox* shadow_text = getChild<LLTextBox>("RenderShadowDetailText"); - - BOOL enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferredSSAO"); - - ctrl_ssao->setEnabled(enabled); - ctrl_dof->setEnabled(enabled); - - enabled = enabled && LLFeatureManager::getInstance()->isFeatureAvailable("RenderShadowDetail"); - - ctrl_shadow->setEnabled(enabled); - shadow_text->setEnabled(enabled); - - if (!LLFeatureManager::instance().isFeatureAvailable("RenderFSAASamples")) - { - getChildView("fsaa")->setEnabled(FALSE); - } - - enabled = false; - if (!LLFeatureManager::instance().isFeatureAvailable("RenderReflectionsEnabled")) - { - getChildView("ReflectionsEnabled")->setEnabled(FALSE); - } - else - { - enabled = gSavedSettings.getBOOL("RenderReflectionsEnabled"); - } - - getChildView("ReflectionDetail")->setEnabled(enabled); - getChildView("ReflectionDetailText")->setEnabled(enabled); - getChildView("ScreenSpaceReflections")->setEnabled(enabled); - - // Hardware settings - - if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderCompressTextures")) - { - getChildView("texture compression")->setEnabled(FALSE); - } - - getChildView("antialiasing restart")->setVisible(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred")); - - // now turn off any features that are unavailable - disableUnavailableSettings(); -} - -// static void LLAvatarComplexityControls::setIndirectControls() { /* @@ -1291,63 +1242,6 @@ void LLAvatarComplexityControls::setIndirectMaxArc() gSavedSettings.setU32("IndirectMaxComplexity", indirect_max_arc); } -void LLFloaterPreferenceGraphicsAdvanced::disableUnavailableSettings() -{ - LLComboBox* ctrl_shadows = getChild<LLComboBox>("ShadowDetail"); - LLTextBox* shadows_text = getChild<LLTextBox>("RenderShadowDetailText"); - LLCheckBoxCtrl* ctrl_ssao = getChild<LLCheckBoxCtrl>("UseSSAO"); - LLCheckBoxCtrl* ctrl_dof = getChild<LLCheckBoxCtrl>("UseDoF"); - LLSliderCtrl* sky = getChild<LLSliderCtrl>("SkyMeshDetail"); - LLTextBox* sky_text = getChild<LLTextBox>("SkyMeshDetailText"); - - // disabled windlight - if (!LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders")) - { - sky->setEnabled(FALSE); - sky_text->setEnabled(FALSE); - - //deferred needs windlight, disable deferred - ctrl_shadows->setEnabled(FALSE); - ctrl_shadows->setValue(0); - shadows_text->setEnabled(FALSE); - - ctrl_ssao->setEnabled(FALSE); - ctrl_ssao->setValue(FALSE); - - ctrl_dof->setEnabled(FALSE); - ctrl_dof->setValue(FALSE); - } - - // disabled deferred - if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred")) - { - ctrl_shadows->setEnabled(FALSE); - ctrl_shadows->setValue(0); - shadows_text->setEnabled(FALSE); - - ctrl_ssao->setEnabled(FALSE); - ctrl_ssao->setValue(FALSE); - - ctrl_dof->setEnabled(FALSE); - ctrl_dof->setValue(FALSE); - } - - // disabled deferred SSAO - if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferredSSAO")) - { - ctrl_ssao->setEnabled(FALSE); - ctrl_ssao->setValue(FALSE); - } - - // disabled deferred shadows - if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderShadowDetail")) - { - ctrl_shadows->setEnabled(FALSE); - ctrl_shadows->setValue(0); - shadows_text->setEnabled(FALSE); - } -} - void LLFloaterPreference::refresh() { LLPanel::refresh(); @@ -1363,32 +1257,6 @@ void LLFloaterPreference::refresh() updateClickActionViews(); } -void LLFloaterPreferenceGraphicsAdvanced::refresh() -{ - getChild<LLUICtrl>("fsaa")->setValue((LLSD::Integer) gSavedSettings.getU32("RenderFSAASamples")); - - // sliders and their text boxes - // mPostProcess = gSavedSettings.getS32("RenderGlowResolutionPow"); - // slider text boxes - updateSliderText(getChild<LLSliderCtrl>("ObjectMeshDetail", true), getChild<LLTextBox>("ObjectMeshDetailText", true)); - updateSliderText(getChild<LLSliderCtrl>("FlexibleMeshDetail", true), getChild<LLTextBox>("FlexibleMeshDetailText", true)); - updateSliderText(getChild<LLSliderCtrl>("TreeMeshDetail", true), getChild<LLTextBox>("TreeMeshDetailText", true)); - updateSliderText(getChild<LLSliderCtrl>("AvatarMeshDetail", true), getChild<LLTextBox>("AvatarMeshDetailText", true)); - updateSliderText(getChild<LLSliderCtrl>("AvatarPhysicsDetail", true), getChild<LLTextBox>("AvatarPhysicsDetailText", true)); - updateSliderText(getChild<LLSliderCtrl>("TerrainMeshDetail", true), getChild<LLTextBox>("TerrainMeshDetailText", true)); - updateSliderText(getChild<LLSliderCtrl>("RenderPostProcess", true), getChild<LLTextBox>("PostProcessText", true)); - updateSliderText(getChild<LLSliderCtrl>("SkyMeshDetail", true), getChild<LLTextBox>("SkyMeshDetailText", true)); - updateSliderText(getChild<LLSliderCtrl>("TerrainDetail", true), getChild<LLTextBox>("TerrainDetailText", true)); - LLAvatarComplexityControls::setIndirectControls(); - setMaxNonImpostorsText( - gSavedSettings.getU32("RenderAvatarMaxNonImpostors"), - getChild<LLTextBox>("IndirectMaxNonImpostorsText", true)); - LLAvatarComplexityControls::setText( - gSavedSettings.getU32("RenderAvatarMaxComplexity"), - getChild<LLTextBox>("IndirectMaxComplexityText", true)); - refreshEnabledState(); -} - void LLFloaterPreference::onCommitWindowedMode() { refresh(); @@ -1600,64 +1468,7 @@ void LLFloaterPreference::refreshUI() refresh(); } -void LLFloaterPreferenceGraphicsAdvanced::updateSliderText(LLSliderCtrl* ctrl, LLTextBox* text_box) -{ - if (text_box == NULL || ctrl== NULL) - return; - - // get range and points when text should change - F32 value = (F32)ctrl->getValue().asReal(); - F32 min = ctrl->getMinValue(); - F32 max = ctrl->getMaxValue(); - F32 range = max - min; - llassert(range > 0); - F32 midPoint = min + range / 3.0f; - F32 highPoint = min + (2.0f * range / 3.0f); - - // choose the right text - if (value < midPoint) - { - text_box->setText(LLTrans::getString("GraphicsQualityLow")); - } - else if (value < highPoint) - { - text_box->setText(LLTrans::getString("GraphicsQualityMid")); - } - else - { - text_box->setText(LLTrans::getString("GraphicsQualityHigh")); - } -} - -void LLFloaterPreferenceGraphicsAdvanced::updateMaxNonImpostors() -{ - // Called when the IndirectMaxNonImpostors control changes - // Responsible for fixing the slider label (IndirectMaxNonImpostorsText) and setting RenderAvatarMaxNonImpostors - LLSliderCtrl* ctrl = getChild<LLSliderCtrl>("IndirectMaxNonImpostors",true); - U32 value = ctrl->getValue().asInteger(); - - if (0 == value || LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER <= value) - { - value=0; - } - gSavedSettings.setU32("RenderAvatarMaxNonImpostors", value); - LLVOAvatar::updateImpostorRendering(value); // make it effective immediately - setMaxNonImpostorsText(value, getChild<LLTextBox>("IndirectMaxNonImpostorsText")); -} - -void LLFloaterPreferenceGraphicsAdvanced::setMaxNonImpostorsText(U32 value, LLTextBox* text_box) -{ - if (0 == value) - { - text_box->setText(LLTrans::getString("no_limit")); - } - else - { - text_box->setText(llformat("%d", value)); - } -} - -void LLAvatarComplexityControls::updateMax(LLSliderCtrl* slider, LLTextBox* value_label) +void LLAvatarComplexityControls::updateMax(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val) { // Called when the IndirectMaxComplexity control changes // Responsible for fixing the slider label (IndirectMaxComplexityText) and setting RenderAvatarMaxComplexity @@ -1679,10 +1490,10 @@ void LLAvatarComplexityControls::updateMax(LLSliderCtrl* slider, LLTextBox* valu } gSavedSettings.setU32("RenderAvatarMaxComplexity", (U32)max_arc); - setText(max_arc, value_label); + setText(max_arc, value_label, short_val); } -void LLAvatarComplexityControls::setText(U32 value, LLTextBox* text_box) +void LLAvatarComplexityControls::setText(U32 value, LLTextBox* text_box, bool short_val) { if (0 == value) { @@ -1690,24 +1501,40 @@ void LLAvatarComplexityControls::setText(U32 value, LLTextBox* text_box) } else { - text_box->setText(llformat("%d", value)); + std::string text_value = short_val ? llformat("%d", value / 1000) : llformat("%d", value); + text_box->setText(text_value); } } +void LLAvatarComplexityControls::updateMaxRenderTime(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val) +{ + setRenderTimeText((F32)(LLPerfStats::renderAvatarMaxART_ns/1000), value_label, short_val); +} + +void LLAvatarComplexityControls::setRenderTimeText(F32 value, LLTextBox* text_box, bool short_val) +{ + if (0 == value) + { + text_box->setText(LLTrans::getString("no_limit")); + } + else + { + text_box->setText(llformat("%.0f", value)); + } +} + void LLFloaterPreference::updateMaxComplexity() { // Called when the IndirectMaxComplexity control changes LLAvatarComplexityControls::updateMax( getChild<LLSliderCtrl>("IndirectMaxComplexity"), getChild<LLTextBox>("IndirectMaxComplexityText")); +} - LLFloaterPreferenceGraphicsAdvanced* floater_graphics_advanced = LLFloaterReg::findTypedInstance<LLFloaterPreferenceGraphicsAdvanced>("prefs_graphics_advanced"); - if (floater_graphics_advanced) - { - LLAvatarComplexityControls::updateMax( - floater_graphics_advanced->getChild<LLSliderCtrl>("IndirectMaxComplexity"), - floater_graphics_advanced->getChild<LLTextBox>("IndirectMaxComplexityText")); - } +void LLFloaterPreference::updateComplexityText() +{ + LLAvatarComplexityControls::setText(gSavedSettings.getU32("RenderAvatarMaxComplexity"), + getChild<LLTextBox>("IndirectMaxComplexityText", true)); } bool LLFloaterPreference::loadFromFilename(const std::string& filename, std::map<std::string, std::string> &label_map) @@ -1749,22 +1576,6 @@ bool LLFloaterPreference::loadFromFilename(const std::string& filename, std::map return true; } -void LLFloaterPreferenceGraphicsAdvanced::updateMaxComplexity() -{ - // Called when the IndirectMaxComplexity control changes - LLAvatarComplexityControls::updateMax( - getChild<LLSliderCtrl>("IndirectMaxComplexity"), - getChild<LLTextBox>("IndirectMaxComplexityText")); - - LLFloaterPreference* floater_preferences = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); - if (floater_preferences) - { - LLAvatarComplexityControls::updateMax( - floater_preferences->getChild<LLSliderCtrl>("IndirectMaxComplexity"), - floater_preferences->getChild<LLTextBox>("IndirectMaxComplexityText")); - } -} - void LLFloaterPreference::onChangeMaturity() { U8 sim_access = gSavedSettings.getU32("PreferredMaturity"); @@ -1877,6 +1688,15 @@ void LLFloaterPreference::onClickRenderExceptions() LLFloaterReg::showInstance("avatar_render_settings"); } +void LLFloaterPreference::onClickAutoAdjustments() +{ + LLFloaterPerformance* performance_floater = LLFloaterReg::showTypedInstance<LLFloaterPerformance>("performance"); + if (performance_floater) + { + performance_floater->showAutoadjustmentsPanel(); + } +} + void LLFloaterPreference::onClickAdvanced() { LLFloaterReg::showInstance("prefs_graphics_advanced"); @@ -1899,6 +1719,22 @@ void LLFloaterPreference::onClickActionChange() updateClickActionControls(); } +void LLFloaterPreference::onAtmosShaderChange() +{ + LLCheckBoxCtrl* ctrl_alm = getChild<LLCheckBoxCtrl>("UseLightShaders"); + if(ctrl_alm) + { + //Deferred/SSAO/Shadows + BOOL bumpshiny = LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump") && gSavedSettings.getBOOL("RenderObjectBump"); + BOOL shaders = gSavedSettings.getBOOL("WindLightUseAtmosShaders"); + BOOL enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && + bumpshiny && + shaders; + + ctrl_alm->setEnabled(enabled); + } +} + void LLFloaterPreference::onClickPermsDefault() { LLFloaterReg::showInstance("perms_default"); @@ -3219,18 +3055,6 @@ void LLPanelPreferenceControls::onCancelKeyBind() pControlsTable->deselectAllItems(); } -LLFloaterPreferenceGraphicsAdvanced::LLFloaterPreferenceGraphicsAdvanced(const LLSD& key) - : LLFloater(key) -{ - mCommitCallbackRegistrar.add("Pref.RenderOptionUpdate", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onRenderOptionEnable, this)); - mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxNonImpostors", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateMaxNonImpostors,this)); - mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateMaxComplexity,this)); -} - -LLFloaterPreferenceGraphicsAdvanced::~LLFloaterPreferenceGraphicsAdvanced() -{ -} - LLFloaterPreferenceProxy::LLFloaterPreferenceProxy(const LLSD& key) : LLFloater(key), mSocksSettingsDirty(false) @@ -3240,41 +3064,6 @@ LLFloaterPreferenceProxy::LLFloaterPreferenceProxy(const LLSD& key) mCommitCallbackRegistrar.add("Proxy.Change", boost::bind(&LLFloaterPreferenceProxy::onChangeSocksSettings, this)); } -BOOL LLFloaterPreferenceGraphicsAdvanced::postBuild() -{ - // Don't do this on Mac as their braindead GL versioning - // sets this when 8x and 16x are indeed available - // -#if !LL_DARWIN - if (gGLManager.mIsIntel || gGLManager.mGLVersion < 3.f) - { //remove FSAA settings above "4x" - LLComboBox* combo = getChild<LLComboBox>("fsaa"); - combo->remove("8x"); - combo->remove("16x"); - } - - LLCheckBoxCtrl *use_HiDPI = getChild<LLCheckBoxCtrl>("use HiDPI"); - use_HiDPI->setVisible(FALSE); -#endif - - return TRUE; -} - -void LLFloaterPreferenceGraphicsAdvanced::onOpen(const LLSD& key) -{ - refresh(); -} - -void LLFloaterPreferenceGraphicsAdvanced::onClickCloseBtn(bool app_quitting) -{ - LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); - if (instance) - { - instance->cancel(); - } - updateMaxComplexity(); -} - LLFloaterPreferenceProxy::~LLFloaterPreferenceProxy() { } diff --git a/indra/newview/llfloaterpreference.h b/indra/newview/llfloaterpreference.h index bab1ffdd56..04ac87364d 100644 --- a/indra/newview/llfloaterpreference.h +++ b/indra/newview/llfloaterpreference.h @@ -109,10 +109,11 @@ public: void updateClickActionViews(); void updateSearchableItems(); -protected: void onBtnOK(const LLSD& userdata); void onBtnCancel(const LLSD& userdata); +protected: + void onClickClearCache(); // Clear viewer texture cache, file cache on next startup void onClickBrowserClearCache(); // Clear web history and caches as well as viewer caches above void onLanguageChange(); @@ -138,6 +139,8 @@ protected: // updates click/double-click action keybindngs depending on view values void updateClickActionControls(); + void onAtmosShaderChange(); + public: // This function squirrels away the current values of the controls so that // cancel() can restore them. @@ -188,6 +191,7 @@ public: void onClickAutoReplace(); void onClickSpellChecker(); void onClickRenderExceptions(); + void onClickAutoAdjustments(); void onClickAdvanced(); void applyUIColor(LLUICtrl* ctrl, const LLSD& param); void getUIColor(LLUICtrl* ctrl, const LLSD& param); @@ -198,12 +202,16 @@ public: void saveCameraPreset(std::string& preset); void saveGraphicsPreset(std::string& preset); + void setRecommendedSettings(); + void resetAutotuneSettings(); + private: void onDeleteTranscripts(); void onDeleteTranscriptsResponse(const LLSD& notification, const LLSD& response); void updateDeleteTranscriptsButton(); void updateMaxComplexity(); + void updateComplexityText(); static bool loadFromFilename(const std::string& filename, std::map<std::string, std::string> &label_map); static std::string sSkin; @@ -225,6 +233,8 @@ private: std::unique_ptr< ll::prefs::SearchData > mSearchData; bool mSearchDataDirty; + boost::signals2::connection mComplexityChangedSignal; + void onUpdateFilterTerm( bool force = false ); void collectSearchableItems(); void filterIgnorableNotifications(); @@ -354,37 +364,13 @@ private: S32 mEditingMode; }; -class LLFloaterPreferenceGraphicsAdvanced : public LLFloater -{ - public: - LLFloaterPreferenceGraphicsAdvanced(const LLSD& key); - ~LLFloaterPreferenceGraphicsAdvanced(); - /*virtual*/ BOOL postBuild(); - void onOpen(const LLSD& key); - void onClickCloseBtn(bool app_quitting); - void disableUnavailableSettings(); - void refreshEnabledGraphics(); - void refreshEnabledState(); - void updateSliderText(LLSliderCtrl* ctrl, LLTextBox* text_box); - void updateMaxNonImpostors(); - void setMaxNonImpostorsText(U32 value, LLTextBox* text_box); - void updateMaxComplexity(); - void setMaxComplexityText(U32 value, LLTextBox* text_box); - static void setIndirectControls(); - static void setIndirectMaxNonImpostors(); - static void setIndirectMaxArc(); - void refresh(); - // callback for when client modifies a render option - void onRenderOptionEnable(); - void onAdvancedAtmosphericsEnable(); - LOG_CLASS(LLFloaterPreferenceGraphicsAdvanced); -}; - class LLAvatarComplexityControls { public: - static void updateMax(LLSliderCtrl* slider, LLTextBox* value_label); - static void setText(U32 value, LLTextBox* text_box); + static void updateMax(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val = false); + static void setText(U32 value, LLTextBox* text_box, bool short_val = false); + static void updateMaxRenderTime(LLSliderCtrl* slider, LLTextBox* value_label, bool short_val = false); + static void setRenderTimeText(F32 value, LLTextBox* text_box, bool short_val = false); static void setIndirectControls(); static void setIndirectMaxNonImpostors(); static void setIndirectMaxArc(); diff --git a/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp b/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp new file mode 100644 index 0000000000..a91f0ec060 --- /dev/null +++ b/indra/newview/llfloaterpreferencesgraphicsadvanced.cpp @@ -0,0 +1,480 @@ +/** + * @file llfloaterpreferencesgraphicsadvanced.cpp + * @brief floater for adjusting camera position + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, 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 "llfloaterpreferencesgraphicsadvanced.h" + +#include "llcheckboxctrl.h" +#include "llcombobox.h" +#include "llfeaturemanager.h" +#include "llfloaterpreference.h" +#include "llfloaterreg.h" +#include "llnotificationsutil.h" +#include "llsliderctrl.h" +#include "lltextbox.h" +#include "lltrans.h" +#include "llviewershadermgr.h" +#include "llviewertexturelist.h" +#include "llvoavatar.h" +#include "pipeline.h" + + +LLFloaterPreferenceGraphicsAdvanced::LLFloaterPreferenceGraphicsAdvanced(const LLSD& key) + : LLFloater(key) +{ + mCommitCallbackRegistrar.add("Pref.RenderOptionUpdate", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onRenderOptionEnable, this)); + mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxNonImpostors", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateMaxNonImpostors,this)); + mCommitCallbackRegistrar.add("Pref.UpdateIndirectMaxComplexity", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateMaxComplexity,this)); + + mCommitCallbackRegistrar.add("Pref.Cancel", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onBtnCancel, this, _2)); + mCommitCallbackRegistrar.add("Pref.OK", boost::bind(&LLFloaterPreferenceGraphicsAdvanced::onBtnOK, this, _2)); + + gSavedSettings.getControl("RenderAvatarMaxNonImpostors")->getSignal()->connect(boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateIndirectMaxNonImpostors, this, _2)); +} + +LLFloaterPreferenceGraphicsAdvanced::~LLFloaterPreferenceGraphicsAdvanced() +{ + mComplexityChangedSignal.disconnect(); + mLODFactorChangedSignal.disconnect(); +} + +BOOL LLFloaterPreferenceGraphicsAdvanced::postBuild() +{ + // Don't do this on Mac as their braindead GL versioning + // sets this when 8x and 16x are indeed available + // +#if !LL_DARWIN + if (gGLManager.mIsIntel || gGLManager.mGLVersion < 3.f) + { //remove FSAA settings above "4x" + LLComboBox* combo = getChild<LLComboBox>("fsaa"); + combo->remove("8x"); + combo->remove("16x"); + } + + LLCheckBoxCtrl *use_HiDPI = getChild<LLCheckBoxCtrl>("use HiDPI"); + use_HiDPI->setVisible(FALSE); +#endif + + mComplexityChangedSignal = gSavedSettings.getControl("RenderAvatarMaxComplexity")->getCommitSignal()->connect(boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateComplexityText, this)); + mLODFactorChangedSignal = gSavedSettings.getControl("RenderVolumeLODFactor")->getCommitSignal()->connect(boost::bind(&LLFloaterPreferenceGraphicsAdvanced::updateObjectMeshDetailText, this)); + return TRUE; +} + +void LLFloaterPreferenceGraphicsAdvanced::onOpen(const LLSD& key) +{ + refresh(); +} + +void LLFloaterPreferenceGraphicsAdvanced::onClickCloseBtn(bool app_quitting) +{ + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); + if (instance) + { + instance->cancel(); + } + updateMaxComplexity(); +} + +void LLFloaterPreferenceGraphicsAdvanced::onRenderOptionEnable() +{ + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); + if (instance) + { + instance->refresh(); + } + + refreshEnabledGraphics(); +} + +void LLFloaterPreferenceGraphicsAdvanced::onAdvancedAtmosphericsEnable() +{ + LLFloaterPreference* instance = LLFloaterReg::findTypedInstance<LLFloaterPreference>("preferences"); + if (instance) + { + instance->refresh(); + } + + refreshEnabledGraphics(); +} + +void LLFloaterPreferenceGraphicsAdvanced::refresh() +{ + getChild<LLUICtrl>("fsaa")->setValue((LLSD::Integer) gSavedSettings.getU32("RenderFSAASamples")); + + // sliders and their text boxes + // mPostProcess = gSavedSettings.getS32("RenderGlowResolutionPow"); + // slider text boxes + updateSliderText(getChild<LLSliderCtrl>("ObjectMeshDetail", true), getChild<LLTextBox>("ObjectMeshDetailText", true)); + updateSliderText(getChild<LLSliderCtrl>("FlexibleMeshDetail", true), getChild<LLTextBox>("FlexibleMeshDetailText", true)); + updateSliderText(getChild<LLSliderCtrl>("TreeMeshDetail", true), getChild<LLTextBox>("TreeMeshDetailText", true)); + updateSliderText(getChild<LLSliderCtrl>("AvatarMeshDetail", true), getChild<LLTextBox>("AvatarMeshDetailText", true)); + updateSliderText(getChild<LLSliderCtrl>("AvatarPhysicsDetail", true), getChild<LLTextBox>("AvatarPhysicsDetailText", true)); + updateSliderText(getChild<LLSliderCtrl>("TerrainMeshDetail", true), getChild<LLTextBox>("TerrainMeshDetailText", true)); + updateSliderText(getChild<LLSliderCtrl>("RenderPostProcess", true), getChild<LLTextBox>("PostProcessText", true)); + updateSliderText(getChild<LLSliderCtrl>("SkyMeshDetail", true), getChild<LLTextBox>("SkyMeshDetailText", true)); + updateSliderText(getChild<LLSliderCtrl>("TerrainDetail", true), getChild<LLTextBox>("TerrainDetailText", true)); + LLAvatarComplexityControls::setIndirectControls(); + setMaxNonImpostorsText( + gSavedSettings.getU32("RenderAvatarMaxNonImpostors"), + getChild<LLTextBox>("IndirectMaxNonImpostorsText", true)); + LLAvatarComplexityControls::setText( + gSavedSettings.getU32("RenderAvatarMaxComplexity"), + getChild<LLTextBox>("IndirectMaxComplexityText", true)); + refreshEnabledState(); +} + +void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledGraphics() +{ + refreshEnabledState(); +} + +void LLFloaterPreferenceGraphicsAdvanced::updateMaxComplexity() +{ + // Called when the IndirectMaxComplexity control changes + LLAvatarComplexityControls::updateMax( + getChild<LLSliderCtrl>("IndirectMaxComplexity"), + getChild<LLTextBox>("IndirectMaxComplexityText")); +} + +void LLFloaterPreferenceGraphicsAdvanced::updateComplexityText() +{ + LLAvatarComplexityControls::setText(gSavedSettings.getU32("RenderAvatarMaxComplexity"), + getChild<LLTextBox>("IndirectMaxComplexityText", true)); +} + +void LLFloaterPreferenceGraphicsAdvanced::updateObjectMeshDetailText() +{ + updateSliderText(getChild<LLSliderCtrl>("ObjectMeshDetail", true), getChild<LLTextBox>("ObjectMeshDetailText", true)); +} + +void LLFloaterPreferenceGraphicsAdvanced::updateSliderText(LLSliderCtrl* ctrl, LLTextBox* text_box) +{ + if (text_box == NULL || ctrl== NULL) + return; + + // get range and points when text should change + F32 value = (F32)ctrl->getValue().asReal(); + F32 min = ctrl->getMinValue(); + F32 max = ctrl->getMaxValue(); + F32 range = max - min; + llassert(range > 0); + F32 midPoint = min + range / 3.0f; + F32 highPoint = min + (2.0f * range / 3.0f); + + // choose the right text + if (value < midPoint) + { + text_box->setText(LLTrans::getString("GraphicsQualityLow")); + } + else if (value < highPoint) + { + text_box->setText(LLTrans::getString("GraphicsQualityMid")); + } + else + { + text_box->setText(LLTrans::getString("GraphicsQualityHigh")); + } +} + +void LLFloaterPreferenceGraphicsAdvanced::updateMaxNonImpostors() +{ + // Called when the IndirectMaxNonImpostors control changes + // Responsible for fixing the slider label (IndirectMaxNonImpostorsText) and setting RenderAvatarMaxNonImpostors + LLSliderCtrl* ctrl = getChild<LLSliderCtrl>("IndirectMaxNonImpostors",true); + U32 value = ctrl->getValue().asInteger(); + + if (0 == value || LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER <= value) + { + value=0; + } + gSavedSettings.setU32("RenderAvatarMaxNonImpostors", value); + LLVOAvatar::updateImpostorRendering(value); // make it effective immediately + setMaxNonImpostorsText(value, getChild<LLTextBox>("IndirectMaxNonImpostorsText")); +} + +void LLFloaterPreferenceGraphicsAdvanced::updateIndirectMaxNonImpostors(const LLSD& newvalue) +{ + U32 value = newvalue.asInteger(); + if ((value != 0) && (value != gSavedSettings.getU32("IndirectMaxNonImpostors"))) + { + gSavedSettings.setU32("IndirectMaxNonImpostors", value); + setMaxNonImpostorsText(value, getChild<LLTextBox>("IndirectMaxNonImpostorsText")); + } +} + +void LLFloaterPreferenceGraphicsAdvanced::setMaxNonImpostorsText(U32 value, LLTextBox* text_box) +{ + if (0 == value) + { + text_box->setText(LLTrans::getString("no_limit")); + } + else + { + text_box->setText(llformat("%d", value)); + } +} + +void LLFloaterPreferenceGraphicsAdvanced::disableUnavailableSettings() +{ + LLComboBox* ctrl_reflections = getChild<LLComboBox>("Reflections"); + LLTextBox* reflections_text = getChild<LLTextBox>("ReflectionsText"); + LLCheckBoxCtrl* ctrl_avatar_vp = getChild<LLCheckBoxCtrl>("AvatarVertexProgram"); + LLCheckBoxCtrl* ctrl_avatar_cloth = getChild<LLCheckBoxCtrl>("AvatarCloth"); + LLCheckBoxCtrl* ctrl_wind_light = getChild<LLCheckBoxCtrl>("WindLightUseAtmosShaders"); + LLCheckBoxCtrl* ctrl_deferred = getChild<LLCheckBoxCtrl>("UseLightShaders"); + LLComboBox* ctrl_shadows = getChild<LLComboBox>("ShadowDetail"); + LLTextBox* shadows_text = getChild<LLTextBox>("RenderShadowDetailText"); + LLCheckBoxCtrl* ctrl_ssao = getChild<LLCheckBoxCtrl>("UseSSAO"); + LLCheckBoxCtrl* ctrl_dof = getChild<LLCheckBoxCtrl>("UseDoF"); + LLSliderCtrl* sky = getChild<LLSliderCtrl>("SkyMeshDetail"); + LLTextBox* sky_text = getChild<LLTextBox>("SkyMeshDetailText"); + + // disabled windlight + if (!LLFeatureManager::getInstance()->isFeatureAvailable("WindLightUseAtmosShaders")) + { + ctrl_wind_light->setEnabled(FALSE); + ctrl_wind_light->setValue(FALSE); + + sky->setEnabled(FALSE); + sky_text->setEnabled(FALSE); + + //deferred needs windlight, disable deferred + ctrl_shadows->setEnabled(FALSE); + ctrl_shadows->setValue(0); + shadows_text->setEnabled(FALSE); + + ctrl_ssao->setEnabled(FALSE); + ctrl_ssao->setValue(FALSE); + + ctrl_dof->setEnabled(FALSE); + ctrl_dof->setValue(FALSE); + + ctrl_deferred->setEnabled(FALSE); + ctrl_deferred->setValue(FALSE); + } + + // disabled deferred + if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred")) + { + ctrl_shadows->setEnabled(FALSE); + ctrl_shadows->setValue(0); + shadows_text->setEnabled(FALSE); + + ctrl_ssao->setEnabled(FALSE); + ctrl_ssao->setValue(FALSE); + + ctrl_dof->setEnabled(FALSE); + ctrl_dof->setValue(FALSE); + + ctrl_deferred->setEnabled(FALSE); + ctrl_deferred->setValue(FALSE); + } + + // disabled deferred SSAO + if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferredSSAO")) + { + ctrl_ssao->setEnabled(FALSE); + ctrl_ssao->setValue(FALSE); + } + + // disabled deferred shadows + if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderShadowDetail")) + { + ctrl_shadows->setEnabled(FALSE); + ctrl_shadows->setValue(0); + shadows_text->setEnabled(FALSE); + } + + // disabled reflections + if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderReflectionDetail")) + { + ctrl_reflections->setEnabled(FALSE); + ctrl_reflections->setValue(FALSE); + reflections_text->setEnabled(FALSE); + } + + // disabled av + if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarVP")) + { + ctrl_avatar_vp->setEnabled(FALSE); + ctrl_avatar_vp->setValue(FALSE); + + ctrl_avatar_cloth->setEnabled(FALSE); + ctrl_avatar_cloth->setValue(FALSE); + + //deferred needs AvatarVP, disable deferred + ctrl_shadows->setEnabled(FALSE); + ctrl_shadows->setValue(0); + shadows_text->setEnabled(FALSE); + + ctrl_ssao->setEnabled(FALSE); + ctrl_ssao->setValue(FALSE); + + ctrl_dof->setEnabled(FALSE); + ctrl_dof->setValue(FALSE); + + ctrl_deferred->setEnabled(FALSE); + ctrl_deferred->setValue(FALSE); + } + + // disabled cloth + if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarCloth")) + { + ctrl_avatar_cloth->setEnabled(FALSE); + ctrl_avatar_cloth->setValue(FALSE); + } +} + +void LLFloaterPreferenceGraphicsAdvanced::refreshEnabledState() +{ + LLComboBox* ctrl_reflections = getChild<LLComboBox>("Reflections"); + LLTextBox* reflections_text = getChild<LLTextBox>("ReflectionsText"); + + // Reflections + BOOL reflections = LLCubeMap::sUseCubeMaps; + ctrl_reflections->setEnabled(reflections); + reflections_text->setEnabled(reflections); + + // Bump & Shiny + LLCheckBoxCtrl* bumpshiny_ctrl = getChild<LLCheckBoxCtrl>("BumpShiny"); + bool bumpshiny = LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump"); + bumpshiny_ctrl->setEnabled(bumpshiny ? TRUE : FALSE); + + // Avatar Mode + // Enable Avatar Shaders + LLCheckBoxCtrl* ctrl_avatar_vp = getChild<LLCheckBoxCtrl>("AvatarVertexProgram"); + // Avatar Render Mode + LLCheckBoxCtrl* ctrl_avatar_cloth = getChild<LLCheckBoxCtrl>("AvatarCloth"); + + bool avatar_vp_enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderAvatarVP"); + if (LLViewerShaderMgr::sInitialized) + { + S32 max_avatar_shader = LLViewerShaderMgr::instance()->mMaxAvatarShaderLevel; + avatar_vp_enabled = (max_avatar_shader > 0) ? TRUE : FALSE; + } + + ctrl_avatar_vp->setEnabled(avatar_vp_enabled); + + if (gSavedSettings.getBOOL("RenderAvatarVP") == FALSE) + { + ctrl_avatar_cloth->setEnabled(FALSE); + } + else + { + ctrl_avatar_cloth->setEnabled(TRUE); + } + + // Vertex Shaders, Global Shader Enable + // SL-12594 Basic shaders are always enabled. DJH TODO clean up now-orphaned state handling code + LLSliderCtrl* terrain_detail = getChild<LLSliderCtrl>("TerrainDetail"); // can be linked with control var + LLTextBox* terrain_text = getChild<LLTextBox>("TerrainDetailText"); + + terrain_detail->setEnabled(FALSE); + terrain_text->setEnabled(FALSE); + + // WindLight + //LLCheckBoxCtrl* ctrl_wind_light = getChild<LLCheckBoxCtrl>("WindLightUseAtmosShaders"); + //ctrl_wind_light->setEnabled(TRUE); + LLSliderCtrl* sky = getChild<LLSliderCtrl>("SkyMeshDetail"); + LLTextBox* sky_text = getChild<LLTextBox>("SkyMeshDetailText"); + sky->setEnabled(TRUE); + sky_text->setEnabled(TRUE); + + BOOL enabled = TRUE; +#if 0 // deferred always on now + //Deferred/SSAO/Shadows + LLCheckBoxCtrl* ctrl_deferred = getChild<LLCheckBoxCtrl>("UseLightShaders"); + + enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && + ((bumpshiny_ctrl && bumpshiny_ctrl->get()) ? TRUE : FALSE) && + (ctrl_wind_light->get()) ? TRUE : FALSE; + + ctrl_deferred->setEnabled(enabled); +#endif + + LLCheckBoxCtrl* ctrl_pbr = getChild<LLCheckBoxCtrl>("UsePBRShaders"); + + //PBR + ctrl_pbr->setEnabled(TRUE); + + LLCheckBoxCtrl* ctrl_ssao = getChild<LLCheckBoxCtrl>("UseSSAO"); + LLCheckBoxCtrl* ctrl_dof = getChild<LLCheckBoxCtrl>("UseDoF"); + LLComboBox* ctrl_shadow = getChild<LLComboBox>("ShadowDetail"); + LLTextBox* shadow_text = getChild<LLTextBox>("RenderShadowDetailText"); + + // note, okay here to get from ctrl_deferred as it's twin, ctrl_deferred2 will alway match it + enabled = enabled && LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferredSSAO");// && (ctrl_deferred->get() ? TRUE : FALSE); + + //ctrl_deferred->set(gSavedSettings.getBOOL("RenderDeferred")); + + ctrl_ssao->setEnabled(enabled); + ctrl_dof->setEnabled(enabled); + + enabled = enabled && LLFeatureManager::getInstance()->isFeatureAvailable("RenderShadowDetail"); + + ctrl_shadow->setEnabled(enabled); + shadow_text->setEnabled(enabled); + + // Hardware settings + + if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderVBOEnable")) + { + getChildView("vbo")->setEnabled(FALSE); + } + + if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderCompressTextures")) + { + getChildView("texture compression")->setEnabled(FALSE); + } + + // if no windlight shaders, turn off nighttime brightness, gamma, and fog distance + LLUICtrl* gamma_ctrl = getChild<LLUICtrl>("gamma"); + gamma_ctrl->setEnabled(!gPipeline.canUseWindLightShaders()); + getChildView("(brightness, lower is brighter)")->setEnabled(!gPipeline.canUseWindLightShaders()); + getChildView("fog")->setEnabled(!gPipeline.canUseWindLightShaders()); + getChildView("antialiasing restart")->setVisible(!LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred")); + + // now turn off any features that are unavailable + disableUnavailableSettings(); +} + +void LLFloaterPreferenceGraphicsAdvanced::onBtnOK(const LLSD& userdata) +{ + LLFloaterPreference* instance = LLFloaterReg::getTypedInstance<LLFloaterPreference>("preferences"); + if (instance) + { + instance->onBtnOK(userdata); + } +} + +void LLFloaterPreferenceGraphicsAdvanced::onBtnCancel(const LLSD& userdata) +{ + LLFloaterPreference* instance = LLFloaterReg::getTypedInstance<LLFloaterPreference>("preferences"); + if (instance) + { + instance->onBtnCancel(userdata); + } +} diff --git a/indra/newview/llfloaterpreferencesgraphicsadvanced.h b/indra/newview/llfloaterpreferencesgraphicsadvanced.h new file mode 100644 index 0000000000..2c92f3dbf1 --- /dev/null +++ b/indra/newview/llfloaterpreferencesgraphicsadvanced.h @@ -0,0 +1,68 @@ +/** + * @file llfloaterpreferencesgraphicsadvanced.h + * + * $LicenseInfo:firstyear=2021&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2021, 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 LLFLOATERPREFERENCEGRAPHICSADVANCED_H +#define LLFLOATERPREFERENCEGRAPHICSADVANCED_H + +#include "llcontrol.h" +#include "llfloater.h" + +class LLSliderCtrl; +class LLTextBox; + +class LLFloaterPreferenceGraphicsAdvanced : public LLFloater +{ +public: + LLFloaterPreferenceGraphicsAdvanced(const LLSD& key); + ~LLFloaterPreferenceGraphicsAdvanced(); + /*virtual*/ BOOL postBuild(); + void onOpen(const LLSD& key); + void onClickCloseBtn(bool app_quitting); + void disableUnavailableSettings(); + void refreshEnabledGraphics(); + void refreshEnabledState(); + void updateSliderText(LLSliderCtrl* ctrl, LLTextBox* text_box); + void updateMaxNonImpostors(); + void updateIndirectMaxNonImpostors(const LLSD& newvalue); + void setMaxNonImpostorsText(U32 value, LLTextBox* text_box); + void updateMaxComplexity(); + void updateComplexityText(); + void updateObjectMeshDetailText(); + void refresh(); + // callback for when client modifies a render option + void onRenderOptionEnable(); + void onAdvancedAtmosphericsEnable(); + LOG_CLASS(LLFloaterPreferenceGraphicsAdvanced); + +protected: + void onBtnOK(const LLSD& userdata); + void onBtnCancel(const LLSD& userdata); + + boost::signals2::connection mComplexityChangedSignal; + boost::signals2::connection mLODFactorChangedSignal; +}; + +#endif //LLFLOATERPREFERENCEGRAPHICSADVANCED_H + diff --git a/indra/newview/llglsandbox.cpp b/indra/newview/llglsandbox.cpp index 2e4d0f85b9..098fe89265 100644 --- a/indra/newview/llglsandbox.cpp +++ b/indra/newview/llglsandbox.cpp @@ -984,6 +984,7 @@ private: //----------------------------------------------------------------------------- // gpu_benchmark() +// returns measured memory bandwidth of GPU in gigabytes per second //----------------------------------------------------------------------------- F32 gpu_benchmark() { @@ -1028,8 +1029,6 @@ F32 gpu_benchmark() //time limit, allocation operations shouldn't take longer then 30 seconds, same for actual benchmark. const F32 time_limit = 30; - ShaderProfileHelper initProfile; - std::vector<LLRenderTarget> dest(count); TextureHolder texHolder(0, count); std::vector<F32> results; @@ -1111,46 +1110,49 @@ F32 gpu_benchmark() buff->unmapBuffer(); - // ensure matched pair of bind() and unbind() calls - ShaderBinder binder(gBenchmarkProgram); - - buff->setBuffer(); - glFinish(); - - F32 time_passed = 0; // seconds - for (S32 c = -1; c < samples && time_passed < time_limit; ++c) - { - LLTimer timer; - timer.start(); - - for (U32 i = 0; i < count; ++i) - { - dest[i].bindTarget(); - texHolder.bind(i); - buff->drawArrays(LLRender::TRIANGLES, 0, 3); - dest[i].flush(); - } - - //wait for current batch of copies to finish - glFinish(); - - F32 time = timer.getElapsedTimeF32(); - time_passed += time; - - if (c >= 0) // <-- ignore the first sample as it tends to be artificially slow - { - //store result in gigabytes per second - F32 gb = (F32) ((F64) (res*res*8*count))/(1000000000); - F32 gbps = gb/time; - results.push_back(gbps); - } - } + LLGLSLShader::unbind(); + + F32 time_passed = 0; // seconds + + { //run CPU timer benchmark + glFinish(); + gBenchmarkProgram.bind(); + for (S32 c = -1; c < samples && time_passed < time_limit; ++c) + { + LLTimer timer; + timer.start(); + + for (U32 i = 0; i < count; ++i) + { + dest[i].bindTarget(); + texHolder.bind(i); + buff->setBuffer(); + buff->drawArrays(LLRender::TRIANGLES, 0, 3); + dest[i].flush(); + } + + //wait for current batch of copies to finish + glFinish(); + + F32 time = timer.getElapsedTimeF32(); + time_passed += time; + + if (c >= 0) // <-- ignore the first sample as it tends to be artificially slow + { + //store result in gigabytes per second + F32 gb = (F32)((F64)(res * res * 8 * count)) / (1000000000); + F32 gbps = gb / time; + results.push_back(gbps); + } + } + gBenchmarkProgram.unbind(); + } std::sort(results.begin(), results.end()); F32 gbps = results[results.size()/2]; - LL_INFOS("Benchmark") << "Memory bandwidth is " << llformat("%.3f", gbps) << "GB/sec according to CPU timers, " << (F32)results.size() << " tests took " << time_passed << " seconds" << LL_ENDL; + LL_INFOS("Benchmark") << "Memory bandwidth is " << llformat("%.3f", gbps) << " GB/sec according to CPU timers, " << (F32)results.size() << " tests took " << time_passed << " seconds" << LL_ENDL; #if LL_DARWIN if (gbps > 512.f) @@ -1161,14 +1163,32 @@ F32 gpu_benchmark() } #endif + // run GPU timer benchmark + { + ShaderProfileHelper initProfile; + dest[0].bindTarget(); + gBenchmarkProgram.bind(); + for (S32 c = 0; c < samples; ++c) + { + for (U32 i = 0; i < count; ++i) + { + texHolder.bind(i); + buff->setBuffer(); + buff->drawArrays(LLRender::TRIANGLES, 0, 3); + } + } + gBenchmarkProgram.unbind(); + dest[0].flush(); + } + F32 ms = gBenchmarkProgram.mTimeElapsed/1000000.f; F32 seconds = ms/1000.f; - F64 samples_drawn = res*res*count*results.size(); + F64 samples_drawn = gBenchmarkProgram.mSamplesDrawn; F32 samples_sec = (samples_drawn/1000000000.0)/seconds; - gbps = samples_sec*8; + gbps = samples_sec*4; // 4 bytes per sample - LL_INFOS("Benchmark") << "Memory bandwidth is " << llformat("%.3f", gbps) << "GB/sec according to ARB_timer_query, total time " << seconds << " seconds" << LL_ENDL; + LL_INFOS("Benchmark") << "Memory bandwidth is " << llformat("%.3f", gbps) << " GB/sec according to ARB_timer_query, total time " << seconds << " seconds" << LL_ENDL; return gbps; } diff --git a/indra/newview/llgltfmateriallist.cpp b/indra/newview/llgltfmateriallist.cpp index 151d7fa969..99a052f719 100644 --- a/indra/newview/llgltfmateriallist.cpp +++ b/indra/newview/llgltfmateriallist.cpp @@ -219,40 +219,36 @@ public: struct ReturnData { public: - LLPointer<LLGLTFMaterial> mMaterial; + LLGLTFMaterial mMaterial; S32 mSide; bool mSuccess; }; - // fromJson() is performance heavy offload to a thread. - main_queue->postTo( - general_queue, - [object_override]() // Work done on general queue + if (!object_override.mSides.empty()) { - std::vector<ReturnData> results; - - if (!object_override.mSides.empty()) + // fromJson() is performance heavy offload to a thread. + main_queue->postTo( + general_queue, + [sides=object_override.mSides]() // Work done on general queue { - results.reserve(object_override.mSides.size()); + std::vector<ReturnData> results; + + results.reserve(sides.size()); // parse json - std::unordered_map<S32, std::string>::const_iterator iter = object_override.mSides.begin(); - std::unordered_map<S32, std::string>::const_iterator end = object_override.mSides.end(); + std::unordered_map<S32, std::string>::const_iterator iter = sides.begin(); + std::unordered_map<S32, std::string>::const_iterator end = sides.end(); while (iter != end) { - LLPointer<LLGLTFMaterial> override_data = new LLGLTFMaterial(); std::string warn_msg, error_msg; - bool success = override_data->fromJSON(iter->second, warn_msg, error_msg); - ReturnData result; + + bool success = result.mMaterial.fromJSON(iter->second, warn_msg, error_msg); + result.mSuccess = success; result.mSide = iter->first; - if (success) - { - result.mMaterial = override_data; - } - else + if (!success) { LL_WARNS("GLTF") << "failed to parse GLTF override data. errors: " << error_msg << " | warnings: " << warn_msg << LL_ENDL; } @@ -260,64 +256,68 @@ public: results.push_back(result); iter++; } - } - return results; - }, - [object_override, this](std::vector<ReturnData> results) // Callback to main thread + return results; + }, + [object_id=object_override.mObjectId, this](std::vector<ReturnData> results) // Callback to main thread { - LLViewerObject * obj = gObjectList.findObject(object_override.mObjectId); + LLViewerObject * obj = gObjectList.findObject(object_id); - if (results.size() > 0 ) - { - std::unordered_set<S32> side_set; - - for (int i = 0; i < results.size(); ++i) + if (results.size() > 0 ) { - if (results[i].mSuccess) + std::unordered_set<S32> side_set; + + for (auto const & result : results) { - // flag this side to not be nulled out later - side_set.insert(results[i].mSide); + S32 side = result.mSide; + if (result.mSuccess) + { + // copy to heap here because LLTextureEntry is going to take ownership with an LLPointer + LLGLTFMaterial * material = new LLGLTFMaterial(result.mMaterial); + + // flag this side to not be nulled out later + side_set.insert(side); - if (obj) + if (obj) + { + obj->setTEGLTFMaterialOverride(side, material); + } + } + + // unblock material editor + if (obj && obj->getTE(side) && obj->getTE(side)->isSelected()) { - obj->setTEGLTFMaterialOverride(results[i].mSide, results[i].mMaterial); + doSelectionCallbacks(object_id, side); } } - - // unblock material editor - if (obj && obj->getTE(results[i].mSide) && obj->getTE(results[i].mSide)->isSelected()) - { - doSelectionCallbacks(object_override.mObjectId, results[i].mSide); - } - } - if (obj && side_set.size() != obj->getNumTEs()) - { // object exists and at least one texture entry needs to have its override data nulled out - for (int i = 0; i < obj->getNumTEs(); ++i) - { - if (side_set.find(i) == side_set.end()) + if (obj && side_set.size() != obj->getNumTEs()) + { // object exists and at least one texture entry needs to have its override data nulled out + for (int i = 0; i < obj->getNumTEs(); ++i) { - obj->setTEGLTFMaterialOverride(i, nullptr); - if (obj->getTE(i) && obj->getTE(i)->isSelected()) + if (side_set.find(i) == side_set.end()) { - doSelectionCallbacks(object_override.mObjectId, i); + obj->setTEGLTFMaterialOverride(i, nullptr); + if (obj->getTE(i) && obj->getTE(i)->isSelected()) + { + doSelectionCallbacks(object_id, i); + } } } } } - } - else if (obj) - { // override list was empty or an error occurred, null out all overrides for this object - for (int i = 0; i < obj->getNumTEs(); ++i) - { - obj->setTEGLTFMaterialOverride(i, nullptr); - if (obj->getTE(i) && obj->getTE(i)->isSelected()) + else if (obj) + { // override list was empty or an error occurred, null out all overrides for this object + for (int i = 0; i < obj->getNumTEs(); ++i) { - doSelectionCallbacks(obj->getID(), i); + obj->setTEGLTFMaterialOverride(i, nullptr); + if (obj->getTE(i) && obj->getTE(i)->isSelected()) + { + doSelectionCallbacks(obj->getID(), i); + } } } - } - }); + }); + } } private: @@ -433,6 +433,19 @@ void LLGLTFMaterialList::queueApply(const LLViewerObject* obj, S32 side, const L } } +void LLGLTFMaterialList::queueApply(const LLViewerObject* obj, S32 side, const LLUUID& asset_id, const LLGLTFMaterial* material_override) +{ + if (asset_id.isNull() || material_override == nullptr) + { + queueApply(obj, side, asset_id); + } + else + { + LLGLTFMaterial* material = new LLGLTFMaterial(*material_override); + sApplyQueue.push_back({ obj->getID(), side, asset_id, material }); + } +} + void LLGLTFMaterialList::queueUpdate(const LLSD& data) { llassert(is_valid_update(data)); @@ -477,7 +490,7 @@ void LLGLTFMaterialList::flushUpdates(void(*done_callback)(bool)) } sModifyQueue.clear(); - for (auto& e : sApplyQueue) + for (ApplyMaterialAssetData& e : sApplyQueue) { data[i]["object_id"] = e.object_id; data[i]["side"] = e.side; diff --git a/indra/newview/llgltfmateriallist.h b/indra/newview/llgltfmateriallist.h index 85e60aa17f..ce8781baba 100644 --- a/indra/newview/llgltfmateriallist.h +++ b/indra/newview/llgltfmateriallist.h @@ -70,6 +70,13 @@ public: // NOTE: Implicitly clears most override data if present static void queueApply(const LLViewerObject* obj, S32 side, const LLUUID& asset_id); + // Queue an application of a material asset we want to send to the simulator. Call "flushUpdates" to flush pending updates. + // object_id - ID of object to apply material asset to + // side - TextureEntry index to apply material to, or -1 for all sides + // asset_id - ID of material asset to apply, or LLUUID::null to disassociate current material asset + // mat - override material, if null, will clear most override data + static void queueApply(const LLViewerObject* obj, S32 side, const LLUUID& asset_id, const LLGLTFMaterial* mat); + // flush pending material updates to the simulator // Automatically called once per frame, but may be called explicitly // for cases that care about the done_callback forwarded to LLCoros::instance().launch diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index e8411dd573..67bf6827ad 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1342,10 +1342,11 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id, bool can_retry) if (header_size > 0) { - const LLSD& header = header_it->second.second; - S32 version = header["version"].asInteger(); - S32 offset = header_size + header["skin"]["offset"].asInteger(); - S32 size = header["skin"]["size"].asInteger(); + const LLMeshHeader& header = header_it->second.second; + + S32 version = header.mVersion; + S32 offset = header_size + header.mSkinOffset; + S32 size = header.mSkinSize; mHeaderMutex->unlock(); @@ -1456,9 +1457,9 @@ bool LLMeshRepoThread::fetchMeshDecomposition(const LLUUID& mesh_id) if (header_size > 0) { const auto& header = header_it->second.second; - S32 version = header["version"].asInteger(); - S32 offset = header_size + header["physics_convex"]["offset"].asInteger(); - S32 size = header["physics_convex"]["size"].asInteger(); + S32 version = header.mVersion; + S32 offset = header_size + header.mPhysicsConvexOffset; + S32 size = header.mPhysicsConvexSize; mHeaderMutex->unlock(); @@ -1555,9 +1556,9 @@ bool LLMeshRepoThread::fetchMeshPhysicsShape(const LLUUID& mesh_id) if (header_size > 0) { const auto& header = header_it->second.second; - S32 version = header["version"].asInteger(); - S32 offset = header_size + header["physics_mesh"]["offset"].asInteger(); - S32 size = header["physics_mesh"]["size"].asInteger(); + S32 version = header.mVersion; + S32 offset = header_size + header.mPhysicsMeshOffset; + S32 size = header.mPhysicsMeshSize; mHeaderMutex->unlock(); @@ -1753,9 +1754,9 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, if (header_size > 0) { const auto& header = header_it->second.second; - S32 version = header["version"].asInteger(); - S32 offset = header_size + header[header_lod[lod]]["offset"].asInteger(); - S32 size = header[header_lod[lod]]["size"].asInteger(); + S32 version = header.mVersion; + S32 offset = header_size + header.mLodOffset[lod]; + S32 size = header.mLodSize[lod]; mHeaderMutex->unlock(); if (version <= MAX_MESH_VERSION && offset >= 0 && size > 0) @@ -1857,8 +1858,10 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod, EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mesh_params, U8* data, S32 data_size) { const LLUUID mesh_id = mesh_params.getSculptID(); - LLSD header; + LLSD header_data; + LLMeshHeader header; + U32 header_size = 0; if (data_size > 0) { @@ -1869,23 +1872,25 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes boost::iostreams::stream<boost::iostreams::array_source> stream(result_ptr, data_size); - if (!LLSDSerialize::fromBinary(header, stream, data_size)) + if (!LLSDSerialize::fromBinary(header_data, stream, data_size)) { LL_WARNS(LOG_MESH) << "Mesh header parse error. Not a valid mesh asset! ID: " << mesh_id << LL_ENDL; return MESH_PARSE_FAILURE; } - if (!header.isMap()) + if (!header_data.isMap()) { LL_WARNS(LOG_MESH) << "Mesh header is invalid for ID: " << mesh_id << LL_ENDL; return MESH_INVALID; } - if (header.has("version") && header["version"].asInteger() > MAX_MESH_VERSION) + header.fromLLSD(header_data); + + if (header.mVersion > MAX_MESH_VERSION) { LL_INFOS(LOG_MESH) << "Wrong version in header for " << mesh_id << LL_ENDL; - header["404"] = 1; + header.m404 = true; } // make sure there is at least one lod, function returns -1 and marks as 404 otherwise else if (LLMeshRepository::getActualMeshLOD(header, 0) >= 0) @@ -1897,7 +1902,7 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes { LL_INFOS(LOG_MESH) << "Non-positive data size. Marking header as non-existent, will not retry. ID: " << mesh_id << LL_ENDL; - header["404"] = 1; + header.m404 = 1; } { @@ -1907,7 +1912,6 @@ EMeshProcessingResult LLMeshRepoThread::headerReceived(const LLVolumeParams& mes mMeshHeader[mesh_id] = { header_size, header }; LLMeshRepository::sCacheBytesHeaders += header_size; } - LLMutexLock lock(mMutex); // make sure only one thread access mPendingLOD at the same time. @@ -2977,7 +2981,7 @@ S32 LLMeshRepoThread::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lo if (iter != mMeshHeader.end()) { - LLSD& header = iter->second.second; + auto& header = iter->second.second; return LLMeshRepository::getActualMeshLOD(header, lod); } @@ -2986,23 +2990,23 @@ S32 LLMeshRepoThread::getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lo } //static -S32 LLMeshRepository::getActualMeshLOD(LLSD& header, S32 lod) +S32 LLMeshRepository::getActualMeshLOD(LLMeshHeader& header, S32 lod) { lod = llclamp(lod, 0, 3); - if (header.has("404")) + if (header.m404) { return -1; } - S32 version = header["version"]; + S32 version = header.mVersion; if (version > MAX_MESH_VERSION) { return -1; } - if (header[header_lod[lod]]["size"].asInteger() > 0) + if (header.mLodSize[lod] > 0) { return lod; } @@ -3010,7 +3014,7 @@ S32 LLMeshRepository::getActualMeshLOD(LLSD& header, S32 lod) //search down to find the next available lower lod for (S32 i = lod-1; i >= 0; --i) { - if (header[header_lod[i]]["size"].asInteger() > 0) + if (header.mLodSize[i] > 0) { return i; } @@ -3019,15 +3023,16 @@ S32 LLMeshRepository::getActualMeshLOD(LLSD& header, S32 lod) //search up to find then ext available higher lod for (S32 i = lod+1; i < 4; ++i) { - if (header[header_lod[i]]["size"].asInteger() > 0) + if (header.mLodSize[i] > 0) { return i; } } //header exists and no good lod found, treat as 404 - header["404"] = 1; - return -1; + header.m404 = true; + + return -1; } // Handle failed or successful requests for mesh assets. @@ -3216,7 +3221,7 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b { // header was successfully retrieved from sim and parsed and is in cache S32 header_bytes = 0; - LLSD header; + LLMeshHeader header; gMeshRepo.mThread->mHeaderMutex->lock(); LLMeshRepoThread::mesh_header_map::iterator iter = gMeshRepo.mThread->mMeshHeader.find(mesh_id); @@ -3227,8 +3232,8 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b } if (header_bytes > 0 - && !header.has("404") - && (!header.has("version") || header["version"].asInteger() <= MAX_MESH_VERSION)) + && !header.m404 + && (header.mVersion <= MAX_MESH_VERSION)) { std::stringstream str; @@ -3237,13 +3242,12 @@ void LLMeshHeaderHandler::processData(LLCore::BufferArray * /* body */, S32 /* b for (U32 i = 0; i < LLModel::LOD_PHYSICS; ++i) { // figure out how many bytes we'll need to reserve in the file - const std::string & lod_name = header_lod[i]; - lod_bytes = llmax(lod_bytes, header[lod_name]["offset"].asInteger()+header[lod_name]["size"].asInteger()); + lod_bytes = llmax(lod_bytes, header.mLodOffset[i]+header.mLodSize[i]); } // just in case skin info or decomposition is at the end of the file (which it shouldn't be) - lod_bytes = llmax(lod_bytes, header["skin"]["offset"].asInteger() + header["skin"]["size"].asInteger()); - lod_bytes = llmax(lod_bytes, header["physics_convex"]["offset"].asInteger() + header["physics_convex"]["size"].asInteger()); + lod_bytes = llmax(lod_bytes, header.mSkinOffset+header.mSkinSize); + lod_bytes = llmax(lod_bytes, header.mPhysicsConvexOffset + header.mPhysicsConvexSize); // Do not unlock mutex untill we are done with LLSD. // LLSD is smart and can work like smart pointer, is not thread safe. @@ -4257,8 +4261,8 @@ bool LLMeshRepoThread::hasPhysicsShapeInHeader(const LLUUID& mesh_id) mesh_header_map::iterator iter = mMeshHeader.find(mesh_id); if (iter != mMeshHeader.end() && iter->second.first > 0) { - LLSD &mesh = iter->second.second; - if (mesh.has("physics_mesh") && mesh["physics_mesh"].has("size") && (mesh["physics_mesh"]["size"].asInteger() > 0)) + LLMeshHeader &mesh = iter->second.second; + if (mesh.mPhysicsMeshSize > 0) { return true; } @@ -4281,20 +4285,21 @@ void LLMeshRepository::uploadModel(std::vector<LLModelInstance>& data, LLVector3 S32 LLMeshRepository::getMeshSize(const LLUUID& mesh_id, S32 lod) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; if (mThread && mesh_id.notNull() && LLPrimitive::NO_LOD != lod) { LLMutexLock lock(mThread->mHeaderMutex); LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); if (iter != mThread->mMeshHeader.end() && iter->second.first > 0) { - const LLSD& header = iter->second.second; + const LLMeshHeader& header = iter->second.second; - if (header.has("404")) + if (header.m404) { return -1; } - S32 size = header[header_lod[lod]]["size"].asInteger(); + S32 size = header.mLodSize[lod]; return size; } @@ -4430,11 +4435,11 @@ F32 LLMeshRepository::getStreamingCostLegacy(LLUUID mesh_id, F32 radius, S32* by // FIXME replace with calc based on LLMeshCostData //static -F32 LLMeshRepository::getStreamingCostLegacy(LLSD& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) +F32 LLMeshRepository::getStreamingCostLegacy(LLMeshHeader& header, F32 radius, S32* bytes, S32* bytes_visible, S32 lod, F32 *unscaled_value) { - if (header.has("404") - || !header.has("lowest_lod") - || (header.has("version") && header["version"].asInteger() > MAX_MESH_VERSION)) + if (header.m404 + || header.mLodSize[0] <= 0 + || (header.mVersion > MAX_MESH_VERSION)) { return 0.f; } @@ -4453,10 +4458,10 @@ F32 LLMeshRepository::getStreamingCostLegacy(LLSD& header, F32 radius, S32* byte F32 minimum_size = (F32)minimum_size_ch; F32 bytes_per_triangle = (F32)bytes_per_triangle_ch; - S32 bytes_lowest = header["lowest_lod"]["size"].asInteger(); - S32 bytes_low = header["low_lod"]["size"].asInteger(); - S32 bytes_mid = header["medium_lod"]["size"].asInteger(); - S32 bytes_high = header["high_lod"]["size"].asInteger(); + S32 bytes_lowest = header.mLodSize[0]; + S32 bytes_low = header.mLodSize[1]; + S32 bytes_mid = header.mLodSize[2]; + S32 bytes_high = header.mLodSize[3]; if (bytes_high == 0) { @@ -4486,10 +4491,10 @@ F32 LLMeshRepository::getStreamingCostLegacy(LLSD& header, F32 radius, S32* byte if (bytes) { *bytes = 0; - *bytes += header["lowest_lod"]["size"].asInteger(); - *bytes += header["low_lod"]["size"].asInteger(); - *bytes += header["medium_lod"]["size"].asInteger(); - *bytes += header["high_lod"]["size"].asInteger(); + *bytes += header.mLodSize[0]; + *bytes += header.mLodSize[1]; + *bytes += header.mLodSize[2]; + *bytes += header.mLodSize[3]; } if (bytes_visible) @@ -4497,7 +4502,7 @@ F32 LLMeshRepository::getStreamingCostLegacy(LLSD& header, F32 radius, S32* byte lod = LLMeshRepository::getActualMeshLOD(header, lod); if (lod >= 0 && lod <= 3) { - *bytes_visible = header[header_lod[lod]]["size"].asInteger(); + *bytes_visible = header.mLodSize[lod]; } } @@ -4539,33 +4544,29 @@ F32 LLMeshRepository::getStreamingCostLegacy(LLSD& header, F32 radius, S32* byte LLMeshCostData::LLMeshCostData() { - mSizeByLOD.resize(4); - mEstTrisByLOD.resize(4); - std::fill(mSizeByLOD.begin(), mSizeByLOD.end(), 0); std::fill(mEstTrisByLOD.begin(), mEstTrisByLOD.end(), 0.f); } -bool LLMeshCostData::init(const LLSD& header) +bool LLMeshCostData::init(const LLMeshHeader& header) { - mSizeByLOD.resize(4); - mEstTrisByLOD.resize(4); - + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; + std::fill(mSizeByLOD.begin(), mSizeByLOD.end(), 0); std::fill(mEstTrisByLOD.begin(), mEstTrisByLOD.end(), 0.f); - S32 bytes_high = header["high_lod"]["size"].asInteger(); - S32 bytes_med = header["medium_lod"]["size"].asInteger(); + S32 bytes_high = header.mLodSize[3]; + S32 bytes_med = header.mLodSize[2]; if (bytes_med == 0) { bytes_med = bytes_high; } - S32 bytes_low = header["low_lod"]["size"].asInteger(); + S32 bytes_low = header.mLodSize[1]; if (bytes_low == 0) { bytes_low = bytes_med; } - S32 bytes_lowest = header["lowest_lod"]["size"].asInteger(); + S32 bytes_lowest = header.mLodSize[0]; if (bytes_lowest == 0) { bytes_lowest = bytes_low; @@ -4700,6 +4701,7 @@ F32 LLMeshCostData::getTriangleBasedStreamingCost() bool LLMeshRepository::getCostData(LLUUID mesh_id, LLMeshCostData& data) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; data = LLMeshCostData(); if (mThread && mesh_id.notNull()) @@ -4708,11 +4710,11 @@ bool LLMeshRepository::getCostData(LLUUID mesh_id, LLMeshCostData& data) LLMeshRepoThread::mesh_header_map::iterator iter = mThread->mMeshHeader.find(mesh_id); if (iter != mThread->mMeshHeader.end() && iter->second.first > 0) { - LLSD& header = iter->second.second; + LLMeshHeader& header = iter->second.second; - bool header_invalid = (header.has("404") - || !header.has("lowest_lod") - || (header.has("version") && header["version"].asInteger() > MAX_MESH_VERSION)); + bool header_invalid = (header.m404 + || header.mLodSize[0] <= 0 + || header.mVersion > MAX_MESH_VERSION); if (!header_invalid) { return getCostData(header, data); @@ -4724,7 +4726,7 @@ bool LLMeshRepository::getCostData(LLUUID mesh_id, LLMeshCostData& data) return false; } -bool LLMeshRepository::getCostData(LLSD& header, LLMeshCostData& data) +bool LLMeshRepository::getCostData(LLMeshHeader& header, LLMeshCostData& data) { data = LLMeshCostData(); diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 6922367ff7..619e076fa6 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -194,6 +194,63 @@ private: LLFrameTimer mTimer; }; +class LLMeshHeader +{ +public: + + LLMeshHeader() {} + + explicit LLMeshHeader(const LLSD& header) + { + fromLLSD(header); + } + + void fromLLSD(const LLSD& header) + { + const char* lod[] = + { + "lowest_lod", + "low_lod", + "medium_lod", + "high_lod" + }; + + mVersion = header["version"].asInteger(); + + for (U32 i = 0; i < 4; ++i) + { + mLodOffset[i] = header[lod[i]]["offset"].asInteger(); + mLodSize[i] = header[lod[i]]["size"].asInteger(); + } + + mSkinOffset = header["skin"]["offset"].asInteger(); + mSkinSize = header["skin"]["size"].asInteger(); + + mPhysicsConvexOffset = header["physics_convex"]["offset"].asInteger(); + mPhysicsConvexSize = header["physics_convex"]["size"].asInteger(); + + mPhysicsMeshOffset = header["physics_mesh"]["offset"].asInteger(); + mPhysicsMeshSize = header["physics_mesh"]["size"].asInteger(); + + m404 = header.has("404"); + } + + S32 mVersion = -1; + S32 mSkinOffset = -1; + S32 mSkinSize = -1; + + S32 mPhysicsConvexOffset = -1; + S32 mPhysicsConvexSize = -1; + + S32 mPhysicsMeshOffset = -1; + S32 mPhysicsMeshSize = -1; + + S32 mLodOffset[4] = { -1 }; + S32 mLodSize[4] = { -1 }; + + bool m404 = false; +}; + class LLMeshRepoThread : public LLThread { public: @@ -210,7 +267,7 @@ public: LLCondition* mSignal; //map of known mesh headers - typedef boost::unordered_map<LLUUID, std::pair<U32, LLSD>> mesh_header_map; // pair is header_size and data + typedef boost::unordered_map<LLUUID, std::pair<U32, LLMeshHeader>> mesh_header_map; // pair is header_size and data mesh_header_map mMeshHeader; class HeaderRequest : public RequestStats @@ -497,7 +554,7 @@ class LLMeshCostData public: LLMeshCostData(); - bool init(const LLSD& header); + bool init(const LLMeshHeader& header); // Size for given LOD S32 getSizeByLOD(S32 lod); @@ -532,10 +589,10 @@ public: private: // From the "size" field of the mesh header. LOD 0=lowest, 3=highest. - std::vector<S32> mSizeByLOD; + std::array<S32,4> mSizeByLOD; // Estimated triangle counts derived from the LOD sizes. LOD 0=lowest, 3=highest. - std::vector<F32> mEstTrisByLOD; + std::array<F32,4> mEstTrisByLOD; }; class LLMeshRepository @@ -566,9 +623,9 @@ public: F32 getEstTrianglesMax(LLUUID mesh_id); F32 getEstTrianglesStreamingCost(LLUUID mesh_id); F32 getStreamingCostLegacy(LLUUID mesh_id, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); - static F32 getStreamingCostLegacy(LLSD& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); + static F32 getStreamingCostLegacy(LLMeshHeader& header, F32 radius, S32* bytes = NULL, S32* visible_bytes = NULL, S32 detail = -1, F32 *unscaled_value = NULL); bool getCostData(LLUUID mesh_id, LLMeshCostData& data); - bool getCostData(LLSD& header, LLMeshCostData& data); + bool getCostData(LLMeshHeader& header, LLMeshCostData& data); LLMeshRepository(); @@ -588,7 +645,7 @@ public: void notifyDecompositionReceived(LLModel::Decomposition* info); S32 getActualMeshLOD(const LLVolumeParams& mesh_params, S32 lod); - static S32 getActualMeshLOD(LLSD& header, S32 lod); + static S32 getActualMeshLOD(LLMeshHeader& header, S32 lod); const LLMeshSkinInfo* getSkinInfo(const LLUUID& mesh_id, LLVOVolume* requesting_obj = nullptr); LLModel::Decomposition* getDecomposition(const LLUUID& mesh_id); void fetchPhysicsShape(const LLUUID& mesh_id); diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp index 8058faa5c7..d7d6fa1893 100644 --- a/indra/newview/llnamelistctrl.cpp +++ b/indra/newview/llnamelistctrl.cpp @@ -67,7 +67,9 @@ LLNameListCtrl::LLNameListCtrl(const LLNameListCtrl::Params& p) mNameColumn(p.name_column.column_name), mAllowCallingCardDrop(p.allow_calling_card_drop), mShortNames(p.short_names), - mPendingLookupsRemaining(0) + mPendingLookupsRemaining(0), + mHoverIconName("Info_Small"), + mNameListType(INDIVIDUAL) {} // public @@ -134,7 +136,12 @@ BOOL LLNameListCtrl::handleDragAndDrop( void LLNameListCtrl::showInspector(const LLUUID& avatar_id, bool is_group, bool is_experience) { - if(is_experience) + if (isSpecialType()) + { + mIconClickedSignal(avatar_id); + return; + } + if(is_experience) { LLFloaterReg::showInstance("experience_profile", avatar_id, true); return; @@ -215,14 +222,16 @@ BOOL LLNameListCtrl::handleToolTip(S32 x, S32 y, MASK mask) S32 column_index = getColumnIndexFromOffset(x); LLNameListItem* hit_item = dynamic_cast<LLNameListItem*>(hitItem(x, y)); LLFloater* floater = gFloaterView->getParentFloater(this); - if (floater + + + if (floater && floater->isFrontmost() && hit_item - && column_index == mNameColumnIndex) + && ((column_index == mNameColumnIndex) || isSpecialType())) { - // ...this is the column with the avatar name - LLUUID avatar_id = hit_item->getUUID(); - if (avatar_id.notNull()) + // ...this is the column with the avatar name + LLUUID item_id = isSpecialType() ? hit_item->getSpecialID() : hit_item->getUUID(); + if (item_id.notNull()) { // ...valid avatar id @@ -230,13 +239,13 @@ BOOL LLNameListCtrl::handleToolTip(S32 x, S32 y, MASK mask) if (hit_cell) { S32 row_index = getItemIndex(hit_item); - LLRect cell_rect = getCellRect(row_index, column_index); + LLRect cell_rect = getCellRect(row_index, isSpecialType() ? getNumColumns() - 1 : column_index); // Convert rect local to screen coordinates LLRect sticky_rect; localRectToScreen(cell_rect, &sticky_rect); // Spawn at right side of cell - LLPointer<LLUIImage> icon = LLUI::getUIImage("Info_Small"); + LLPointer<LLUIImage> icon = LLUI::getUIImage(mHoverIconName); S32 screenX = sticky_rect.mRight - info_icon_size; S32 screenY = sticky_rect.mTop - (sticky_rect.getHeight() - icon->getHeight()) / 2; LLCoordGL pos(screenX, screenY); @@ -250,7 +259,7 @@ BOOL LLNameListCtrl::handleToolTip(S32 x, S32 y, MASK mask) LLToolTip::Params params; params.background_visible(false); - params.click_callback(boost::bind(&LLNameListCtrl::showInspector, this, avatar_id, is_group, is_experience)); + params.click_callback(boost::bind(&LLNameListCtrl::showInspector, this, item_id, is_group, is_experience)); params.delay_time(0.0f); // spawn instantly on hover params.image(icon); params.message(""); @@ -340,6 +349,7 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow( // use supplied name by default std::string fullname = name_item.name; + switch(name_item.target) { case GROUP: @@ -358,8 +368,10 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow( } break; case SPECIAL: - // just use supplied name - break; + { + item->setSpecialID(name_item.special_id()); + return item; + } case INDIVIDUAL: { LLAvatarName av_name; @@ -370,7 +382,7 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow( else if (LLAvatarNameCache::get(id, &av_name)) { if (mShortNames) - fullname = av_name.getDisplayName(); + fullname = av_name.getDisplayName(true); else fullname = av_name.getCompleteName(); } @@ -440,7 +452,8 @@ void LLNameListCtrl::removeNameItem(const LLUUID& agent_id) for (item_list::iterator it = getItemList().begin(); it != getItemList().end(); it++) { LLScrollListItem* item = *it; - if (item->getUUID() == agent_id) + LLUUID cur_id = isSpecialType() ? dynamic_cast<LLNameListItem*>(item)->getSpecialID() : item->getUUID(); + if (cur_id == agent_id) { idx = getItemIndex(item); break; @@ -471,6 +484,34 @@ LLScrollListItem* LLNameListCtrl::getNameItemByAgentId(const LLUUID& agent_id) return NULL; } +void LLNameListCtrl::selectItemBySpecialId(const LLUUID& special_id) +{ + if (special_id.isNull()) + { + return; + } + + for (item_list::iterator it = getItemList().begin(); it != getItemList().end(); it++) + { + LLNameListItem* item = dynamic_cast<LLNameListItem*>(*it); + if (item && item->getSpecialID() == special_id) + { + item->setSelected(TRUE); + break; + } + } +} + +LLUUID LLNameListCtrl::getSelectedSpecialId() +{ + LLNameListItem* item = dynamic_cast<LLNameListItem*>(getFirstSelected()); + if(item) + { + return item->getSpecialID(); + } + return LLUUID(); +} + void LLNameListCtrl::onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name, std::string suffix, diff --git a/indra/newview/llnamelistctrl.h b/indra/newview/llnamelistctrl.h index 5dd5da5892..4a4bd4ba09 100644 --- a/indra/newview/llnamelistctrl.h +++ b/indra/newview/llnamelistctrl.h @@ -46,6 +46,8 @@ public: void setIsGroup(bool is_group) { mIsGroup = is_group; } bool isExperience() const { return mIsExperience; } void setIsExperience(bool is_experience) { mIsExperience = is_experience; } + void setSpecialID(const LLUUID& special_id) { mSpecialID = special_id; } + const LLUUID& getSpecialID() const { return mSpecialID; } protected: friend class LLNameListCtrl; @@ -68,6 +70,8 @@ protected: private: bool mIsGroup; bool mIsExperience; + + LLUUID mSpecialID; }; @@ -95,10 +99,12 @@ public: { Optional<std::string> name; Optional<ENameType, NameTypeNames> target; + Optional<LLUUID> special_id; NameItem() : name("name"), - target("target", INDIVIDUAL) + target("target", INDIVIDUAL), + special_id("special_id", LLUUID()) {} }; @@ -156,6 +162,9 @@ public: LLScrollListItem* getNameItemByAgentId(const LLUUID& agent_id); + void selectItemBySpecialId(const LLUUID& special_id); + LLUUID getSelectedSpecialId(); + // LLView interface /*virtual*/ BOOL handleDragAndDrop(S32 x, S32 y, MASK mask, BOOL drop, EDragAndDropType cargo_type, void *cargo_data, @@ -170,7 +179,14 @@ public: /*virtual*/ void updateColumns(bool force_update); /*virtual*/ void mouseOverHighlightNthItem( S32 index ); + /*virtual*/ BOOL handleRightMouseDown(S32 x, S32 y, MASK mask); + + bool isSpecialType() { return (mNameListType == SPECIAL); } + + void setNameListType(e_name_type type) { mNameListType = type; } + void setHoverIconName(std::string icon_name) { mHoverIconName = icon_name; } + private: void showInspector(const LLUUID& avatar_id, bool is_group, bool is_experience = false); void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name, std::string suffix, std::string prefix, LLHandle<LLNameListItem> item); @@ -187,6 +203,11 @@ private: S32 mPendingLookupsRemaining; namelist_complete_signal_t mNameListCompleteSignal; + + std::string mHoverIconName; + e_name_type mNameListType; + + boost::signals2::signal<void(const LLUUID &)> mIconClickedSignal; public: boost::signals2::connection setOnNameListCompleteCallback(boost::function<void(bool)> onNameListCompleteCallback) @@ -194,6 +215,10 @@ public: return mNameListCompleteSignal.connect(onNameListCompleteCallback); } + boost::signals2::connection setIconClickedCallback(boost::function<void(const LLUUID &)> cb) + { + return mIconClickedSignal.connect(cb); + } }; diff --git a/indra/newview/llpanelpresetspulldown.cpp b/indra/newview/llpanelpresetspulldown.cpp index 23e4fa8887..f6e501f147 100644 --- a/indra/newview/llpanelpresetspulldown.cpp +++ b/indra/newview/llpanelpresetspulldown.cpp @@ -34,6 +34,7 @@ #include "llbutton.h" #include "lltabcontainer.h" #include "llfloater.h" +#include "llfloaterperformance.h" #include "llfloaterreg.h" #include "llpresetsmanager.h" #include "llsliderctrl.h" @@ -50,6 +51,7 @@ LLPanelPresetsPulldown::LLPanelPresetsPulldown() mHoverTimer.stop(); mCommitCallbackRegistrar.add("Presets.GoGraphicsPrefs", boost::bind(&LLPanelPresetsPulldown::onGraphicsButtonClick, this, _2)); + mCommitCallbackRegistrar.add("Presets.GoAutofpsPrefs", boost::bind(&LLPanelPresetsPulldown::onAutofpsButtonClick, this, _2)); mCommitCallbackRegistrar.add("Presets.RowClick", boost::bind(&LLPanelPresetsPulldown::onRowClick, this, _2)); buildFromFile( "panel_presets_pulldown.xml"); @@ -157,3 +159,13 @@ void LLPanelPresetsPulldown::onGraphicsButtonClick(const LLSD& user_data) } } } + +void LLPanelPresetsPulldown::onAutofpsButtonClick(const LLSD& user_data) +{ + setVisible(FALSE); + LLFloaterPerformance* performance_floater = LLFloaterReg::showTypedInstance<LLFloaterPerformance>("performance"); + if (performance_floater) + { + performance_floater->showAutoadjustmentsPanel(); + } +} diff --git a/indra/newview/llpanelpresetspulldown.h b/indra/newview/llpanelpresetspulldown.h index c0d32b9b21..79bd6886b1 100644 --- a/indra/newview/llpanelpresetspulldown.h +++ b/indra/newview/llpanelpresetspulldown.h @@ -41,6 +41,7 @@ class LLPanelPresetsPulldown : public LLPanelPulldown private: void onGraphicsButtonClick(const LLSD& user_data); + void onAutofpsButtonClick(const LLSD& user_data); void onRowClick(const LLSD& user_data); std::list<std::string> mPresetNames; diff --git a/indra/newview/llperfstats.cpp b/indra/newview/llperfstats.cpp new file mode 100644 index 0000000000..395ac0e788 --- /dev/null +++ b/indra/newview/llperfstats.cpp @@ -0,0 +1,566 @@ +/** +* @file llperfstats.cpp +* @brief Statistics collection to support autotune and perf flaoter. +* +* $LicenseInfo:firstyear=2022&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2022, 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 "llperfstats.h" +#include "llcontrol.h" +#include "pipeline.h" +#include "llagentcamera.h" +#include "llviewerwindow.h" +#include "llvoavatar.h" +#include "llwindow.h" +#include "llworld.h" +#include <llthread.h> + +extern LLControlGroup gSavedSettings; + +namespace LLPerfStats +{ + // avatar timing metrics in ms (updated once per mainloop iteration) + std::atomic<F32> sTotalAvatarTime = 0.f; + std::atomic<F32> sAverageAvatarTime = 0.f; + std::atomic<F32> sMaxAvatarTime = 0.f; + + std::atomic<int64_t> tunedAvatars{0}; + std::atomic<U64> renderAvatarMaxART_ns{(U64)(ART_UNLIMITED_NANOS)}; // highest render time we'll allow without culling features + bool belowTargetFPS{false}; + U32 lastGlobalPrefChange{0}; + U32 lastSleepedFrame{0}; + U64 meanFrameTime{0}; + std::mutex bufferToggleLock{}; + + F64 cpu_hertz{0.0}; + U32 vsync_max_fps{60}; + + Tunables tunables; + + std::atomic<int> StatsRecorder::writeBuffer{0}; + bool StatsRecorder::collectionEnabled{true}; + LLUUID StatsRecorder::focusAv{LLUUID::null}; + bool StatsRecorder::autotuneInit{false}; + std::array<StatsRecorder::StatsTypeMatrix,2> StatsRecorder::statsDoubleBuffer{ {} }; + std::array<StatsRecorder::StatsSummaryArray,2> StatsRecorder::max{ {} }; + std::array<StatsRecorder::StatsSummaryArray,2> StatsRecorder::sum{ {} }; + + void Tunables::applyUpdates() + { + assert_main_thread(); + // these following variables are proxies for pipeline statics we do not need a two way update (no llviewercontrol handler) + if( tuningFlag & NonImpostors ){ gSavedSettings.setU32("IndirectMaxNonImpostors", nonImpostors); }; + if( tuningFlag & ReflectionDetail ){ gSavedSettings.setS32("RenderReflectionDetail", reflectionDetail); }; + if( tuningFlag & FarClip ){ gSavedSettings.setF32("RenderFarClip", farClip); }; + if( tuningFlag & UserMinDrawDistance ){ gSavedSettings.setF32("AutoTuneRenderFarClipMin", userMinDrawDistance); }; + if( tuningFlag & UserTargetDrawDistance ){ gSavedSettings.setF32("AutoTuneRenderFarClipTarget", userTargetDrawDistance); }; + if( tuningFlag & UserImpostorDistance ){ gSavedSettings.setF32("AutoTuneImpostorFarAwayDistance", userImpostorDistance); }; + if( tuningFlag & UserImpostorDistanceTuningEnabled ){ gSavedSettings.setBOOL("AutoTuneImpostorByDistEnabled", userImpostorDistanceTuningEnabled); }; + if( tuningFlag & UserFPSTuningStrategy ){ gSavedSettings.setU32("TuningFPSStrategy", userFPSTuningStrategy); }; + if( tuningFlag & UserAutoTuneEnabled ){ gSavedSettings.setBOOL("AutoTuneFPS", userAutoTuneEnabled); }; + if( tuningFlag & UserAutoTuneLock ){ gSavedSettings.setBOOL("AutoTuneLock", userAutoTuneLock); }; + if( tuningFlag & UserTargetFPS ){ gSavedSettings.setU32("TargetFPS", userTargetFPS); }; + // Note: The Max ART slider is logarithmic and thus we have an intermediate proxy value + if( tuningFlag & UserARTCutoff ){ gSavedSettings.setF32("RenderAvatarMaxART", userARTCutoffSliderValue); }; + resetChanges(); + } + + void Tunables::updateRenderCostLimitFromSettings() + { + assert_main_thread(); + const auto newval = gSavedSettings.getF32("RenderAvatarMaxART"); + if(newval < log10(LLPerfStats::ART_UNLIMITED_NANOS/1000)) + { + LLPerfStats::renderAvatarMaxART_ns = pow(10,newval)*1000; + } + else + { + LLPerfStats::renderAvatarMaxART_ns = 0; + } + } + + // static + void Tunables::updateSettingsFromRenderCostLimit() + { + if( userARTCutoffSliderValue != log10( ( (F32)LLPerfStats::renderAvatarMaxART_ns )/1000 ) ) + { + if( LLPerfStats::renderAvatarMaxART_ns != 0 ) + { + updateUserARTCutoffSlider(log10( ( (F32)LLPerfStats::renderAvatarMaxART_ns )/1000 ) ); + } + else + { + updateUserARTCutoffSlider(log10( (F32)LLPerfStats::ART_UNLIMITED_NANOS/1000 ) ); + } + } + } + + void Tunables::initialiseFromSettings() + { + assert_main_thread(); + // the following variables are two way and have "push" in llviewercontrol + LLPerfStats::tunables.userMinDrawDistance = gSavedSettings.getF32("AutoTuneRenderFarClipMin"); + LLPerfStats::tunables.userTargetDrawDistance = gSavedSettings.getF32("AutoTuneRenderFarClipTarget"); + LLPerfStats::tunables.userImpostorDistance = gSavedSettings.getF32("AutoTuneImpostorFarAwayDistance"); + LLPerfStats::tunables.userImpostorDistanceTuningEnabled = gSavedSettings.getBOOL("AutoTuneImpostorByDistEnabled"); + LLPerfStats::tunables.userFPSTuningStrategy = gSavedSettings.getU32("TuningFPSStrategy"); + LLPerfStats::tunables.userTargetFPS = gSavedSettings.getU32("TargetFPS"); + LLPerfStats::tunables.vsyncEnabled = gSavedSettings.getBOOL("RenderVSyncEnable"); + + LLPerfStats::tunables.userAutoTuneLock = gSavedSettings.getBOOL("AutoTuneLock") && gSavedSettings.getU32("KeepAutoTuneLock"); + + if(gSavedSettings.getBOOL("AutoTuneLock") && !gSavedSettings.getU32("KeepAutoTuneLock")) + { + gSavedSettings.setBOOL("AutoTuneLock", FALSE); + } + + LLPerfStats::tunables.userAutoTuneEnabled = LLPerfStats::tunables.userAutoTuneLock; + + if (LLPerfStats::tunables.userAutoTuneEnabled && !gSavedSettings.getBOOL("AutoTuneFPS")) + { + gSavedSettings.setBOOL("AutoTuneFPS", TRUE); + } + + // Note: The Max ART slider is logarithmic and thus we have an intermediate proxy value + updateRenderCostLimitFromSettings(); + resetChanges(); + } + + StatsRecorder::StatsRecorder():q(1024*16) + { + // create a queue + tunables.initialiseFromSettings(); + LLPerfStats::cpu_hertz = (F64)LLTrace::BlockTimer::countsPerSecond(); + LLPerfStats::vsync_max_fps = gViewerWindow->getWindow()->getRefreshRate(); + } + + // static + void StatsRecorder::toggleBuffer() + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + using ST = StatType_t; + + bool unreliable{false}; + LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_FRAME); + auto& sceneStats = statsDoubleBuffer[writeBuffer][static_cast<size_t>(ObjType_t::OT_GENERAL)][LLUUID::null]; + auto& lastStats = statsDoubleBuffer[writeBuffer ^ 1][static_cast<size_t>(ObjType_t::OT_GENERAL)][LLUUID::null]; + + static constexpr std::initializer_list<StatType_t> sceneStatsToAvg = { + StatType_t::RENDER_FRAME, + StatType_t::RENDER_DISPLAY, + StatType_t::RENDER_HUDS, + StatType_t::RENDER_UI, + StatType_t::RENDER_SWAP, + // RENDER_LFS, + // RENDER_MESHREPO, + StatType_t::RENDER_IDLE }; + +#if 0 + static constexpr std::initializer_list<StatType_t> avatarStatsToAvg = { + StatType_t::RENDER_GEOMETRY, + StatType_t::RENDER_SHADOWS, + StatType_t::RENDER_COMBINED, + StatType_t::RENDER_IDLE }; +#endif + + + if( /*sceneStats[static_cast<size_t>(StatType_t::RENDER_FPSLIMIT)] != 0 ||*/ sceneStats[static_cast<size_t>(StatType_t::RENDER_SLEEP)] != 0 ) + { + unreliable = true; + //lastStats[static_cast<size_t>(StatType_t::RENDER_FPSLIMIT)] = sceneStats[static_cast<size_t>(StatType_t::RENDER_FPSLIMIT)]; + lastStats[static_cast<size_t>(StatType_t::RENDER_SLEEP)] = sceneStats[static_cast<size_t>(StatType_t::RENDER_SLEEP)]; + lastStats[static_cast<size_t>(StatType_t::RENDER_FRAME)] = sceneStats[static_cast<size_t>(StatType_t::RENDER_FRAME)]; // bring over the total frame render time to deal with region crossing overlap issues + } + + if(!unreliable) + { + // only use these stats when things are reliable. + + for(auto & statEntry : sceneStatsToAvg) + { + auto avg = lastStats[static_cast<size_t>(statEntry)]; + auto val = sceneStats[static_cast<size_t>(statEntry)]; + sceneStats[static_cast<size_t>(statEntry)] = avg + (val / SMOOTHING_PERIODS) - (avg / SMOOTHING_PERIODS); + // LL_INFOS("scenestats") << "Scenestat: " << static_cast<size_t>(statEntry) << " before=" << avg << " new=" << val << " newavg=" << statsDoubleBuffer[writeBuffer][static_cast<size_t>(ObjType_t::OT_GENERAL)][LLUUID::null][static_cast<size_t>(statEntry)] << LL_ENDL; + } + } + + // swap the buffers + if(enabled()) + { + std::lock_guard<std::mutex> lock{bufferToggleLock}; + writeBuffer ^= 1; + }; // note we are relying on atomic updates here. The risk is low and would cause minor errors in the stats display. + + // clean the write maps in all cases. + auto& statsTypeMatrix = statsDoubleBuffer[writeBuffer]; + for(auto& statsMapByType : statsTypeMatrix) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_STATS("Clear stats maps"); + for(auto& stat_entry : statsMapByType) + { + std::fill_n(stat_entry.second.begin() ,static_cast<size_t>(ST::STATS_COUNT),0); + } + statsMapByType.clear(); + } + for(int i=0; i< static_cast<size_t>(ObjType_t::OT_COUNT); i++) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_STATS("clear max/sum"); + max[writeBuffer][i].fill(0); + sum[writeBuffer][i].fill(0); + } + + // and now adjust the proxy vars so that the main thread can adjust the visuals. + if(autotuneInit && tunables.userAutoTuneEnabled) + { + updateAvatarParams(); + } + } + + // clear buffers when we change region or need a hard reset. + // static + void StatsRecorder::clearStatsBuffers() + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + using ST = StatType_t; + + auto& statsTypeMatrix = statsDoubleBuffer[writeBuffer]; + for(auto& statsMap : statsTypeMatrix) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_STATS("Clear stats maps"); + for(auto& stat_entry : statsMap) + { + std::fill_n(stat_entry.second.begin() ,static_cast<size_t>(ST::STATS_COUNT),0); + } + statsMap.clear(); + } + for(int i=0; i< static_cast<size_t>(ObjType_t::OT_COUNT); i++) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_STATS("clear max/sum"); + max[writeBuffer][i].fill(0); + sum[writeBuffer][i].fill(0); + } + // swap the clean buffers in + if(enabled()) + { + std::lock_guard<std::mutex> lock{bufferToggleLock}; + writeBuffer ^= 1; + }; + // repeat before we start processing new stuff + for(auto& statsMap : statsTypeMatrix) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_STATS("Clear stats maps"); + for(auto& stat_entry : statsMap) + { + std::fill_n(stat_entry.second.begin() ,static_cast<size_t>(ST::STATS_COUNT),0); + } + statsMap.clear(); + } + for(int i=0; i< static_cast<size_t>(ObjType_t::OT_COUNT); i++) + { + LL_PROFILE_ZONE_NAMED_CATEGORY_STATS("clear max/sum"); + max[writeBuffer][i].fill(0); + sum[writeBuffer][i].fill(0); + } + } + + // called once per main loop iteration on main thread + void updateClass() + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + + sTotalAvatarTime = LLVOAvatar::getTotalGPURenderTime(); + sAverageAvatarTime = LLVOAvatar::getAverageGPURenderTime(); + sMaxAvatarTime = LLVOAvatar::getMaxGPURenderTime(); + + auto general = LL::WorkQueue::getInstance("General"); + + if (general) + { + general->post([] { StatsRecorder::update(); }); + } + } + + // called once per main loop iteration on General thread + void StatsRecorder::update() + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + StatsRecord upd; + auto& instance{ StatsRecorder::getInstance() }; + + while (enabled() && !LLApp::isQuitting() && instance.q.tryPop(upd)) + { + instance.processUpdate(upd); + } + } + + //static + int StatsRecorder::countNearbyAvatars(S32 distance) + { + const auto our_pos = gAgentCamera.getCameraPositionGlobal(); + + std::vector<LLVector3d> positions; + uuid_vec_t avatar_ids; + LLWorld::getInstance()->getAvatars(&avatar_ids, &positions, our_pos, distance); + return positions.size(); + } + + const U32 NUM_PERIODS = 50; + void StatsRecorder::updateMeanFrameTime(U64 cur_frame_time_raw) + { + static std::deque<U64> frame_time_deque; + frame_time_deque.push_front(cur_frame_time_raw); + if (frame_time_deque.size() > NUM_PERIODS) + { + frame_time_deque.pop_back(); + } + + std::vector<U64> buf(frame_time_deque.begin(), frame_time_deque.end()); + std::sort(buf.begin(), buf.end()); + + LLPerfStats::meanFrameTime = (buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]; + } + U64 StatsRecorder::getMeanTotalFrameTime() + { + return LLPerfStats::meanFrameTime; + } + + // static + void StatsRecorder::updateAvatarParams() + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + + if(tunables.autoTuneTimeout) + { + LLPerfStats::lastSleepedFrame = gFrameCount; + tunables.autoTuneTimeout = false; + return; + } + // sleep time is basically forced sleep when window out of focus + auto tot_sleep_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_SLEEP); + // similar to sleep time, induced by FPS limit + //auto tot_limit_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_FPSLIMIT); + + + // the time spent this frame on the "doFrame" call. Treated as "tot time for frame" + auto tot_frame_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_FRAME); + + if( tot_sleep_time_raw != 0 ) + { + // Note: we do not average sleep + // if at some point we need to, the averaging will need to take this into account or + // we forever think we're in the background due to residuals. + LL_DEBUGS() << "No tuning when not in focus" << LL_ENDL; + LLPerfStats::lastSleepedFrame = gFrameCount; + return; + } + + U32 target_fps = tunables.vsyncEnabled ? std::min(LLPerfStats::vsync_max_fps, tunables.userTargetFPS) : tunables.userTargetFPS; + + if(LLPerfStats::lastSleepedFrame != 0) + { + // wait a short time after viewer regains focus + if((gFrameCount - LLPerfStats::lastSleepedFrame) > target_fps * 5) + { + LLPerfStats::lastSleepedFrame = 0; + } + else + { + return; + } + } + updateMeanFrameTime(tot_frame_time_raw); + + if(tunables.userImpostorDistanceTuningEnabled) + { + // if we have less than the user's "max Non-Impostors" avatars within the desired range then adjust the limit. + // also adjusts back up again for nearby crowds. + auto count = countNearbyAvatars(std::min(LLPipeline::RenderFarClip, tunables.userImpostorDistance)); + if( count != tunables.nonImpostors ) + { + tunables.updateNonImposters( (count < LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER)?count : LLVOAvatar::NON_IMPOSTORS_MAX_SLIDER ); + LL_DEBUGS("AutoTune") << "There are " << count << "avatars within " << std::min(LLPipeline::RenderFarClip, tunables.userImpostorDistance) << "m of the camera" << LL_ENDL; + } + } + + auto av_render_max_raw = ms_to_raw(sMaxAvatarTime); + // Is our target frame time lower than current? If so we need to take action to reduce draw overheads. + // cumulative avatar time (includes idle processing, attachments and base av) + auto tot_avatar_time_raw = ms_to_raw(sTotalAvatarTime); + + // The frametime budget we have based on the target FPS selected + auto target_frame_time_raw = (U64)llround(LLPerfStats::cpu_hertz / (target_fps == 0 ? 1 : target_fps)); + // LL_INFOS() << "Effective FPS(raw):" << tot_frame_time_raw << " Target:" << target_frame_time_raw << LL_ENDL; + auto inferredFPS{1000/(U32)std::max(raw_to_ms(tot_frame_time_raw),1.0)}; + U32 settingsChangeFrequency{inferredFPS > 50?inferredFPS:50}; + /*if( tot_limit_time_raw != 0) + { + // This could be problematic. + tot_frame_time_raw -= tot_limit_time_raw; + }*/ + + F64 time_buf = target_frame_time_raw * 0.1; + + // 1) Is the target frame time lower than current? + if ((target_frame_time_raw + time_buf) <= tot_frame_time_raw) + { + if (target_frame_time_raw - time_buf >= getMeanTotalFrameTime()) + { + belowTargetFPS = false; + LLPerfStats::lastGlobalPrefChange = gFrameCount; + return; + } + + if(belowTargetFPS == false) + { + // this is the first frame under. hold fire to add a little hysteresis + belowTargetFPS = true; + LLPerfStats::lastGlobalPrefChange = gFrameCount; + } + // if so we've got work to do + + // how much of the frame was spent on non avatar related work? + U64 non_avatar_time_raw = tot_frame_time_raw > tot_avatar_time_raw ? tot_frame_time_raw - tot_avatar_time_raw : 0; + + // If the target frame time < scene time (estimated as non_avatar time) + U64 target_avatar_time_raw; + if(target_frame_time_raw < non_avatar_time_raw) + { + // we cannnot do this by avatar adjustment alone. + if((gFrameCount - LLPerfStats::lastGlobalPrefChange) > settingsChangeFrequency) // give changes a short time to take effect. + { + if(tunables.userFPSTuningStrategy != TUNE_AVATARS_ONLY) + { + // 1 - hack the water to opaque. all non opaque have a significant hit, this is a big boost for (arguably) a minor visual hit. + // the other reflection options make comparatively little change and if this overshoots we'll be stepping back up later +# if 0 // TODO RenderReflectionDetail went away + if(LLPipeline::RenderReflectionDetail != -2) + { + LLPerfStats::tunables.updateReflectionDetail(-2); + LLPerfStats::lastGlobalPrefChange = gFrameCount; + return; + } + else // deliberately "else" here so we only do one of these in any given frame +#endif + { + // step down the DD by 10m per update + auto new_dd = (LLPipeline::RenderFarClip - DD_STEP > tunables.userMinDrawDistance)?(LLPipeline::RenderFarClip - DD_STEP) : tunables.userMinDrawDistance; + if(new_dd != LLPipeline::RenderFarClip) + { + LLPerfStats::tunables.updateFarClip( new_dd ); + LLPerfStats::lastGlobalPrefChange = gFrameCount; + return; + } + } + } + // if we reach here, we've no more changes to make to tune scenery so we'll resort to agressive Avatar tuning + // Note: moved from outside "if changefrequency elapsed" to stop fallthrough and allow scenery changes time to take effect. + target_avatar_time_raw = 0; + } + else + { + // we made a settings change recently so let's give it time. + return; + } + } + else + { + // set desired avatar budget. + target_avatar_time_raw = target_frame_time_raw - non_avatar_time_raw; + } + + if ((target_avatar_time_raw < tot_avatar_time_raw) && (tunables.userFPSTuningStrategy != TUNE_SCENE_ONLY)) + { + // we need to spend less time drawing avatars to meet our budget + auto new_render_limit_ns {LLPerfStats::raw_to_ns(av_render_max_raw)}; + // max render this frame may be higher than the last (cos new entrants and jitter) so make sure we are heading in the right direction + if( new_render_limit_ns > renderAvatarMaxART_ns ) + { + new_render_limit_ns = renderAvatarMaxART_ns; + } + + if (new_render_limit_ns > LLPerfStats::ART_MIN_ADJUST_DOWN_NANOS) + { + new_render_limit_ns -= LLPerfStats::ART_MIN_ADJUST_DOWN_NANOS; + } + + // bounce at the bottom to prevent "no limit" + new_render_limit_ns = std::max((U64)new_render_limit_ns, (U64)LLPerfStats::ART_MINIMUM_NANOS); + + // assign the new value + if(renderAvatarMaxART_ns != new_render_limit_ns) + { + renderAvatarMaxART_ns = new_render_limit_ns; + tunables.updateSettingsFromRenderCostLimit(); + } + // LL_DEBUGS() << "AUTO_TUNE: avatar_budget adjusted to:" << new_render_limit_ns << LL_ENDL; + } + // LL_DEBUGS() << "AUTO_TUNE: Target frame time:"<< LLPerfStats::raw_to_us(target_frame_time_raw) << "usecs (non_avatar is " << LLPerfStats::raw_to_us(non_avatar_time_raw) << "usecs) Max cost limited=" << renderAvatarMaxART_ns << LL_ENDL; + } + else if(( LLPerfStats::raw_to_ns(target_frame_time_raw) > (LLPerfStats::raw_to_ns(tot_frame_time_raw) + renderAvatarMaxART_ns) ) || + (tunables.vsyncEnabled && (target_fps == LLPerfStats::vsync_max_fps) && (target_frame_time_raw > getMeanTotalFrameTime()))) + { + if(belowTargetFPS == true) + { + // we reached target, force a pause + lastGlobalPrefChange = gFrameCount; + belowTargetFPS = false; + } + + // once we're over the FPS target we slow down further + if((gFrameCount - lastGlobalPrefChange) > settingsChangeFrequency*3) + { + if(!tunables.userAutoTuneLock) + { + // we've reached the target and stayed long enough to consider stable. + // turn off if we are not locked. + tunables.updateUserAutoTuneEnabled(false); + } + if(renderAvatarMaxART_ns != 0 && LLPerfStats::tunedAvatars > 0 && (tunables.userFPSTuningStrategy != TUNE_SCENE_ONLY) ) + { + // if we have more time to spare let's shift up little in the hope we'll restore an avatar. + U64 up_step = LLPerfStats::tunedAvatars > 2 ? LLPerfStats::ART_MIN_ADJUST_UP_NANOS : LLPerfStats::ART_MIN_ADJUST_UP_NANOS * 2; + renderAvatarMaxART_ns += up_step; + tunables.updateSettingsFromRenderCostLimit(); + return; + } + if(tunables.userFPSTuningStrategy != TUNE_AVATARS_ONLY) + { + if( LLPipeline::RenderFarClip < tunables.userTargetDrawDistance ) + { + LLPerfStats::tunables.updateFarClip( std::min(LLPipeline::RenderFarClip + DD_STEP, tunables.userTargetDrawDistance) ); + LLPerfStats::lastGlobalPrefChange = gFrameCount; + return; + } + if( (tot_frame_time_raw * 1.5) < target_frame_time_raw ) + { + // if everything else is "max" and we have >50% headroom let's knock the water quality up a notch at a time. +# if 0 // RenderReflectionDetail went away + LLPerfStats::tunables.updateReflectionDetail( std::min(LLPipeline::RenderReflectionDetail + 1, tunables.userTargetReflections) ); +#endif + } + } + } + } + } +} diff --git a/indra/newview/llperfstats.h b/indra/newview/llperfstats.h new file mode 100644 index 0000000000..bb5677f237 --- /dev/null +++ b/indra/newview/llperfstats.h @@ -0,0 +1,350 @@ +/** +* @file llperfstats.h +* @brief Statistics collection to support autotune and perf flaoter. +* +* $LicenseInfo:firstyear=2022&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2022, 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$ +*/ +#pragma once +#ifndef LL_PERFSTATS_H_INCLUDED +#define LL_PERFSTATS_H_INCLUDED + +#include <atomic> +#include <chrono> +#include <array> +#include <unordered_map> +#include <mutex> +#include "lluuid.h" +#include "llfasttimer.h" +#include "llapp.h" +#include "llprofiler.h" +#include "pipeline.h" + +extern U32 gFrameCount; +extern LLUUID gAgentID; +namespace LLPerfStats +{ + + // called once per main loop iteration + void updateClass(); + +// Note if changing these, they should correspond with the log range of the correpsonding sliders + static constexpr U64 ART_UNLIMITED_NANOS{50000000}; + static constexpr U64 ART_MINIMUM_NANOS{100000}; + static constexpr U64 ART_MIN_ADJUST_UP_NANOS{5000}; + static constexpr U64 ART_MIN_ADJUST_DOWN_NANOS{10000}; + + static constexpr F32 PREFERRED_DD{180}; + static constexpr U32 SMOOTHING_PERIODS{50}; + static constexpr U32 DD_STEP{10}; + + static constexpr U32 TUNE_AVATARS_ONLY{0}; + static constexpr U32 TUNE_SCENE_AND_AVATARS{1}; + static constexpr U32 TUNE_SCENE_ONLY{2}; + + extern F64 cpu_hertz; + + extern std::atomic<int64_t> tunedAvatars; + extern std::atomic<U64> renderAvatarMaxART_ns; + extern bool belowTargetFPS; + extern U32 lastGlobalPrefChange; + extern U32 lastSleepedFrame; + extern U64 meanFrameTime; + extern std::mutex bufferToggleLock; + + enum class ObjType_t{ + OT_GENERAL=0, // Also Unknown. Used for n/a type stats such as scenery + OT_COUNT + }; + enum class StatType_t{ + RENDER_GEOMETRY=0, + RENDER_SHADOWS, + RENDER_HUDS, + RENDER_UI, + RENDER_COMBINED, + RENDER_SWAP, + RENDER_FRAME, + RENDER_DISPLAY, + RENDER_SLEEP, + RENDER_LFS, + RENDER_MESHREPO, + //RENDER_FPSLIMIT, + RENDER_FPS, + RENDER_IDLE, + RENDER_DONE, // toggle buffer & clearbuffer (see processUpdate for hackery) + STATS_COUNT + }; + + struct StatsRecord + { + StatType_t statType; + ObjType_t objType; + LLUUID avID; + LLUUID objID; + uint64_t time; + bool isRigged; + bool isHUD; + }; + + struct Tunables + { + static constexpr U32 Nothing{0}; + static constexpr U32 NonImpostors{1}; + static constexpr U32 ReflectionDetail{2}; + static constexpr U32 FarClip{4}; + static constexpr U32 UserMinDrawDistance{8}; + static constexpr U32 UserTargetDrawDistance{16}; + static constexpr U32 UserImpostorDistance{32}; + static constexpr U32 UserImpostorDistanceTuningEnabled{64}; + static constexpr U32 UserFPSTuningStrategy{128}; + static constexpr U32 UserAutoTuneEnabled{256}; + static constexpr U32 UserTargetFPS{512}; + static constexpr U32 UserARTCutoff{1024}; + static constexpr U32 UserAutoTuneLock{4096}; + + U32 tuningFlag{0}; // bit mask for changed settings + + // proxy variables, used to pas the new value to be set via the mainthread + U32 nonImpostors{0}; + S32 reflectionDetail{0}; + F32 farClip{0.0}; + F32 userMinDrawDistance{0.0}; + F32 userTargetDrawDistance{0.0}; + F32 userImpostorDistance{0.0}; + bool userImpostorDistanceTuningEnabled{false}; + U32 userFPSTuningStrategy{0}; + bool userAutoTuneEnabled{false}; + bool userAutoTuneLock{true}; + U32 userTargetFPS{0}; + F32 userARTCutoffSliderValue{0}; + S32 userTargetReflections{0}; + bool autoTuneTimeout{true}; + bool vsyncEnabled{true}; + + void updateNonImposters(U32 nv){nonImpostors=nv; tuningFlag |= NonImpostors;}; + void updateReflectionDetail(S32 nv){reflectionDetail=nv; tuningFlag |= ReflectionDetail;}; + void updateFarClip(F32 nv){farClip=nv; tuningFlag |= FarClip;}; + void updateUserMinDrawDistance(F32 nv){userMinDrawDistance=nv; tuningFlag |= UserMinDrawDistance;}; + void updateUserTargetDrawDistance(F32 nv){userTargetDrawDistance=nv; tuningFlag |= UserTargetDrawDistance;}; + void updateImposterDistance(F32 nv){userImpostorDistance=nv; tuningFlag |= UserImpostorDistance;}; + void updateImposterDistanceTuningEnabled(bool nv){userImpostorDistanceTuningEnabled=nv; tuningFlag |= UserImpostorDistanceTuningEnabled;}; + void updateUserFPSTuningStrategy(U32 nv){userFPSTuningStrategy=nv; tuningFlag |= UserFPSTuningStrategy;}; + void updateTargetFps(U32 nv){userTargetFPS=nv; tuningFlag |= UserTargetFPS;}; + void updateUserARTCutoffSlider(F32 nv){userARTCutoffSliderValue=nv; tuningFlag |= UserARTCutoff;}; + void updateUserAutoTuneEnabled(bool nv){userAutoTuneEnabled=nv; tuningFlag |= UserAutoTuneEnabled;}; + void updateUserAutoTuneLock(bool nv){userAutoTuneLock=nv; tuningFlag |= UserAutoTuneLock;}; + + void resetChanges(){tuningFlag=Nothing;}; + void initialiseFromSettings(); + void updateRenderCostLimitFromSettings(); + void updateSettingsFromRenderCostLimit(); + void applyUpdates(); + }; + + extern Tunables tunables; + + class StatsRecorder{ + using Queue = LLThreadSafeQueue<StatsRecord>; + public: + + // called once per main loop iteration on General thread + static void update(); + + static inline StatsRecorder& getInstance() + { + static StatsRecorder instance; + return instance; + } + static inline void setFocusAv(const LLUUID& avID){focusAv = avID;}; + static inline const LLUUID& getFocusAv(){return focusAv;}; + static inline void setAutotuneInit(){autotuneInit = true;}; + static inline void send(StatsRecord && upd){StatsRecorder::getInstance().q.pushFront(std::move(upd));}; + static void endFrame(){StatsRecorder::getInstance().q.pushFront(StatsRecord{StatType_t::RENDER_DONE, ObjType_t::OT_GENERAL, LLUUID::null, LLUUID::null, 0});}; + static void clearStats(){StatsRecorder::getInstance().q.pushFront(StatsRecord{StatType_t::RENDER_DONE, ObjType_t::OT_GENERAL, LLUUID::null, LLUUID::null, 1});}; + + static inline void setEnabled(bool on_or_off){collectionEnabled=on_or_off;}; + static inline void enable() { collectionEnabled=true; }; + static inline void disable() { collectionEnabled=false; }; + static inline bool enabled() { return collectionEnabled; }; + + static inline int getReadBufferIndex() { return (writeBuffer ^ 1); }; + // static inline const StatsTypeMatrix& getCurrentStatsMatrix(){ return statsDoubleBuffer[getReadBufferIndex()];} + static inline uint64_t get(ObjType_t otype, LLUUID id, StatType_t type) + { + return statsDoubleBuffer[getReadBufferIndex()][static_cast<size_t>(otype)][id][static_cast<size_t>(type)]; + } + static inline uint64_t getSceneStat(StatType_t type) + { + return statsDoubleBuffer[getReadBufferIndex()][static_cast<size_t>(ObjType_t::OT_GENERAL)][LLUUID::null][static_cast<size_t>(type)]; + } + + static inline uint64_t getSum(ObjType_t otype, StatType_t type) + { + return sum[getReadBufferIndex()][static_cast<size_t>(otype)][static_cast<size_t>(type)]; + } + static inline uint64_t getMax(ObjType_t otype, StatType_t type) + { + return max[getReadBufferIndex()][static_cast<size_t>(otype)][static_cast<size_t>(type)]; + } + static void updateAvatarParams(); + private: + StatsRecorder(); + + static int countNearbyAvatars(S32 distance); + static U64 getMeanTotalFrameTime(); + static void updateMeanFrameTime(U64 tot_frame_time_raw); +// StatsArray is a uint64_t for each possible statistic type. + using StatsArray = std::array<uint64_t, static_cast<size_t>(LLPerfStats::StatType_t::STATS_COUNT)>; + using StatsMap = std::unordered_map<LLUUID, StatsArray, boost::hash<LLUUID>>; + using StatsTypeMatrix = std::array<StatsMap, static_cast<size_t>(LLPerfStats::ObjType_t::OT_COUNT)>; + using StatsSummaryArray = std::array<StatsArray, static_cast<size_t>(LLPerfStats::ObjType_t::OT_COUNT)>; + + static std::atomic<int> writeBuffer; + static LLUUID focusAv; + static bool autotuneInit; + static std::array<StatsTypeMatrix,2> statsDoubleBuffer; + static std::array<StatsSummaryArray,2> max; + static std::array<StatsSummaryArray,2> sum; + static bool collectionEnabled; + + + void processUpdate(const StatsRecord& upd) const + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + // LL_INFOS("perfstats") << "processing update:" << LL_ENDL; + // Note: nullptr is used as the key for global stats + + if (upd.statType == StatType_t::RENDER_DONE && upd.objType == ObjType_t::OT_GENERAL && upd.time == 0) + { + // LL_INFOS("perfstats") << "End of Frame Toggle Buffer:" << gFrameCount << LL_ENDL; + toggleBuffer(); + return; + } + if (upd.statType == StatType_t::RENDER_DONE && upd.objType == ObjType_t::OT_GENERAL && upd.time == 1) + { + // LL_INFOS("perfstats") << "New region - clear buffers:" << gFrameCount << LL_ENDL; + clearStatsBuffers(); + return; + } + + auto ot{upd.objType}; + auto& key{upd.objID}; + auto type {upd.statType}; + auto val {upd.time}; + + if (ot == ObjType_t::OT_GENERAL) + { + // LL_INFOS("perfstats") << "General update:" << LL_ENDL; + doUpd(key, ot, type,val); + return; + } + } + + static inline void doUpd(const LLUUID& key, ObjType_t ot, StatType_t type, uint64_t val) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + using ST = StatType_t; + StatsMap& stm {statsDoubleBuffer[writeBuffer][static_cast<size_t>(ot)]}; + auto& thisAsset = stm[key]; + + thisAsset[static_cast<size_t>(type)] += val; + thisAsset[static_cast<size_t>(ST::RENDER_COMBINED)] += val; + + sum[writeBuffer][static_cast<size_t>(ot)][static_cast<size_t>(type)] += val; + sum[writeBuffer][static_cast<size_t>(ot)][static_cast<size_t>(ST::RENDER_COMBINED)] += val; + + if(max[writeBuffer][static_cast<size_t>(ot)][static_cast<size_t>(type)] < thisAsset[static_cast<size_t>(type)]) + { + max[writeBuffer][static_cast<size_t>(ot)][static_cast<size_t>(type)] = thisAsset[static_cast<size_t>(type)]; + } + if(max[writeBuffer][static_cast<size_t>(ot)][static_cast<size_t>(ST::RENDER_COMBINED)] < thisAsset[static_cast<size_t>(ST::RENDER_COMBINED)]) + { + max[writeBuffer][static_cast<size_t>(ot)][static_cast<size_t>(ST::RENDER_COMBINED)] = thisAsset[static_cast<size_t>(ST::RENDER_COMBINED)]; + } + } + + static void toggleBuffer(); + static void clearStatsBuffers(); + + Queue q; + + ~StatsRecorder() = default; + StatsRecorder(const StatsRecorder&) = delete; + StatsRecorder& operator=(const StatsRecorder&) = delete; + + }; + + template <enum ObjType_t ObjTypeDiscriminator> + class RecordTime + { + + private: + RecordTime(const RecordTime&) = delete; + RecordTime() = delete; + U64 start; + public: + StatsRecord stat; + + RecordTime( const LLUUID& av, const LLUUID& id, StatType_t type, bool isRiggedAtt=false, bool isHUDAtt=false): + start{LLTrace::BlockTimer::getCPUClockCount64()}, + stat{type, ObjTypeDiscriminator, std::move(av), std::move(id), 0, isRiggedAtt, isHUDAtt} + { + //LL_PROFILE_ZONE_COLOR(tracy::Color::Orange); + }; + + template < ObjType_t OD = ObjTypeDiscriminator, + std::enable_if_t<OD == ObjType_t::OT_GENERAL> * = nullptr> + explicit RecordTime( StatType_t type ):RecordTime<ObjTypeDiscriminator>(LLUUID::null, LLUUID::null, type ) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + }; + + ~RecordTime() + { + if(!LLPerfStats::StatsRecorder::enabled()) + { + return; + } + + //LL_PROFILE_ZONE_COLOR(tracy::Color::Red); + + stat.time = LLTrace::BlockTimer::getCPUClockCount64() - start; + StatsRecorder::send(std::move(stat)); + }; + }; + + + inline double raw_to_ns(U64 raw) { return (static_cast<double>(raw) * 1000000000.0) / LLPerfStats::cpu_hertz; }; + inline double raw_to_us(U64 raw) { return (static_cast<double>(raw) * 1000000.0) / LLPerfStats::cpu_hertz; }; + inline double raw_to_ms(U64 raw) { return (static_cast<double>(raw) * 1000.0) / LLPerfStats::cpu_hertz; }; + + inline U64 ns_to_raw(double ns) { return (U64)(LLPerfStats::cpu_hertz * (ns / 1000000000.0)); } + inline U64 us_to_raw(double us) { return (U64)(LLPerfStats::cpu_hertz * (us / 1000000.0)); } + inline U64 ms_to_raw(double ms) { return (U64)(LLPerfStats::cpu_hertz * (ms / 1000.0)); + + } + + + using RecordSceneTime = RecordTime<ObjType_t::OT_GENERAL>; + +};// namespace LLPerfStats + +#endif diff --git a/indra/newview/llreflectionmap.h b/indra/newview/llreflectionmap.h index 803f7bdc97..7ea0fe6187 100644 --- a/indra/newview/llreflectionmap.h +++ b/indra/newview/llreflectionmap.h @@ -78,8 +78,12 @@ public: // point at which environment map was last generated from (in agent space) LLVector4a mOrigin; - // distance from viewer camera - F32 mDistance; + // distance from main viewer camera + F32 mDistance = -1.f; + + // Minimum and maximum depth in current render camera + F32 mMinDepth = -1.f; + F32 mMaxDepth = -1.f; // radius of this probe's affected area F32 mRadius = 16.f; diff --git a/indra/newview/llreflectionmapmanager.cpp b/indra/newview/llreflectionmapmanager.cpp index 88edbc9224..2235453e47 100644 --- a/indra/newview/llreflectionmapmanager.cpp +++ b/indra/newview/llreflectionmapmanager.cpp @@ -45,10 +45,13 @@ extern U32 nhpo2(U32 v); static void touch_default_probe(LLReflectionMap* probe) { - LLVector3 origin = LLViewerCamera::getInstance()->getOrigin(); - origin.mV[2] += 64.f; + if (LLViewerCamera::getInstance()) + { + LLVector3 origin = LLViewerCamera::getInstance()->getOrigin(); + origin.mV[2] += 64.f; - probe->mOrigin.load3(origin.mV); + probe->mOrigin.load3(origin.mV); + } } LLReflectionMapManager::LLReflectionMapManager() @@ -58,17 +61,17 @@ LLReflectionMapManager::LLReflectionMapManager() void LLReflectionMapManager::initCubeFree() { + // start at 1 because index 0 is reserved for mDefaultProbe for (int i = 1; i < LL_MAX_REFLECTION_PROBE_COUNT; ++i) { - mCubeFree[i] = true; + mCubeFree.push_back(i); } - - // cube index 0 is reserved for the fallback probe - mCubeFree[0] = false; } struct CompareProbeDistance { + LLReflectionMap* mDefaultProbe; + bool operator()(const LLPointer<LLReflectionMap>& lhs, const LLPointer<LLReflectionMap>& rhs) { return lhs->mDistance < rhs->mDistance; @@ -83,7 +86,15 @@ static F32 update_score(LLReflectionMap* p) // return true if a is higher priority for an update than b static bool check_priority(LLReflectionMap* a, LLReflectionMap* b) { - if (!a->mComplete && !b->mComplete) + if (a->mCubeIndex == -1) + { // not a candidate for updating + return false; + } + else if (b->mCubeIndex == -1) + { // certainly higher priority than b + return true; + } + else if (!a->mComplete && !b->mComplete) { //neither probe is complete, use distance return a->mDistance < b->mDistance; } @@ -133,14 +144,7 @@ void LLReflectionMapManager::update() } } - - if (mDefaultProbe.isNull()) - { - mDefaultProbe = addProbe(); - mDefaultProbe->mDistance = -4096.f; // hack to make sure the default probe is always first in sort order - mDefaultProbe->mRadius = 4096.f; - touch_default_probe(mDefaultProbe); - } + llassert(mProbes[0] == mDefaultProbe); LLVector4a camera_pos; camera_pos.load3(LLViewerCamera::instance().getOrigin().mV); @@ -170,6 +174,7 @@ void LLReflectionMapManager::update() return; } + bool did_update = false; static LLCachedControl<S32> sDetail(gSavedSettings, "RenderReflectionProbeDetail", -1); @@ -188,7 +193,46 @@ void LLReflectionMapManager::update() doProbeUpdate(); } - //LL_INFOS() << mProbes.size() << LL_ENDL; + // update distance to camera for all probes + std::sort(mProbes.begin()+1, mProbes.end(), CompareProbeDistance()); + llassert(mProbes[0] == mDefaultProbe); + llassert(mProbes[0]->mCubeArray == mTexture); + llassert(mProbes[0]->mCubeIndex == 0); + + // make sure we're assigning cube slots to the closest probes + + // first free any cube indices for distant probes + for (U32 i = mReflectionProbeCount; i < mProbes.size(); ++i) + { + LLReflectionMap* probe = mProbes[i]; + llassert(probe != nullptr); + + if (probe->mCubeIndex != -1 && mUpdatingProbe != probe) + { // free this index + mCubeFree.push_back(probe->mCubeIndex); + + probe->mCubeArray = nullptr; + probe->mCubeIndex = -1; + probe->mComplete = false; + } + } + + // next distribute the free indices + U32 count = llmin(mReflectionProbeCount, (U32)mProbes.size()); + + for (S32 i = 1; i < count && !mCubeFree.empty(); ++i) + { + // find the closest probe that needs a cube index + LLReflectionMap* probe = mProbes[i]; + + if (probe->mCubeIndex == -1) + { + S32 idx = allocateCubeIndex(); + llassert(idx > 0); //if we're still in this loop, mCubeFree should not be empty and allocateCubeIndex should be returning good indices + probe->mCubeArray = mTexture; + probe->mCubeIndex = idx; + } + } for (int i = 0; i < mProbes.size(); ++i) { @@ -205,8 +249,6 @@ void LLReflectionMapManager::update() continue; } - probe->mProbeIndex = i; - LLVector4a d; if (probe != mDefaultProbe) @@ -219,6 +261,10 @@ void LLReflectionMapManager::update() // make default probe have a distance of 64m for the purposes of prioritization (if it's already been generated once) probe->mDistance = 64.f; } + else + { + probe->mDistance = -4096.f; //boost priority of default probe when it's not complete + } if (probe->mComplete) { @@ -288,13 +334,8 @@ void LLReflectionMapManager::update() if (!did_update && oldestProbe != nullptr) { LLReflectionMap* probe = oldestProbe; - if (probe->mCubeIndex == -1) - { - probe->mCubeArray = mTexture; - - probe->mCubeIndex = probe == mDefaultProbe ? 0 : allocateCubeIndex(); - } - + llassert(probe->mCubeIndex != -1); + probe->autoAdjustOrigin(); mUpdatingProbe = probe; @@ -307,10 +348,6 @@ void LLReflectionMapManager::update() oldestOccluded->autoAdjustOrigin(); oldestOccluded->mLastUpdateTime = gFrameTimeSeconds; } - - // update distance to camera for all probes - mDefaultProbe->mDistance = -4096.f; // make default probe always end up at index 0 - std::sort(mProbes.begin(), mProbes.end(), CompareProbeDistance()); } LLReflectionMap* LLReflectionMapManager::addProbe(LLSpatialGroup* group) @@ -318,6 +355,14 @@ LLReflectionMap* LLReflectionMapManager::addProbe(LLSpatialGroup* group) LLReflectionMap* probe = new LLReflectionMap(); probe->mGroup = group; + if (mDefaultProbe.isNull()) + { //safety check to make sure default probe is always first probe added + mDefaultProbe = new LLReflectionMap(); + mProbes.push_back(mDefaultProbe); + } + + llassert(mProbes[0] == mDefaultProbe); + if (group) { probe->mOrigin = group->getOctreeNode()->getCenter(); @@ -335,10 +380,22 @@ LLReflectionMap* LLReflectionMapManager::addProbe(LLSpatialGroup* group) return probe; } +struct CompareProbeDepth +{ + bool operator()(const LLReflectionMap* lhs, const LLReflectionMap* rhs) + { + return lhs->mMinDepth < rhs->mMinDepth; + } +}; + void LLReflectionMapManager::getReflectionMaps(std::vector<LLReflectionMap*>& maps) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DISPLAY; + LLMatrix4a modelview; + modelview.loadu(gGLModelView); + LLVector4a oa; // scratch space for transformed origin + U32 count = 0; U32 lastIdx = 0; for (U32 i = 0; count < maps.size() && i < mProbes.size(); ++i) @@ -348,8 +405,10 @@ void LLReflectionMapManager::getReflectionMaps(std::vector<LLReflectionMap*>& ma { if (!mProbes[i]->mOccluded && mProbes[i]->mComplete) { - mProbes[i]->mProbeIndex = count; maps[count++] = mProbes[i]; + modelview.affineTransform(mProbes[i]->mOrigin, oa); + mProbes[i]->mMinDepth = -oa.getF32ptr()[2] - mProbes[i]->mRadius; + mProbes[i]->mMaxDepth = -oa.getF32ptr()[2] + mProbes[i]->mRadius; } } else @@ -365,6 +424,16 @@ void LLReflectionMapManager::getReflectionMaps(std::vector<LLReflectionMap*>& ma mProbes[i]->mProbeIndex = -1; } + if (count > 1) + { + std::sort(maps.begin(), maps.begin() + count, CompareProbeDepth()); + } + + for (U32 i = 0; i < count; ++i) + { + maps[i]->mProbeIndex = i; + } + // null terminate list if (count < maps.size()) { @@ -407,32 +476,15 @@ LLReflectionMap* LLReflectionMapManager::registerViewerObject(LLViewerObject* vo return probe; } - S32 LLReflectionMapManager::allocateCubeIndex() { - for (int i = 0; i < mReflectionProbeCount; ++i) + if (!mCubeFree.empty()) { - if (mCubeFree[i]) - { - mCubeFree[i] = false; - return i; - } + S32 ret = mCubeFree.front(); + mCubeFree.pop_front(); + return ret; } - // no cubemaps free, steal one from the back of the probe list - for (int i = mProbes.size() - 1; i >= mReflectionProbeCount; --i) - { - if (mProbes[i]->mCubeIndex != -1) - { - S32 ret = mProbes[i]->mCubeIndex; - mProbes[i]->mCubeIndex = -1; - mProbes[i]->mCubeArray = nullptr; - mProbes[i]->mComplete = false; - return ret; - } - } - - llassert(false); // should never fail to allocate, something is probably wrong with mCubeFree return -1; } @@ -445,7 +497,7 @@ void LLReflectionMapManager::deleteProbe(U32 i) if (probe->mCubeIndex != -1) { // mark the cube index used by this probe as being free - mCubeFree[probe->mCubeIndex] = true; + mCubeFree.push_back(probe->mCubeIndex); } if (mUpdatingProbe == probe) { @@ -776,13 +828,14 @@ void LLReflectionMapManager::updateNeighbors(LLReflectionMap* probe) } // search for new neighbors + if (probe->isRelevant()) { LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("rmmun - search"); for (auto& other : mProbes) { if (other != mDefaultProbe && other != probe) { - if (probe->intersects(other)) + if (other->isRelevant() && probe->intersects(other)) { probe->mNeighbors.push_back(other); other->mNeighbors.push_back(probe); @@ -816,6 +869,7 @@ void LLReflectionMapManager::updateUniforms() // x - irradiance scale // y - radiance scale // z - fade in + // w - znear LLVector4 refParams[LL_MAX_REFLECTION_PROBE_COUNT]; // indices used by probe: @@ -828,6 +882,7 @@ void LLReflectionMapManager::updateUniforms() // list of neighbor indices GLint refNeighbor[4096]; + GLint refBucket[256][4]; //lookup table for which index to start with for the given Z depth // numbrer of active refmaps GLint refmapCount; }; @@ -837,6 +892,17 @@ void LLReflectionMapManager::updateUniforms() ReflectionProbeData rpd; + F32 minDepth[256]; + + for (int i = 0; i < 256; ++i) + { + rpd.refBucket[i][0] = mReflectionProbeCount; + rpd.refBucket[i][1] = mReflectionProbeCount; + rpd.refBucket[i][2] = mReflectionProbeCount; + rpd.refBucket[i][3] = mReflectionProbeCount; + minDepth[i] = FLT_MAX; + } + // load modelview matrix into matrix 4a LLMatrix4a modelview; modelview.loadu(gGLModelView); @@ -861,6 +927,28 @@ void LLReflectionMapManager::updateUniforms() break; } + if (refmap != mDefaultProbe) + { + // bucket search data + // theory of operation: + // 1. Determine minimum and maximum depth of each influence volume and store in mDepth (done in getReflectionMaps) + // 2. Sort by minimum depth + // 3. Prepare a bucket for each 1m of depth out to 256m + // 4. For each bucket, store the index of the nearest probe that might influence pixels in that bucket + // 5. In the shader, lookup the bucket for the pixel depth to get the index of the first probe that could possibly influence + // the current pixel. + int depth_min = llclamp(llfloor(refmap->mMinDepth), 0, 255); + int depth_max = llclamp(llfloor(refmap->mMaxDepth), 0, 255); + for (U32 i = depth_min; i <= depth_max; ++i) + { + if (refmap->mMinDepth < minDepth[i]) + { + minDepth[i] = refmap->mMinDepth; + rpd.refBucket[i][0] = refmap->mProbeIndex; + } + } + } + llassert(refmap->mProbeIndex == count); llassert(mReflectionMaps[refmap->mProbeIndex] == refmap); @@ -890,7 +978,11 @@ void LLReflectionMapManager::updateUniforms() rpd.refIndex[count][3] = -rpd.refIndex[count][3]; } - rpd.refParams[count].set(llmax(minimum_ambiance, refmap->getAmbiance())*ambscale, radscale, refmap->mFadeIn, 0.f); + rpd.refParams[count].set( + llmax(minimum_ambiance, refmap->getAmbiance())*ambscale, // ambiance scale + radscale, // radiance scale + refmap->mFadeIn, // fade in weight + oa.getF32ptr()[2] - refmap->mRadius); // z near S32 ni = nc; // neighbor ("index") - index into refNeighbor to write indices for current reflection probe's neighbors { @@ -907,7 +999,7 @@ void LLReflectionMapManager::updateUniforms() } GLint idx = neighbor->mProbeIndex; - if (idx == -1 || neighbor->mOccluded) + if (idx == -1 || neighbor->mOccluded || neighbor->mCubeIndex == -1) { continue; } @@ -944,6 +1036,30 @@ void LLReflectionMapManager::updateUniforms() count++; } +#if 0 + { + // fill in gaps in refBucket + S32 probe_idx = mReflectionProbeCount; + + for (int i = 0; i < 256; ++i) + { + if (i < count) + { // for debugging, store depth of mReflectionsMaps[i] + rpd.refBucket[i][1] = (S32) (mReflectionMaps[i]->mDepth * 10); + } + + if (rpd.refBucket[i][0] == mReflectionProbeCount) + { + rpd.refBucket[i][0] = probe_idx; + } + else + { + probe_idx = rpd.refBucket[i][0]; + } + } + } +#endif + rpd.refmapCount = count; //copy rpd into uniform buffer object @@ -958,6 +1074,21 @@ void LLReflectionMapManager::updateUniforms() glBufferData(GL_UNIFORM_BUFFER, sizeof(ReflectionProbeData), &rpd, GL_STREAM_DRAW); glBindBuffer(GL_UNIFORM_BUFFER, 0); } + +#if 0 + if (!gCubeSnapshot) + { + for (auto& probe : mProbes) + { + LLViewerObject* vobj = probe->mViewerObject; + if (vobj) + { + F32 time = (F32)gFrameTimeSeconds - probe->mLastUpdateTime; + vobj->setDebugText(llformat("%d/%d/%d/%.1f - %.1f/%.1f", probe->mCubeIndex, probe->mProbeIndex, (U32) probe->mNeighbors.size(), probe->mMinDepth, probe->mMaxDepth, time), time > 1.f ? LLColor4::white : LLColor4::green); + } + } + } +#endif } void LLReflectionMapManager::setUniforms() @@ -977,37 +1108,40 @@ void LLReflectionMapManager::setUniforms() void renderReflectionProbe(LLReflectionMap* probe) { - F32* po = probe->mOrigin.getF32ptr(); - - //draw orange line from probe to neighbors - gGL.flush(); - gGL.diffuseColor4f(1, 0.5f, 0, 1); - gGL.begin(gGL.LINES); - for (auto& neighbor : probe->mNeighbors) + if (probe->isRelevant()) { - if (probe->mViewerObject && neighbor->mViewerObject) - { - continue; - } - - gGL.vertex3fv(po); - gGL.vertex3fv(neighbor->mOrigin.getF32ptr()); - } - gGL.end(); - gGL.flush(); + F32* po = probe->mOrigin.getF32ptr(); - gGL.diffuseColor4f(1, 1, 0, 1); - gGL.begin(gGL.LINES); - for (auto& neighbor : probe->mNeighbors) - { - if (probe->mViewerObject && neighbor->mViewerObject) + //draw orange line from probe to neighbors + gGL.flush(); + gGL.diffuseColor4f(1, 0.5f, 0, 1); + gGL.begin(gGL.LINES); + for (auto& neighbor : probe->mNeighbors) { + if (probe->mViewerObject && neighbor->mViewerObject) + { + continue; + } + gGL.vertex3fv(po); gGL.vertex3fv(neighbor->mOrigin.getF32ptr()); } + gGL.end(); + gGL.flush(); + + gGL.diffuseColor4f(1, 1, 0, 1); + gGL.begin(gGL.LINES); + for (auto& neighbor : probe->mNeighbors) + { + if (probe->mViewerObject && neighbor->mViewerObject) + { + gGL.vertex3fv(po); + gGL.vertex3fv(neighbor->mOrigin.getF32ptr()); + } + } + gGL.end(); + gGL.flush(); } - gGL.end(); - gGL.flush(); #if 0 LLSpatialGroup* group = probe->mGroup; @@ -1095,7 +1229,6 @@ void LLReflectionMapManager::initReflectionMaps() mUpdatingProbe = nullptr; mRadiancePass = false; mRealtimeRadiancePass = false; - mDefaultProbe = nullptr; for (auto& probe : mProbes) { @@ -1104,14 +1237,28 @@ void LLReflectionMapManager::initReflectionMaps() probe->mProbeIndex = -1; probe->mCubeArray = nullptr; probe->mCubeIndex = -1; + probe->mNeighbors.clear(); } - for (bool& is_free : mCubeFree) + mCubeFree.clear(); + initCubeFree(); + + if (mDefaultProbe.isNull()) { - is_free = true; + llassert(mProbes.empty()); // default probe MUST be the first probe created + mDefaultProbe = new LLReflectionMap(); + mProbes.push_back(mDefaultProbe); } - mCubeFree[0] = false; + llassert(mProbes[0] == mDefaultProbe); + + mDefaultProbe->mCubeIndex = 0; + mDefaultProbe->mCubeArray = mTexture; + mDefaultProbe->mDistance = 64.f; + mDefaultProbe->mRadius = 4096.f; + mDefaultProbe->mProbeIndex = 0; + touch_default_probe(mDefaultProbe); + } if (mVertexBuffer.isNull()) diff --git a/indra/newview/llreflectionmapmanager.h b/indra/newview/llreflectionmapmanager.h index 234bde51a8..c0618de410 100644 --- a/indra/newview/llreflectionmapmanager.h +++ b/indra/newview/llreflectionmapmanager.h @@ -110,7 +110,7 @@ private: void deleteProbe(U32 i); // get a free cube index - // if no cube indices are free, free one starting from the back of the probe list + // returns -1 if allocation failed S32 allocateCubeIndex(); // update the neighbors of the given probe @@ -137,12 +137,9 @@ private: // storage for reflection probe irradiance maps LLPointer<LLCubeMapArray> mIrradianceMaps; - // array indicating if a particular cubemap is free - bool mCubeFree[LL_MAX_REFLECTION_PROBE_COUNT]; + // list of free cubemap indices + std::list<S32> mCubeFree; - // start tracking the given spatial group - void trackGroup(LLSpatialGroup* group); - // perform an update on the currently updating Probe void doProbeUpdate(); diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index 22c1176b05..71dcc56197 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -2188,8 +2188,8 @@ void LLSelectMgr::selectionRevertGLTFMaterials() // Enqueue update to server if (asset_id.notNull()) { - // Restore overrides - LLGLTFMaterialList::queueModify(objectp, te, nodep->mSavedGLTFOverrideMaterials[te]); + // Restore overrides and base material + LLGLTFMaterialList::queueApply(objectp, te, asset_id, nodep->mSavedGLTFOverrideMaterials[te]); } else { @@ -5797,7 +5797,7 @@ void LLSelectMgr::processObjectProperties(LLMessageSystem* msg, void** user_data if (can_copy && can_transfer && node->getObject()->getVolume()) { uuid_vec_t material_ids; - gltf_materials_vec_t materials; + gltf_materials_vec_t override_materials; LLVOVolume* vobjp = (LLVOVolume*)node->getObject(); for (int i = 0; i < vobjp->getNumTEs(); ++i) { @@ -5812,18 +5812,16 @@ void LLSelectMgr::processObjectProperties(LLMessageSystem* msg, void** user_data if (old_override) { LLPointer<LLGLTFMaterial> mat = new LLGLTFMaterial(*old_override); - materials.push_back(mat); + override_materials.push_back(mat); } else { - materials.push_back(nullptr); + override_materials.push_back(nullptr); } } - node->saveGLTFMaterialIds(material_ids); - // processObjectProperties does not include overrides so this // might need to be moved to LLGLTFMaterialOverrideDispatchHandler - node->saveGLTFOverrideMaterials(materials); + node->saveGLTFMaterials(material_ids, override_materials); } } @@ -6576,8 +6574,7 @@ LLSelectNode::LLSelectNode(const LLSelectNode& nodep) } saveTextures(nodep.mSavedTextures); - saveGLTFMaterialIds(nodep.mSavedGLTFMaterialIds); - saveGLTFOverrideMaterials(nodep.mSavedGLTFOverrideMaterials); + saveGLTFMaterials(nodep.mSavedGLTFMaterialIds, nodep.mSavedGLTFOverrideMaterials); } LLSelectNode::~LLSelectNode() @@ -6711,28 +6708,21 @@ void LLSelectNode::saveTextures(const uuid_vec_t& textures) } } -void LLSelectNode::saveGLTFMaterialIds(const uuid_vec_t& materials) +void LLSelectNode::saveGLTFMaterials(const uuid_vec_t& materials, const gltf_materials_vec_t& override_materials) { if (mObject.notNull()) { mSavedGLTFMaterialIds.clear(); + mSavedGLTFOverrideMaterials.clear(); for (uuid_vec_t::const_iterator materials_it = materials.begin(); materials_it != materials.end(); ++materials_it) { mSavedGLTFMaterialIds.push_back(*materials_it); } - } -} - -void LLSelectNode::saveGLTFOverrideMaterials(const gltf_materials_vec_t& materials) -{ - if (mObject.notNull()) - { - mSavedGLTFOverrideMaterials.clear(); - for (gltf_materials_vec_t::const_iterator mat_it = materials.begin(); - mat_it != materials.end(); ++mat_it) + for (gltf_materials_vec_t::const_iterator mat_it = override_materials.begin(); + mat_it != override_materials.end(); ++mat_it) { mSavedGLTFOverrideMaterials.push_back(*mat_it); } @@ -7833,7 +7823,7 @@ S32 LLObjectSelection::getSelectedObjectRenderCost() for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter) { // add the cost of each individual texture in the linkset - cost += iter->second; + cost += LLVOVolume::getTextureCost(*iter); } textures.clear(); @@ -7855,7 +7845,7 @@ S32 LLObjectSelection::getSelectedObjectRenderCost() for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter) { // add the cost of each individual texture in the linkset - cost += iter->second; + cost += LLVOVolume::getTextureCost(*iter); } textures.clear(); diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 3ee78f9a58..ca9a32f0db 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -197,8 +197,7 @@ public: // final gltf material that users see. // Ids get applied and restored by tools floater, // overrides get applied in live material editor - void saveGLTFMaterialIds(const uuid_vec_t& materials); - void saveGLTFOverrideMaterials(const gltf_materials_vec_t& materials); + void saveGLTFMaterials(const uuid_vec_t& materials, const gltf_materials_vec_t& override_materials); BOOL allowOperationOnNode(PermissionBit op, U64 group_proxy_power) const; diff --git a/indra/newview/llsettingsvo.cpp b/indra/newview/llsettingsvo.cpp index 1427dbefa1..a7a5a9223c 100644 --- a/indra/newview/llsettingsvo.cpp +++ b/indra/newview/llsettingsvo.cpp @@ -574,11 +574,11 @@ void LLSettingsVOSky::convertAtmosphericsToLegacy(LLSD& legacy, LLSD& settings) legacy[SETTING_BLUE_DENSITY] = ensure_array_4(legacyhaze[SETTING_BLUE_DENSITY], 1.0); legacy[SETTING_BLUE_HORIZON] = ensure_array_4(legacyhaze[SETTING_BLUE_HORIZON], 1.0); - legacy[SETTING_DENSITY_MULTIPLIER] = LLSDArray(legacyhaze[SETTING_DENSITY_MULTIPLIER].asReal())(0.0f)(0.0f)(1.0f); - legacy[SETTING_DISTANCE_MULTIPLIER] = LLSDArray(legacyhaze[SETTING_DISTANCE_MULTIPLIER].asReal())(0.0f)(0.0f)(1.0f); + legacy[SETTING_DENSITY_MULTIPLIER] = llsd::array(legacyhaze[SETTING_DENSITY_MULTIPLIER].asReal(), 0.0f, 0.0f, 1.0f); + legacy[SETTING_DISTANCE_MULTIPLIER] = llsd::array(legacyhaze[SETTING_DISTANCE_MULTIPLIER].asReal(), 0.0f, 0.0f, 1.0f); - legacy[SETTING_HAZE_DENSITY] = LLSDArray(legacyhaze[SETTING_HAZE_DENSITY])(0.0f)(0.0f)(1.0f); - legacy[SETTING_HAZE_HORIZON] = LLSDArray(legacyhaze[SETTING_HAZE_HORIZON])(0.0f)(0.0f)(1.0f); + legacy[SETTING_HAZE_DENSITY] = llsd::array(legacyhaze[SETTING_HAZE_DENSITY], 0.0f, 0.0f, 1.0f); + legacy[SETTING_HAZE_HORIZON] = llsd::array(legacyhaze[SETTING_HAZE_HORIZON], 0.0f, 0.0f, 1.0f); } } @@ -592,15 +592,15 @@ LLSD LLSettingsVOSky::convertToLegacy(const LLSettingsSky::ptr_t &psky, bool isA legacy[SETTING_CLOUD_COLOR] = ensure_array_4(settings[SETTING_CLOUD_COLOR], 1.0); legacy[SETTING_CLOUD_POS_DENSITY1] = ensure_array_4(settings[SETTING_CLOUD_POS_DENSITY1], 1.0); legacy[SETTING_CLOUD_POS_DENSITY2] = ensure_array_4(settings[SETTING_CLOUD_POS_DENSITY2], 1.0); - legacy[SETTING_CLOUD_SCALE] = LLSDArray(settings[SETTING_CLOUD_SCALE])(LLSD::Real(0.0))(LLSD::Real(0.0))(LLSD::Real(1.0)); + legacy[SETTING_CLOUD_SCALE] = llsd::array(settings[SETTING_CLOUD_SCALE], LLSD::Real(0.0), LLSD::Real(0.0), LLSD::Real(1.0)); legacy[SETTING_CLOUD_SCROLL_RATE] = settings[SETTING_CLOUD_SCROLL_RATE]; - legacy[SETTING_LEGACY_ENABLE_CLOUD_SCROLL] = LLSDArray(LLSD::Boolean(!is_approx_zero(settings[SETTING_CLOUD_SCROLL_RATE][0].asReal()))) - (LLSD::Boolean(!is_approx_zero(settings[SETTING_CLOUD_SCROLL_RATE][1].asReal()))); - legacy[SETTING_CLOUD_SHADOW] = LLSDArray(settings[SETTING_CLOUD_SHADOW].asReal())(0.0f)(0.0f)(1.0f); - legacy[SETTING_GAMMA] = LLSDArray(settings[SETTING_GAMMA])(0.0f)(0.0f)(1.0f); + legacy[SETTING_LEGACY_ENABLE_CLOUD_SCROLL] = llsd::array(LLSD::Boolean(!is_approx_zero(settings[SETTING_CLOUD_SCROLL_RATE][0].asReal())), + LLSD::Boolean(!is_approx_zero(settings[SETTING_CLOUD_SCROLL_RATE][1].asReal()))); + legacy[SETTING_CLOUD_SHADOW] = llsd::array(settings[SETTING_CLOUD_SHADOW].asReal(), 0.0f, 0.0f, 1.0f); + legacy[SETTING_GAMMA] = llsd::array(settings[SETTING_GAMMA], 0.0f, 0.0f, 1.0f); legacy[SETTING_GLOW] = ensure_array_4(settings[SETTING_GLOW], 1.0); legacy[SETTING_LIGHT_NORMAL] = ensure_array_4(psky->getLightDirection().getValue(), 0.0f); - legacy[SETTING_MAX_Y] = LLSDArray(settings[SETTING_MAX_Y])(0.0f)(0.0f)(1.0f); + legacy[SETTING_MAX_Y] = llsd::array(settings[SETTING_MAX_Y], 0.0f, 0.0f, 1.0f); legacy[SETTING_STAR_BRIGHTNESS] = settings[SETTING_STAR_BRIGHTNESS].asReal() / 250.0f; // convert from 0-500 -> 0-2 ala pre-FS-compat changes legacy[SETTING_SUNLIGHT_COLOR] = ensure_array_4(settings[SETTING_SUNLIGHT_COLOR], 1.0f); @@ -1113,7 +1113,7 @@ LLSettingsDay::ptr_t LLSettingsVODay::buildFromLegacyPreset(const std::string &n newsettings[SETTING_NAME] = name; - LLSD watertrack = LLSDArray( + LLSD watertrack = llsd::array( LLSDMap(SETTING_KEYKFRAME, LLSD::Real(0.0f)) (SETTING_KEYNAME, "water:Default")); @@ -1128,7 +1128,7 @@ LLSettingsDay::ptr_t LLSettingsVODay::buildFromLegacyPreset(const std::string &n skytrack.append(entry); } - newsettings[SETTING_TRACKS] = LLSDArray(watertrack)(skytrack); + newsettings[SETTING_TRACKS] = llsd::array(watertrack, skytrack); LLSD frames(LLSD::emptyMap()); @@ -1216,7 +1216,7 @@ LLSettingsDay::ptr_t LLSettingsVODay::buildFromLegacyMessage(const LLUUID ®io watersettings[SETTING_NAME] = watername; frames[watername] = watersettings; - LLSD watertrack = LLSDArray( + LLSD watertrack = llsd::array( LLSDMap(SETTING_KEYKFRAME, LLSD::Real(0.0f)) (SETTING_KEYNAME, watername)); @@ -1230,7 +1230,7 @@ LLSettingsDay::ptr_t LLSettingsVODay::buildFromLegacyMessage(const LLUUID ®io LLSD newsettings = LLSDMap ( SETTING_NAME, "Region (legacy)" ) - ( SETTING_TRACKS, LLSDArray(watertrack)(skytrack)) + ( SETTING_TRACKS, llsd::array(watertrack, skytrack)) ( SETTING_FRAMES, frames ) ( SETTING_TYPE, "daycycle" ); @@ -1411,7 +1411,7 @@ LLSD LLSettingsVODay::convertToLegacy(const LLSettingsVODay::ptr_t &pday) skys[name.str()] = std::static_pointer_cast<LLSettingsSky>((*it).second); F32 frame = ((tracksky.size() == 1) && (it == tracksky.begin())) ? -1.0f : (*it).first; - llsdcycle.append( LLSDArray(LLSD::Real(frame))(name.str()) ); + llsdcycle.append( llsd::array(LLSD::Real(frame), name.str()) ); } LLSD llsdskylist(LLSD::emptyMap()); @@ -1424,7 +1424,7 @@ LLSD LLSettingsVODay::convertToLegacy(const LLSettingsVODay::ptr_t &pday) llsdskylist[(*its).first] = llsdsky; } - return LLSDArray(LLSD::emptyMap())(llsdcycle)(llsdskylist)(llsdwater); + return llsd::array(LLSD::emptyMap(), llsdcycle, llsdskylist, llsdwater); } LLSettingsSkyPtr_t LLSettingsVODay::getDefaultSky() const diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp index 4d99ee1386..f7df4286fe 100644 --- a/indra/newview/llspatialpartition.cpp +++ b/indra/newview/llspatialpartition.cpp @@ -1826,116 +1826,6 @@ void renderUpdateType(LLDrawable* drawablep) } } -void renderComplexityDisplay(LLDrawable* drawablep) -{ - LLViewerObject* vobj = drawablep->getVObj(); - if (!vobj) - { - return; - } - - LLVOVolume *voVol = dynamic_cast<LLVOVolume*>(vobj); - - if (!voVol) - { - return; - } - - if (!voVol->isRoot()) - { - return; - } - - LLVOVolume::texture_cost_t textures; - F32 cost = (F32) voVol->getRenderCost(textures); - - // add any child volumes - LLViewerObject::const_child_list_t children = voVol->getChildren(); - for (LLViewerObject::const_child_list_t::const_iterator iter = children.begin(); iter != children.end(); ++iter) - { - const LLViewerObject *child = *iter; - const LLVOVolume *child_volume = dynamic_cast<const LLVOVolume*>(child); - if (child_volume) - { - cost += child_volume->getRenderCost(textures); - } - } - - // add texture cost - for (LLVOVolume::texture_cost_t::iterator iter = textures.begin(); iter != textures.end(); ++iter) - { - // add the cost of each individual texture in the linkset - cost += iter->second; - } - - F32 cost_max = (F32) LLVOVolume::getRenderComplexityMax(); - - - - // allow user to set a static color scale - if (gSavedSettings.getS32("RenderComplexityStaticMax") > 0) - { - cost_max = gSavedSettings.getS32("RenderComplexityStaticMax"); - } - - F32 cost_ratio = cost / cost_max; - - // cap cost ratio at 1.0f in case cost_max is at a low threshold - cost_ratio = cost_ratio > 1.0f ? 1.0f : cost_ratio; - - LLGLEnable blend(GL_BLEND); - - LLColor4 color; - const LLColor4 color_min = gSavedSettings.getColor4("RenderComplexityColorMin"); - const LLColor4 color_mid = gSavedSettings.getColor4("RenderComplexityColorMid"); - const LLColor4 color_max = gSavedSettings.getColor4("RenderComplexityColorMax"); - - if (cost_ratio < 0.5f) - { - color = color_min * (1 - cost_ratio * 2) + color_mid * (cost_ratio * 2); - } - else - { - color = color_mid * (1 - (cost_ratio - 0.5) * 2) + color_max * ((cost_ratio - 0.5) * 2); - } - - LLSD color_val = color.getValue(); - - // don't highlight objects below the threshold - if (cost > gSavedSettings.getS32("RenderComplexityThreshold")) - { - glColor4f(color[0],color[1],color[2],0.5f); - - - S32 num_faces = drawablep->getNumFaces(); - if (num_faces) - { - for (S32 i = 0; i < num_faces; ++i) - { - pushVerts(drawablep->getFace(i)); - } - } - LLViewerObject::const_child_list_t children = voVol->getChildren(); - for (LLViewerObject::const_child_list_t::const_iterator iter = children.begin(); iter != children.end(); ++iter) - { - const LLViewerObject *child = *iter; - if (child) - { - num_faces = child->getNumFaces(); - if (num_faces) - { - for (S32 i = 0; i < num_faces; ++i) - { - pushVerts(child->mDrawable->getFace(i)); - } - } - } - } - } - - voVol->setDebugText(llformat("%4.0f", cost)); -} - void renderBoundingBox(LLDrawable* drawable, BOOL set_color = TRUE) { if (set_color) @@ -3261,10 +3151,6 @@ public: { renderUpdateType(drawable); } - if(gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY)) - { - renderComplexityDisplay(drawable); - } if(gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_TEXEL_DENSITY)) { renderTexelDensity(drawable); @@ -3575,7 +3461,6 @@ void LLSpatialPartition::renderDebug() LLPipeline::RENDER_DEBUG_AGENT_TARGET | //LLPipeline::RENDER_DEBUG_BUILD_QUEUE | LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA | - LLPipeline::RENDER_DEBUG_RENDER_COMPLEXITY | LLPipeline::RENDER_DEBUG_TEXEL_DENSITY)) { return; diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 6bcee31b72..65fdd400bf 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -208,6 +208,7 @@ #include "llstacktrace.h" #include "threadpool.h" +#include "llperfstats.h" #if LL_WINDOWS @@ -1502,6 +1503,8 @@ bool idle_startup() LLViewerParcelAskPlay::getInstance()->loadSettings(); } + gAgent.addRegionChangedCallback(boost::bind(&LLPerfStats::StatsRecorder::clearStats)); + // *Note: this is where gWorldMap used to be initialized. // register null callbacks for audio until the audio system is initialized @@ -2346,6 +2349,8 @@ bool idle_startup() LLUIUsage::instance().clear(); + LLPerfStats::StatsRecorder::setAutotuneInit(); + return TRUE; } @@ -3408,6 +3413,9 @@ bool process_login_success_response() if(!text.empty()) gAgentID.set(text); gDebugInfo["AgentID"] = text; + LLPerfStats::StatsRecorder::setEnabled(gSavedSettings.getBOOL("PerfStatsCaptureEnabled")); + LLPerfStats::StatsRecorder::setFocusAv(gAgentID); + // Agent id needed for parcel info request in LLUrlEntryParcel // to resolve parcel name. LLUrlEntryParcel::setAgentID(gAgentID); diff --git a/indra/newview/lltoolbarview.cpp b/indra/newview/lltoolbarview.cpp index 01d799dcd5..4f47c465c4 100644 --- a/indra/newview/lltoolbarview.cpp +++ b/indra/newview/lltoolbarview.cpp @@ -44,6 +44,7 @@ #include "llagent.h" // HACK for destinations guide on startup #include "llfloaterreg.h" // HACK for destinations guide on startup #include "llviewercontrol.h" // HACK for destinations guide on startup +#include "llinventorymodel.h" // HACK to disable starter avatars button for NUX #include <boost/foreach.hpp> @@ -319,6 +320,25 @@ bool LLToolBarView::loadToolbars(bool force_default) } } } + + // SL-18581: Don't show the starter avatar toolbar button for NUX users + LLViewerInventoryCategory* my_outfits_cat = gInventory.getCategory(gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS)); + if (gAgent.isFirstLogin()) + { + LL_WARNS() << "First login: checking for NUX user." << LL_ENDL; + if (my_outfits_cat != NULL && my_outfits_cat->getDescendentCount() > 0) + { + LL_WARNS() << "First login: My Outfits folder is not empty, removing the avatar picker button." << LL_ENDL; + for (S32 i = LLToolBarEnums::TOOLBAR_FIRST; i <= LLToolBarEnums::TOOLBAR_LAST; i++) + { + if (mToolbars[i]) + { + mToolbars[i]->removeCommand(LLCommandId("avatar")); + } + } + } + } + mToolbarsLoaded = true; return true; } diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 1b19ba33a3..6633951db3 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -2150,12 +2150,14 @@ EAcceptance LLToolDragAndDrop::dad3dApplyToObject( if (nodep) { uuid_vec_t material_ids; + gltf_materials_vec_t override_materials; S32 num_faces = obj->getNumTEs(); for (S32 face = 0; face < num_faces; face++) { material_ids.push_back(obj->getRenderMaterialID(face)); + override_materials.push_back(nullptr); } - nodep->saveGLTFMaterialIds(material_ids); + nodep->saveGLTFMaterials(material_ids, override_materials); } } else @@ -2169,6 +2171,7 @@ EAcceptance LLToolDragAndDrop::dad3dApplyToObject( && nodep->mSavedGLTFMaterialIds.size() > face) { nodep->mSavedGLTFMaterialIds[face] = obj->getRenderMaterialID(face); + nodep->mSavedGLTFOverrideMaterials[face] = nullptr; } } } diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp index bbdae95b7f..faeebc33ee 100644 --- a/indra/newview/llviewercontrol.cpp +++ b/indra/newview/llviewercontrol.cpp @@ -74,6 +74,7 @@ #include "llspellcheck.h" #include "llslurl.h" #include "llstartup.h" +#include "llperfstats.h" // Third party library includes #include <boost/algorithm/string.hpp> @@ -247,8 +248,15 @@ static bool handleAnisotropicChanged(const LLSD& newvalue) static bool handleVSyncChanged(const LLSD& newvalue) { + LLPerfStats::tunables.vsyncEnabled = newvalue.asBoolean(); gViewerWindow->getWindow()->toggleVSync(newvalue.asBoolean()); + if(newvalue.asBoolean() == true) + { + U32 current_target = gSavedSettings.getU32("TargetFPS"); + gSavedSettings.setU32("TargetFPS", std::min((U32)gViewerWindow->getWindow()->getRefreshRate(), current_target)); + } + return true; } @@ -585,6 +593,71 @@ bool toggle_show_object_render_cost(const LLSD& newvalue) } void handleRenderAutoMuteByteLimitChanged(const LLSD& new_value); + +void handleTargetFPSChanged(const LLSD& newValue) +{ + const auto targetFPS = gSavedSettings.getU32("TargetFPS"); + + U32 frame_rate_limit = gViewerWindow->getWindow()->getRefreshRate(); + if(LLPerfStats::tunables.vsyncEnabled && (targetFPS > frame_rate_limit)) + { + gSavedSettings.setU32("TargetFPS", std::min(frame_rate_limit, targetFPS)); + } + else + { + LLPerfStats::tunables.userTargetFPS = targetFPS; + } +} + +void handleAutoTuneLockChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getBOOL("AutoTuneLock"); + LLPerfStats::tunables.userAutoTuneLock = newval; + + gSavedSettings.setBOOL("AutoTuneFPS", newval); +} + +void handleAutoTuneFPSChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getBOOL("AutoTuneFPS"); + LLPerfStats::tunables.userAutoTuneEnabled = newval; + if(newval && LLPerfStats::renderAvatarMaxART_ns == 0) // If we've enabled autotune we override "unlimited" to max + { + gSavedSettings.setF32("RenderAvatarMaxART",log10(LLPerfStats::ART_UNLIMITED_NANOS-1000));//triggers callback to update static var + } +} + +void handleRenderAvatarMaxARTChanged(const LLSD& newValue) +{ + LLPerfStats::tunables.updateRenderCostLimitFromSettings(); +} + +void handleUserTargetDrawDistanceChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getF32("AutoTuneRenderFarClipTarget"); + LLPerfStats::tunables.userTargetDrawDistance = newval; +} + +void handlePerformanceStatsEnabledChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getBOOL("PerfStatsCaptureEnabled"); + LLPerfStats::StatsRecorder::setEnabled(newval); +} +void handleUserImpostorByDistEnabledChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getBOOL("AutoTuneImpostorByDistEnabled"); + LLPerfStats::tunables.userImpostorDistanceTuningEnabled = newval; +} +void handleUserImpostorDistanceChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getF32("AutoTuneImpostorFarAwayDistance"); + LLPerfStats::tunables.userImpostorDistance = newval; +} +void handleFPSTuningStrategyChanged(const LLSD& newValue) +{ + const auto newval = gSavedSettings.getU32("TuningFPSStrategy"); + LLPerfStats::tunables.userFPSTuningStrategy = newval; +} //////////////////////////////////////////////////////////////////////////// LLPointer<LLControlVariable> setting_get_control(LLControlGroup& group, const std::string& setting) @@ -618,142 +691,152 @@ void setting_setup_signal_listener(LLControlGroup& group, const std::string& set void settings_setup_listeners() { setting_setup_signal_listener(gSavedSettings, "FirstPersonAvatarVisible", handleRenderAvatarMouselookChanged); - setting_setup_signal_listener(gSavedSettings, "RenderFarClip", handleRenderFarClipChanged); - setting_setup_signal_listener(gSavedSettings, "RenderTerrainDetail", handleTerrainDetailChanged); - setting_setup_signal_listener(gSavedSettings, "OctreeStaticObjectSizeFactor", handleRepartition); - setting_setup_signal_listener(gSavedSettings, "OctreeDistanceFactor", handleRepartition); - setting_setup_signal_listener(gSavedSettings, "OctreeMaxNodeCapacity", handleRepartition); - setting_setup_signal_listener(gSavedSettings, "OctreeAlphaDistanceFactor", handleRepartition); - setting_setup_signal_listener(gSavedSettings, "OctreeAttachmentSizeFactor", handleRepartition); - setting_setup_signal_listener(gSavedSettings, "RenderMaxTextureIndex", handleSetShaderChanged); - setting_setup_signal_listener(gSavedSettings, "RenderUIBuffer", handleWindowResized); - setting_setup_signal_listener(gSavedSettings, "RenderDepthOfField", handleReleaseGLBufferChanged); - setting_setup_signal_listener(gSavedSettings, "RenderFSAASamples", handleReleaseGLBufferChanged); - setting_setup_signal_listener(gSavedSettings, "RenderSpecularResX", handleLUTBufferChanged); - setting_setup_signal_listener(gSavedSettings, "RenderSpecularResY", handleLUTBufferChanged); - setting_setup_signal_listener(gSavedSettings, "RenderSpecularExponent", handleLUTBufferChanged); - setting_setup_signal_listener(gSavedSettings, "RenderAnisotropic", handleAnisotropicChanged); - setting_setup_signal_listener(gSavedSettings, "RenderShadowResolutionScale", handleShadowsResized); - setting_setup_signal_listener(gSavedSettings, "RenderGlow", handleReleaseGLBufferChanged); - setting_setup_signal_listener(gSavedSettings, "RenderGlow", handleSetShaderChanged); - setting_setup_signal_listener(gSavedSettings, "RenderGlowResolutionPow", handleReleaseGLBufferChanged); - setting_setup_signal_listener(gSavedSettings, "RenderGammaFull", handleSetShaderChanged); - setting_setup_signal_listener(gSavedSettings, "RenderVolumeLODFactor", handleVolumeLODChanged); - setting_setup_signal_listener(gSavedSettings, "RenderAvatarLODFactor", handleAvatarLODChanged); - setting_setup_signal_listener(gSavedSettings, "RenderAvatarPhysicsLODFactor", handleAvatarPhysicsLODChanged); - setting_setup_signal_listener(gSavedSettings, "RenderTerrainLODFactor", handleTerrainLODChanged); - setting_setup_signal_listener(gSavedSettings, "RenderTreeLODFactor", handleTreeLODChanged); - setting_setup_signal_listener(gSavedSettings, "RenderFlexTimeFactor", handleFlexLODChanged); - setting_setup_signal_listener(gSavedSettings, "RenderGamma", handleGammaChanged); - setting_setup_signal_listener(gSavedSettings, "RenderFogRatio", handleFogRatioChanged); - setting_setup_signal_listener(gSavedSettings, "RenderMaxPartCount", handleMaxPartCountChanged); - setting_setup_signal_listener(gSavedSettings, "RenderDynamicLOD", handleRenderDynamicLODChanged); - setting_setup_signal_listener(gSavedSettings, "RenderLocalLights", handleRenderLocalLightsChanged); + setting_setup_signal_listener(gSavedSettings, "RenderFarClip", handleRenderFarClipChanged); + setting_setup_signal_listener(gSavedSettings, "RenderTerrainDetail", handleTerrainDetailChanged); + setting_setup_signal_listener(gSavedSettings, "OctreeStaticObjectSizeFactor", handleRepartition); + setting_setup_signal_listener(gSavedSettings, "OctreeDistanceFactor", handleRepartition); + setting_setup_signal_listener(gSavedSettings, "OctreeMaxNodeCapacity", handleRepartition); + setting_setup_signal_listener(gSavedSettings, "OctreeAlphaDistanceFactor", handleRepartition); + setting_setup_signal_listener(gSavedSettings, "OctreeAttachmentSizeFactor", handleRepartition); + setting_setup_signal_listener(gSavedSettings, "RenderMaxTextureIndex", handleSetShaderChanged); + setting_setup_signal_listener(gSavedSettings, "RenderUIBuffer", handleWindowResized); + setting_setup_signal_listener(gSavedSettings, "RenderDepthOfField", handleReleaseGLBufferChanged); + setting_setup_signal_listener(gSavedSettings, "RenderFSAASamples", handleReleaseGLBufferChanged); + setting_setup_signal_listener(gSavedSettings, "RenderSpecularResX", handleLUTBufferChanged); + setting_setup_signal_listener(gSavedSettings, "RenderSpecularResY", handleLUTBufferChanged); + setting_setup_signal_listener(gSavedSettings, "RenderSpecularExponent", handleLUTBufferChanged); + setting_setup_signal_listener(gSavedSettings, "RenderAnisotropic", handleAnisotropicChanged); + setting_setup_signal_listener(gSavedSettings, "RenderShadowResolutionScale", handleShadowsResized); + setting_setup_signal_listener(gSavedSettings, "RenderGlow", handleReleaseGLBufferChanged); + setting_setup_signal_listener(gSavedSettings, "RenderGlow", handleSetShaderChanged); + setting_setup_signal_listener(gSavedSettings, "RenderGlowResolutionPow", handleReleaseGLBufferChanged); + setting_setup_signal_listener(gSavedSettings, "RenderGammaFull", handleSetShaderChanged); + setting_setup_signal_listener(gSavedSettings, "RenderVolumeLODFactor", handleVolumeLODChanged); + setting_setup_signal_listener(gSavedSettings, "RenderAvatarLODFactor", handleAvatarLODChanged); + setting_setup_signal_listener(gSavedSettings, "RenderAvatarPhysicsLODFactor", handleAvatarPhysicsLODChanged); + setting_setup_signal_listener(gSavedSettings, "RenderTerrainLODFactor", handleTerrainLODChanged); + setting_setup_signal_listener(gSavedSettings, "RenderTreeLODFactor", handleTreeLODChanged); + setting_setup_signal_listener(gSavedSettings, "RenderFlexTimeFactor", handleFlexLODChanged); + setting_setup_signal_listener(gSavedSettings, "RenderGamma", handleGammaChanged); + setting_setup_signal_listener(gSavedSettings, "RenderFogRatio", handleFogRatioChanged); + setting_setup_signal_listener(gSavedSettings, "RenderMaxPartCount", handleMaxPartCountChanged); + setting_setup_signal_listener(gSavedSettings, "RenderDynamicLOD", handleRenderDynamicLODChanged); + setting_setup_signal_listener(gSavedSettings, "RenderLocalLights", handleRenderLocalLightsChanged); setting_setup_signal_listener(gSavedSettings, "RenderVSyncEnable", handleVSyncChanged); - setting_setup_signal_listener(gSavedSettings, "RenderDeferredNoise", handleReleaseGLBufferChanged); - setting_setup_signal_listener(gSavedSettings, "RenderDebugPipeline", handleRenderDebugPipelineChanged); - setting_setup_signal_listener(gSavedSettings, "RenderResolutionDivisor", handleRenderResolutionDivisorChanged); + setting_setup_signal_listener(gSavedSettings, "RenderDeferredNoise", handleReleaseGLBufferChanged); + setting_setup_signal_listener(gSavedSettings, "RenderDebugPipeline", handleRenderDebugPipelineChanged); + setting_setup_signal_listener(gSavedSettings, "RenderResolutionDivisor", handleRenderResolutionDivisorChanged); setting_setup_signal_listener(gSavedSettings, "RenderReflectionProbeLevel", handleReflectionProbeDetailChanged); - setting_setup_signal_listener(gSavedSettings, "RenderReflectionProbeDetail", handleReflectionProbeDetailChanged); + setting_setup_signal_listener(gSavedSettings, "RenderReflectionProbeDetail", handleReflectionProbeDetailChanged); setting_setup_signal_listener(gSavedSettings, "RenderReflectionsEnabled", handleReflectionProbeDetailChanged); setting_setup_signal_listener(gSavedSettings, "RenderScreenSpaceReflections", handleReflectionProbeDetailChanged); - setting_setup_signal_listener(gSavedSettings, "RenderShadowDetail", handleSetShaderChanged); - setting_setup_signal_listener(gSavedSettings, "RenderDeferredSSAO", handleSetShaderChanged); - setting_setup_signal_listener(gSavedSettings, "RenderPerformanceTest", handleRenderPerfTestChanged); - setting_setup_signal_listener(gSavedSettings, "ChatFontSize", handleChatFontSizeChanged); - setting_setup_signal_listener(gSavedSettings, "ChatPersistTime", handleChatPersistTimeChanged); - setting_setup_signal_listener(gSavedSettings, "ConsoleMaxLines", handleConsoleMaxLinesChanged); - setting_setup_signal_listener(gSavedSettings, "UploadBakedTexOld", handleUploadBakedTexOldChanged); - setting_setup_signal_listener(gSavedSettings, "UseOcclusion", handleUseOcclusionChanged); - setting_setup_signal_listener(gSavedSettings, "AudioLevelMaster", handleAudioVolumeChanged); - setting_setup_signal_listener(gSavedSettings, "AudioLevelSFX", handleAudioVolumeChanged); - setting_setup_signal_listener(gSavedSettings, "AudioLevelUI", handleAudioVolumeChanged); - setting_setup_signal_listener(gSavedSettings, "AudioLevelAmbient", handleAudioVolumeChanged); - setting_setup_signal_listener(gSavedSettings, "AudioLevelMusic", handleAudioVolumeChanged); - setting_setup_signal_listener(gSavedSettings, "AudioLevelMedia", handleAudioVolumeChanged); - setting_setup_signal_listener(gSavedSettings, "AudioLevelVoice", handleAudioVolumeChanged); - setting_setup_signal_listener(gSavedSettings, "AudioLevelDoppler", handleAudioVolumeChanged); - setting_setup_signal_listener(gSavedSettings, "AudioLevelRolloff", handleAudioVolumeChanged); - setting_setup_signal_listener(gSavedSettings, "AudioLevelUnderwaterRolloff", handleAudioVolumeChanged); - setting_setup_signal_listener(gSavedSettings, "MuteAudio", handleAudioVolumeChanged); - setting_setup_signal_listener(gSavedSettings, "MuteMusic", handleAudioVolumeChanged); - setting_setup_signal_listener(gSavedSettings, "MuteMedia", handleAudioVolumeChanged); - setting_setup_signal_listener(gSavedSettings, "MuteVoice", handleAudioVolumeChanged); - setting_setup_signal_listener(gSavedSettings, "MuteAmbient", handleAudioVolumeChanged); - setting_setup_signal_listener(gSavedSettings, "MuteUI", handleAudioVolumeChanged); - setting_setup_signal_listener(gSavedSettings, "WLSkyDetail", handleWLSkyDetailChanged); - setting_setup_signal_listener(gSavedSettings, "JoystickAxis0", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "JoystickAxis1", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "JoystickAxis2", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "JoystickAxis3", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "JoystickAxis4", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "JoystickAxis5", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "JoystickAxis6", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "FlycamAxisScale0", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "FlycamAxisScale1", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "FlycamAxisScale2", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "FlycamAxisScale3", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "FlycamAxisScale4", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "FlycamAxisScale5", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "FlycamAxisScale6", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "FlycamAxisDeadZone0", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "FlycamAxisDeadZone1", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "FlycamAxisDeadZone2", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "FlycamAxisDeadZone3", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "FlycamAxisDeadZone4", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "FlycamAxisDeadZone5", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "FlycamAxisDeadZone6", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "AvatarAxisScale0", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "AvatarAxisScale1", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "AvatarAxisScale2", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "AvatarAxisScale3", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "AvatarAxisScale4", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "AvatarAxisScale5", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "AvatarAxisDeadZone0", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "AvatarAxisDeadZone1", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "AvatarAxisDeadZone2", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "AvatarAxisDeadZone3", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "AvatarAxisDeadZone4", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "AvatarAxisDeadZone5", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "BuildAxisScale0", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "BuildAxisScale1", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "BuildAxisScale2", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "BuildAxisScale3", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "BuildAxisScale4", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "BuildAxisScale5", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "BuildAxisDeadZone0", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "BuildAxisDeadZone1", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "BuildAxisDeadZone2", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "BuildAxisDeadZone3", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "BuildAxisDeadZone4", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "BuildAxisDeadZone5", handleJoystickChanged); - setting_setup_signal_listener(gSavedSettings, "DebugViews", handleDebugViewsChanged); - setting_setup_signal_listener(gSavedSettings, "UserLogFile", handleLogFileChanged); - setting_setup_signal_listener(gSavedSettings, "RenderHideGroupTitle", handleHideGroupTitleChanged); - setting_setup_signal_listener(gSavedSettings, "HighResSnapshot", handleHighResSnapshotChanged); - setting_setup_signal_listener(gSavedSettings, "EnableVoiceChat", handleVoiceClientPrefsChanged); - setting_setup_signal_listener(gSavedSettings, "PTTCurrentlyEnabled", handleVoiceClientPrefsChanged); - setting_setup_signal_listener(gSavedSettings, "PushToTalkButton", handleVoiceClientPrefsChanged); - setting_setup_signal_listener(gSavedSettings, "PushToTalkToggle", handleVoiceClientPrefsChanged); - setting_setup_signal_listener(gSavedSettings, "VoiceEarLocation", handleVoiceClientPrefsChanged); - setting_setup_signal_listener(gSavedSettings, "VoiceInputAudioDevice", handleVoiceClientPrefsChanged); - setting_setup_signal_listener(gSavedSettings, "VoiceOutputAudioDevice", handleVoiceClientPrefsChanged); - setting_setup_signal_listener(gSavedSettings, "AudioLevelMic", handleVoiceClientPrefsChanged); - setting_setup_signal_listener(gSavedSettings, "LipSyncEnabled", handleVoiceClientPrefsChanged); - setting_setup_signal_listener(gSavedSettings, "VelocityInterpolate", handleVelocityInterpolate); - setting_setup_signal_listener(gSavedSettings, "QAMode", show_debug_menus); - setting_setup_signal_listener(gSavedSettings, "UseDebugMenus", show_debug_menus); - setting_setup_signal_listener(gSavedSettings, "AgentPause", toggle_agent_pause); - setting_setup_signal_listener(gSavedSettings, "ShowNavbarNavigationPanel", toggle_show_navigation_panel); - setting_setup_signal_listener(gSavedSettings, "ShowMiniLocationPanel", toggle_show_mini_location_panel); - setting_setup_signal_listener(gSavedSettings, "ShowObjectRenderingCost", toggle_show_object_render_cost); - setting_setup_signal_listener(gSavedSettings, "ForceShowGrid", handleForceShowGrid); - setting_setup_signal_listener(gSavedSettings, "RenderTransparentWater", handleRenderTransparentWaterChanged); - setting_setup_signal_listener(gSavedSettings, "SpellCheck", handleSpellCheckChanged); - setting_setup_signal_listener(gSavedSettings, "SpellCheckDictionary", handleSpellCheckChanged); - setting_setup_signal_listener(gSavedSettings, "LoginLocation", handleLoginLocationChanged); - setting_setup_signal_listener(gSavedSettings, "DebugAvatarJoints", handleDebugAvatarJointsChanged); - setting_setup_signal_listener(gSavedSettings, "RenderAutoMuteByteLimit", handleRenderAutoMuteByteLimitChanged); + setting_setup_signal_listener(gSavedSettings, "RenderShadowDetail", handleSetShaderChanged); + setting_setup_signal_listener(gSavedSettings, "RenderDeferredSSAO", handleSetShaderChanged); + setting_setup_signal_listener(gSavedSettings, "RenderPerformanceTest", handleRenderPerfTestChanged); + setting_setup_signal_listener(gSavedSettings, "ChatFontSize", handleChatFontSizeChanged); + setting_setup_signal_listener(gSavedSettings, "ChatPersistTime", handleChatPersistTimeChanged); + setting_setup_signal_listener(gSavedSettings, "ConsoleMaxLines", handleConsoleMaxLinesChanged); + setting_setup_signal_listener(gSavedSettings, "UploadBakedTexOld", handleUploadBakedTexOldChanged); + setting_setup_signal_listener(gSavedSettings, "UseOcclusion", handleUseOcclusionChanged); + setting_setup_signal_listener(gSavedSettings, "AudioLevelMaster", handleAudioVolumeChanged); + setting_setup_signal_listener(gSavedSettings, "AudioLevelSFX", handleAudioVolumeChanged); + setting_setup_signal_listener(gSavedSettings, "AudioLevelUI", handleAudioVolumeChanged); + setting_setup_signal_listener(gSavedSettings, "AudioLevelAmbient", handleAudioVolumeChanged); + setting_setup_signal_listener(gSavedSettings, "AudioLevelMusic", handleAudioVolumeChanged); + setting_setup_signal_listener(gSavedSettings, "AudioLevelMedia", handleAudioVolumeChanged); + setting_setup_signal_listener(gSavedSettings, "AudioLevelVoice", handleAudioVolumeChanged); + setting_setup_signal_listener(gSavedSettings, "AudioLevelDoppler", handleAudioVolumeChanged); + setting_setup_signal_listener(gSavedSettings, "AudioLevelRolloff", handleAudioVolumeChanged); + setting_setup_signal_listener(gSavedSettings, "AudioLevelUnderwaterRolloff", handleAudioVolumeChanged); + setting_setup_signal_listener(gSavedSettings, "MuteAudio", handleAudioVolumeChanged); + setting_setup_signal_listener(gSavedSettings, "MuteMusic", handleAudioVolumeChanged); + setting_setup_signal_listener(gSavedSettings, "MuteMedia", handleAudioVolumeChanged); + setting_setup_signal_listener(gSavedSettings, "MuteVoice", handleAudioVolumeChanged); + setting_setup_signal_listener(gSavedSettings, "MuteAmbient", handleAudioVolumeChanged); + setting_setup_signal_listener(gSavedSettings, "MuteUI", handleAudioVolumeChanged); + setting_setup_signal_listener(gSavedSettings, "WLSkyDetail", handleWLSkyDetailChanged); + setting_setup_signal_listener(gSavedSettings, "JoystickAxis0", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "JoystickAxis1", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "JoystickAxis2", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "JoystickAxis3", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "JoystickAxis4", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "JoystickAxis5", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "JoystickAxis6", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "FlycamAxisScale0", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "FlycamAxisScale1", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "FlycamAxisScale2", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "FlycamAxisScale3", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "FlycamAxisScale4", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "FlycamAxisScale5", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "FlycamAxisScale6", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "FlycamAxisDeadZone0", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "FlycamAxisDeadZone1", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "FlycamAxisDeadZone2", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "FlycamAxisDeadZone3", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "FlycamAxisDeadZone4", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "FlycamAxisDeadZone5", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "FlycamAxisDeadZone6", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "AvatarAxisScale0", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "AvatarAxisScale1", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "AvatarAxisScale2", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "AvatarAxisScale3", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "AvatarAxisScale4", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "AvatarAxisScale5", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "AvatarAxisDeadZone0", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "AvatarAxisDeadZone1", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "AvatarAxisDeadZone2", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "AvatarAxisDeadZone3", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "AvatarAxisDeadZone4", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "AvatarAxisDeadZone5", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "BuildAxisScale0", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "BuildAxisScale1", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "BuildAxisScale2", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "BuildAxisScale3", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "BuildAxisScale4", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "BuildAxisScale5", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "BuildAxisDeadZone0", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "BuildAxisDeadZone1", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "BuildAxisDeadZone2", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "BuildAxisDeadZone3", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "BuildAxisDeadZone4", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "BuildAxisDeadZone5", handleJoystickChanged); + setting_setup_signal_listener(gSavedSettings, "DebugViews", handleDebugViewsChanged); + setting_setup_signal_listener(gSavedSettings, "UserLogFile", handleLogFileChanged); + setting_setup_signal_listener(gSavedSettings, "RenderHideGroupTitle", handleHideGroupTitleChanged); + setting_setup_signal_listener(gSavedSettings, "HighResSnapshot", handleHighResSnapshotChanged); + setting_setup_signal_listener(gSavedSettings, "EnableVoiceChat", handleVoiceClientPrefsChanged); + setting_setup_signal_listener(gSavedSettings, "PTTCurrentlyEnabled", handleVoiceClientPrefsChanged); + setting_setup_signal_listener(gSavedSettings, "PushToTalkButton", handleVoiceClientPrefsChanged); + setting_setup_signal_listener(gSavedSettings, "PushToTalkToggle", handleVoiceClientPrefsChanged); + setting_setup_signal_listener(gSavedSettings, "VoiceEarLocation", handleVoiceClientPrefsChanged); + setting_setup_signal_listener(gSavedSettings, "VoiceInputAudioDevice", handleVoiceClientPrefsChanged); + setting_setup_signal_listener(gSavedSettings, "VoiceOutputAudioDevice", handleVoiceClientPrefsChanged); + setting_setup_signal_listener(gSavedSettings, "AudioLevelMic", handleVoiceClientPrefsChanged); + setting_setup_signal_listener(gSavedSettings, "LipSyncEnabled", handleVoiceClientPrefsChanged); + setting_setup_signal_listener(gSavedSettings, "VelocityInterpolate", handleVelocityInterpolate); + setting_setup_signal_listener(gSavedSettings, "QAMode", show_debug_menus); + setting_setup_signal_listener(gSavedSettings, "UseDebugMenus", show_debug_menus); + setting_setup_signal_listener(gSavedSettings, "AgentPause", toggle_agent_pause); + setting_setup_signal_listener(gSavedSettings, "ShowNavbarNavigationPanel", toggle_show_navigation_panel); + setting_setup_signal_listener(gSavedSettings, "ShowMiniLocationPanel", toggle_show_mini_location_panel); + setting_setup_signal_listener(gSavedSettings, "ShowObjectRenderingCost", toggle_show_object_render_cost); + setting_setup_signal_listener(gSavedSettings, "ForceShowGrid", handleForceShowGrid); + setting_setup_signal_listener(gSavedSettings, "RenderTransparentWater", handleRenderTransparentWaterChanged); + setting_setup_signal_listener(gSavedSettings, "SpellCheck", handleSpellCheckChanged); + setting_setup_signal_listener(gSavedSettings, "SpellCheckDictionary", handleSpellCheckChanged); + setting_setup_signal_listener(gSavedSettings, "LoginLocation", handleLoginLocationChanged); + setting_setup_signal_listener(gSavedSettings, "DebugAvatarJoints", handleDebugAvatarJointsChanged); + setting_setup_signal_listener(gSavedSettings, "RenderAutoMuteByteLimit", handleRenderAutoMuteByteLimitChanged); + + setting_setup_signal_listener(gSavedSettings, "TargetFPS", handleTargetFPSChanged); + setting_setup_signal_listener(gSavedSettings, "AutoTuneFPS", handleAutoTuneFPSChanged); + setting_setup_signal_listener(gSavedSettings, "AutoTuneLock", handleAutoTuneLockChanged); + setting_setup_signal_listener(gSavedSettings, "RenderAvatarMaxART", handleRenderAvatarMaxARTChanged); + setting_setup_signal_listener(gSavedSettings, "PerfStatsCaptureEnabled", handlePerformanceStatsEnabledChanged); + setting_setup_signal_listener(gSavedSettings, "AutoTuneRenderFarClipTarget", handleUserTargetDrawDistanceChanged); + setting_setup_signal_listener(gSavedSettings, "AutoTuneImpostorFarAwayDistance", handleUserImpostorDistanceChanged); + setting_setup_signal_listener(gSavedSettings, "AutoTuneImpostorByDistEnabled", handleUserImpostorByDistEnabledChanged); + setting_setup_signal_listener(gSavedSettings, "TuningFPSStrategy", handleFPSTuningStrategyChanged); setting_setup_signal_listener(gSavedPerAccountSettings, "AvatarHoverOffsetZ", handleAvatarHoverOffsetChanged); } diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 1730b02017..a2938eaefe 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -79,6 +79,7 @@ #include "llscenemonitor.h" #include "llenvironment.h" +#include "llperfstats.h" extern LLPointer<LLViewerTexture> gStartTexture; extern bool gShiftFrame; @@ -243,6 +244,7 @@ void display_stats() // Paint the display! void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot) { + LLPerfStats::RecordSceneTime T (LLPerfStats::StatType_t::RENDER_DISPLAY); // render time capture - This is the main stat for overall rendering. LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Render"); if (gWindowResized) @@ -1090,7 +1092,8 @@ void display_cube_face() void render_hud_attachments() { - gGL.matrixMode(LLRender::MM_PROJECTION); + LLPerfStats::RecordSceneTime T ( LLPerfStats::StatType_t::RENDER_HUDS); // render time capture - Primary contributor to HUDs (though these end up in render batches) + gGL.matrixMode(LLRender::MM_PROJECTION); gGL.pushMatrix(); gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.pushMatrix(); @@ -1289,7 +1292,8 @@ bool setup_hud_matrices(const LLRect& screen_region) void render_ui(F32 zoom_factor, int subfield) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI); + LLPerfStats::RecordSceneTime T ( LLPerfStats::StatType_t::RENDER_UI ); // render time capture - Primary UI stat can have HUD time overlap (TODO) + LL_PROFILE_ZONE_SCOPED_CATEGORY_UI; //LL_RECORD_BLOCK_TIME(FTM_RENDER_UI); LL_PROFILE_GPU_ZONE("ui"); LLGLState::checkStates(); @@ -1368,6 +1372,7 @@ void render_ui(F32 zoom_factor, int subfield) void swap() { + LLPerfStats::RecordSceneTime T ( LLPerfStats::StatType_t::RENDER_SWAP ); // render time capture - Swap buffer time - can signify excessive data transfer to/from GPU LL_PROFILE_ZONE_NAMED_CATEGORY_DISPLAY("Swap"); LL_PROFILE_GPU_ZONE("swap"); if (gDisplaySwapBuffers) diff --git a/indra/newview/llviewerfloaterreg.cpp b/indra/newview/llviewerfloaterreg.cpp index 14d5a7c276..ca87ff0092 100644 --- a/indra/newview/llviewerfloaterreg.cpp +++ b/indra/newview/llviewerfloaterreg.cpp @@ -108,9 +108,11 @@ #include "llfloaterpathfindingconsole.h" #include "llfloaterpathfindinglinksets.h" #include "llfloaterpay.h" +#include "llfloaterperformance.h" #include "llfloaterperms.h" #include "llfloaterpostprocess.h" #include "llfloaterpreference.h" +#include "llfloaterpreferencesgraphicsadvanced.h" #include "llfloaterpreferenceviewadvanced.h" #include "llfloaterpreviewtrash.h" #include "llfloaterprofile.h" @@ -408,6 +410,7 @@ void LLViewerFloaterReg::registerFloaters() LLFloaterReg::add("pathfinding_linksets", "floater_pathfinding_linksets.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingLinksets>); LLFloaterReg::add("pathfinding_console", "floater_pathfinding_console.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPathfindingConsole>); LLFloaterReg::add("people", "floater_people.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); + LLFloaterReg::add("performance", "floater_performance.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPerformance>); LLFloaterReg::add("perms_default", "floater_perms_default.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPermsDefault>); LLFloaterReg::add("places", "floater_places.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterSidePanelContainer>); LLFloaterReg::add("preferences", "floater_preferences.xml", (LLFloaterBuildFunc)&LLFloaterReg::build<LLFloaterPreference>); diff --git a/indra/newview/llviewerjointmesh.cpp b/indra/newview/llviewerjointmesh.cpp index be2a1da968..5ce8f4023d 100644 --- a/indra/newview/llviewerjointmesh.cpp +++ b/indra/newview/llviewerjointmesh.cpp @@ -55,6 +55,7 @@ #include "m3math.h" #include "m4math.h" #include "llmatrix4a.h" +#include "llperfstats.h" #if !LL_DARWIN && !LL_LINUX extern PFNGLWEIGHTPOINTERARBPROC glWeightPointerARB; diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index 25efe189cb..d22ffc784a 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -3281,6 +3281,8 @@ class LLAvatarCheckImpostorMode : public view_listener_t return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_DO_NOT_RENDER); case 2: return (avatar->getVisualMuteSettings() == LLVOAvatar::AV_ALWAYS_RENDER); + case 4: + return (avatar->getVisualMuteSettings() != LLVOAvatar::AV_RENDER_NORMALLY); default: return false; } diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 100c73377f..77b4804076 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -369,7 +369,7 @@ LLViewerObject::~LLViewerObject() } // Delete memory associated with extra parameters. - std::map<U16, ExtraParameter*>::iterator iter; + std::unordered_map<U16, ExtraParameter*>::iterator iter; for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) { if(iter->second != NULL) @@ -1555,7 +1555,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, unpackParticleSource(block_num, owner_id); // Mark all extra parameters not used - std::map<U16, ExtraParameter*>::iterator iter; + std::unordered_map<U16, ExtraParameter*>::iterator iter; for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) { iter->second->in_use = FALSE; @@ -1947,7 +1947,7 @@ U32 LLViewerObject::processUpdateMessage(LLMessageSystem *mesgsys, } // Mark all extra parameters not used - std::map<U16, ExtraParameter*>::iterator iter; + std::unordered_map<U16, ExtraParameter*>::iterator iter; for (iter = mExtraParameterList.begin(); iter != mExtraParameterList.end(); ++iter) { iter->second->in_use = FALSE; @@ -3965,6 +3965,7 @@ U32 LLViewerObject::recursiveGetTriangleCount(S32* vcount) const // prim's scale. Should revisit at some point. F32 LLViewerObject::recursiveGetScaledSurfaceArea() const { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; F32 area = 0.f; const LLDrawable* drawable = mDrawable; if (drawable) @@ -5689,7 +5690,7 @@ S32 LLViewerObject::countInventoryContents(LLAssetType::EType type) return count; } -void LLViewerObject::setDebugText(const std::string &utf8text) +void LLViewerObject::setDebugText(const std::string &utf8text, const LLColor4& color) { if (utf8text.empty() && !mText) { @@ -5700,7 +5701,7 @@ void LLViewerObject::setDebugText(const std::string &utf8text) { initHudText(); } - mText->setColor(LLColor4::white); + mText->setColor(color); mText->setString(utf8text); mText->setZCompare(FALSE); mText->setDoFade(FALSE); @@ -6241,7 +6242,8 @@ LLViewerObject::ExtraParameter* LLViewerObject::createNewParameterEntry(U16 para LLViewerObject::ExtraParameter* LLViewerObject::getExtraParameterEntry(U16 param_type) const { - std::map<U16, ExtraParameter*>::const_iterator itor = mExtraParameterList.find(param_type); + LL_PROFILE_ZONE_SCOPED_CATEGORY_VIEWER; + std::unordered_map<U16, ExtraParameter*>::const_iterator itor = mExtraParameterList.find(param_type); if (itor != mExtraParameterList.end()) { return itor->second; diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h index e647fdd045..a18d07d970 100644 --- a/indra/newview/llviewerobject.h +++ b/indra/newview/llviewerobject.h @@ -28,6 +28,7 @@ #define LL_LLVIEWEROBJECT_H #include <map> +#include <unordered_map> #include "llassetstorage.h" //#include "llhudicon.h" @@ -122,7 +123,7 @@ protected: BOOL in_use; LLNetworkData *data; }; - std::map<U16, ExtraParameter*> mExtraParameterList; + std::unordered_map<U16, ExtraParameter*> mExtraParameterList; public: typedef std::list<LLPointer<LLViewerObject> > child_list_t; @@ -441,7 +442,7 @@ public: void sendMaterialUpdate() const; - void setDebugText(const std::string &utf8text); + void setDebugText(const std::string &utf8text, const LLColor4& color = LLColor4::white); void appendDebugText(const std::string &utf8text); void initHudText(); void restoreHudText(); @@ -941,6 +942,10 @@ public: // reflection probe state bool mIsReflectionProbe = false; // if true, this object should register itself with LLReflectionProbeManager LLPointer<LLReflectionMap> mReflectionProbe = nullptr; // reflection probe coupled to this viewer object. If not null, should be deregistered when this object is destroyed + + // the amount of GPU time (in ms) it took to render this object according to LLPipeline::profileAvatar + // -1.f if no profile data available + F32 mGPURenderTime = -1.f; }; /////////////////// diff --git a/indra/newview/llviewerpartsim.cpp b/indra/newview/llviewerpartsim.cpp index e5265f1dcd..449fd4ba43 100644 --- a/indra/newview/llviewerpartsim.cpp +++ b/indra/newview/llviewerpartsim.cpp @@ -716,7 +716,7 @@ void LLViewerPartSim::updateSimulation() if (upd && vobj && (vobj->getPCode() == LL_PCODE_VOLUME)) { - if(vobj->getAvatar() && vobj->getAvatar()->isTooComplex()) + if(vobj->getAvatar() && vobj->getAvatar()->isTooComplex() && vobj->getAvatar()->isTooSlow()) { upd = FALSE; } diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index 63cc7ba623..4ceef07e72 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -188,6 +188,8 @@ LLGLSLShader gDeferredPostProgram; LLGLSLShader gDeferredCoFProgram; LLGLSLShader gDeferredDoFCombineProgram; LLGLSLShader gDeferredPostGammaCorrectProgram; +LLGLSLShader gNoPostGammaCorrectProgram; +LLGLSLShader gLegacyPostGammaCorrectProgram; LLGLSLShader gExposureProgram; LLGLSLShader gLuminanceProgram; LLGLSLShader gFXAAProgram; @@ -295,6 +297,8 @@ LLViewerShaderMgr::LLViewerShaderMgr() : mShaderList.push_back(&gHUDPBRAlphaProgram); mShaderList.push_back(&gDeferredSkinnedPBRAlphaProgram); mShaderList.push_back(&gDeferredPostGammaCorrectProgram); // for gamma + mShaderList.push_back(&gNoPostGammaCorrectProgram); + mShaderList.push_back(&gLegacyPostGammaCorrectProgram); } @@ -1010,6 +1014,8 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gExposureProgram.unload(); gLuminanceProgram.unload(); gDeferredPostGammaCorrectProgram.unload(); + gNoPostGammaCorrectProgram.unload(); + gLegacyPostGammaCorrectProgram.unload(); gFXAAProgram.unload(); gDeferredWLSkyProgram.unload(); gDeferredWLCloudProgram.unload(); @@ -2338,11 +2344,10 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() gDeferredShadowGLTFAlphaMaskProgram.mName = "Deferred GLTF Shadow Alpha Mask Shader"; gDeferredShadowGLTFAlphaMaskProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels; gDeferredShadowGLTFAlphaMaskProgram.mShaderFiles.clear(); - gDeferredShadowGLTFAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/shadowAlphaMaskV.glsl", GL_VERTEX_SHADER)); - gDeferredShadowGLTFAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/shadowAlphaMaskF.glsl", GL_FRAGMENT_SHADER)); + gDeferredShadowGLTFAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/pbrShadowAlphaMaskV.glsl", GL_VERTEX_SHADER)); + gDeferredShadowGLTFAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/pbrShadowAlphaMaskF.glsl", GL_FRAGMENT_SHADER)); gDeferredShadowGLTFAlphaMaskProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; gDeferredShadowGLTFAlphaMaskProgram.clearPermutations(); - gDeferredShadowGLTFAlphaMaskProgram.addPermutation("GLTF", "1"); success = make_rigged_variant(gDeferredShadowGLTFAlphaMaskProgram, gDeferredSkinnedShadowGLTFAlphaMaskProgram); success = success && gDeferredShadowGLTFAlphaMaskProgram.createShader(NULL, NULL); llassert(success); @@ -2537,6 +2542,37 @@ BOOL LLViewerShaderMgr::loadShadersDeferred() success = gDeferredPostGammaCorrectProgram.createShader(NULL, NULL); llassert(success); } + + if (success) + { + gNoPostGammaCorrectProgram.mName = "No Post Gamma Correction Post Process"; + gNoPostGammaCorrectProgram.mFeatures.hasSrgb = true; + gNoPostGammaCorrectProgram.mFeatures.isDeferred = true; + gNoPostGammaCorrectProgram.mShaderFiles.clear(); + gNoPostGammaCorrectProgram.clearPermutations(); + gNoPostGammaCorrectProgram.addPermutation("NO_POST", "1"); + gNoPostGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER)); + gNoPostGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredGammaCorrect.glsl", GL_FRAGMENT_SHADER)); + gNoPostGammaCorrectProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + success = gNoPostGammaCorrectProgram.createShader(NULL, NULL); + llassert(success); + } + + if (success) + { + gLegacyPostGammaCorrectProgram.mName = "Legacy Gamma Correction Post Process"; + gLegacyPostGammaCorrectProgram.mFeatures.hasSrgb = true; + gLegacyPostGammaCorrectProgram.mFeatures.isDeferred = true; + gLegacyPostGammaCorrectProgram.mShaderFiles.clear(); + gLegacyPostGammaCorrectProgram.clearPermutations(); + gLegacyPostGammaCorrectProgram.addPermutation("LEGACY_GAMMA", "1"); + gLegacyPostGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER)); + gLegacyPostGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredGammaCorrect.glsl", GL_FRAGMENT_SHADER)); + gLegacyPostGammaCorrectProgram.mShaderLevel = mShaderLevel[SHADER_DEFERRED]; + success = gLegacyPostGammaCorrectProgram.createShader(NULL, NULL); + llassert(success); + } + if (success && gGLManager.mGLVersion > 3.9f) { diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index 129802aca5..492e60b840 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -235,6 +235,8 @@ extern LLGLSLShader gDeferredDoFCombineProgram; extern LLGLSLShader gFXAAProgram; extern LLGLSLShader gDeferredPostNoDoFProgram; extern LLGLSLShader gDeferredPostGammaCorrectProgram; +extern LLGLSLShader gNoPostGammaCorrectProgram; +extern LLGLSLShader gLegacyPostGammaCorrectProgram; extern LLGLSLShader gExposureProgram; extern LLGLSLShader gLuminanceProgram; extern LLGLSLShader gDeferredAvatarShadowProgram; diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp index 986319f26d..37999e58ff 100644 --- a/indra/newview/llviewerstats.cpp +++ b/indra/newview/llviewerstats.cpp @@ -58,6 +58,7 @@ #include "llfeaturemanager.h" #include "llviewernetwork.h" #include "llmeshrepository.h" //for LLMeshRepository::sBytesReceived +#include "llperfstats.h" #include "llsdserialize.h" #include "llsdutil.h" #include "llcorehttputil.h" @@ -254,6 +255,13 @@ LLTrace::EventStatHandle<F64Seconds > AVATAR_EDIT_TIME("avataredittime", "Second LLTrace::EventStatHandle<LLUnit<F32, LLUnits::Percent> > OBJECT_CACHE_HIT_RATE("object_cache_hits"); LLTrace::EventStatHandle<F64Seconds > TEXTURE_FETCH_TIME("texture_fetch_time"); + +LLTrace::SampleStatHandle<LLUnit<F32, LLUnits::Percent> > SCENERY_FRAME_PCT("scenery_frame_pct"); +LLTrace::SampleStatHandle<LLUnit<F32, LLUnits::Percent> > AVATAR_FRAME_PCT("avatar_frame_pct"); +LLTrace::SampleStatHandle<LLUnit<F32, LLUnits::Percent> > HUDS_FRAME_PCT("huds_frame_pct"); +LLTrace::SampleStatHandle<LLUnit<F32, LLUnits::Percent> > UI_FRAME_PCT("ui_frame_pct"); +LLTrace::SampleStatHandle<LLUnit<F32, LLUnits::Percent> > SWAP_FRAME_PCT("swap_frame_pct"); +LLTrace::SampleStatHandle<LLUnit<F32, LLUnits::Percent> > IDLE_FRAME_PCT("idle_frame_pct"); } LLViewerStats::LLViewerStats() @@ -452,6 +460,89 @@ void update_statistics() texture_stats_timer.reset(); } } + + if (LLFloaterReg::instanceVisible("scene_load_stats")) + { + static const F32 perf_stats_freq = 1; + static LLFrameTimer perf_stats_timer; + if (perf_stats_timer.getElapsedTimeF32() >= perf_stats_freq) + { + LLStringUtil::format_map_t args; + LLPerfStats::bufferToggleLock.lock(); // prevent toggle for a moment + + auto tot_frame_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_FRAME); + // cumulative avatar time (includes idle processing, attachments and base av) + auto tot_avatar_time_raw = LLPerfStats::us_to_raw(LLVOAvatar::getTotalGPURenderTime()); + // cumulative avatar render specific time (a bit arbitrary as the processing is too.) + // auto tot_av_idle_time_raw = LLPerfStats::StatsRecorder::getSum(AvType, LLPerfStats::StatType_t::RENDER_IDLE); + // auto tot_avatar_render_time_raw = tot_avatar_time_raw - tot_av_idle_time_raw; + // the time spent this frame on the "display()" call. Treated as "tot time rendering" + auto tot_render_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_DISPLAY); + // sleep time is basically forced sleep when window out of focus + auto tot_sleep_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_SLEEP); + // time spent on UI + auto tot_ui_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_UI); + // cumulative time spent rendering HUDS + auto tot_huds_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_HUDS); + // "idle" time. This is the time spent in the idle poll section of the main loop + auto tot_idle_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_IDLE); + // similar to sleep time, induced by FPS limit + //auto tot_limit_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_FPSLIMIT); + // swap time is time spent in swap buffer + auto tot_swap_time_raw = LLPerfStats::StatsRecorder::getSceneStat(LLPerfStats::StatType_t::RENDER_SWAP); + + LLPerfStats::bufferToggleLock.unlock(); + + auto tot_frame_time_ns = LLPerfStats::raw_to_ns(tot_frame_time_raw); + auto tot_avatar_time_ns = LLPerfStats::raw_to_ns(tot_avatar_time_raw); + auto tot_huds_time_ns = LLPerfStats::raw_to_ns(tot_huds_time_raw); + // UI time includes HUD time so dedut that before we calc percentages + auto tot_ui_time_ns = LLPerfStats::raw_to_ns(tot_ui_time_raw - tot_huds_time_raw); + + // auto tot_sleep_time_ns = LLPerfStats::raw_to_ns( tot_sleep_time_raw ); + // auto tot_limit_time_ns = LLPerfStats::raw_to_ns( tot_limit_time_raw ); + + // auto tot_render_time_ns = LLPerfStats::raw_to_ns( tot_render_time_raw ); + auto tot_idle_time_ns = LLPerfStats::raw_to_ns(tot_idle_time_raw); + auto tot_swap_time_ns = LLPerfStats::raw_to_ns(tot_swap_time_raw); + auto tot_scene_time_ns = LLPerfStats::raw_to_ns(tot_render_time_raw - tot_avatar_time_raw - tot_swap_time_raw - tot_ui_time_raw); + // auto tot_overhead_time_ns = LLPerfStats::raw_to_ns( tot_frame_time_raw - tot_render_time_raw - tot_idle_time_raw ); + + // // remove time spent sleeping for fps limit or out of focus. + // tot_frame_time_ns -= tot_limit_time_ns; + // tot_frame_time_ns -= tot_sleep_time_ns; + + if (tot_frame_time_ns != 0) + { + auto pct_avatar_time = (tot_avatar_time_ns * 100) / tot_frame_time_ns; + auto pct_huds_time = (tot_huds_time_ns * 100) / tot_frame_time_ns; + auto pct_ui_time = (tot_ui_time_ns * 100) / tot_frame_time_ns; + auto pct_idle_time = (tot_idle_time_ns * 100) / tot_frame_time_ns; + auto pct_swap_time = (tot_swap_time_ns * 100) / tot_frame_time_ns; + auto pct_scene_render_time = (tot_scene_time_ns * 100) / tot_frame_time_ns; + pct_avatar_time = llclamp(pct_avatar_time, 0., 100.); + pct_huds_time = llclamp(pct_huds_time, 0., 100.); + pct_ui_time = llclamp(pct_ui_time, 0., 100.); + pct_idle_time = llclamp(pct_idle_time, 0., 100.); + pct_swap_time = llclamp(pct_swap_time, 0., 100.); + pct_scene_render_time = llclamp(pct_scene_render_time, 0., 100.); + if (tot_sleep_time_raw == 0) + { + sample(LLStatViewer::SCENERY_FRAME_PCT, (U32)llround(pct_scene_render_time)); + sample(LLStatViewer::AVATAR_FRAME_PCT, (U32)llround(pct_avatar_time)); + sample(LLStatViewer::HUDS_FRAME_PCT, (U32)llround(pct_huds_time)); + sample(LLStatViewer::UI_FRAME_PCT, (U32)llround(pct_ui_time)); + sample(LLStatViewer::SWAP_FRAME_PCT, (U32)llround(pct_swap_time)); + sample(LLStatViewer::IDLE_FRAME_PCT, (U32)llround(pct_idle_time)); + } + } + else + { + LL_WARNS("performance") << "Scene time 0. Skipping til we have data." << LL_ENDL; + } + perf_stats_timer.reset(); + } + } } /* @@ -551,6 +642,7 @@ void send_viewer_stats(bool include_preferences) system["gpu"] = gpu_desc; system["gpu_class"] = (S32)LLFeatureManager::getInstance()->getGPUClass(); + system["gpu_memory_bandwidth"] = LLFeatureManager::getInstance()->getGPUMemoryBandwidth(); system["gpu_vendor"] = gGLManager.mGLVendorShort; system["gpu_version"] = gGLManager.mDriverVersionVendorString; system["opengl_version"] = gGLManager.mGLVersionString; @@ -737,12 +829,11 @@ void send_viewer_stats(bool include_preferences) LL_INFOS("LogViewerStatsPacket") << "Sending viewer statistics: " << body << LL_ENDL; - if (debugLoggingEnabled("LogViewerStatsPacket")) - { - std::string filename("viewer_stats_packet.xml"); - llofstream of(filename.c_str()); - LLSDSerialize::toPrettyXML(body,of); - } + LL_DEBUGS("LogViewerStatsPacket"); + std::string filename("viewer_stats_packet.xml"); + llofstream of(filename.c_str()); + LLSDSerialize::toPrettyXML(body,of); + LL_ENDL; // The session ID token must never appear in logs body["session_id"] = gAgentSessionID; diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 5adb3f9ede..af65588709 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -113,6 +113,8 @@ #include "llrendersphere.h" #include "llskinningutil.h" +#include "llperfstats.h" + #include <boost/lexical_cast.hpp> extern F32 SPEED_ADJUST_MAX; @@ -205,6 +207,8 @@ const F64 HUD_OVERSIZED_TEXTURE_DATA_SIZE = 1024 * 1024; const F32 MAX_TEXTURE_WAIT_TIME_SEC = 60; +const S32 MIN_NONTUNED_AVS = 5; + enum ERenderName { RENDER_NAME_NEVER, @@ -616,6 +620,8 @@ F32 LLVOAvatar::sUnbakedUpdateTime = 0.f; F32 LLVOAvatar::sGreyTime = 0.f; F32 LLVOAvatar::sGreyUpdateTime = 0.f; LLPointer<LLViewerTexture> LLVOAvatar::sCloudTexture = NULL; +std::vector<LLUUID> LLVOAvatar::sAVsIgnoringARTLimit; +S32 LLVOAvatar::sAvatarsNearby = 0; //----------------------------------------------------------------------------- // Helper functions @@ -814,6 +820,14 @@ LLVOAvatar::~LLVOAvatar() debugAvatarRezTime("AvatarRezLeftNotification","left sometime after declouding"); } + if(mTuned) + { + LLPerfStats::tunedAvatars--; + mTuned = false; + } + sAVsIgnoringARTLimit.erase(std::remove(sAVsIgnoringARTLimit.begin(), sAVsIgnoringARTLimit.end(), mID), sAVsIgnoringARTLimit.end()); + + logPendingPhases(); LL_DEBUGS("Avatar") << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << LL_ENDL; @@ -1434,7 +1448,7 @@ void LLVOAvatar::calculateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax) continue; } } - if (vol && vol->isRiggedMesh()) + if (vol && vol->isRiggedMeshFast()) { continue; } @@ -2547,11 +2561,17 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) LL_INFOS() << "Warning! Idle on dead avatar" << LL_ENDL; return; } + // record time and refresh "tooSlow" status + updateTooSlow(); static LLCachedControl<bool> disable_all_render_types(gSavedSettings, "DisableAllRenderTypes"); if (!(gPipeline.hasRenderType(mIsControlAvatar ? LLPipeline::RENDER_TYPE_CONTROL_AV : LLPipeline::RENDER_TYPE_AVATAR)) && !disable_all_render_types && !isSelf()) { + if (!mIsControlAvatar) + { + idleUpdateNameTag( mLastRootPos ); + } return; } @@ -2676,6 +2696,10 @@ void LLVOAvatar::idleUpdate(LLAgent &agent, const F64 &time) if ((LLFrameTimer::getFrameCount() + mID.mData[0]) % compl_upd_freq == 0) { + // DEPRECATED + // replace with LLPipeline::profileAvatar? + // Avatar profile takes ~ 0.5ms while idleUpdateRenderComplexity takes ~5ms + // (both are unacceptably costly) idleUpdateRenderComplexity(); } idleUpdateDebugInfo(); @@ -3131,7 +3155,7 @@ void LLVOAvatar::idleUpdateLoadingEffect() LLPartData::LL_PART_TARGET_POS_MASK ); // do not generate particles for dummy or overly-complex avatars - if (!mIsDummy && !isTooComplex()) + if (!mIsDummy && !isTooComplex() && !isTooSlow()) { setParticleSource(particle_parameters, getID()); } @@ -3216,11 +3240,9 @@ void LLVOAvatar::idleUpdateNameTag(const LLVector3& root_pos_last) static LLCachedControl<F32> FADE_DURATION(gSavedSettings, "RenderNameFadeDuration"); // seconds static LLCachedControl<bool> use_chat_bubbles(gSavedSettings, "UseChatBubbles"); - bool visible_avatar = isVisible() || mNeedsAnimUpdate; bool visible_chat = use_chat_bubbles && (mChats.size() || mTyping); bool render_name = visible_chat || - (visible_avatar && - ((sRenderName == RENDER_NAME_ALWAYS) || + (((sRenderName == RENDER_NAME_ALWAYS) || (sRenderName == RENDER_NAME_FADE && time_visible < NAME_SHOW_TIME))); // If it's your own avatar, don't draw in mouselook, and don't // draw if we're specifically hiding our own name. @@ -3715,7 +3737,7 @@ bool LLVOAvatar::isVisuallyMuted() } else { - muted = isTooComplex(); + muted = isTooComplex() || isTooSlow(); } } @@ -8275,6 +8297,86 @@ bool LLVOAvatar::isTooComplex() const return too_complex; } +bool LLVOAvatar::isTooSlow() const +{ + static LLCachedControl<bool> always_render_friends(gSavedSettings, "AlwaysRenderFriends"); + bool render_friend = (LLAvatarTracker::instance().isBuddy(getID()) && always_render_friends); + + if (render_friend || mVisuallyMuteSetting == AV_ALWAYS_RENDER) + { + return false; + } + return mTooSlow; +} + +// Udpate Avatar state based on render time +void LLVOAvatar::updateTooSlow() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + static LLCachedControl<bool> alwaysRenderFriends(gSavedSettings, "AlwaysRenderFriends"); + static LLCachedControl<bool> allowSelfImpostor(gSavedSettings, "AllowSelfImpostor"); + const auto id = getID(); + + // mTooSlow - Is the avatar flagged as being slow (includes shadow time) + // mTooSlowWithoutShadows - Is the avatar flagged as being slow even with shadows removed. + + // get max render time in ms + F32 max_art_ms = (F32) (LLPerfStats::renderAvatarMaxART_ns / 1000000.0); + + bool autotune = LLPerfStats::tunables.userAutoTuneEnabled && !mIsControlAvatar && !isSelf(); + + bool ignore_tune = false; + if (autotune && sAVsIgnoringARTLimit.size() > 0) + { + auto it = std::find(sAVsIgnoringARTLimit.begin(), sAVsIgnoringARTLimit.end(), mID); + if (it != sAVsIgnoringARTLimit.end()) + { + S32 index = it - sAVsIgnoringARTLimit.begin(); + ignore_tune = (index < (MIN_NONTUNED_AVS - sAvatarsNearby + 1 + LLPerfStats::tunedAvatars)); + } + } + + bool exceeds_max_ART = + ((LLPerfStats::renderAvatarMaxART_ns > 0) && + (mGPURenderTime >= max_art_ms)); // NOTE: don't use getGPURenderTime accessor here to avoid "isTooSlow" feedback loop + + if (exceeds_max_ART && !ignore_tune) + { + mTooSlow = true; + + if(!mTooSlowWithoutShadows) // if we were not previously above the full impostor cap + { + bool render_friend_or_exception = ( alwaysRenderFriends && LLAvatarTracker::instance().isBuddy( id ) ) || + ( getVisualMuteSettings() == LLVOAvatar::AV_ALWAYS_RENDER ); + if( (!isSelf() || allowSelfImpostor) && !render_friend_or_exception ) + { + // Note: slow rendering Friends still get their shadows zapped. + mTooSlowWithoutShadows = getGPURenderTime()*2.f >= max_art_ms; // NOTE: assumes shadow rendering doubles render time + } + } + } + else + { + mTooSlow = false; + mTooSlowWithoutShadows = false; + + if (ignore_tune) + { + return; + } + } + if(mTooSlow && !mTuned) + { + LLPerfStats::tunedAvatars++; // increment the number of avatars that have been tweaked. + mTuned = true; + } + else if(!mTooSlow && mTuned) + { + LLPerfStats::tunedAvatars--; + mTuned = false; + } +} + //----------------------------------------------------------------------------- // findMotion() //----------------------------------------------------------------------------- @@ -10536,6 +10638,64 @@ void LLVOAvatar::idleUpdateRenderComplexity() // Render Complexity calculateUpdateRenderComplexity(); // Update mVisualComplexity if needed + + bool autotune = LLPerfStats::tunables.userAutoTuneEnabled && !mIsControlAvatar && !isSelf(); + if (autotune && !isDead()) + { + static LLCachedControl<F32> render_far_clip(gSavedSettings, "RenderFarClip", 64); + F32 radius = render_far_clip * render_far_clip; + + bool is_nearby = true; + if ((dist_vec_squared(getPositionGlobal(), gAgent.getPositionGlobal()) > radius) && + (dist_vec_squared(getPositionGlobal(), gAgentCamera.getCameraPositionGlobal()) > radius)) + { + is_nearby = false; + } + + if (is_nearby && (sAVsIgnoringARTLimit.size() < MIN_NONTUNED_AVS)) + { + if (std::count(sAVsIgnoringARTLimit.begin(), sAVsIgnoringARTLimit.end(), mID) == 0) + { + sAVsIgnoringARTLimit.push_back(mID); + } + } + else if (!is_nearby) + { + sAVsIgnoringARTLimit.erase(std::remove(sAVsIgnoringARTLimit.begin(), sAVsIgnoringARTLimit.end(), mID), + sAVsIgnoringARTLimit.end()); + } + updateNearbyAvatarCount(); + } +} + +void LLVOAvatar::updateNearbyAvatarCount() +{ + static LLFrameTimer agent_update_timer; + + if (agent_update_timer.getElapsedTimeF32() > 1.0f) + { + S32 avs_nearby = 0; + static LLCachedControl<F32> render_far_clip(gSavedSettings, "RenderFarClip", 64); + F32 radius = render_far_clip * render_far_clip; + std::vector<LLCharacter *>::iterator char_iter = LLCharacter::sInstances.begin(); + while (char_iter != LLCharacter::sInstances.end()) + { + LLVOAvatar *avatar = dynamic_cast<LLVOAvatar *>(*char_iter); + if (avatar && !avatar->isDead() && !avatar->isControlAvatar()) + { + if ((dist_vec_squared(avatar->getPositionGlobal(), gAgent.getPositionGlobal()) > radius) && + (dist_vec_squared(avatar->getPositionGlobal(), gAgentCamera.getCameraPositionGlobal()) > radius)) + { + char_iter++; + continue; + } + avs_nearby++; + } + char_iter++; + } + sAvatarsNearby = avs_nearby; + agent_update_timer.reset(); + } } void LLVOAvatar::idleUpdateDebugInfo() @@ -10626,6 +10786,7 @@ void LLVOAvatar::updateVisualComplexity() mVisualComplexityStale = true; } + // Account for the complexity of a single top-level object associated // with an avatar. This will be either an attached object or an animated // object. @@ -10634,137 +10795,149 @@ void LLVOAvatar::accountRenderComplexityForObject( const F32 max_attachment_complexity, LLVOVolume::texture_cost_t& textures, U32& cost, - hud_complexity_list_t& hud_complexity_list) + hud_complexity_list_t& hud_complexity_list, + object_complexity_list_t& object_complexity_list) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; if (attached_object && !attached_object->isHUDAttachment()) - { + { mAttachmentVisibleTriangleCount += attached_object->recursiveGetTriangleCount(); mAttachmentEstTriangleCount += attached_object->recursiveGetEstTrianglesMax(); mAttachmentSurfaceArea += attached_object->recursiveGetScaledSurfaceArea(); - textures.clear(); - const LLDrawable* drawable = attached_object->mDrawable; - if (drawable) - { - const LLVOVolume* volume = drawable->getVOVolume(); - if (volume) - { - F32 attachment_total_cost = 0; - F32 attachment_volume_cost = 0; - F32 attachment_texture_cost = 0; - F32 attachment_children_cost = 0; + textures.clear(); + const LLDrawable* drawable = attached_object->mDrawable; + if (drawable) + { + const LLVOVolume* volume = drawable->getVOVolume(); + if (volume) + { + F32 attachment_total_cost = 0; + F32 attachment_volume_cost = 0; + F32 attachment_texture_cost = 0; + F32 attachment_children_cost = 0; const F32 animated_object_attachment_surcharge = 1000; - if (attached_object->isAnimatedObject()) + if (volume->isAnimatedObjectFast()) { attachment_volume_cost += animated_object_attachment_surcharge; } - attachment_volume_cost += volume->getRenderCost(textures); + attachment_volume_cost += volume->getRenderCost(textures); - const_child_list_t children = volume->getChildren(); - for (const_child_list_t::const_iterator child_iter = children.begin(); - child_iter != children.end(); - ++child_iter) - { - LLViewerObject* child_obj = *child_iter; - LLVOVolume *child = dynamic_cast<LLVOVolume*>( child_obj ); - if (child) - { - attachment_children_cost += child->getRenderCost(textures); - } - } + const_child_list_t children = volume->getChildren(); + for (const_child_list_t::const_iterator child_iter = children.begin(); + child_iter != children.end(); + ++child_iter) + { + LLViewerObject* child_obj = *child_iter; + LLVOVolume* child = dynamic_cast<LLVOVolume*>(child_obj); + if (child) + { + attachment_children_cost += child->getRenderCost(textures); + } + } - for (LLVOVolume::texture_cost_t::iterator volume_texture = textures.begin(); - volume_texture != textures.end(); - ++volume_texture) - { - // add the cost of each individual texture in the linkset - attachment_texture_cost += volume_texture->second; - } - attachment_total_cost = attachment_volume_cost + attachment_texture_cost + attachment_children_cost; - LL_DEBUGS("ARCdetail") << "Attachment costs " << attached_object->getAttachmentItemID() - << " total: " << attachment_total_cost - << ", volume: " << attachment_volume_cost - << ", " << textures.size() - << " textures: " << attachment_texture_cost - << ", " << volume->numChildren() - << " children: " << attachment_children_cost - << LL_ENDL; - // Limit attachment complexity to avoid signed integer flipping of the wearer's ACI - cost += (U32)llclamp(attachment_total_cost, MIN_ATTACHMENT_COMPLEXITY, max_attachment_complexity); - } - } - } - if (isSelf() - && attached_object - && attached_object->isHUDAttachment() - && !attached_object->isTempAttachment() - && attached_object->mDrawable) + for (LLVOVolume::texture_cost_t::iterator volume_texture = textures.begin(); + volume_texture != textures.end(); + ++volume_texture) { - textures.clear(); - BOOL is_rigged_mesh = attached_object->isRiggedMesh(); + // add the cost of each individual texture in the linkset + attachment_texture_cost += LLVOVolume::getTextureCost(*volume_texture); + } + attachment_total_cost = attachment_volume_cost + attachment_texture_cost + attachment_children_cost; + LL_DEBUGS("ARCdetail") << "Attachment costs " << attached_object->getAttachmentItemID() + << " total: " << attachment_total_cost + << ", volume: " << attachment_volume_cost + << ", " << textures.size() + << " textures: " << attachment_texture_cost + << ", " << volume->numChildren() + << " children: " << attachment_children_cost + << LL_ENDL; + // Limit attachment complexity to avoid signed integer flipping of the wearer's ACI + cost += (U32)llclamp(attachment_total_cost, MIN_ATTACHMENT_COMPLEXITY, max_attachment_complexity); + + if (isSelf()) + { + LLObjectComplexity object_complexity; + object_complexity.objectName = attached_object->getAttachmentItemName(); + object_complexity.objectId = attached_object->getAttachmentItemID(); + object_complexity.objectCost = attachment_total_cost; + object_complexity_list.push_back(object_complexity); + } + } + } + } + if (isSelf() + && attached_object + && attached_object->isHUDAttachment() + && !attached_object->isTempAttachment() + && attached_object->mDrawable) + { + textures.clear(); mAttachmentSurfaceArea += attached_object->recursiveGetScaledSurfaceArea(); - const LLVOVolume* volume = attached_object->mDrawable->getVOVolume(); - if (volume) - { - LLHUDComplexity hud_object_complexity; - hud_object_complexity.objectName = attached_object->getAttachmentItemName(); - hud_object_complexity.objectId = attached_object->getAttachmentItemID(); - std::string joint_name; - gAgentAvatarp->getAttachedPointName(attached_object->getAttachmentItemID(), joint_name); - hud_object_complexity.jointName = joint_name; - // get cost and individual textures - hud_object_complexity.objectsCost += volume->getRenderCost(textures); - hud_object_complexity.objectsCount++; - - LLViewerObject::const_child_list_t& child_list = attached_object->getChildren(); - for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); - iter != child_list.end(); ++iter) - { - LLViewerObject* childp = *iter; - is_rigged_mesh |= childp->isRiggedMesh(); - const LLVOVolume* chld_volume = dynamic_cast<LLVOVolume*>(childp); - if (chld_volume) - { - // get cost and individual textures - hud_object_complexity.objectsCost += chld_volume->getRenderCost(textures); - hud_object_complexity.objectsCount++; - } - } - if (is_rigged_mesh && !attached_object->mRiggedAttachedWarned) - { - LLSD args; - LLViewerInventoryItem* itemp = gInventory.getItem(attached_object->getAttachmentItemID()); - args["NAME"] = itemp ? itemp->getName() : LLTrans::getString("Unknown"); - args["POINT"] = LLTrans::getString(getTargetAttachmentPoint(attached_object)->getName()); - LLNotificationsUtil::add("RiggedMeshAttachedToHUD", args); + const LLVOVolume* volume = attached_object->mDrawable->getVOVolume(); + if (volume) + { + BOOL is_rigged_mesh = volume->isRiggedMeshFast(); + LLHUDComplexity hud_object_complexity; + hud_object_complexity.objectName = attached_object->getAttachmentItemName(); + hud_object_complexity.objectId = attached_object->getAttachmentItemID(); + std::string joint_name; + gAgentAvatarp->getAttachedPointName(attached_object->getAttachmentItemID(), joint_name); + hud_object_complexity.jointName = joint_name; + // get cost and individual textures + hud_object_complexity.objectsCost += volume->getRenderCost(textures); + hud_object_complexity.objectsCount++; + + LLViewerObject::const_child_list_t& child_list = attached_object->getChildren(); + for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin(); + iter != child_list.end(); ++iter) + { + LLViewerObject* childp = *iter; + const LLVOVolume* chld_volume = dynamic_cast<LLVOVolume*>(childp); + if (chld_volume) + { + is_rigged_mesh = is_rigged_mesh || chld_volume->isRiggedMeshFast(); + // get cost and individual textures + hud_object_complexity.objectsCost += chld_volume->getRenderCost(textures); + hud_object_complexity.objectsCount++; + } + } + if (is_rigged_mesh && !attached_object->mRiggedAttachedWarned) + { + LLSD args; + LLViewerInventoryItem* itemp = gInventory.getItem(attached_object->getAttachmentItemID()); + args["NAME"] = itemp ? itemp->getName() : LLTrans::getString("Unknown"); + args["POINT"] = LLTrans::getString(getTargetAttachmentPoint(attached_object)->getName()); + LLNotificationsUtil::add("RiggedMeshAttachedToHUD", args); - attached_object->mRiggedAttachedWarned = true; - } + attached_object->mRiggedAttachedWarned = true; + } - hud_object_complexity.texturesCount += textures.size(); + hud_object_complexity.texturesCount += textures.size(); - for (LLVOVolume::texture_cost_t::iterator volume_texture = textures.begin(); - volume_texture != textures.end(); - ++volume_texture) - { - // add the cost of each individual texture (ignores duplicates) - hud_object_complexity.texturesCost += volume_texture->second; - LLViewerFetchedTexture *tex = LLViewerTextureManager::getFetchedTexture(volume_texture->first); - if (tex) - { - // Note: Texture memory might be incorect since texture might be still loading. - hud_object_complexity.texturesMemoryTotal += tex->getTextureMemory(); - if (tex->getOriginalHeight() * tex->getOriginalWidth() >= HUD_OVERSIZED_TEXTURE_DATA_SIZE) - { - hud_object_complexity.largeTexturesCount++; - } - } - } - hud_complexity_list.push_back(hud_object_complexity); + for (LLVOVolume::texture_cost_t::iterator volume_texture = textures.begin(); + volume_texture != textures.end(); + ++volume_texture) + { + // add the cost of each individual texture (ignores duplicates) + hud_object_complexity.texturesCost += LLVOVolume::getTextureCost(*volume_texture); + const LLViewerTexture* img = *volume_texture; + if (img->getType() == LLViewerTexture::FETCHED_TEXTURE) + { + LLViewerFetchedTexture* tex = (LLViewerFetchedTexture*)img; + // Note: Texture memory might be incorect since texture might be still loading. + hud_object_complexity.texturesMemoryTotal += tex->getTextureMemory(); + if (tex->getOriginalHeight() * tex->getOriginalWidth() >= HUD_OVERSIZED_TEXTURE_DATA_SIZE) + { + hud_object_complexity.largeTexturesCount++; } } + } + hud_complexity_list.push_back(hud_object_complexity); + } + } } // Calculations for mVisualComplexity value @@ -10776,19 +10949,22 @@ void LLVOAvatar::calculateUpdateRenderComplexity() * everyone. If you have suggested improvements, submit them to * the official viewer for consideration. *****************************************************************/ - static const U32 COMPLEXITY_BODY_PART_COST = 200; - static LLCachedControl<F32> max_complexity_setting(gSavedSettings,"MaxAttachmentComplexity"); - F32 max_attachment_complexity = max_complexity_setting; - max_attachment_complexity = llmax(max_attachment_complexity, DEFAULT_MAX_ATTACHMENT_COMPLEXITY); - - // Diagnostic list of all textures on our avatar - static std::set<LLUUID> all_textures; - if (mVisualComplexityStale) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + + static const U32 COMPLEXITY_BODY_PART_COST = 200; + static LLCachedControl<F32> max_complexity_setting(gSavedSettings, "MaxAttachmentComplexity"); + F32 max_attachment_complexity = max_complexity_setting; + max_attachment_complexity = llmax(max_attachment_complexity, DEFAULT_MAX_ATTACHMENT_COMPLEXITY); + + // Diagnostic list of all textures on our avatar + static std::unordered_set<const LLViewerTexture*> all_textures; + U32 cost = VISUAL_COMPLEXITY_UNKNOWN; LLVOVolume::texture_cost_t textures; hud_complexity_list_t hud_complexity_list; + object_complexity_list_t object_complexity_list; for (U8 baked_index = 0; baked_index < BAKED_NUM_INDICES; baked_index++) { @@ -10832,7 +11008,7 @@ void LLVOAvatar::calculateUpdateRenderComplexity() if (volp && !volp->isAttachment()) { accountRenderComplexityForObject(volp, max_attachment_complexity, - textures, cost, hud_complexity_list); + textures, cost, hud_complexity_list, object_complexity_list); } } @@ -10848,45 +11024,7 @@ void LLVOAvatar::calculateUpdateRenderComplexity() { LLViewerObject* attached_object = attachment_iter->get(); accountRenderComplexityForObject(attached_object, max_attachment_complexity, - textures, cost, hud_complexity_list); - } - } - - // Diagnostic output to identify all avatar-related textures. - // Does not affect rendering cost calculation. - if (isSelf() && debugLoggingEnabled("ARCdetail")) - { - // print any attachment textures we didn't already know about. - for (LLVOVolume::texture_cost_t::iterator it = textures.begin(); it != textures.end(); ++it) - { - LLUUID image_id = it->first; - if( ! (image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR) - && (all_textures.find(image_id) == all_textures.end())) - { - // attachment texture not previously seen. - LL_DEBUGS("ARCdetail") << "attachment_texture: " << image_id.asString() << LL_ENDL; - all_textures.insert(image_id); - } - } - - // print any avatar textures we didn't already know about - for (LLAvatarAppearanceDictionary::Textures::const_iterator iter = LLAvatarAppearance::getDictionary()->getTextures().begin(); - iter != LLAvatarAppearance::getDictionary()->getTextures().end(); - ++iter) - { - const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = iter->second; - // TODO: MULTI-WEARABLE: handle multiple textures for self - const LLViewerTexture* te_image = getImage(iter->first,0); - if (!te_image) - continue; - LLUUID image_id = te_image->getID(); - if( image_id.isNull() || image_id == IMG_DEFAULT || image_id == IMG_DEFAULT_AVATAR) - continue; - if (all_textures.find(image_id) == all_textures.end()) - { - LL_DEBUGS("ARCdetail") << "local_texture: " << texture_dict->mName << ": " << image_id << LL_ENDL; - all_textures.insert(image_id); - } + textures, cost, hud_complexity_list, object_complexity_list); } } @@ -10913,10 +11051,25 @@ void LLVOAvatar::calculateUpdateRenderComplexity() { // Avatar complexity LLAvatarRenderNotifier::getInstance()->updateNotificationAgent(mVisualComplexity); - + LLAvatarRenderNotifier::getInstance()->setObjectComplexityList(object_complexity_list); // HUD complexity LLHUDRenderNotifier::getInstance()->updateNotificationHUD(hud_complexity_list); } + + //schedule an update to ART next frame if needed + if (LLPerfStats::tunables.userAutoTuneEnabled && + LLPerfStats::tunables.userFPSTuningStrategy != LLPerfStats::TUNE_SCENE_ONLY && + !isVisuallyMuted()) + { + LLUUID id = getID(); // <== use id to make sure this avatar didn't get deleted between frames + LL::WorkQueue::getInstance("mainloop")->post([this, id]() + { + if (gObjectList.findObject(id) != nullptr) + { + gPipeline.profileAvatar(this); + } + }); + } } } @@ -11088,7 +11241,7 @@ LLVOAvatar::AvatarOverallAppearance LLVOAvatar::getOverallAppearance() const { // Always want to see this AV as an impostor result = AOA_JELLYDOLL; } - else if (isTooComplex()) + else if (isTooComplex() || isTooSlow()) { result = AOA_JELLYDOLL; } @@ -11115,7 +11268,7 @@ void LLVOAvatar::calcMutedAVColor() new_color = LLColor4::grey4; change_msg = " blocked: color is grey4"; } - else if (!isTooComplex()) + else if (!isTooComplex() && !isTooSlow()) { new_color = LLColor4::white; change_msg = " simple imposter "; @@ -11251,3 +11404,110 @@ BOOL LLVOAvatar::isTextureVisible(LLAvatarAppearanceDefines::ETextureIndex type, // non-self avatars don't have wearables return FALSE; } + +void LLVOAvatar::placeProfileQuery() +{ + if (mGPUTimerQuery == 0) + { + glGenQueries(1, &mGPUTimerQuery); + } + + glBeginQuery(GL_TIME_ELAPSED, mGPUTimerQuery); +} + +void LLVOAvatar::readProfileQuery(S32 retries) +{ + if (!mGPUProfilePending) + { + glEndQuery(GL_TIME_ELAPSED); + mGPUProfilePending = true; + } + + GLuint64 result = 0; + glGetQueryObjectui64v(mGPUTimerQuery, GL_QUERY_RESULT_AVAILABLE, &result); + + if (result == GL_TRUE || --retries <= 0) + { // query available, readback result + GLuint64 time_elapsed = 0; + glGetQueryObjectui64v(mGPUTimerQuery, GL_QUERY_RESULT, &time_elapsed); + mGPURenderTime = time_elapsed / 1000000.f; + mGPUProfilePending = false; + + setDebugText(llformat("%d", (S32)(mGPURenderTime * 1000.f))); + + } + else + { // wait until next frame + LLUUID id = getID(); + + LL::WorkQueue::getInstance("mainloop")->post([id, retries] { + LLVOAvatar* avatar = (LLVOAvatar*) gObjectList.findObject(id); + avatar->readProfileQuery(retries); + }); + } +} + + +F32 LLVOAvatar::getGPURenderTime() +{ + return isVisuallyMuted() ? 0.f : mGPURenderTime; +} + +// static +F32 LLVOAvatar::getTotalGPURenderTime() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + + F32 ret = 0.f; + + for (LLCharacter* iter : LLCharacter::sInstances) + { + LLVOAvatar* inst = (LLVOAvatar*) iter; + ret += inst->getGPURenderTime(); + } + + return ret; +} + +F32 LLVOAvatar::getMaxGPURenderTime() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + + F32 ret = 0.f; + + for (LLCharacter* iter : LLCharacter::sInstances) + { + LLVOAvatar* inst = (LLVOAvatar*)iter; + ret = llmax(inst->getGPURenderTime(), ret); + } + + return ret; +} + +F32 LLVOAvatar::getAverageGPURenderTime() +{ + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; + + F32 ret = 0.f; + + S32 count = 0; + + for (LLCharacter* iter : LLCharacter::sInstances) + { + LLVOAvatar* inst = (LLVOAvatar*)iter; + if (!inst->isTooSlow()) + { + ret += inst->getGPURenderTime(); + ++count; + } + } + + if (count > 0) + { + ret /= count; + } + + return ret; +} + + diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h index 7cc3337243..e8604464ae 100644 --- a/indra/newview/llvoavatar.h +++ b/indra/newview/llvoavatar.h @@ -299,13 +299,39 @@ public: const F32 max_attachment_complexity, LLVOVolume::texture_cost_t& textures, U32& cost, - hud_complexity_list_t& hud_complexity_list); + hud_complexity_list_t& hud_complexity_list, + object_complexity_list_t& object_complexity_list); void calculateUpdateRenderComplexity(); static const U32 VISUAL_COMPLEXITY_UNKNOWN; void updateVisualComplexity(); - U32 getVisualComplexity() { return mVisualComplexity; }; // Numbers calculated here by rendering AV - F32 getAttachmentSurfaceArea() { return mAttachmentSurfaceArea; }; // estimated surface area of attachments + void placeProfileQuery(); + void readProfileQuery(S32 retries); + + // get the GPU time in ms of rendering this avatar including all attachments + // returns 0.f if this avatar has not been profiled using gPipeline.profileAvatar + // or the avatar is visually muted + F32 getGPURenderTime(); + + // get the total GPU render time in ms of all avatars that have been benched + static F32 getTotalGPURenderTime(); + + // get the max GPU render time in ms of all avatars that have been benched + static F32 getMaxGPURenderTime(); + + // get the average GPU render time in ms of all avatars that have been benched + static F32 getAverageGPURenderTime(); + + // get the CPU time in ms of rendering this avatar including all attachments + // return 0.f if this avatar has not been profiled using gPipeline.mProfileAvatar + F32 getCPURenderTime() { return mCPURenderTime; } + + + // avatar render cost + U32 getVisualComplexity() { return mVisualComplexity; }; + + // surface area calculation + F32 getAttachmentSurfaceArea() { return mAttachmentSurfaceArea; }; U32 getReportedVisualComplexity() { return mReportedVisualComplexity; }; // Numbers as reported by the SL server void setReportedVisualComplexity(U32 value) { mReportedVisualComplexity = value; }; @@ -316,6 +342,8 @@ public: void idleUpdateBelowWater(); + static void updateNearbyAvatarCount(); + //-------------------------------------------------------------------- // Static preferences (controlled by user settings/menus) //-------------------------------------------------------------------- @@ -340,6 +368,9 @@ public: static LLPointer<LLViewerTexture> sCloudTexture; + static std::vector<LLUUID> sAVsIgnoringARTLimit; + static S32 sAvatarsNearby; + //-------------------------------------------------------------------- // Region state //-------------------------------------------------------------------- @@ -351,6 +382,16 @@ public: //-------------------------------------------------------------------- public: BOOL isFullyLoaded() const; + + // check and return current state relative to limits + // default will test only the geometry (combined=false). + // this allows us to disable shadows separately on complex avatars. + + inline bool isTooSlowWithoutShadows() const {return mTooSlowWithoutShadows;}; + bool isTooSlow() const; + + void updateTooSlow(); + bool isTooComplex() const; bool visualParamWeightsAreDefault(); virtual bool getIsCloud() const; @@ -370,7 +411,7 @@ public: void logMetricsTimerRecord(const std::string& phase_name, F32 elapsed, bool completed); void calcMutedAVColor(); - + protected: LLViewerStats::PhaseMap& getPhases() { return mPhases; } BOOL updateIsFullyLoaded(); @@ -391,6 +432,12 @@ private: LLFrameTimer mFullyLoadedTimer; LLFrameTimer mRuthTimer; + // variables to hold "slowness" status + bool mTooSlow{false}; + bool mTooSlowWithoutShadows{false}; + + bool mTuned{false}; + private: LLViewerStats::PhaseMap mPhases; @@ -495,6 +542,7 @@ public: S32 mSpecialRenderMode; // special lighting private: + friend class LLPipeline; AvatarOverallAppearance mOverallAppearance; F32 mAttachmentSurfaceArea; //estimated surface area of attachments U32 mAttachmentVisibleTriangleCount; @@ -507,7 +555,20 @@ private: S32 mUpdatePeriod; S32 mNumInitFaces; //number of faces generated when creating the avatar drawable, does not inculde splitted faces due to long vertex buffer. + // profile handle + U32 mGPUTimerQuery = 0; + + // profile results + + // GPU render time in ms + F32 mGPURenderTime = 0.f; + bool mGPUProfilePending = false; + + // CPU render time in ms + F32 mCPURenderTime = 0.f; + // the isTooComplex method uses these mutable values to avoid recalculating too frequently + // DEPRECATED -- obsolete avatar render cost values mutable U32 mVisualComplexity; mutable bool mVisualComplexityStale; U32 mReportedVisualComplexity; // from other viewers through the simulator @@ -623,7 +684,7 @@ private: //-------------------------------------------------------------------- public: virtual LLViewerTexture::EBoostLevel getAvatarBoostLevel() const { return LLGLTexture::BOOST_AVATAR; } - virtual LLViewerTexture::EBoostLevel getAvatarBakedBoostLevel() const { return LLGLTexture::BOOST_AVATAR_BAKED; } + virtual LLViewerTexture::EBoostLevel getAvatarBakedBoostLevel() const { return LLGLTexture::BOOST_AVATAR_BAKED_SELF; } virtual S32 getTexImageSize() const; /*virtual*/ S32 getTexImageArea() const { return getTexImageSize()*getTexImageSize(); } diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp index d8b82d3114..82dfb1ca2a 100644 --- a/indra/newview/llvoavatarself.cpp +++ b/indra/newview/llvoavatarself.cpp @@ -1155,6 +1155,7 @@ LLViewerObject* LLVOAvatarSelf::getWornAttachment(const LLUUID& inv_item_id) bool LLVOAvatarSelf::getAttachedPointName(const LLUUID& inv_item_id, std::string& name) const { + LL_PROFILE_ZONE_SCOPED_CATEGORY_AVATAR; if (!gInventory.getItem(inv_item_id)) { name = "ATTACHMENT_MISSING_ITEM"; diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index a73d149b10..aa60578cee 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -1603,7 +1603,9 @@ BOOL LLVOVolume::updateLOD() { return FALSE; } - + + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; + BOOL lod_changed = FALSE; if (!LLSculptIDSize::instance().isUnloaded(getVolume()->getParams().getSculptID())) @@ -1617,16 +1619,6 @@ BOOL LLVOVolume::updateLOD() if (lod_changed) { - if (debugLoggingEnabled("AnimatedObjectsLinkset")) - { - if (isAnimatedObject() && isRiggedMesh()) - { - std::string vobj_name = llformat("Vol%p", this); - F32 est_tris = getEstTrianglesMax(); - LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " updateLOD to " << getLOD() << ", tris " << est_tris << LL_ENDL; - } - } - gPipeline.markRebuild(mDrawable, LLDrawable::REBUILD_VOLUME, FALSE); mLODChanged = TRUE; } @@ -3198,7 +3190,13 @@ void LLVOVolume::setLightCutoff(F32 cutoff) BOOL LLVOVolume::getIsLight() const { - return getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT); + mIsLight = getParameterEntryInUse(LLNetworkData::PARAMS_LIGHT); + return mIsLight; +} + +bool LLVOVolume::getIsLightFast() const +{ + return mIsLight; } LLColor3 LLVOVolume::getLightSRGBBaseColor() const @@ -3584,6 +3582,31 @@ BOOL LLVOVolume::hasLightTexture() const return FALSE; } +bool LLVOVolume::isFlexibleFast() const +{ + return mVolumep && mVolumep->getParams().getPathParams().getCurveType() == LL_PCODE_PATH_FLEXIBLE; +} + +bool LLVOVolume::isSculptedFast() const +{ + return mVolumep && mVolumep->getParams().isSculpt(); +} + +bool LLVOVolume::isMeshFast() const +{ + return mVolumep && mVolumep->getParams().isMeshSculpt(); +} + +bool LLVOVolume::isRiggedMeshFast() const +{ + return mSkinInfo.notNull(); +} + +bool LLVOVolume::isAnimatedObjectFast() const +{ + return mIsAnimatedObject; +} + BOOL LLVOVolume::isVolumeGlobal() const { if (mVolumeImpl) @@ -3744,8 +3767,8 @@ bool LLVOVolume::canBeAnimatedObject() const bool LLVOVolume::isAnimatedObject() const { LLVOVolume *root_vol = (LLVOVolume*)getRootEdit(); - bool root_is_animated_flag = root_vol->getExtendedMeshFlags() & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG; - return root_is_animated_flag; + mIsAnimatedObject = root_vol->getExtendedMeshFlags() & LLExtendedMeshParams::ANIMATED_MESH_ENABLED_FLAG; + return mIsAnimatedObject; } // Called any time parenting changes for a volume. Update flags and @@ -3932,12 +3955,41 @@ const LLMatrix4 LLVOVolume::getRenderMatrix() const return mDrawable->getWorldMatrix(); } +//static +S32 LLVOVolume::getTextureCost(const LLViewerTexture* img) +{ + static const U32 ARC_TEXTURE_COST = 16; // multiplier for texture resolution - performance tested + + S32 texture_cost = 0; + S8 type = img->getType(); + if (type == LLViewerTexture::FETCHED_TEXTURE || type == LLViewerTexture::LOD_TEXTURE) + { + const LLViewerFetchedTexture* fetched_texturep = static_cast<const LLViewerFetchedTexture*>(img); + if (fetched_texturep + && fetched_texturep->getFTType() == FTT_LOCAL_FILE + && (img->getID() == IMG_ALPHA_GRAD_2D || img->getID() == IMG_ALPHA_GRAD) + ) + { + // These two textures appear to switch between each other, but are of different sizes (4x256 and 256x256). + // Hardcode cost from larger one to not cause random complexity changes + texture_cost = 320; + } + } + if (texture_cost == 0) + { + texture_cost = 256 + (S32)(ARC_TEXTURE_COST * (img->getFullHeight() / 128.f + img->getFullWidth() / 128.f)); + } + + return texture_cost; +} + // Returns a base cost and adds textures to passed in set. // total cost is returned value + 5 * size of the resulting set. // Cannot include cost of textures, as they may be re-used in linked // children, and cost should only be increased for unique textures -Nyx U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const { + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; /***************************************************************** * This calculation should not be modified by third party viewers, * since it is used to limit rendering and should be uniform for @@ -3947,17 +3999,16 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const // Get access to params we'll need at various points. // Skip if this is object doesn't have a volume (e.g. is an avatar). - BOOL has_volume = (getVolume() != NULL); - LLVolumeParams volume_params; - LLPathParams path_params; - LLProfileParams profile_params; + if (getVolume() == NULL) + { + return 0; + } U32 num_triangles = 0; // per-prim costs static const U32 ARC_PARTICLE_COST = 1; // determined experimentally static const U32 ARC_PARTICLE_MAX = 2048; // default values - static const U32 ARC_TEXTURE_COST = 16; // multiplier for texture resolution - performance tested static const U32 ARC_LIGHT_COST = 500; // static cost for light-producing prims static const U32 ARC_MEDIA_FACE_COST = 1500; // static cost per media-enabled face @@ -3992,45 +4043,41 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const const LLDrawable* drawablep = mDrawable; U32 num_faces = drawablep->getNumFaces(); - if (has_volume) - { - volume_params = getVolume()->getParams(); - path_params = volume_params.getPathParams(); - profile_params = volume_params.getProfileParams(); + const LLVolumeParams& volume_params = getVolume()->getParams(); - LLMeshCostData costs; - if (getCostData(costs)) - { - if (isAnimatedObject() && isRiggedMesh()) - { - // Scaling here is to make animated object vs - // non-animated object ARC proportional to the - // corresponding calculations for streaming cost. - num_triangles = (ANIMATED_OBJECT_COST_PER_KTRI * 0.001 * costs.getEstTrisForStreamingCost())/0.06; - } - else - { - F32 radius = getScale().length()*0.5f; - num_triangles = costs.getRadiusWeightedTris(radius); - } - } + LLMeshCostData costs; + if (getCostData(costs)) + { + if (isAnimatedObjectFast() && isRiggedMeshFast()) + { + // Scaling here is to make animated object vs + // non-animated object ARC proportional to the + // corresponding calculations for streaming cost. + num_triangles = (ANIMATED_OBJECT_COST_PER_KTRI * 0.001 * costs.getEstTrisForStreamingCost())/0.06; + } + else + { + F32 radius = getScale().length()*0.5f; + num_triangles = costs.getRadiusWeightedTris(radius); + } } + if (num_triangles <= 0) { num_triangles = 4; } - if (isSculpted()) + if (isSculptedFast()) { - if (isMesh()) + if (isMeshFast()) { // base cost is dependent on mesh complexity // note that 3 is the highest LOD as of the time of this coding. S32 size = gMeshRepo.getMeshSize(volume_params.getSculptID(), getLOD()); if ( size > 0) { - if (isRiggedMesh()) + if (isRiggedMeshFast()) { // weighted attachment - 1 point for every 3 bytes weighted_mesh = 1; @@ -4044,21 +4091,15 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const } else { - const LLSculptParams *sculpt_params = (LLSculptParams *) getParameterEntry(LLNetworkData::PARAMS_SCULPT); - LLUUID sculpt_id = sculpt_params->getSculptTexture(); - if (textures.find(sculpt_id) == textures.end()) + LLViewerFetchedTexture* texture = mSculptTexture; + if (texture && textures.find(texture) == textures.end()) { - LLViewerFetchedTexture *texture = LLViewerTextureManager::getFetchedTexture(sculpt_id); - if (texture) - { - S32 texture_cost = 256 + (S32)(ARC_TEXTURE_COST * (texture->getFullHeight() / 128.f + texture->getFullWidth() / 128.f)); - textures.insert(texture_cost_t::value_type(sculpt_id, texture_cost)); - } + textures.insert(texture); } } } - if (isFlexible()) + if (isFlexibleFast()) { flexi = 1; } @@ -4067,85 +4108,66 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const particles = 1; } - if (getIsLight()) + if (getIsLightFast()) { produces_light = 1; } - for (S32 i = 0; i < num_faces; ++i) - { - const LLFace* face = drawablep->getFace(i); - if (!face) continue; - const LLTextureEntry* te = face->getTextureEntry(); - const LLViewerTexture* img = face->getTexture(); + { + LL_PROFILE_ZONE_NAMED_CATEGORY_VOLUME("ARC - face list"); + for (S32 i = 0; i < num_faces; ++i) + { + const LLFace* face = drawablep->getFace(i); + if (!face) continue; + const LLTextureEntry* te = face->getTextureEntry(); + const LLViewerTexture* img = face->getTexture(); - if (img) - { - if (textures.find(img->getID()) == textures.end()) - { - S32 texture_cost = 0; - S8 type = img->getType(); - if (type == LLViewerTexture::FETCHED_TEXTURE || type == LLViewerTexture::LOD_TEXTURE) + if (img) + { + textures.insert(img); + } + + if (face->isInAlphaPool()) + { + alpha = 1; + } + else if (img && img->getPrimaryFormat() == GL_ALPHA) + { + invisi = 1; + } + if (face->hasMedia()) + { + media_faces++; + } + + if (te) + { + if (te->getBumpmap()) { - const LLViewerFetchedTexture* fetched_texturep = static_cast<const LLViewerFetchedTexture*>(img); - if (fetched_texturep - && fetched_texturep->getFTType() == FTT_LOCAL_FILE - && (img->getID() == IMG_ALPHA_GRAD_2D || img->getID() == IMG_ALPHA_GRAD) - ) - { - // These two textures appear to switch between each other, but are of different sizes (4x256 and 256x256). - // Hardcode cost from larger one to not cause random complexity changes - texture_cost = 320; - } + // bump is a multiplier, don't add per-face + bump = 1; } - if (texture_cost == 0) + if (te->getShiny()) { - texture_cost = 256 + (S32)(ARC_TEXTURE_COST * (img->getFullHeight() / 128.f + img->getFullWidth() / 128.f)); + // shiny is a multiplier, don't add per-face + shiny = 1; } - textures.insert(texture_cost_t::value_type(img->getID(), texture_cost)); - } - } - - if (face->isInAlphaPool()) - { - alpha = 1; - } - else if (img && img->getPrimaryFormat() == GL_ALPHA) - { - invisi = 1; - } - if (face->hasMedia()) - { - media_faces++; - } - - if (te) - { - if (te->getBumpmap()) - { - // bump is a multiplier, don't add per-face - bump = 1; - } - if (te->getShiny()) - { - // shiny is a multiplier, don't add per-face - shiny = 1; - } - if (te->getGlow() > 0.f) - { - // glow is a multiplier, don't add per-face - glow = 1; - } - if (face->mTextureMatrix != NULL) - { - animtex = 1; - } - if (te->getTexGen()) - { - planar = 1; - } - } - } + if (te->getGlow() > 0.f) + { + // glow is a multiplier, don't add per-face + glow = 1; + } + if (face->mTextureMatrix != NULL) + { + animtex = 1; + } + if (te->getTexGen()) + { + planar = 1; + } + } + } + } // shame currently has the "base" cost of 1 point per 15 triangles, min 2. shame = num_triangles * 5.f; @@ -4224,7 +4246,7 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const // Streaming cost for animated objects includes a fixed cost // per linkset. Add a corresponding charge here translated into // triangles, but not weighted by any graphics properties. - if (isAnimatedObject() && isRootEdit()) + if (isAnimatedObjectFast() && isRootEdit()) { shame += (ANIMATED_OBJECT_BASE_COST/0.06) * 5.0f; } @@ -4239,7 +4261,7 @@ U32 LLVOVolume::getRenderCost(texture_cost_t &textures) const F32 LLVOVolume::getEstTrianglesMax() const { - if (isMesh() && getVolume()) + if (isMeshFast() && getVolume()) { return gMeshRepo.getEstTrianglesMax(getVolume()->getParams().getSculptID()); } @@ -4248,7 +4270,7 @@ F32 LLVOVolume::getEstTrianglesMax() const F32 LLVOVolume::getEstTrianglesStreamingCost() const { - if (isMesh() && getVolume()) + if (isMeshFast() && getVolume()) { return gMeshRepo.getEstTrianglesStreamingCost(getVolume()->getParams().getSculptID()); } @@ -4263,7 +4285,7 @@ F32 LLVOVolume::getStreamingCost() const LLMeshCostData costs; if (getCostData(costs)) { - if (isAnimatedObject() && isRootEdit()) + if (isRootEdit() && isAnimatedObject()) { // Root object of an animated object has this to account for skeleton overhead. linkset_base_cost = ANIMATED_OBJECT_BASE_COST; @@ -4293,7 +4315,9 @@ F32 LLVOVolume::getStreamingCost() const // virtual bool LLVOVolume::getCostData(LLMeshCostData& costs) const { - if (isMesh()) + LL_PROFILE_ZONE_SCOPED_CATEGORY_VOLUME; + + if (isMeshFast()) { return gMeshRepo.getCostData(getVolume()->getParams().getSculptID(), costs); } @@ -4303,11 +4327,11 @@ bool LLVOVolume::getCostData(LLMeshCostData& costs) const S32 counts[4]; LLVolume::getLoDTriangleCounts(volume->getParams(), counts); - LLSD header; - header["lowest_lod"]["size"] = counts[0] * 10; - header["low_lod"]["size"] = counts[1] * 10; - header["medium_lod"]["size"] = counts[2] * 10; - header["high_lod"]["size"] = counts[3] * 10; + LLMeshHeader header; + header.mLodSize[0] = counts[0] * 10; + header.mLodSize[1] = counts[1] * 10; + header.mLodSize[2] = counts[2] * 10; + header.mLodSize[3] = counts[3] * 10; return gMeshRepo.getCostData(header, costs); } @@ -4532,16 +4556,6 @@ const LLMatrix4& LLVOVolume::getWorldMatrix(LLXformMatrix* xform) const void LLVOVolume::markForUpdate(BOOL priority) { - if (debugLoggingEnabled("AnimatedObjectsLinkset")) - { - if (isAnimatedObject() && isRiggedMesh()) - { - std::string vobj_name = llformat("Vol%p", this); - F32 est_tris = getEstTrianglesMax(); - LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " markForUpdate, tris " << est_tris << LL_ENDL; - } - } - if (mDrawable) { shrinkWrap(); @@ -5454,7 +5468,7 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, } } - if (type == LLRenderPass::PASS_ALPHA) + // if (type == LLRenderPass::PASS_ALPHA) // always populate the draw_info ptr { //for alpha sorting facep->setDrawInfo(draw_info); } @@ -5826,7 +5840,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) const LLTextureEntry* te = facep->getTextureEntry(); LLViewerTexture* tex = facep->getTexture(); - if (te->getGlow() >= 1.f/255.f) + if (te->getGlow() > 0.f) { emissive = true; } @@ -5910,7 +5924,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) { LLGLTFMaterial* gltf_mat = te->getGLTFRenderMaterial(); - if (gltf_mat != nullptr || (te->getMaterialParams().notNull() && !te->getMaterialID().isNull())) + if (gltf_mat != nullptr || (te->getMaterialParams().notNull())) { if (gltf_mat != nullptr) { @@ -6088,7 +6102,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) U32 buffer_count = 0; - for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) + for (LLSpatialGroup::element_iter drawable_iter = group->getDataBegin(); drawable_iter != group->getDataEnd(); ++drawable_iter) { LLDrawable* drawablep = (LLDrawable*)(*drawable_iter)->getDrawable(); @@ -6097,16 +6111,7 @@ void LLVolumeGeometryManager::rebuildMesh(LLSpatialGroup* group) LLVOVolume* vobj = drawablep->getVOVolume(); if (!vobj) continue; - - if (debugLoggingEnabled("AnimatedObjectsLinkset")) - { - if (vobj->isAnimatedObject() && vobj->isRiggedMesh()) - { - std::string vobj_name = llformat("Vol%p", vobj); - F32 est_tris = vobj->getEstTrianglesMax(); - LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " rebuildMesh, tris " << est_tris << LL_ENDL; - } - } + if (vobj->isNoLOD()) continue; vobj->preRebuild(); @@ -6466,10 +6471,11 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace U32 indices_index = 0; U16 index_offset = 0; - while (face_iter < i) + while (face_iter < i) { //update face indices for new buffer facep = *face_iter; + if (buffer.isNull()) { // Bulk allocation failed diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h index 9cfd90a940..d509a7e2ab 100644 --- a/indra/newview/llvovolume.h +++ b/indra/newview/llvovolume.h @@ -34,8 +34,8 @@ #include "lllocalbitmaps.h" #include "m3math.h" // LLMatrix3 #include "m4math.h" // LLMatrix4 -#include <map> -#include <set> +#include <unordered_map> +#include <unordered_set> class LLViewerTextureAnim; @@ -146,7 +146,8 @@ public: const LLMatrix4& getRelativeXform() const { return mRelativeXform; } const LLMatrix3& getRelativeXformInvTrans() const { return mRelativeXformInvTrans; } /*virtual*/ const LLMatrix4 getRenderMatrix() const override; - typedef std::map<LLUUID, S32> texture_cost_t; + typedef std::unordered_set<const LLViewerTexture*> texture_cost_t; + static S32 getTextureCost(const LLViewerTexture* img); U32 getRenderCost(texture_cost_t &textures) const; /*virtual*/ F32 getEstTrianglesMax() const override; /*virtual*/ F32 getEstTrianglesStreamingCost() const override; @@ -267,6 +268,7 @@ public: void setSpotLightParams(LLVector3 params); BOOL getIsLight() const; + bool getIsLightFast() const; // Get the light color in sRGB color space NOT scaled by intensity. @@ -315,7 +317,15 @@ public: virtual BOOL isRiggedMesh() const override; virtual BOOL hasLightTexture() const override; - + // fast variants above that use state that is filled in later + // not reliable early in the life of an object, but should be used after + // object is loaded + bool isFlexibleFast() const; + bool isSculptedFast() const; + bool isMeshFast() const; + bool isRiggedMeshFast() const; + bool isAnimatedObjectFast() const; + BOOL isVolumeGlobal() const; BOOL canBeFlexible() const; BOOL setIsFlexible(BOOL is_flexible); @@ -461,6 +471,13 @@ private: S32 mIndexInTex[LLRender::NUM_VOLUME_TEXTURE_CHANNELS]; S32 mMDCImplCount; + // cached value of getIsLight to avoid redundant map lookups + // accessed by getIsLightFast + mutable bool mIsLight = false; + + // cached value of getIsAnimatedObject to avoid redundant map lookups + // accessed by getIsAnimatedObjectFast + mutable bool mIsAnimatedObject = false; bool mResetDebugText; LLPointer<LLRiggedVolume> mRiggedVolume; @@ -475,7 +492,6 @@ public: static LLPointer<LLObjectMediaDataClient> sObjectMediaClient; static LLPointer<LLObjectMediaNavigateClient> sObjectMediaNavigateClient; - protected: static S32 sNumLODChanges; diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 9fa3d18a40..0e0dbdc071 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -33,6 +33,7 @@ #include "llstl.h" #include "llagent.h" +#include "llagentcamera.h" #include "llviewercontrol.h" #include "lldrawpool.h" #include "llglheaders.h" @@ -1423,6 +1424,36 @@ void LLWorld::getAvatars(uuid_vec_t* avatar_ids, std::vector<LLVector3d>* positi } } +F32 LLWorld::getNearbyAvatarsAndMaxGPUTime(std::vector<LLCharacter*> &valid_nearby_avs) +{ + static LLCachedControl<F32> render_far_clip(gSavedSettings, "RenderFarClip", 64); + F32 nearby_max_complexity = 0; + F32 radius = render_far_clip * render_far_clip; + std::vector<LLCharacter*>::iterator char_iter = LLCharacter::sInstances.begin(); + while (char_iter != LLCharacter::sInstances.end()) + { + LLVOAvatar* avatar = dynamic_cast<LLVOAvatar*>(*char_iter); + if (avatar && !avatar->isDead() && !avatar->isControlAvatar()) + { + if ((dist_vec_squared(avatar->getPositionGlobal(), gAgent.getPositionGlobal()) > radius) && + (dist_vec_squared(avatar->getPositionGlobal(), gAgentCamera.getCameraPositionGlobal()) > radius)) + { + char_iter++; + continue; + } + + if (!avatar->isTooSlow()) + { + gPipeline.profileAvatar(avatar); + } + nearby_max_complexity = llmax(nearby_max_complexity, avatar->getGPURenderTime()); + valid_nearby_avs.push_back(*char_iter); + } + char_iter++; + } + return nearby_max_complexity; +} + bool LLWorld::isRegionListed(const LLViewerRegion* region) const { region_list_t::const_iterator it = find(mRegionList.begin(), mRegionList.end(), region); diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h index 5dee8eea0f..f78cbcaa48 100644 --- a/indra/newview/llworld.h +++ b/indra/newview/llworld.h @@ -51,6 +51,7 @@ class LLHost; class LLViewerObject; class LLSurfacePatch; +class LLCharacter; class LLCloudPuff; class LLCloudGroup; class LLVOAvatar; @@ -171,6 +172,10 @@ public: // or if the circuit to this simulator had been lost. bool isRegionListed(const LLViewerRegion* region) const; + // profile nearby avatars using gPipeline.profileAvatar and update their render times + // return max GPU time + F32 getNearbyAvatarsAndMaxGPUTime(std::vector<LLCharacter*> &valid_nearby_avs); + private: void clearHoleWaterObjects(); void clearEdgeWaterObjects(); diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 283be64af4..327a51de85 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -43,6 +43,7 @@ #include "llui.h" #include "llglheaders.h" #include "llrender.h" +#include "llstartup.h" #include "llwindow.h" // swapBuffers() // newview includes @@ -127,6 +128,7 @@ U32 LLPipeline::RenderFSAASamples; U32 LLPipeline::RenderResolutionDivisor; bool LLPipeline::RenderUIBuffer; S32 LLPipeline::RenderShadowDetail; +S32 LLPipeline::RenderShadowSplits; bool LLPipeline::RenderDeferredSSAO; F32 LLPipeline::RenderShadowResolutionScale; bool LLPipeline::RenderLocalLights; @@ -200,6 +202,7 @@ LLTrace::EventStatHandle<S64> LLPipeline::sStatBatchSize("renderbatchsize"); const F32 BACKLIGHT_DAY_MAGNITUDE_OBJECT = 0.1f; const F32 BACKLIGHT_NIGHT_MAGNITUDE_OBJECT = 0.08f; +const F32 ALPHA_BLEND_CUTOFF = 0.598f; const F32 DEFERRED_LIGHT_FALLOFF = 0.5f; const U32 DEFERRED_VB_MASK = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1; @@ -486,6 +489,7 @@ void LLPipeline::init() connectRefreshCachedSettingsSafe("RenderResolutionDivisor"); connectRefreshCachedSettingsSafe("RenderUIBuffer"); connectRefreshCachedSettingsSafe("RenderShadowDetail"); + connectRefreshCachedSettingsSafe("RenderShadowSplits"); connectRefreshCachedSettingsSafe("RenderDeferredSSAO"); connectRefreshCachedSettingsSafe("RenderShadowResolutionScale"); connectRefreshCachedSettingsSafe("RenderLocalLights"); @@ -559,7 +563,6 @@ void LLPipeline::init() LLPipeline::~LLPipeline() { - } void LLPipeline::cleanup() @@ -971,10 +974,11 @@ void LLPipeline::refreshCachedSettings() WindLightUseAtmosShaders = TRUE; // DEPRECATED -- gSavedSettings.getBOOL("WindLightUseAtmosShaders"); RenderDeferred = TRUE; // DEPRECATED -- gSavedSettings.getBOOL("RenderDeferred"); RenderDeferredSunWash = gSavedSettings.getF32("RenderDeferredSunWash"); - RenderFSAASamples = gSavedSettings.getU32("RenderFSAASamples"); + RenderFSAASamples = LLFeatureManager::getInstance()->isFeatureAvailable("RenderFSAASamples") ? gSavedSettings.getU32("RenderFSAASamples") : 0; RenderResolutionDivisor = gSavedSettings.getU32("RenderResolutionDivisor"); RenderUIBuffer = gSavedSettings.getBOOL("RenderUIBuffer"); RenderShadowDetail = gSavedSettings.getS32("RenderShadowDetail"); + RenderShadowSplits = gSavedSettings.getS32("RenderShadowSplits"); RenderDeferredSSAO = gSavedSettings.getBOOL("RenderDeferredSSAO"); RenderShadowResolutionScale = gSavedSettings.getF32("RenderShadowResolutionScale"); RenderLocalLights = gSavedSettings.getBOOL("RenderLocalLights"); @@ -2250,12 +2254,18 @@ bool LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3& static LLTrace::BlockTimerStatHandle FTM_CULL("Object Culling"); +// static +bool LLPipeline::isWaterClip() +{ + return (!sRenderTransparentWater || gCubeSnapshot) && !sRenderingHUDs; +} + void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result) { LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; //LL_RECORD_BLOCK_TIME(FTM_CULL); LL_PROFILE_GPU_ZONE("updateCull"); // should always be zero GPU time, but drop a timer to flush stuff out - bool water_clip = !sRenderTransparentWater && !sRenderingHUDs; + bool water_clip = isWaterClip(); if (water_clip) { @@ -3027,18 +3037,6 @@ void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags f { if (drawablep && !drawablep->isDead() && assertInitialized()) { - if (debugLoggingEnabled("AnimatedObjectsLinkset")) - { - LLVOVolume *vol_obj = drawablep->getVOVolume(); - if (vol_obj && vol_obj->isAnimatedObject() && vol_obj->isRiggedMesh()) - { - std::string vobj_name = llformat("Vol%p", vol_obj); - F32 est_tris = vol_obj->getEstTrianglesMax(); - LL_DEBUGS("AnimatedObjectsLinkset") << vobj_name << " markRebuild, tris " << est_tris - << " priority " << (S32) priority << " flag " << std::hex << flag << LL_ENDL; - } - } - if (!drawablep->isState(LLDrawable::BUILT)) { priority = true; @@ -5492,7 +5490,7 @@ void LLPipeline::calcNearbyLights(LLCamera& camera) LLDrawable* drawable = light->drawable; const LLViewerObject *vobj = light->drawable->getVObj(); if(vobj && vobj->getAvatar() - && (vobj->getAvatar()->isTooComplex() || vobj->getAvatar()->isInMuteList()) + && (vobj->getAvatar()->isTooComplex() || vobj->getAvatar()->isInMuteList() || vobj->getAvatar()->isTooSlow()) ) { drawable->clearState(LLDrawable::NEARBY_LIGHT); @@ -5571,7 +5569,7 @@ void LLPipeline::calcNearbyLights(LLCamera& camera) continue; } LLVOAvatar * av = light->getAvatar(); - if (av && (av->isTooComplex() || av->isInMuteList())) + if (av && (av->isTooComplex() || av->isInMuteList() || av->isTooSlow())) { // avatars that are already in the list will be removed by removeMutedAVsLights continue; @@ -6776,6 +6774,8 @@ void LLPipeline::renderAlphaObjects(bool rigged) assertInitialized(); gGL.loadMatrix(gGLModelView); gGLLastMatrix = NULL; + S32 sun_up = LLEnvironment::instance().getIsSunUp() ? 1 : 0; + U32 target_width = LLRenderTarget::sCurResX; U32 type = LLRenderPass::PASS_ALPHA; LLVOAvatar* lastAvatar = nullptr; U64 lastMeshId = 0; @@ -6798,10 +6798,18 @@ void LLPipeline::renderAlphaObjects(bool rigged) { if (pparams->mGLTFMaterial) { + gDeferredShadowGLTFAlphaMaskProgram.bind(rigged); + LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up); + LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width); + LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(ALPHA_BLEND_CUTOFF); mSimplePool->pushRiggedGLTFBatch(*pparams, lastAvatar, lastMeshId); } else { + gDeferredShadowAlphaMaskProgram.bind(rigged); + LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up); + LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width); + LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(ALPHA_BLEND_CUTOFF); if (lastAvatar != pparams->mAvatar || lastMeshId != pparams->mSkinInfo->mHash) { mSimplePool->uploadMatrixPalette(*pparams); @@ -6809,18 +6817,26 @@ void LLPipeline::renderAlphaObjects(bool rigged) lastMeshId = pparams->mSkinInfo->mHash; } - mSimplePool->pushBatch(*pparams, true, true, true); + mSimplePool->pushBatch(*pparams, true, true); } } else { if (pparams->mGLTFMaterial) { + gDeferredShadowGLTFAlphaMaskProgram.bind(rigged); + LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up); + LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width); + LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(ALPHA_BLEND_CUTOFF); mSimplePool->pushGLTFBatch(*pparams); } else { - mSimplePool->pushBatch(*pparams, true, true, true); + gDeferredShadowAlphaMaskProgram.bind(rigged); + LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up); + LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width); + LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(ALPHA_BLEND_CUTOFF); + mSimplePool->pushBatch(*pparams, true, true); } } } @@ -6837,11 +6853,11 @@ void LLPipeline::renderMaskedObjects(U32 type, bool texture, bool batch_texture, gGLLastMatrix = NULL; if (rigged) { - mAlphaMaskPool->pushRiggedMaskBatches(type+1, texture, batch_texture, true); + mAlphaMaskPool->pushRiggedMaskBatches(type+1, texture, batch_texture); } else { - mAlphaMaskPool->pushMaskBatches(type, texture, batch_texture, true); + mAlphaMaskPool->pushMaskBatches(type, texture, batch_texture); } gGL.loadMatrix(gGLModelView); gGLLastMatrix = NULL; @@ -6855,11 +6871,11 @@ void LLPipeline::renderFullbrightMaskedObjects(U32 type, bool texture, bool batc gGLLastMatrix = NULL; if (rigged) { - mFullbrightAlphaMaskPool->pushRiggedMaskBatches(type+1, texture, batch_texture, true); + mFullbrightAlphaMaskPool->pushRiggedMaskBatches(type+1, texture, batch_texture); } else { - mFullbrightAlphaMaskPool->pushMaskBatches(type, texture, batch_texture, true); + mFullbrightAlphaMaskPool->pushMaskBatches(type, texture, batch_texture); } gGL.loadMatrix(gGLModelView); gGLLastMatrix = NULL; @@ -6927,7 +6943,8 @@ void LLPipeline::bindScreenToTexture() static LLTrace::BlockTimerStatHandle FTM_RENDER_BLOOM("Bloom"); -void LLPipeline::visualizeBuffers(LLRenderTarget* src, LLRenderTarget* dst, U32 bufferIndex) { +void LLPipeline::visualizeBuffers(LLRenderTarget* src, LLRenderTarget* dst, U32 bufferIndex) +{ dst->bindTarget(); gDeferredBufferVisualProgram.bind(); gDeferredBufferVisualProgram.bindTexture(LLShaderMgr::DEFERRED_DIFFUSE, src, false, LLTexUnit::TFO_BILINEAR, bufferIndex); @@ -6944,7 +6961,8 @@ void LLPipeline::visualizeBuffers(LLRenderTarget* src, LLRenderTarget* dst, U32 dst->flush(); } -void LLPipeline::generateLuminance(LLRenderTarget* src, LLRenderTarget* dst) { +void LLPipeline::generateLuminance(LLRenderTarget* src, LLRenderTarget* dst) +{ // luminance sample and mipmap generation { LL_PROFILE_GPU_ZONE("luminance sample"); @@ -7020,9 +7038,19 @@ void LLPipeline::generateExposure(LLRenderTarget* src, LLRenderTarget* dst) { static LLCachedControl<F32> dynamic_exposure_min(gSavedSettings, "RenderDynamicExposureMin", 0.125f); static LLCachedControl<F32> dynamic_exposure_max(gSavedSettings, "RenderDynamicExposureMax", 1.3f); + F32 exposure_max = dynamic_exposure_max; + LLSettingsSky::ptr_t sky = LLEnvironment::instance().getCurrentSky(); + + if (sky->getReflectionProbeAmbiance() > 0.f) + { //not a legacy sky, use gamma as a boost to max exposure + exposure_max = llmax(exposure_max - 1.f, 0.f); + exposure_max *= sky->getGamma(); + exposure_max += 1.f; + } + gExposureProgram.uniform1f(dt, gFrameIntervalSeconds); gExposureProgram.uniform2f(noiseVec, ll_frand() * 2.0 - 1.0, ll_frand() * 2.0 - 1.0); - gExposureProgram.uniform3f(dynamic_exposure_params, dynamic_exposure_coefficient, dynamic_exposure_min, dynamic_exposure_max); + gExposureProgram.uniform3f(dynamic_exposure_params, dynamic_exposure_coefficient, dynamic_exposure_min, exposure_max); mScreenTriangleVB->setBuffer(); mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); @@ -7039,18 +7067,25 @@ void LLPipeline::gammaCorrect(LLRenderTarget* src, LLRenderTarget* dst) { { LL_PROFILE_GPU_ZONE("gamma correct"); + static LLCachedControl<bool> no_post(gSavedSettings, "RenderDisablePostProcessing", false); + LLGLDepthTest depth(GL_FALSE, GL_FALSE); // Apply gamma correction to the frame here. - gDeferredPostGammaCorrectProgram.bind(); + + LLGLSLShader& shader = no_post && gFloaterTools->isAvailable() ? gNoPostGammaCorrectProgram : // no post (no gamma, no exposure, no tonemapping) + LLEnvironment::instance().getCurrentSky()->getReflectionProbeAmbiance() == 0.f ? gLegacyPostGammaCorrectProgram : + gDeferredPostGammaCorrectProgram; + + shader.bind(); S32 channel = 0; - gDeferredPostGammaCorrectProgram.bindTexture(LLShaderMgr::DEFERRED_DIFFUSE, src, false, LLTexUnit::TFO_POINT); + shader.bindTexture(LLShaderMgr::DEFERRED_DIFFUSE, src, false, LLTexUnit::TFO_POINT); - gDeferredPostGammaCorrectProgram.bindTexture(LLShaderMgr::EXPOSURE_MAP, &mExposureMap); + shader.bindTexture(LLShaderMgr::EXPOSURE_MAP, &mExposureMap); - gDeferredPostGammaCorrectProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, src->getWidth(), src->getHeight()); + shader.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, src->getWidth(), src->getHeight()); static LLCachedControl<F32> exposure(gSavedSettings, "RenderExposure", 1.f); @@ -7058,18 +7093,19 @@ void LLPipeline::gammaCorrect(LLRenderTarget* src, LLRenderTarget* dst) { static LLStaticHashedString s_exposure("exposure"); - gDeferredPostGammaCorrectProgram.uniform1f(s_exposure, e); + shader.uniform1f(s_exposure, e); mScreenTriangleVB->setBuffer(); mScreenTriangleVB->drawArrays(LLRender::TRIANGLES, 0, 3); gGL.getTexUnit(channel)->unbind(src->getUsage()); - gDeferredPostGammaCorrectProgram.unbind(); + shader.unbind(); } dst->flush(); } -void LLPipeline::copyScreenSpaceReflections(LLRenderTarget* src, LLRenderTarget* dst) { +void LLPipeline::copyScreenSpaceReflections(LLRenderTarget* src, LLRenderTarget* dst) +{ if (RenderScreenSpaceReflections && !gCubeSnapshot) { @@ -7095,7 +7131,8 @@ void LLPipeline::copyScreenSpaceReflections(LLRenderTarget* src, LLRenderTarget* } } -void LLPipeline::generateGlow(LLRenderTarget* src) { +void LLPipeline::generateGlow(LLRenderTarget* src) +{ if (sRenderGlow) { LL_PROFILE_GPU_ZONE("glow"); @@ -7192,7 +7229,8 @@ void LLPipeline::generateGlow(LLRenderTarget* src) { } } -void LLPipeline::applyFXAA(LLRenderTarget* src, LLRenderTarget* dst) { +void LLPipeline::applyFXAA(LLRenderTarget* src, LLRenderTarget* dst) +{ { llassert(!gCubeSnapshot); bool multisample = RenderFSAASamples > 1 && mRT->fxaaBuffer.isComplete(); @@ -7272,7 +7310,8 @@ void LLPipeline::applyFXAA(LLRenderTarget* src, LLRenderTarget* dst) { } } -void LLPipeline::copyRenderTarget(LLRenderTarget* src, LLRenderTarget* dst) { +void LLPipeline::copyRenderTarget(LLRenderTarget* src, LLRenderTarget* dst) +{ LL_PROFILE_GPU_ZONE("copyRenderTarget"); dst->bindTarget(); @@ -7292,7 +7331,8 @@ void LLPipeline::copyRenderTarget(LLRenderTarget* src, LLRenderTarget* dst) { dst->flush(); } -void LLPipeline::combineGlow(LLRenderTarget* src, LLRenderTarget* dst) { +void LLPipeline::combineGlow(LLRenderTarget* src, LLRenderTarget* dst) +{ // Go ahead and do our glow combine here in our destination. We blit this later into the front buffer. dst->bindTarget(); @@ -7311,7 +7351,8 @@ void LLPipeline::combineGlow(LLRenderTarget* src, LLRenderTarget* dst) { dst->flush(); } -void LLPipeline::renderDoF(LLRenderTarget* src, LLRenderTarget* dst) { +void LLPipeline::renderDoF(LLRenderTarget* src, LLRenderTarget* dst) +{ { bool dof_enabled = (RenderDepthOfFieldInEditMode || !LLToolMgr::getInstance()->inBuildMode()) && @@ -7477,10 +7518,12 @@ void LLPipeline::renderDoF(LLRenderTarget* src, LLRenderTarget* dst) { { // combine result based on alpha dst->bindTarget(); - if (RenderFSAASamples > 1 && mRT->fxaaBuffer.isComplete()) { + if (RenderFSAASamples > 1 && mRT->fxaaBuffer.isComplete()) + { glViewport(0, 0, dst->getWidth(), dst->getHeight()); } - else { + else + { gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth(); @@ -7515,6 +7558,7 @@ void LLPipeline::renderDoF(LLRenderTarget* src, LLRenderTarget* dst) { void LLPipeline::renderFinalize() { + llassert(!gCubeSnapshot); LLVertexBuffer::unbind(); LLGLState::checkStates(); @@ -7535,22 +7579,20 @@ void LLPipeline::renderFinalize() gGL.setColorMask(true, true); glClearColor(0, 0, 0, 0); - if (!gCubeSnapshot) - { - copyScreenSpaceReflections(&mRT->screen, &mSceneMap); + + copyScreenSpaceReflections(&mRT->screen, &mSceneMap); - generateLuminance(&mRT->screen, &mLuminanceMap); + generateLuminance(&mRT->screen, &mLuminanceMap); - generateExposure(&mLuminanceMap, &mExposureMap); + generateExposure(&mLuminanceMap, &mExposureMap); - gammaCorrect(&mRT->screen, &mPostMap); + gammaCorrect(&mRT->screen, &mPostMap); - LLVertexBuffer::unbind(); - } + LLVertexBuffer::unbind(); - generateGlow(&mPostMap); + generateGlow(&mPostMap); - combineGlow(&mPostMap, &mRT->screen); + combineGlow(&mPostMap, &mRT->screen); gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft; gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom; @@ -7562,7 +7604,8 @@ void LLPipeline::renderFinalize() applyFXAA(&mPostMap, &mRT->screen); LLRenderTarget* finalBuffer = &mRT->screen; - if (RenderBufferVisualization > -1) { + if (RenderBufferVisualization > -1) + { finalBuffer = &mPostMap; switch (RenderBufferVisualization) { @@ -7663,10 +7706,18 @@ void LLPipeline::bindShadowMaps(LLGLSLShader& shader) void LLPipeline::bindDeferredShaderFast(LLGLSLShader& shader) { - shader.bind(); - bindLightFunc(shader); - bindShadowMaps(shader); - bindReflectionProbes(shader); + if (shader.mCanBindFast) + { // was previously fully bound, use fast path + shader.bind(); + bindLightFunc(shader); + bindShadowMaps(shader); + bindReflectionProbes(shader); + } + else + { //wasn't previously bound, use slow path + bindDeferredShader(shader); + shader.mCanBindFast = true; + } } void LLPipeline::bindDeferredShader(LLGLSLShader& shader, LLRenderTarget* light_target) @@ -8826,8 +8877,6 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera stop_glerror(); - LLEnvironment& environment = LLEnvironment::instance(); - struct CompareVertexBuffer { bool operator()(const LLDrawInfo* const& lhs, const LLDrawInfo* const& rhs) @@ -8842,7 +8891,6 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera { bool rigged = j == 1; gDeferredShadowProgram.bind(rigged); - LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); gGL.diffuseColor4f(1, 1, 1, 1); @@ -8887,27 +8935,25 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera { LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha"); LL_PROFILE_GPU_ZONE("shadow alpha"); - + const S32 sun_up = LLEnvironment::instance().getIsSunUp() ? 1 : 0; U32 target_width = LLRenderTarget::sCurResX; for (int i = 0; i < 2; ++i) { bool rigged = i == 1; - gDeferredShadowAlphaMaskProgram.bind(rigged); - LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width); - LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); - { LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha masked"); LL_PROFILE_GPU_ZONE("shadow alpha masked"); + gDeferredShadowAlphaMaskProgram.bind(rigged); + LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up); + LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width); renderMaskedObjects(LLRenderPass::PASS_ALPHA_MASK, true, true, rigged); } { LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha blend"); LL_PROFILE_GPU_ZONE("shadow alpha blend"); - LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(0.598f); renderAlphaObjects(rigged); } @@ -8915,8 +8961,8 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow fullbright alpha masked"); LL_PROFILE_GPU_ZONE("shadow alpha masked"); gDeferredShadowFullbrightAlphaMaskProgram.bind(rigged); + LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up); LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width); - LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); renderFullbrightMaskedObjects(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, true, true, rigged); } @@ -8924,9 +8970,10 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera LL_PROFILE_ZONE_NAMED_CATEGORY_PIPELINE("shadow alpha grass"); LL_PROFILE_GPU_ZONE("shadow alpha grass"); gDeferredTreeShadowProgram.bind(rigged); + LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(ALPHA_BLEND_CUTOFF); + if (i == 0) { - LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(0.598f); renderObjects(LLRenderPass::PASS_GRASS, true); } @@ -8945,8 +8992,8 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera { bool rigged = i == 1; gDeferredShadowGLTFAlphaMaskProgram.bind(rigged); + LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up); LLGLSLShader::sCurBoundShaderPtr->uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width); - LLGLSLShader::sCurBoundShaderPtr->uniform1i(LLShaderMgr::SUN_UP_FACTOR, environment.getIsSunUp() ? 1 : 0); gGL.loadMatrix(gGLModelView); gGLLastMatrix = NULL; @@ -9449,14 +9496,7 @@ void LLPipeline::generateSunShadow(LLCamera& camera) if (mSunDiffuse == LLColor4::black) { //sun diffuse is totally black shadows don't matter - LLGLDepthTest depth(GL_TRUE); - - for (S32 j = 0; j < 4; j++) - { - mRT->shadow[j].bindTarget(); - mRT->shadow[j].clear(); - mRT->shadow[j].flush(); - } + skipRenderingShadows(); } else { @@ -9512,7 +9552,8 @@ void LLPipeline::generateSunShadow(LLCamera& camera) std::vector<LLVector3> fp; - if (!gPipeline.getVisiblePointCloud(shadow_cam, min, max, fp, lightDir)) + if (!gPipeline.getVisiblePointCloud(shadow_cam, min, max, fp, lightDir) + || j > RenderShadowSplits) { //no possible shadow receivers if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA) && !gCubeSnapshot) @@ -10051,11 +10092,79 @@ void LLPipeline::renderRiggedGroups(LLRenderPass* pass, U32 type, bool texture) } } -static LLTrace::BlockTimerStatHandle FTM_GENERATE_IMPOSTOR("Generate Impostor"); +void LLPipeline::profileAvatar(LLVOAvatar* avatar, bool profile_attachments) +{ + if (gGLManager.mGLVersion < 3.25f) + { // profiling requires GL 3.3 or later + return; + } + + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; + + // don't continue to profile an avatar that is known to be too slow + llassert(!avatar->isTooSlow()); + + LLGLSLShader* cur_shader = LLGLSLShader::sCurBoundShaderPtr; + + mRT->deferredScreen.bindTarget(); + mRT->deferredScreen.clear(); + + if (!profile_attachments) + { + // profile entire avatar all at once and readback asynchronously + avatar->placeProfileQuery(); + + LLTimer cpu_timer; + + generateImpostor(avatar, false, true); + + avatar->mCPURenderTime = (F32)cpu_timer.getElapsedTimeF32() * 1000.f; + + avatar->readProfileQuery(5); // allow up to 5 frames of latency + } + else + { + // profile attachments one at a time + LLVOAvatar::attachment_map_t::iterator iter; + LLVOAvatar::attachment_map_t::iterator begin = avatar->mAttachmentPoints.begin(); + LLVOAvatar::attachment_map_t::iterator end = avatar->mAttachmentPoints.end(); + + for (iter = begin; + iter != end; + ++iter) + { + LLViewerJointAttachment* attachment = iter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) + { + LLViewerObject* attached_object = attachment_iter->get(); + if (attached_object) + { + // use gDebugProgram to do the GPU queries + gDebugProgram.clearStats(); + gDebugProgram.placeProfileQuery(true); + + generateImpostor(avatar, false, true, attached_object); + gDebugProgram.readProfileQuery(true, true); + + attached_object->mGPURenderTime = gDebugProgram.mTimeElapsed / 1000000.f; + } + } + } + } + + mRT->deferredScreen.flush(); -void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar) + if (cur_shader) + { + cur_shader->bind(); + } +} + +void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar, bool for_profile, LLViewerObject* specific_attachment) { - LL_RECORD_BLOCK_TIME(FTM_GENERATE_IMPOSTOR); + LL_PROFILE_ZONE_SCOPED_CATEGORY_PIPELINE; LL_PROFILE_GPU_ZONE("generateImpostor"); LLGLState::checkStates(); @@ -10073,19 +10182,19 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar) assertInitialized(); // previews can't be muted or impostered - bool visually_muted = !preview_avatar && avatar->isVisuallyMuted(); + bool visually_muted = !for_profile && !preview_avatar && avatar->isVisuallyMuted(); LL_DEBUGS_ONCE("AvatarRenderPipeline") << "Avatar " << avatar->getID() << " is " << ( visually_muted ? "" : "not ") << "visually muted" << LL_ENDL; - bool too_complex = !preview_avatar && avatar->isTooComplex(); + bool too_complex = !for_profile && !preview_avatar && avatar->isTooComplex(); LL_DEBUGS_ONCE("AvatarRenderPipeline") << "Avatar " << avatar->getID() << " is " << ( too_complex ? "" : "not ") << "too complex" << LL_ENDL; - pushRenderTypeMask(); - - if (visually_muted || too_complex) - { + pushRenderTypeMask(); + + if (visually_muted || too_complex) + { // only show jelly doll geometry andRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, LLPipeline::RENDER_TYPE_CONTROL_AV, @@ -10103,6 +10212,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar) RENDER_TYPE_TREE, RENDER_TYPE_VOIDWATER, RENDER_TYPE_WATER, + RENDER_TYPE_ALPHA_POST_WATER, RENDER_TYPE_PASS_GRASS, RENDER_TYPE_HUD, RENDER_TYPE_PARTICLES, @@ -10112,6 +10222,11 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar) ); } + if (specific_attachment && specific_attachment->isHUDAttachment()) + { //enable HUD rendering + setRenderTypeMask(RENDER_TYPE_HUD, END_RENDER_TYPES); + } + S32 occlusion = sUseOcclusion; sUseOcclusion = 0; @@ -10168,20 +10283,30 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar) } else { - LLVOAvatar::attachment_map_t::iterator iter; - for (iter = avatar->mAttachmentPoints.begin(); - iter != avatar->mAttachmentPoints.end(); - ++iter) + if (specific_attachment) { - LLViewerJointAttachment *attachment = iter->second; - for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); - attachment_iter != attachment->mAttachedObjects.end(); - ++attachment_iter) + markVisible(specific_attachment->mDrawable->getSpatialBridge(), *viewer_camera); + } + else + { + LLVOAvatar::attachment_map_t::iterator iter; + LLVOAvatar::attachment_map_t::iterator begin = avatar->mAttachmentPoints.begin(); + LLVOAvatar::attachment_map_t::iterator end = avatar->mAttachmentPoints.end(); + + for (iter = begin; + iter != end; + ++iter) { - LLViewerObject* attached_object = attachment_iter->get(); - if (attached_object) + LLViewerJointAttachment* attachment = iter->second; + for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin(); + attachment_iter != attachment->mAttachedObjects.end(); + ++attachment_iter) { - markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera); + LLViewerObject* attached_object = attachment_iter->get(); + if (attached_object) + { + markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera); + } } } } @@ -10251,25 +10376,28 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar) resY = llmin(nhpo2((U32) (fov*pa)), (U32) 512); resX = llmin(nhpo2((U32) (atanf(tdim.mV[0]/distance)*2.f*RAD_TO_DEG*pa)), (U32) 512); - if (!avatar->mImpostor.isComplete()) - { - avatar->mImpostor.allocate(resX, resY, GL_RGBA, true); + if (!for_profile) + { + if (!avatar->mImpostor.isComplete()) + { + avatar->mImpostor.allocate(resX, resY, GL_RGBA, true); - if (LLPipeline::sRenderDeferred) - { - addDeferredAttachments(avatar->mImpostor, true); - } - - gGL.getTexUnit(0)->bind(&avatar->mImpostor); - gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); - gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); - } - else if(resX != avatar->mImpostor.getWidth() || resY != avatar->mImpostor.getHeight()) - { - avatar->mImpostor.resize(resX,resY); - } + if (LLPipeline::sRenderDeferred) + { + addDeferredAttachments(avatar->mImpostor, true); + } + + gGL.getTexUnit(0)->bind(&avatar->mImpostor); + gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT); + gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE); + } + else if (resX != avatar->mImpostor.getWidth() || resY != avatar->mImpostor.getHeight()) + { + avatar->mImpostor.resize(resX, resY); + } - avatar->mImpostor.bindTarget(); + avatar->mImpostor.bindTarget(); + } } F32 old_alpha = LLDrawPoolAvatar::sMinimumAlpha; @@ -10279,9 +10407,9 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar) LLDrawPoolAvatar::sMinimumAlpha = 0.f; } - if (preview_avatar) + if (preview_avatar || for_profile) { - // previews don't care about imposters + // previews and profiles don't care about imposters renderGeomDeferred(camera); renderGeomPostDeferred(camera); } @@ -10310,6 +10438,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar) LLDrawPoolAvatar::sMinimumAlpha = old_alpha; + if (!for_profile) { //create alpha mask based on depth buffer (grey out if muted) if (LLPipeline::sRenderDeferred) { @@ -10371,7 +10500,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar) gGL.popMatrix(); } - if (!preview_avatar) + if (!preview_avatar && !for_profile) { avatar->mImpostor.flush(); avatar->setImpostorDim(tdim); @@ -10388,7 +10517,7 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar, bool preview_avatar) gGL.matrixMode(LLRender::MM_MODELVIEW); gGL.popMatrix(); - if (!preview_avatar) + if (!preview_avatar && !for_profile) { avatar->mNeedsImpostorUpdate = FALSE; avatar->cacheImpostorValues(); @@ -10713,9 +10842,32 @@ void LLPipeline::restoreHiddenObject( const LLUUID& id ) } } +void LLPipeline::skipRenderingShadows() +{ + LLGLDepthTest depth(GL_TRUE); + + for (S32 j = 0; j < 4; j++) + { + mRT->shadow[j].bindTarget(); + mRT->shadow[j].clear(); + mRT->shadow[j].flush(); + } +} + +void LLPipeline::handleShadowDetailChanged() +{ + if (RenderShadowDetail > gSavedSettings.getS32("RenderShadowDetail")) + { + skipRenderingShadows(); + } + else + { + LLViewerShaderMgr::instance()->setShaders(); + } +} + void LLPipeline::overrideEnvironmentMap() { //mReflectionMapManager.mProbes.clear(); //mReflectionMapManager.addProbe(LLViewerCamera::instance().getOrigin()); } - diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 64a26c264a..4654f05694 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -132,7 +132,17 @@ public: bool allocateShadowBuffer(U32 resX, U32 resY); void resetVertexBuffers(LLDrawable* drawable); - void generateImpostor(LLVOAvatar* avatar, bool preview_avatar = false); + + // perform a profile of the given avatar + // if profile_attachments is true, run a profile for each attachment + void profileAvatar(LLVOAvatar* avatar, bool profile_attachments = false); + + // generate an impostor for the given avatar + // preview_avatar - if true, a preview window render is being performed + // for_profile - if true, a profile is being performed, do not update actual impostor + // specific_attachment - specific attachment to profile, or nullptr to profile entire avatar + void generateImpostor(LLVOAvatar* avatar, bool preview_avatar = false, bool for_profile = false, LLViewerObject* specific_attachment = nullptr); + void bindScreenToTexture(); void renderFinalize(); void copyScreenSpaceReflections(LLRenderTarget* src, LLRenderTarget* dst); @@ -366,6 +376,8 @@ public: bool hasRenderType(const U32 type) const; bool hasAnyRenderType(const U32 type, ...) const; + static bool isWaterClip(); + void setRenderTypeMask(U32 type, ...); // This is equivalent to 'setRenderTypeMask' //void orRenderTypeMask(U32 type, ...); @@ -435,6 +447,7 @@ public: void skipRenderingOfTerrain( bool flag ); void hideObject( const LLUUID& id ); void restoreHiddenObject( const LLUUID& id ); + void handleShadowDetailChanged(); LLReflectionMapManager mReflectionMapManager; void overrideEnvironmentMap(); @@ -449,6 +462,7 @@ private: void connectRefreshCachedSettingsSafe(const std::string name); void hideDrawable( LLDrawable *pDrawable ); void unhideDrawable( LLDrawable *pDrawable ); + void skipRenderingShadows(); public: enum {GPU_CLASS_MAX = 3 }; @@ -591,7 +605,6 @@ public: RENDER_DEBUG_PHYSICS_SHAPES = 0x02000000, RENDER_DEBUG_NORMALS = 0x04000000, RENDER_DEBUG_LOD_INFO = 0x08000000, - RENDER_DEBUG_RENDER_COMPLEXITY = 0x10000000, RENDER_DEBUG_ATTACHMENT_BYTES = 0x20000000, // not used RENDER_DEBUG_TEXEL_DENSITY = 0x40000000, RENDER_DEBUG_TRIANGLE_COUNT = 0x80000000, @@ -765,7 +778,6 @@ protected: U64 mOldRenderDebugMask; std::stack<U32> mRenderDebugFeatureStack; - ///////////////////////////////////////////// // // @@ -959,6 +971,7 @@ public: static U32 RenderResolutionDivisor; static bool RenderUIBuffer; static S32 RenderShadowDetail; + static S32 RenderShadowSplits; static bool RenderDeferredSSAO; static F32 RenderShadowResolutionScale; static bool RenderLocalLights; diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml index 8bb3feaeb0..6efe302f30 100644 --- a/indra/newview/skins/default/colors.xml +++ b/indra/newview/skins/default/colors.xml @@ -983,12 +983,15 @@ name="OutfitGalleryItemUnselected" value="0.4 0.4 0.4 1" /> <color - name="AddPaymentPanel" + name="PanelGray" value="0.27 0.27 0.27 1" /> <color + name="PerformanceMid" + value="1 0.8 0 1" /> + <color name="OutfitSnapshotMacMask" value="0.115 0.115 0.115 1"/> - <color - name="OutfitSnapshotMacMask2" - value="0.1 0.1 0.1 1"/> + <color + name="OutfitSnapshotMacMask2" + value="0.1 0.1 0.1 1"/> </colors> diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml index bdf12d73fc..61257466aa 100644 --- a/indra/newview/skins/default/textures/textures.xml +++ b/indra/newview/skins/default/textures/textures.xml @@ -150,6 +150,7 @@ with the same filename but different name <texture name="Command_Move_Icon" file_name="toolbar_icons/move.png" preload="true" /> <texture name="Command_Environments_Icon" file_name="toolbar_icons/environments.png" preload="true" /> <texture name="Command_People_Icon" file_name="toolbar_icons/people.png" preload="true" /> + <texture name="Command_Performance_Icon" file_name="toolbar_icons/performance.png" preload="true" /> <texture name="Command_Picks_Icon" file_name="toolbar_icons/picks.png" preload="true" /> <texture name="Command_Places_Icon" file_name="toolbar_icons/places.png" preload="true" /> <texture name="Command_Preferences_Icon" file_name="toolbar_icons/preferences.png" preload="true" /> diff --git a/indra/newview/skins/default/textures/toolbar_icons/performance.png b/indra/newview/skins/default/textures/toolbar_icons/performance.png Binary files differnew file mode 100644 index 0000000000..91baf849c8 --- /dev/null +++ b/indra/newview/skins/default/textures/toolbar_icons/performance.png diff --git a/indra/newview/skins/default/xui/en/floater_add_payment_method.xml b/indra/newview/skins/default/xui/en/floater_add_payment_method.xml index 1f980564d4..ac88263aa1 100644 --- a/indra/newview/skins/default/xui/en/floater_add_payment_method.xml +++ b/indra/newview/skins/default/xui/en/floater_add_payment_method.xml @@ -19,7 +19,7 @@ </floater.string> <panel background_opaque="false" - bg_alpha_color="AddPaymentPanel" + bg_alpha_color="PanelGray" border_visible="false" background_visible="true" label="wrapper_panel" diff --git a/indra/newview/skins/default/xui/en/floater_adjust_environment.xml b/indra/newview/skins/default/xui/en/floater_adjust_environment.xml index ca5c7fe264..aef923feb2 100644 --- a/indra/newview/skins/default/xui/en/floater_adjust_environment.xml +++ b/indra/newview/skins/default/xui/en/floater_adjust_environment.xml @@ -239,7 +239,7 @@ layout="topleft" left_delta="-5" top_pad="15" - width="80">Scene Gamma:</text> + width="80">Brightness:</text> <slider decimal_digits="2" follows="left|top" height="16" diff --git a/indra/newview/skins/default/xui/en/floater_avatar_render_settings.xml b/indra/newview/skins/default/xui/en/floater_avatar_render_settings.xml index e088d4d2a1..d222dca98b 100644 --- a/indra/newview/skins/default/xui/en/floater_avatar_render_settings.xml +++ b/indra/newview/skins/default/xui/en/floater_avatar_render_settings.xml @@ -10,7 +10,7 @@ save_rect="true" single_instance="true" reuse_instance="true" - title="AVATAR RENDER SETTINGS" + title="AVATAR DISPLAY EXCEPTIONS" width="300"> <string name="av_never_render" @@ -18,53 +18,45 @@ <string name="av_always_render" value="Always"/> - <filter_editor - follows="left|top|right" - height="23" - layout="topleft" - left="8" - right="-47" - label="Filter People" - max_length_chars="300" - name="people_filter_input" - text_color="Black" - text_pad_left="10" - top="4" /> - <menu_button - follows="top|right" - height="25" - image_hover_unselected="Toolbar_Middle_Over" - image_overlay="AddItem_Off" - image_selected="Toolbar_Middle_Selected" - image_unselected="Toolbar_Middle_Off" - layout="topleft" - left_pad="7" - menu_filename="menu_avatar_rendering_settings_add.xml" - menu_position="bottomleft" - name="plus_btn" - tool_tip="Actions on selected person" - top="3" - width="31" /> <name_list - bottom="-8" + bottom="-33" draw_heading="true" follows="all" left="8" multi_select="false" name="render_settings_list" right="-8" - top="32"> + top="0"> <name_list.columns label="Name" name="name" - relative_width="0.5" /> + relative_width="0.65" /> <name_list.columns - label="Render setting" + label="Full detail" name="setting" - relative_width="0.25" /> - <name_list.columns - label="Date added" - name="timestamp" - relative_width="0.25" /> + relative_width="0.35" /> </name_list> + <panel + bg_alpha_color="ScrollBgWriteableColor" + background_visible="true" + background_opaque="false" + bevel_style="none" + follows="bottom|left|right" + name="add_subpanel" + layout="topleft" + height="28" + top_pad="0"> + <menu_button + follows="bottom|left" + height="25" + label="Add someone..." + layout="topleft" + menu_filename="menu_avatar_rendering_settings_add.xml" + menu_position="bottomleft" + name="plus_btn" + tool_tip="Actions on selected person" + top="1" + left="8" + width="120" /> + </panel> </floater> diff --git a/indra/newview/skins/default/xui/en/floater_performance.xml b/indra/newview/skins/default/xui/en/floater_performance.xml new file mode 100644 index 0000000000..d1a1119f77 --- /dev/null +++ b/indra/newview/skins/default/xui/en/floater_performance.xml @@ -0,0 +1,368 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<floater + height="642" + layout="topleft" + name="performance" + save_rect="true" + reuse_instance="true" + title="IMPROVE GRAPHICS SPEED" + width="580"> + <string + name="fps_text" + value="frames per second"/> + <string + name="max_text" + value=" (maximum)"/> + <panel + bevel_style="none" + follows="left|top" + height="540" + width="580" + name="panel_top" + visible="true" + layout="topleft" + left="0" + top="0"> + <panel + bg_alpha_color="black" + background_visible="true" + background_opaque="false" + border="false" + bevel_style="none" + follows="left|top" + height="40" + width="560" + name="fps_subpanel" + layout="topleft" + left="10" + top="5"> + <text + follows="left|top" + font="SansSerifHuge" + text_color="White" + height="20" + layout="topleft" + left="10" + top="8" + name="fps_value" + width="42"> + 167 + </text> + <text + follows="left|top" + font="SansSerifLarge" + text_color="White" + height="20" + layout="topleft" + left_pad="3" + top="13" + name="fps_lbl" + width="450"> + frames per second + </text> + <text + follows="left|top" + text_color="White" + height="20" + layout="topleft" + left="395" + top="7" + name="fps_desc1_lbl" + width="150"> + Allow 5-10 seconds for + </text> + <text + follows="left|top" + text_color="White" + height="20" + layout="topleft" + top_pad="-3" + name="fps_desc2_lbl" + width="150"> + changes to take full effect. + </text> + </panel> + </panel> + <panel + bevel_style="none" + follows="left|top" + height="540" + width="580" + name="panel_performance_main" + visible="true" + layout="topleft" + left="0" + top="60"> + <panel + bg_alpha_color="PanelGray" + background_visible="true" + background_opaque="false" + border="true" + bevel_style="none" + follows="left|top" + height="50" + width="560" + name="autoadjustments_subpanel" + layout="topleft" + left="10" + top="5"> + <text + follows="left|top" + font="SansSerifBoldLarge" + text_color="White" + height="20" + layout="topleft" + left="10" + name="auto_adj_lbl" + top="7" + width="375"> + Auto-adjust settings (recommended) + </text> + <text + follows="left|top" + font="SansSerif" + text_color="White" + height="20" + layout="topleft" + left="10" + name="auto_adj_desc" + top_pad="0" + width="485"> + Allow automatic adjustments to reach your preferred frame rate. + </text> + <icon + height="16" + width="16" + image_name="Arrow_Right_Off" + mouse_opaque="true" + name="icon_arrow4" + follows="right|top" + top="19" + right="-20"/> + </panel> + <panel + bg_alpha_color="PanelGray" + background_visible="true" + background_opaque="false" + border="true" + bevel_style="none" + follows="left|top" + height="50" + width="560" + name="settings_subpanel" + layout="topleft" + top_pad="10"> + <text + follows="left|top" + font="SansSerifLarge" + text_color="White" + height="20" + layout="topleft" + left="10" + name="settings_lbl" + top="7" + width="180"> + Graphics settings + </text> + <text + follows="left|top" + font="SansSerif" + text_color="White" + height="20" + layout="topleft" + left="10" + name="settings_desc" + top_pad="0" + width="395"> + Choose settings for distance, water, lighting and more. + </text> + <icon + height="16" + width="16" + image_name="Arrow_Right_Off" + mouse_opaque="true" + name="icon_arrow3" + follows="right|top" + top="19" + right="-20"/> + </panel> + <panel + bg_alpha_color="PanelGray" + background_visible="true" + background_opaque="false" + border="true" + bevel_style="none" + follows="left|top" + height="50" + width="560" + name="nearby_subpanel" + layout="topleft" + top_pad="10"> + <text + follows="left|top" + font="SansSerifLarge" + text_color="White" + height="20" + layout="topleft" + left="10" + name="avatars_nearby_lbl" + top="7" + width="205"> + Avatars nearby + </text> + <text + follows="left|top" + font="SansSerif" + text_color="White" + height="20" + layout="topleft" + left="10" + name="avatars_nearby_desc" + top_pad="0" + width="395"> + Manage which nearby avatars are fully displayed. + </text> + <icon + height="16" + width="16" + image_name="Arrow_Right_Off" + mouse_opaque="true" + name="icon_arrow2" + follows="right|top" + top="19" + right="-20"/> + </panel> + <panel + bg_alpha_color="PanelGray" + background_visible="true" + background_opaque="false" + border="true" + bevel_style="none" + follows="left|top" + height="50" + width="560" + name="complexity_subpanel" + layout="topleft" + top_pad="10"> + <text + follows="left|top" + font="SansSerifLarge" + text_color="White" + height="20" + layout="topleft" + left="10" + name="complexity_lbl" + top="7" + width="180"> + Your avatar complexity + </text> + <text + follows="left|top" + font="SansSerif" + text_color="White" + height="20" + layout="topleft" + left="10" + name="complexity_info" + top_pad="0" + width="455"> + Reduce the complexity of your avatar if you aren't satisfied with current FPS. + </text> + <icon + height="16" + width="16" + image_name="Arrow_Right_Off" + mouse_opaque="true" + name="icon_arrow4" + follows="right|top" + top="19" + right="-20"/> + </panel> + <panel + bg_alpha_color="PanelGray" + background_visible="true" + background_opaque="false" + border="true" + bevel_style="none" + follows="left|top" + height="50" + width="560" + name="huds_subpanel" + layout="topleft" + top_pad="10"> + <text + follows="left|top" + font="SansSerifLarge" + text_color="White" + height="20" + layout="topleft" + left="10" + name="huds_lbl" + top="7" + width="135"> + Your active HUDs + </text> + <text + follows="left|top" + font="SansSerif" + text_color="White" + height="20" + layout="topleft" + left="10" + name="huds_desc" + top_pad="0" + width="395"> + Removing HUDs you are not using can improve speed. + </text> + <icon + height="16" + width="16" + image_name="Arrow_Right_Off" + mouse_opaque="true" + name="icon_arrow4" + follows="right|top" + top="19" + right="-20"/> + </panel> + </panel> + <panel + filename="panel_performance_nearby.xml" + follows="all" + layout="topleft" + left="0" + name="panel_performance_nearby" + visible="false" + top="55" /> + <panel + filename="panel_performance_complexity.xml" + follows="all" + layout="topleft" + left="0" + name="panel_performance_complexity" + visible="false" + top="55" /> + <panel + filename="panel_performance_preferences.xml" + follows="all" + layout="topleft" + left="0" + name="panel_performance_preferences" + visible="false" + top="55" /> + <panel + filename="panel_performance_huds.xml" + follows="all" + layout="topleft" + left="0" + name="panel_performance_huds" + visible="false" + top="55" /> + <panel + filename="panel_performance_autoadjustments.xml" + follows="all" + layout="topleft" + left="0" + name="panel_performance_autoadjustments" + visible="false" + top="55" /> +</floater> diff --git a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml index 22e889a99c..fd80673903 100644 --- a/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml +++ b/indra/newview/skins/default/xui/en/floater_preferences_graphics_advanced.xml @@ -39,7 +39,8 @@ max_val="512" name="DrawDistance" top_delta="16" - width="330" /> + width="330"> + </slider> <text type="string" length="1" @@ -459,8 +460,8 @@ label_width="185" layout="topleft" left="420" - min_val="1" - max_val="2" + min_val="0" + max_val="4" name="ObjectMeshDetail" show_text="false" top_delta="16" diff --git a/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml b/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml index 2abd8ec5c0..37efbe654e 100644 --- a/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml +++ b/indra/newview/skins/default/xui/en/floater_scene_load_stats.xml @@ -410,6 +410,59 @@ </stat_view> </stat_view> </stat_view> + <stat_view + name="frame_stats" + label="Frame breakdown" + show_label="true"> + <stat_bar name="packet_loss" + label="Scenery" + orientation="horizontal" + unit_label=" %" + stat="scenery_frame_pct" + bar_max="100" + tick_spacing="0.5" + show_bar="false"/> + <stat_bar name="packet_loss" + label="Avatar" + orientation="horizontal" + unit_label=" %" + stat="avatar_frame_pct" + bar_max="100" + tick_spacing="0.5" + show_bar="false"/> + <stat_bar name="packet_loss" + label="UI" + orientation="horizontal" + unit_label=" %" + stat="ui_frame_pct" + bar_max="100" + tick_spacing="0.5" + show_bar="false"/> + <stat_bar name="packet_loss" + label="HUDs" + orientation="horizontal" + unit_label=" %" + stat="huds_frame_pct" + bar_max="100" + tick_spacing="0.5" + show_bar="false"/> + <stat_bar name="packet_loss" + label="Swap" + orientation="horizontal" + unit_label=" %" + stat="swap_frame_pct" + bar_max="100" + tick_spacing="0.5" + show_bar="false"/> + <stat_bar name="packet_loss" + label="Tasks" + orientation="horizontal" + unit_label=" %" + stat="idle_frame_pct" + bar_max="100" + tick_spacing="0.5" + show_bar="false"/> + </stat_view> </container_view> </scroll_container> </floater> diff --git a/indra/newview/skins/default/xui/en/menu_attachment_other.xml b/indra/newview/skins/default/xui/en/menu_attachment_other.xml index 7ad692038e..22006c287f 100644 --- a/indra/newview/skins/default/xui/en/menu_attachment_other.xml +++ b/indra/newview/skins/default/xui/en/menu_attachment_other.xml @@ -131,22 +131,12 @@ <menu_item_separator /> <context_menu - label="Render Avatar" + label="Display this avatar" layout="topleft" - name="Render Avatar"> - <menu_item_check - name="RenderNormally" - label="Default"> - <menu_item_check.on_check - function="Avatar.CheckImpostorMode" - parameter="0" /> - <menu_item_check.on_click - function="Avatar.SetImpostorMode" - parameter="0" /> - </menu_item_check> + name="Render Avatar"> <menu_item_check name="AlwaysRenderFully" - label="Always"> + label="Always full detail"> <menu_item_check.on_check function="Avatar.CheckImpostorMode" parameter="2" /> @@ -156,7 +146,7 @@ </menu_item_check> <menu_item_check name="DoNotRender" - label="Never"> + label="Never full detail"> <menu_item_check.on_check function="Avatar.CheckImpostorMode" parameter="1" /> @@ -164,6 +154,16 @@ function="Avatar.SetImpostorMode" parameter="1" /> </menu_item_check> + <menu_item_call + name="RenderNormally" + label="Remove from exceptions"> + <menu_item_call.on_visible + function="Avatar.CheckImpostorMode" + parameter="4" /> + <menu_item_call.on_click + function="Avatar.SetImpostorMode" + parameter="0" /> + </menu_item_call> <menu_item_separator /> <menu_item_call label="Exceptions..." diff --git a/indra/newview/skins/default/xui/en/menu_avatar_other.xml b/indra/newview/skins/default/xui/en/menu_avatar_other.xml index acbb9b860d..665eb9a82f 100644 --- a/indra/newview/skins/default/xui/en/menu_avatar_other.xml +++ b/indra/newview/skins/default/xui/en/menu_avatar_other.xml @@ -122,39 +122,39 @@ <menu_item_separator /> <context_menu - label="Render Avatar" + label="Display this avatar" layout="topleft" - name="Render Avatar"> - <menu_item_check - name="RenderNormally" - label="Default"> - <menu_item_check.on_check - function="Avatar.CheckImpostorMode" - parameter="0" /> - <menu_item_check.on_click - function="Avatar.SetImpostorMode" - parameter="0" /> - </menu_item_check> - <menu_item_check - name="AlwaysRenderFully" - label="Always"> - <menu_item_check.on_check - function="Avatar.CheckImpostorMode" - parameter="2" /> - <menu_item_check.on_click - function="Avatar.SetImpostorMode" - parameter="2" /> - </menu_item_check> - <menu_item_check - name="DoNotRender" - label="Never"> - <menu_item_check.on_check - function="Avatar.CheckImpostorMode" - parameter="1" /> - <menu_item_check.on_click - function="Avatar.SetImpostorMode" - parameter="1" /> - </menu_item_check> + name="Render Avatar"> + <menu_item_check + name="AlwaysRenderFully" + label="Always full detail"> + <menu_item_check.on_check + function="Avatar.CheckImpostorMode" + parameter="2" /> + <menu_item_check.on_click + function="Avatar.SetImpostorMode" + parameter="2" /> + </menu_item_check> + <menu_item_check + name="DoNotRender" + label="Never full detail"> + <menu_item_check.on_check + function="Avatar.CheckImpostorMode" + parameter="1" /> + <menu_item_check.on_click + function="Avatar.SetImpostorMode" + parameter="1" /> + </menu_item_check> + <menu_item_call + name="RenderNormally" + label="Remove from exceptions"> + <menu_item_call.on_visible + function="Avatar.CheckImpostorMode" + parameter="4" /> + <menu_item_call.on_click + function="Avatar.SetImpostorMode" + parameter="0" /> + </menu_item_call> <menu_item_separator /> <menu_item_call label="Exceptions..." diff --git a/indra/newview/skins/default/xui/en/menu_avatar_rendering_settings.xml b/indra/newview/skins/default/xui/en/menu_avatar_rendering_settings.xml index 5163cd3115..1a18483418 100644 --- a/indra/newview/skins/default/xui/en/menu_avatar_rendering_settings.xml +++ b/indra/newview/skins/default/xui/en/menu_avatar_rendering_settings.xml @@ -3,24 +3,25 @@ layout="topleft" name="Settings"> <menu_item_check - label="Default" - layout="topleft" - name="default"> - <on_click function="Settings.SetRendering" parameter="default"/> - <on_check function="Settings.IsSelected" parameter="default" /> - </menu_item_check> - <menu_item_check - label="Always render" + label="Always full detail" layout="topleft" name="always_render"> <on_click function="Settings.SetRendering" parameter="always"/> - <on_check function="Settings.IsSelected" parameter="always" /> + <on_check function="Settings.IsSelected" parameter="always" /> </menu_item_check> <menu_item_check - label="Never render" + label="Never full detail" layout="topleft" name="never_render"> <on_click function="Settings.SetRendering" parameter="never"/> - <on_check function="Settings.IsSelected" parameter="never" /> - </menu_item_check> + <on_check function="Settings.IsSelected" parameter="never" /> + </menu_item_check> + <menu_item_check + label="Remove from exceptions" + layout="topleft" + name="default"> + <on_click function="Settings.SetRendering" parameter="default"/> + <on_check function="Settings.IsSelected" parameter="default" /> + <on_visible function="Settings.IsSelected" parameter="non_default" /> + </menu_item_check> </context_menu> diff --git a/indra/newview/skins/default/xui/en/menu_avatar_rendering_settings_add.xml b/indra/newview/skins/default/xui/en/menu_avatar_rendering_settings_add.xml index c64b24ed70..6e09eb5981 100644 --- a/indra/newview/skins/default/xui/en/menu_avatar_rendering_settings_add.xml +++ b/indra/newview/skins/default/xui/en/menu_avatar_rendering_settings_add.xml @@ -4,13 +4,13 @@ left="0" bottom="0" visible="false" mouse_opaque="false"> <menu_item_call - label="Always Render a Resident..." + label="Always full detail..." name="add_avatar_always_render"> <on_click function="Settings.AddNewEntry" parameter="always"/> </menu_item_call> <menu_item_call - label="Never Render a Resident..." + label="Never full detail..." name="add_avatar_never_render"> <on_click function="Settings.AddNewEntry" parameter="never"/> diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml index 4a92bdc601..df067d2b88 100644 --- a/indra/newview/skins/default/xui/en/menu_viewer.xml +++ b/indra/newview/skins/default/xui/en/menu_viewer.xml @@ -862,7 +862,16 @@ parameter="UseDebugMenus" /> </menu_item_check> </menu> - + <menu_item_check + label="Improve graphics speed..." + name="Performance"> + <menu_item_check.on_click + function="Floater.Toggle" + parameter="performance" /> + <menu_item_check.on_check + function="Floater.Visible" + parameter="performance" /> + </menu_item_check> <menu_item_separator/> <!-- <menu_item_check label="Show Navigation Bar" @@ -1492,7 +1501,28 @@ function="World.EnvPreset" function="ToggleControl" parameter="ShowSelectionBeam" /> </menu_item_check> - + <menu_item_check + label="Highlight Transparent" + name="Highlight Transparent" + shortcut="control|alt|T" + use_mac_ctrl="true"> + <menu_item_check.on_check + function="View.CheckHighlightTransparent" /> + <menu_item_check.on_click + function="View.HighlightTransparent" /> + </menu_item_check> + <menu_item_separator/> + + <menu_item_check + label="No Post" + name="No Post"> + <menu_item_check.on_check + control="RenderDisablePostProcessing" /> + <menu_item_check.on_click + function="ToggleControl" + parameter="RenderDisablePostProcessing" /> + </menu_item_check> + <menu_item_separator/> <menu_item_check @@ -1902,16 +1932,6 @@ function="World.EnvPreset" parameter="HideSelectedObjects" /> </menu_item_check> <menu_item_check - label="Highlight Transparent" - name="Highlight Transparent" - shortcut="control|alt|T" - use_mac_ctrl="true"> - <menu_item_check.on_check - function="View.CheckHighlightTransparent" /> - <menu_item_check.on_click - function="View.HighlightTransparent" /> - </menu_item_check> - <menu_item_check label="Show Mouselook Crosshairs" name="ShowCrosshairs"> <menu_item_check.on_check diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml index bf67118eac..4949075f2d 100644 --- a/indra/newview/skins/default/xui/en/notifications.xml +++ b/indra/newview/skins/default/xui/en/notifications.xml @@ -1900,6 +1900,41 @@ Graphics Quality can be raised in Preferences > Graphics. <notification icon="alertmodal.tga" + name="AutoFPSConfirmDisable" + type="alertmodal"> +Changing this setting will disable automatic adjustment and turn off 'Automatic settings'. +Are you sure you want to continue? + <tag>confirm</tag> + <usetemplate + name="okcancelbuttons" + notext="Cancel" + yestext="Continue"/> + </notification> + <notification + icon="alertmodal.tga" + name="AdvancedLightingConfirm" + type="alertmodal"> +To turn on advanced lighting, we need to increase quality to level 4. + <tag>confirm</tag> + <usetemplate + name="okcancelbuttons" + notext="Cancel" + yestext="OK"/> + </notification> + <notification + icon="alertmodal.tga" + name="ShadowsConfirm" + type="alertmodal"> +To enable shadows, we need to increase quality to level 4. + <tag>confirm</tag> + <usetemplate + name="okcancelbuttons" + notext="Cancel" + yestext="OK"/> + </notification> + + <notification + icon="alertmodal.tga" name="RegionNoTerraforming" type="alertmodal"> The region [REGION] does not allow terraforming. @@ -12029,6 +12064,20 @@ If you want others to see this object, remove it and re-attach it to an avatar a yestext="OK"/> </notification> + <notification + icon="alertmodal.tga" + name="EnableAutoFPSWarning" + type="alertmodal"> +You are about to enable AutoFPS. All unsaved graphics settings will be lost. + +Would you like to save them first? + <tag>confirm</tag> + <usetemplate + name="okcancelbuttons" + notext="No" + yestext="Yes"/> + </notification> + <notification icon="notifytip.tga" name="MaterialCreated" diff --git a/indra/newview/skins/default/xui/en/panel_performance_autoadjustments.xml b/indra/newview/skins/default/xui/en/panel_performance_autoadjustments.xml new file mode 100644 index 0000000000..904ce1cc52 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_performance_autoadjustments.xml @@ -0,0 +1,387 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + bevel_style="none" + follows="left|top" + height="580" + width="580" + name="panel_performance_autoadjustments" + layout="topleft" + left="0" + top="0"> + <button + height="16" + width="16" + layout="topleft" + mouse_opaque="true" + follows="left|top" + name="back_btn" + top="7" + image_selected="Arrow_Left_Off" + image_pressed="Arrow_Left_Off" + image_unselected="Arrow_Left_Off" + left="15" + is_toggle="true"> + </button> + <text + follows="left|top" + height="18" + layout="topleft" + left_pad="0" + valign="center" + halign="center" + top="6" + name="back_lbl" + width="32"> + Back + </text> + <text + follows="left|top" + font="SansSerifLarge" + text_color="white" + height="20" + layout="topleft" + left="20" + top_pad="15" + name="settings_title" + width="300"> + Auto-adjust settings + </text> + <button + follows="top|left" + height="23" + label="Reset to recommended settings" + layout="topleft" + left="360" + name="defaults_btn" + top_delta="0" + width="200"/> + <view_border + bevel_style="in" + height="0" + layout="topleft" + name="border0" + top_pad="15" + left="20" + width="540"/> + <text + follows="left|top" + font="SansSerif" + text_color="White" + height="20" + layout="topleft" + left="20" + name="targetfps_desc" + wrap="true" + width="115" + top_pad="20"> + Desired frame rate + </text> + <spinner + name="target_fps" + control_name="TargetFPS" + font="SansSerifLarge" + tool_tip="The viewer will attempt to achieve this by adjusting your graphics settings." + layout="topleft" + follows="left|top" + left_pad="25" + top_delta="0" + height="25" + visible="true" + decimal_digits="0" + increment="1" + initial_value="25" + max_val="300" + min_val="1" + width="48" + label_width="0" /> + <text + follows="left|top" + text_color="White" + height="20" + layout="topleft" + name="display_desc" + top_delta="5" + left_pad="15" + wrap="true" + width="225"> + Your display supports up to [FPS_LIMIT] fps. + </text> + <text + follows="left|top" + font="SansSerif" + text_color="White" + height="20" + layout="topleft" + left="20" + name="settings_desc" + top_pad="15" + wrap="true" + width="115"> + Settings affect + </text> + <combo_box + follows="top|left" + font="SansSerif" + height="20" + layout="topleft" + left_pad="25" + control_name="TuningFPSStrategy" + name="TuningFPSStrategy" + width="160"> + <combo_box.item + label="Avatars Only" + name="av_only" + value="0" /> + <combo_box.item + label="Avatars and World" + name="av_and_scene" + value="1" /> + <combo_box.item + label="World Only" + name="scene_only" + value="2" /> + </combo_box> + <button + follows="top|left" + height="22" + image_pressed="PushButton_Press" + image_pressed_selected="PushButton_Selected_Press" + image_selected="PushButton_Selected_Press" + label="Auto-adjust now" + layout="topleft" + top_pad="15" + left="20" + name="start_autotune" + tool_tip="The viewer will attempt to adjust settings to meet the target FPS then stop." + width="124"/> + <button + follows="top|left" + height="22" + image_pressed="PushButton_Press" + image_pressed_selected="PushButton_Selected_Press" + image_selected="PushButton_Selected_Press" + label="Cancel" + layout="topleft" + left_pad="15" + name="stop_autotune" + tool_tip="Stop adjusting settings." + width="90"/> + <text + follows="left|top" + text_color="Yellow" + height="20" + layout="topleft" + name="wip_desc" + top_delta="5" + left_pad="20" + wrap="true" + width="115"> + Working on it... + </text> + <check_box + control_name="AutoTuneLock" + follows="top|left" + height="20" + initial_value="true" + image_pressed="PushButton_Press" + image_pressed_selected="PushButton_Selected_Press" + image_selected="PushButton_Selected_Press" + is_toggle="true" + label="Adjust continuously" + layout="topleft" + left="17" + top_pad="10" + name="AutoTuneContinuous" + tool_tip="The viewer will continually adapt the settings to meet the target FPS until stopped even with the floater closed." + width="64"> + </check_box> + <radio_group + control_name="KeepAutoTuneLock" + enabled_control="AutoTuneLock" + height="50" + layout="topleft" + follows="top|left" + name="autotune_lock_type" + top_pad="5" + left_delta="15" + width="120"> + <radio_item + height="16" + label="This login session only" + layout="topleft" + name="one_session_lock" + value="0" + width="120" /> + <radio_item + height="16" + label="Future login sessions" + layout="topleft" + name="next_session_lock" + value="1" + width="120" /> + </radio_group> + <view_border + bevel_style="in" + height="0" + layout="topleft" + name="border_vsync" + top_pad="3" + left="20" + width="540"/> + <check_box + control_name="RenderVSyncEnable" + height="16" + left="17" + initial_value="true" + label="Enable VSync" + label_text.text_color="White" + layout="topleft" + top_pad="12" + name="vsync" + tool_tip="Enable Vertical synchronization to reduce screen tearing and stuttering." + width="315" /> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + left="20" + top_pad="15" + name="vsync_desc" + width="580"> + Matches monitor refresh rate with frame rate. + </text> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + top_pad="3" + left="20" + name="vsync_desc_limit" + width="580"> + Note: Turning on VSync limits frame rate to [FPS_LIMIT] fps. + </text> + <view_border + bevel_style="in" + height="0" + layout="topleft" + name="border1" + top_pad="10" + left="20" + width="540"/> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + left="20" + top_pad="15" + name="simplify_dist_desc" + width="580"> + Reducing detail shown on avatars that are far away will improve graphics speed. + </text> + <check_box + control_name="AutoTuneImpostorByDistEnabled" + height="19" + label="Simplify avatars beyond" + label_text.text_color="White" + layout="topleft" + follows="top|left" + name="AutoTuneImpostorByDistEnabled" + tool_tip="When enabled the viewer will adjust the MaxNonImpostors setting to limit fully rendered avatars to those within the defined radius." + top_pad="15" + width="190" /> + <spinner + control_name="AutoTuneImpostorFarAwayDistance" + height="20" + layout="topleft" + follows="top|left" + name="ffa_autotune" + left_pad="20" + decimal_digits="2" + min_val="16" + max_val="256" + width="60" > + </spinner> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + left_pad="10" + name="dist_meters" + width="70"> + meters + </text> + <view_border + bevel_style="in" + height="0" + layout="topleft" + name="border2" + top_pad="20" + left="20" + width="540"/> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + left="20" + top_pad="15" + name="dist_limits_desc" + width="580"> + Choose the distance range that automatic settings will affect. + </text> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + top_pad="15" + name="min_dist_lbl" + width="120"> + Minimum distance + </text> + <spinner + control_name="AutoTuneRenderFarClipMin" + height="20" + layout="topleft" + left_pad="15" + follows="top|left" + name="min_dd_autotune" + decimal_digits="2" + min_val="32" + max_val="256" + width="60"> + </spinner> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + top_pad="15" + left="20" + name="pref_dist_lbl" + width="120"> + Maximum distance + </text> + <spinner + control_name="AutoTuneRenderFarClipTarget" + height="20" + layout="topleft" + follows="top|left" + name="pref_dd_autotune" + left_pad="15" + min_val="32" + max_val="256" + width="60"> + </spinner> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_performance_complexity.xml b/indra/newview/skins/default/xui/en/panel_performance_complexity.xml new file mode 100644 index 0000000000..cd3f610a92 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_performance_complexity.xml @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + bevel_style="none" + follows="left|top" + height="580" + width="580" + name="panel_performance_complexity" + layout="topleft" + left="0" + top="0"> + <button + height="16" + width="16" + layout="topleft" + mouse_opaque="true" + follows="left|top" + name="back_btn" + top="7" + image_selected="Arrow_Left_Off" + image_pressed="Arrow_Left_Off" + image_unselected="Arrow_Left_Off" + left="15" + is_toggle="true"> + </button> + <text + follows="left|top" + height="18" + layout="topleft" + left_pad="0" + valign="center" + halign="center" + top="6" + name="back_lbl" + width="32"> + Back + </text> + <text + follows="left|top" + font="SansSerifLarge" + text_color="white" + height="20" + layout="topleft" + left="20" + top_pad="15" + name="attachments_title" + width="195"> + Your avatar complexity + </text> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + top_pad="5" + left="20" + name="attachments_desc1" + width="580"> + Attachments make your avatar more complex. If your avatar is very complex, some other + </text> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + top_pad="3" + left="20" + name="attachments_desc2" + width="580"> + people may not see you in full detail, and your graphics speed may be reduced. Removing + </text> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + top_pad="3" + left="20" + name="attachments_desc3" + width="580"> + heavy attachments that you don’t need can help. + </text> + <name_list + column_padding="0" + draw_stripes="true" + height="429" + follows="left|top" + layout="topleft" + name="obj_list" + top_pad="10" + width="540"> + <name_list.columns + label="" + name="complex_visual" + width="90" /> + <name_list.columns + label="" + name="complex_value" + width="40" /> + <name_list.columns + label="" + name="name"/> + </name_list> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_performance_huds.xml b/indra/newview/skins/default/xui/en/panel_performance_huds.xml new file mode 100644 index 0000000000..2fddcb3b9e --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_performance_huds.xml @@ -0,0 +1,95 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + bevel_style="none" + follows="left|top" + height="580" + width="580" + name="panel_performance_huds" + layout="topleft" + left="0" + top="0"> + <button + height="16" + width="16" + layout="topleft" + mouse_opaque="true" + follows="left|top" + name="back_btn" + top="7" + image_selected="Arrow_Left_Off" + image_pressed="Arrow_Left_Off" + image_unselected="Arrow_Left_Off" + left="15" + is_toggle="true"> + </button> + <text + follows="left|top" + height="18" + layout="topleft" + left_pad="0" + valign="center" + halign="center" + top="6" + name="back_lbl" + width="32"> + Back + </text> + <text + follows="left|top" + font="SansSerifLarge" + text_color="White" + height="20" + layout="topleft" + left="20" + top_pad="15" + name="huds_title" + width="135"> + Your active HUDs + </text> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + top_pad="5" + left="20" + name="huds_desc1" + width="540"> + Detaching HUDs you aren't using saves memory and can make Second Life run faster. + </text> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + top_pad="3" + left="20" + name="huds_desc2" + width="540"> + Note: Using a HUD's minimize button does not detach it. + </text> + <name_list + column_padding="0" + draw_stripes="true" + height="450" + follows="left|top" + layout="topleft" + name="hud_list" + top_pad="10" + width="540"> + <name_list.columns + label="" + name="complex_visual" + width="90" /> + <name_list.columns + label="" + name="complex_value" + width="40" /> + <name_list.columns + label="" + name="name"/> + </name_list> +</panel> + diff --git a/indra/newview/skins/default/xui/en/panel_performance_nearby.xml b/indra/newview/skins/default/xui/en/panel_performance_nearby.xml new file mode 100644 index 0000000000..cb795e59a9 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_performance_nearby.xml @@ -0,0 +1,216 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + bevel_style="none" + follows="left|top" + height="530" + width="580" + name="panel_performance_nearby" + layout="topleft" + left="0" + top="0"> + <button + height="16" + width="16" + layout="topleft" + mouse_opaque="true" + follows="left|top" + name="back_btn" + top="7" + image_selected="Arrow_Left_Off" + image_pressed="Arrow_Left_Off" + image_unselected="Arrow_Left_Off" + left="15" + is_toggle="true"> + </button> + <text + follows="left|top" + height="18" + layout="topleft" + left_pad="0" + valign="center" + halign="center" + top="6" + name="back_lbl" + width="32"> + Back + </text> + <text + follows="left|top" + font="SansSerifLarge" + text_color="White" + height="20" + layout="topleft" + left="20" + top_pad="15" + name="av_nearby_title" + width="205"> + Avatars nearby + </text> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + left="20" + top_pad="5" + name="av_nearby_desc" + width="580"> + Hide the most complex avatars to boost speed. + </text> + <slider + control_name="RenderAvatarMaxART" + tool_tip="Controls when a visually complex avatar is considered to be taking too long to render (unit: microseconds)" + follows="left|top" + height="16" + initial_value="4.7" + increment="0.01" + label="Maximum render time (μs)" + text_color="White" + label_width="165" + layout="topleft" + min_val="2" + max_val="4.7" + name="RenderAvatarMaxART" + show_text="false" + top_pad="10" + width="490"> + </slider> + <text + type="string" + length="1" + follows="left|top" + height="16" + layout="topleft" + top_delta="0" + left_pad="5" + text_color="White" + name="RenderAvatarMaxARTText" + width="65"> + no limit + </text> + <name_list + column_padding="0" + draw_stripes="true" + height="280" + left="20" + follows="left|top" + layout="topleft" + sort_column="complex_value" + short_names="true" + name="nearby_list" + name_column="name" + top_pad="10" + width="540"> + <name_list.columns + label="" + name="complex_visual" + width="90" /> + <name_list.columns + label="" + name="complex_value" + width="50" /> + <name_list.columns + label="" + name="name"/> + </name_list> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + left="20" + top_pad="10" + name="av_nearby_desc2" + width="580"> + You can also right-click on an avatar in-world to control display. + </text> + <button + height="23" + label="Exceptions..." + layout="topleft" + left="460" + top_delta="2" + name="exceptions_btn" + width="100"> + </button> + <check_box + control_name="AlwaysRenderFriends" + height="16" + initial_value="true" + label="Always display friends in full detail" + label_text.text_color="White" + layout="topleft" + name="display_friends" + top_pad="3" + left="18" + width="256"> + </check_box> + <view_border + bevel_style="in" + height="0" + layout="topleft" + name="border" + top_pad="15" + left="20" + width="540"/> + <check_box + height="16" + initial_value="true" + label="Hide avatars completely (good for landscape photos)" + layout="topleft" + name="hide_avatars" + top_delta="15" + left="18" + width="280"> + </check_box> + <text + type="string" + length="1" + follows="left|top" + height="15" + layout="topleft" + left="20" + name="name_tags_textbox" + top_pad="10" + width="400"> + Name tags: + </text> + <radio_group + control_name="AvatarNameTagMode" + height="20" + layout="topleft" + left="120" + top_delta="0" + name="name_tag_mode"> + <radio_item + label="Off" + name="radio" + top_delta="20" + layout="topleft" + height="16" + left="0" + value="0" + width="75" /> + <radio_item + label="On" + left_pad="0" + layout="topleft" + top_delta="0" + height="16" + name="radio2" + value="1" + width="75" /> + <radio_item + label="Show briefly" + left_pad="0" + name="radio3" + height="16" + layout="topleft" + top_delta="0" + value="2" + width="160" /> + </radio_group> + +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_performance_preferences.xml b/indra/newview/skins/default/xui/en/panel_performance_preferences.xml new file mode 100644 index 0000000000..83db17b679 --- /dev/null +++ b/indra/newview/skins/default/xui/en/panel_performance_preferences.xml @@ -0,0 +1,494 @@ +<?xml version="1.0" encoding="utf-8" standalone="yes" ?> +<panel + bevel_style="none" + follows="left|top" + height="580" + width="580" + name="panel_performance_preferences" + layout="topleft" + left="0" + top="0"> + <button + height="16" + width="16" + layout="topleft" + mouse_opaque="true" + follows="left|top" + name="back_btn" + top="7" + image_selected="Arrow_Left_Off" + image_pressed="Arrow_Left_Off" + image_unselected="Arrow_Left_Off" + left="15" + is_toggle="true"> + </button> + <text + follows="left|top" + height="18" + layout="topleft" + left_pad="0" + valign="center" + halign="center" + top="6" + name="back_lbl" + width="32"> + Back + </text> + <text + follows="left|top" + font="SansSerifLarge" + text_color="white" + height="20" + layout="topleft" + left="20" + top_pad="15" + name="settings_title" + width="300"> + Graphics settings + </text> + <button + follows="top|left" + height="23" + label="Open Advanced Settings" + layout="topleft" + left="360" + name="advanced_btn" + top_delta="-35" + width="200"/> + <button + follows="top|left" + height="23" + label="Reset to recommended settings" + layout="topleft" + left="350" + name="defaults_btn" + top_pad="10" + width="210"/> + <view_border + bevel_style="in" + height="0" + layout="topleft" + name="border0" + top_pad="8" + left="20" + width="540"/> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + top_pad="30" + name="quality_lbl" + width="100"> + Quality & Speed + </text> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + left_pad="40" + name="fastest_lbl" + width="40"> + Fastest + </text> + <radio_group + control_name="RenderQualityPerformance" + follows="top|left" + draw_border="false" + height="25" + layout="topleft" + left_pad="5" + name="graphics_quality" + top_delta="0" + width="243"> + <radio_item + height="16" + layout="topleft" + left="3" + name="0" + top="0" + width="7" /> + <radio_item + height="16" + layout="topleft" + left_pad="30" + name="1" + width="7" /> + <radio_item + height="16" + layout="topleft" + left_pad="30" + name="2" + width="7" /> + <radio_item + height="16" + layout="topleft" + left_pad="30" + name="3" + width="7" /> + <radio_item + height="16" + layout="topleft" + left_pad="30" + name="4" + width="7" /> + <radio_item + height="16" + layout="topleft" + left_pad="30" + name="5" + width="7" /> + <radio_item + height="16" + layout="topleft" + left_pad="30" + name="6" + width="7" /> + </radio_group> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + left_pad="10" + top_delta="1" + name="quality_lbl" + width="70"> + Best quality + </text> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + top_pad="15" + left="160" + name="quality_desc" + width="380"> + Choosing a shortcut will reset all manual changes you have made. + </text> + <view_border + bevel_style="in" + height="0" + layout="topleft" + name="border2" + top_pad="5" + left="20" + width="540"/> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + top_pad="20" + left="20" + name="distance_lbl" + width="100"> + Visibility distance + </text> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + left_pad="40" + name="faster_lbl" + width="40"> + Faster + </text> + <slider + control_name="RenderFarClip" + decimal_digits="0" + follows="left|top" + top_delta="-1" + height="16" + increment="8" + initial_value="160" + label_width="90" + layout="topleft" + min_val="64" + max_val="512" + name="draw_distance" + left_pad="5" + width="250"> + </slider> + <text + type="string" + length="1" + follows="left|top" + height="12" + layout="topleft" + left_pad="1" + top_delta="0" + name="draw_distance_m" + width="20"> + m + </text> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + left_pad="10" + top_delta="1" + name="farther_lbl" + width="40"> + Farther + </text> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + top_pad="15" + left="160" + name="distance_desc1" + width="350"> + To see more land when you zoom out, increase the distance. + </text> + <view_border + bevel_style="in" + height="0" + layout="topleft" + name="border3" + top_pad="5" + left="20" + width="540"/> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + top_pad="20" + left="20" + name="environment_lbl" + width="100"> + Shadows + </text> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + top_delta="0" + left="160" + name="enhancements_desc" + width="350"> + Shadows significantly improve visual quality but can reduce speed. + </text> + <text + type="string" + length="1" + follows="left|top" + height="16" + layout="topleft" + left="160" + name="RenderShadowDetailText" + text_readonly_color="LabelDisabledColor" + top_pad="10" + width="128"> + Shadow Detail: + </text> + <combo_box + control_name="RenderShadowDetail" + height="18" + layout="topleft" + left_delta="150" + top_delta="0" + name="ShadowDetail" + width="150"> + <combo_box.item + label="None" + name="0" + value="0"/> + <combo_box.item + label="Sun/Moon" + name="1" + value="1"/> + <combo_box.item + label="Sun/Moon + Projectors" + name="2" + value="2"/> + </combo_box> + <view_border + bevel_style="in" + height="0" + layout="topleft" + name="border3" + top_pad="7" + left="20" + width="540"/> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + top_pad="20" + left="20" + name="water_lbl" + width="100"> + Water + </text> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + top_delta="0" + left="160" + name="water_desc" + width="380"> + Reducing or turning off transparent water may improve frame rate. + </text> + <check_box + control_name="RenderTransparentWater" + height="16" + initial_value="true" + label="Transparent Water" + layout="topleft" + name="TransparentWater" + top_delta="24" + left="157" + width="280"> + </check_box> + <view_border + bevel_style="in" + height="0" + layout="topleft" + name="border4" + top_pad="7" + left="20" + width="540"/> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + top_pad="20" + left="20" + name="photo_lbl" + width="100"> + Photography + </text> + <text + follows="left|top" + font="SansSerifSmall" + text_color="White" + height="18" + layout="topleft" + top_delta="0" + left="160" + name="photo_desc" + width="350"> + Maximum detail is good for photos, but can slow frame rate. + </text> + <spinner + control_name="RenderVolumeLODFactor" + follows="left|top" + height="23" + increment="0.125" + label="Distance detail:" + label_width="95" + layout="topleft" + max_val="4" + min_val="0" + name="render_volume_lod" + top_pad="10" + width="150" /> + <text + follows="left|top" + font="SansSerifSmall" + height="18" + layout="topleft" + top_delta="3" + left_pad="10" + name="photo_desc" + width="180"> + (Enter value between 0.0 and 4.0) + </text> + <text + follows="left|top" + font="SansSerifSmall" + height="18" + layout="topleft" + top="80" + left="213" + name="1_lbl" + width="7"> + 1 + </text> + <text + follows="left|top" + font="SansSerifSmall" + height="18" + layout="topleft" + left_pad="31" + name="2_lbl" + width="7"> + 2 + </text> + <text + follows="left|top" + font="SansSerifSmall" + height="18" + layout="topleft" + left_pad="30" + name="3_lbl" + width="7"> + 3 + </text> + <text + follows="left|top" + font="SansSerifSmall" + height="18" + layout="topleft" + left_pad="30" + name="4_lbl" + width="7"> + 4 + </text> + <text + follows="left|top" + font="SansSerifSmall" + height="18" + layout="topleft" + left_pad="30" + name="5_lbl" + width="7"> + 5 + </text> + <text + follows="left|top" + font="SansSerifSmall" + height="18" + layout="topleft" + left_pad="30" + name="6_lbl" + width="7"> + 6 + </text> + <text + follows="left|top" + font="SansSerifSmall" + height="18" + layout="topleft" + left_pad="30" + name="7_lbl" + width="7"> + 7 + </text> +</panel> diff --git a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml index 38d364cf9a..74a44b6b09 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml @@ -231,6 +231,18 @@ m </text> + <button + height="23" + label="Automatic adjustments settings" + layout="topleft" + left="30" + name="AutoAdjustmentsButton" + top_delta="30" + width="200"> + <button.commit_callback + function="Pref.AutoAdjustments"/> + </button> + <slider control_name="IndirectMaxComplexity" tool_tip="Controls at what point a visually complex avatar is drawn as a JellyDoll" @@ -246,7 +258,7 @@ max_val="101" name="IndirectMaxComplexity" show_text="false" - top_delta="36" + top_delta="40" width="300"> <slider.commit_callback function="Pref.UpdateIndirectMaxComplexity" diff --git a/indra/newview/skins/default/xui/en/panel_presets_pulldown.xml b/indra/newview/skins/default/xui/en/panel_presets_pulldown.xml index b87dda2315..b3d165c4fd 100644 --- a/indra/newview/skins/default/xui/en/panel_presets_pulldown.xml +++ b/indra/newview/skins/default/xui/en/panel_presets_pulldown.xml @@ -8,7 +8,7 @@ border="false" chrome="true" follows="bottom" - height="155" + height="185" layout="topleft" name="presets_pulldown" width="225"> @@ -57,7 +57,7 @@ width="215" /> <button name="open_prefs_btn" - label="Open Graphics Preferences" + label="Graphics Preferences" tool_tip = "Bring up graphics prefs" top_delta="5" left="15" @@ -66,4 +66,15 @@ <button.commit_callback function="Presets.GoGraphicsPrefs" /> </button> + <button + name="open_autofps_btn" + label="Auto-FPS settings" + tool_tip = "Bring up auto-adjust settings" + top_pad="5" + left="15" + height="20" + width="200"> + <button.commit_callback + function="Presets.GoAutofpsPrefs" /> + </button> </panel> diff --git a/indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml b/indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml index 622c999254..e90e6caf84 100644 --- a/indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml +++ b/indra/newview/skins/default/xui/en/panel_settings_sky_atmos.xml @@ -223,7 +223,7 @@ left_delta="-5" top_delta="25" width="80"> - Scene Gamma: + Brightness: </text> <slider decimal_digits="2" diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 62b26da552..9c634b661a 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -4163,6 +4163,7 @@ name="Command_360_Capture_Label">360 snapshot</string> <string name="Command_MiniMap_Label">Mini-map</string> <string name="Command_Move_Label">Walk / run / fly</string> <string name="Command_People_Label">People</string> + <string name="Command_Performance_Label">Graphics speed</string> <string name="Command_Picks_Label">Picks</string> <string name="Command_Places_Label">Places</string> <string name="Command_Preferences_Label">Preferences</string> @@ -4195,6 +4196,7 @@ name="Command_360_Capture_Tooltip">Capture a 360 equirectangular image</string> <string name="Command_MiniMap_Tooltip">Show nearby people</string> <string name="Command_Move_Tooltip">Moving your avatar</string> <string name="Command_People_Tooltip">Friends, groups, and nearby people</string> + <string name="Command_Performance_Tooltip">Improve graphics speed</string> <string name="Command_Picks_Tooltip">Places to show as favorites in your profile</string> <string name="Command_Places_Tooltip">Places you've saved</string> <string name="Command_Preferences_Tooltip">Preferences</string> @@ -4296,7 +4298,7 @@ name="Command_360_Capture_Tooltip">Capture a 360 equirectangular image</string> <string name="preset_combo_label">-Empty list-</string> <string name="Default">Default</string> <string name="none_paren_cap">(None)</string> - <string name="no_limit">No Limit</string> + <string name="no_limit">No limit</string> <string name="Mav_Details_MAV_FOUND_DEGENERATE_TRIANGLES"> The physics shape contains triangles which are too small. Try simplifying the physics model. |