diff options
author | Erik Kundiman <erik@megapahit.org> | 2025-02-18 17:50:06 +0800 |
---|---|---|
committer | Erik Kundiman <erik@megapahit.org> | 2025-02-18 17:50:06 +0800 |
commit | 4bf9c1314565bbca8ca62db994e201de7c5a97b7 (patch) | |
tree | 9e118846d4abb1fa6edccbcc615beac8b7f8972a | |
parent | 54afd71f42d8bc15217dd14d3924661bd9aaa044 (diff) | |
parent | 0679cbdec89fbd3ec470768bdf469f6a1d326859 (diff) |
Merge commit '0679cbdec89fbd3ec470768bdf469f6a1d326859' into tmp
61 files changed, 1099 insertions, 540 deletions
diff --git a/.github/workflows/tag-release.yaml b/.github/workflows/tag-release.yaml index 65d1d43a83..24ee2de794 100644 --- a/.github/workflows/tag-release.yaml +++ b/.github/workflows/tag-release.yaml @@ -37,7 +37,12 @@ jobs: - name: Update Tag uses: actions/github-script@v7.0.1 with: - github-token: ${{ secrets.GITHUB_TOKEN }} + # use a real access token instead of GITHUB_TOKEN default. + # required so that the results of this tag creation can trigger the build workflow + # https://stackoverflow.com/a/71372524 + # https://docs.github.com/en/actions/using-workflows/triggering-a-workflow#triggering-a-workflow-from-a-workflow + # this token will need to be renewed anually in January + github-token: ${{ secrets.LL_TAG_RELEASE_TOKEN }} script: | github.rest.git.createRef({ owner: context.repo.owner, diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index 87625b6ead..41893a35e5 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -308,6 +308,7 @@ namespace LLError class LLUserWarningMsg { public: + // error codes, tranlates to last_exec states like LAST_EXEC_OTHER_CRASH typedef enum { ERROR_OTHER = 0, diff --git a/indra/llrender/llfontbitmapcache.cpp b/indra/llrender/llfontbitmapcache.cpp index ee9cfd0719..83f5d31186 100644 --- a/indra/llrender/llfontbitmapcache.cpp +++ b/indra/llrender/llfontbitmapcache.cpp @@ -107,7 +107,7 @@ bool LLFontBitmapCache::nextOpenPos(S32 width, S32& pos_x, S32& pos_y, EFontGlyp mBitmapHeight = image_height; S32 num_components = getNumComponents(bitmap_type); - mImageRawVec[bitmap_idx].push_back(new LLImageRaw(mBitmapWidth, mBitmapHeight, num_components)); + mImageRawVec[bitmap_idx].emplace_back(new LLImageRaw(mBitmapWidth, mBitmapHeight, num_components)); bitmap_num = static_cast<U32>(mImageRawVec[bitmap_idx].size()) - 1; LLImageRaw* image_raw = getImageRaw(bitmap_type, bitmap_num); @@ -117,7 +117,7 @@ bool LLFontBitmapCache::nextOpenPos(S32 width, S32& pos_x, S32& pos_y, EFontGlyp } // Make corresponding GL image. - mImageGLVec[bitmap_idx].push_back(new LLImageGL(image_raw, false, false)); + mImageGLVec[bitmap_idx].emplace_back(new LLImageGL(image_raw, false, false)); LLImageGL* image_gl = getImageGL(bitmap_type, bitmap_num); // Start at beginning of the new image. diff --git a/indra/llrender/llfontfreetype.h b/indra/llrender/llfontfreetype.h index 1ad795060a..a2d925c5f6 100644 --- a/indra/llrender/llfontfreetype.h +++ b/indra/llrender/llfontfreetype.h @@ -148,6 +148,7 @@ public: void setStyle(U8 style); U8 getStyle() const; + S32 getAddedGlyphs() const { return mAddGlyphCount; } private: void resetBitmapCache(); diff --git a/indra/llrender/llfontgl.cpp b/indra/llrender/llfontgl.cpp index 4c9a062246..4037c036e5 100644 --- a/indra/llrender/llfontgl.cpp +++ b/indra/llrender/llfontgl.cpp @@ -58,6 +58,7 @@ F32 LLFontGL::sVertDPI = 96.f; F32 LLFontGL::sHorizDPI = 96.f; F32 LLFontGL::sScaleX = 1.f; F32 LLFontGL::sScaleY = 1.f; +S32 LLFontGL::sResolutionGeneration = 0; bool LLFontGL::sDisplayFont = true ; std::string LLFontGL::sAppDir; @@ -109,6 +110,11 @@ S32 LLFontGL::getNumFaces(const std::string& filename) return mFontFreetype->getNumFaces(filename); } +S32 LLFontGL::getKnownGlyphCount() const +{ + return mFontFreetype ? mFontFreetype->getAddedGlyphs() : 0; +} + S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, const LLRect& rect, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, ShadowType shadow, S32 max_chars, F32* right_x, bool use_ellipses, bool use_color) const { @@ -249,6 +255,10 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons const LLFontBitmapCache* font_bitmap_cache = mFontFreetype->getFontBitmapCache(); + // This looks wrong, value is dynamic. + // LLFontBitmapCache::nextOpenPos can alter these values when + // new characters get added to cache, which affects whole string. + // Todo: Perhaps value should update after symbols were added? F32 inv_width = 1.f / font_bitmap_cache->getBitmapWidth(); F32 inv_height = 1.f / font_bitmap_cache->getBitmapHeight(); @@ -270,6 +280,10 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons const LLFontGlyphInfo* next_glyph = NULL; + // string can have more than one glyph per char (ex: bold or shadow), + // make sure that GLYPH_BATCH_SIZE won't end up with half a symbol. + // See drawGlyph. + // Ex: with shadows it's 6 glyps per char. 30 fits exactly 5 chars. static constexpr S32 GLYPH_BATCH_SIZE = 30; static thread_local LLVector4a vertices[GLYPH_BATCH_SIZE * 6]; static thread_local LLVector2 uvs[GLYPH_BATCH_SIZE * 6]; @@ -282,6 +296,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons std::pair<EFontGlyphType, S32> bitmap_entry = std::make_pair(EFontGlyphType::Grayscale, -1); S32 glyph_count = 0; + llwchar last_char = wstr[begin_offset]; for (i = begin_offset; i < begin_offset + length; i++) { llwchar wch = wstr[i]; @@ -299,7 +314,7 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons } // Per-glyph bitmap texture. std::pair<EFontGlyphType, S32> next_bitmap_entry = fgi->mBitmapEntry; - if (next_bitmap_entry != bitmap_entry) + if (next_bitmap_entry != bitmap_entry || last_char != wch) { // Actually draw the queued glyphs before switching their texture; // otherwise the queued glyphs will be taken from wrong textures. @@ -316,6 +331,11 @@ S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, cons bitmap_entry = next_bitmap_entry; LLImageGL* font_image = font_bitmap_cache->getImageGL(bitmap_entry.first, bitmap_entry.second); gGL.getTexUnit(0)->bind(font_image); + + // For some reason it's not enough to compare by bitmap_entry. + // Issue hits emojis, japenese and chinese glyphs, only on first run. + // Todo: figure it out, there might be a bug with raw image data. + last_char = wch; } if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth)) diff --git a/indra/llrender/llfontgl.h b/indra/llrender/llfontgl.h index 4bb6c55c65..73efc6b1eb 100644 --- a/indra/llrender/llfontgl.h +++ b/indra/llrender/llfontgl.h @@ -90,6 +90,7 @@ public: bool loadFace(const std::string& filename, F32 point_size, const F32 vert_dpi, const F32 horz_dpi, bool is_fallback, S32 face_n); S32 getNumFaces(const std::string& filename); + S32 getKnownGlyphCount() const; S32 render(const LLWString &text, S32 begin_offset, const LLRect& rect, @@ -224,6 +225,7 @@ public: static F32 sHorizDPI; static F32 sScaleX; static F32 sScaleY; + static S32 sResolutionGeneration; static bool sDisplayFont ; static std::string sAppDir; // For loading fonts diff --git a/indra/llrender/llfontvertexbuffer.cpp b/indra/llrender/llfontvertexbuffer.cpp index 5bd1ca5eed..b53a841a87 100644 --- a/indra/llrender/llfontvertexbuffer.cpp +++ b/indra/llrender/llfontvertexbuffer.cpp @@ -146,7 +146,9 @@ S32 LLFontVertexBuffer::render( || mLastScaleY != LLFontGL::sScaleY || mLastVertDPI != LLFontGL::sVertDPI || mLastHorizDPI != LLFontGL::sHorizDPI - || mLastOrigin != LLFontGL::sCurOrigin) + || mLastOrigin != LLFontGL::sCurOrigin + || mLastResGeneration != LLFontGL::sResolutionGeneration + || mLastFontGlyphCount != fontp->getKnownGlyphCount()) { genBuffers(fontp, text, begin_offset, x, y, color, halign, valign, style, shadow, max_chars, max_pixels, right_x, use_ellipses, use_color); @@ -201,6 +203,8 @@ void LLFontVertexBuffer::genBuffers( mLastVertDPI = LLFontGL::sVertDPI; mLastHorizDPI = LLFontGL::sHorizDPI; mLastOrigin = LLFontGL::sCurOrigin; + mLastResGeneration = LLFontGL::sResolutionGeneration; + mLastFontGlyphCount = fontp->getKnownGlyphCount(); if (right_x) { diff --git a/indra/llrender/llfontvertexbuffer.h b/indra/llrender/llfontvertexbuffer.h index af195dfff9..d5e1280dbf 100644 --- a/indra/llrender/llfontvertexbuffer.h +++ b/indra/llrender/llfontvertexbuffer.h @@ -117,8 +117,13 @@ private: F32 mLastScaleY = 1.f; F32 mLastVertDPI = 0.f; F32 mLastHorizDPI = 0.f; + S32 mLastResGeneration = 0; LLCoordGL mLastOrigin; + // Adding new characters to bitmap cache can alter value from getBitmapWidth(); + // which alters whole string. So rerender when new characters were added to cache. + S32 mLastFontGlyphCount = 0; + static bool sEnableBufferCollection; }; diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h index 58c456f134..873ab0cff5 100644 --- a/indra/llrender/llglslshader.h +++ b/indra/llrender/llglslshader.h @@ -59,6 +59,7 @@ public: bool attachNothing = false; bool hasHeroProbes = false; bool isPBRTerrain = false; + bool hasTonemap = false; }; // ============= Structure for caching shader uniforms =============== diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp index 37697f8a15..4807c12226 100644 --- a/indra/llrender/llshadermgr.cpp +++ b/indra/llrender/llshadermgr.cpp @@ -291,6 +291,14 @@ bool LLShaderMgr::attachShaderFeatures(LLGLSLShader * shader) } } + if (features->hasTonemap) + { + if (!shader->attachFragmentObject("deferred/tonemapUtilF.glsl")) + { + return false; + } + } + // NOTE order of shader object attaching is VERY IMPORTANT!!! if (features->hasAtmospherics) { @@ -1392,6 +1400,7 @@ void LLShaderMgr::initAttribsAndUniforms() mReservedUniforms.push_back("screenTex"); mReservedUniforms.push_back("screenDepth"); mReservedUniforms.push_back("refTex"); + mReservedUniforms.push_back("exclusionTex"); mReservedUniforms.push_back("eyeVec"); mReservedUniforms.push_back("time"); mReservedUniforms.push_back("waveDir1"); diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h index 34bd73a42e..46788841a5 100644 --- a/indra/llrender/llshadermgr.h +++ b/indra/llrender/llshadermgr.h @@ -36,6 +36,8 @@ public: LLShaderMgr(); virtual ~LLShaderMgr(); + // Note: although you can use statically hashed strings to just bind a random uniform, it's generally preferably that you use this. + // Always document what the actual shader uniform is next to the shader uniform in this struct. // clang-format off typedef enum { // Shader uniform name, set in LLShaderMgr::initAttribsAndUniforms() @@ -234,6 +236,7 @@ public: WATER_SCREENTEX, // "screenTex" WATER_SCREENDEPTH, // "screenDepth" WATER_REFTEX, // "refTex" + WATER_EXCLUSIONTEX, // "exclusionTex" WATER_EYEVEC, // "eyeVec" WATER_TIME, // "time" WATER_WAVE_DIR1, // "waveDir1" diff --git a/indra/llui/llfolderview.cpp b/indra/llui/llfolderview.cpp index 42a9e267d2..a059c4d741 100644 --- a/indra/llui/llfolderview.cpp +++ b/indra/llui/llfolderview.cpp @@ -28,6 +28,7 @@ #include "llfolderview.h" #include "llfolderviewmodel.h" +#include "llcallbacklist.h" #include "llclipboard.h" // *TODO: remove this once hack below gone. #include "llkeyboard.h" #include "lllineeditor.h" @@ -274,7 +275,11 @@ LLFolderView::~LLFolderView( void ) mRenamer = NULL; mStatusTextBox = NULL; - if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die(); + if (mPopupMenuHandle.get()) + { + mPopupMenuHandle.get()->die(); + gIdleCallbacks.deleteFunction(onIdleUpdateMenu, this); + } mPopupMenuHandle.markDead(); mAutoOpenItems.removeAllNodes(); @@ -1095,7 +1100,10 @@ bool LLFolderView::handleKeyHere( KEY key, MASK mask ) LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); if (menu && menu->isOpen()) { - LLMenuGL::sMenuContainer->hideMenus(); + if (LLMenuGL::sMenuContainer->hideMenus()) + { + gIdleCallbacks.deleteFunction(onIdleUpdateMenu, this); + } } switch( key ) @@ -1340,7 +1348,10 @@ bool LLFolderView::handleUnicodeCharHere(llwchar uni_char) LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); if (menu && menu->isOpen()) { - LLMenuGL::sMenuContainer->hideMenus(); + if (LLMenuGL::sMenuContainer->hideMenus()) + { + gIdleCallbacks.deleteFunction(onIdleUpdateMenu, this); + } } //do text search @@ -1612,7 +1623,11 @@ void LLFolderView::deleteAllChildren() { LLUI::getInstance()->removePopup(mRenamer); } - if (mPopupMenuHandle.get()) mPopupMenuHandle.get()->die(); + if (mPopupMenuHandle.get()) + { + mPopupMenuHandle.get()->die(); + gIdleCallbacks.deleteFunction(onIdleUpdateMenu, this); + } mPopupMenuHandle.markDead(); mScrollContainer = NULL; mRenameItem = NULL; @@ -1979,9 +1994,24 @@ void LLFolderView::updateMenu() LLMenuGL* menu = (LLMenuGL*)mPopupMenuHandle.get(); if (menu && menu->getVisible()) { - updateMenuOptions(menu); + // When fetching folders in bulk or in parts, each callback + // cause updateMenu individually, so make sure it gets called + // only once per frame, after callbacks are done. + // gIdleCallbacks has built in dupplicate protection. + gIdleCallbacks.addFunction(onIdleUpdateMenu, this); + } +} + +void LLFolderView::onIdleUpdateMenu(void* user_data) +{ + LLFolderView* self = (LLFolderView*)user_data; + LLMenuGL* menu = (LLMenuGL*)self->mPopupMenuHandle.get(); + if (menu) + { + self->updateMenuOptions(menu); menu->needsArrange(); // update menu height if needed } + gIdleCallbacks.deleteFunction(onIdleUpdateMenu, NULL); } bool LLFolderView::isFolderSelected() diff --git a/indra/llui/llfolderview.h b/indra/llui/llfolderview.h index 82637e33ea..7ed10d9223 100644 --- a/indra/llui/llfolderview.h +++ b/indra/llui/llfolderview.h @@ -266,6 +266,7 @@ public: private: void updateMenuOptions(LLMenuGL* menu); void updateRenamerPosition(); + static void onIdleUpdateMenu(void* user_data); protected: LLScrollContainer* mScrollContainer; // NULL if this is not a child of a scroll container. diff --git a/indra/llwindow/llwindowcallbacks.cpp b/indra/llwindow/llwindowcallbacks.cpp index c160382c17..195f68e08b 100644 --- a/indra/llwindow/llwindowcallbacks.cpp +++ b/indra/llwindow/llwindowcallbacks.cpp @@ -194,6 +194,11 @@ bool LLWindowCallbacks::handleDPIChanged(LLWindow *window, F32 ui_scale_factor, return false; } +bool LLWindowCallbacks::handleDisplayChanged() +{ + return false; +} + bool LLWindowCallbacks::handleWindowDidChangeScreen(LLWindow *window) { return false; diff --git a/indra/llwindow/llwindowcallbacks.h b/indra/llwindow/llwindowcallbacks.h index 63b585231f..d812f93524 100644 --- a/indra/llwindow/llwindowcallbacks.h +++ b/indra/llwindow/llwindowcallbacks.h @@ -69,6 +69,7 @@ public: virtual bool handleTimerEvent(LLWindow *window); virtual bool handleDeviceChange(LLWindow *window); virtual bool handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height); + virtual bool handleDisplayChanged(); virtual bool handleWindowDidChangeScreen(LLWindow *window); enum DragNDropAction { diff --git a/indra/llwindow/llwindowwin32.cpp b/indra/llwindow/llwindowwin32.cpp index bc39e7f6f7..557af1b158 100644 --- a/indra/llwindow/llwindowwin32.cpp +++ b/indra/llwindow/llwindowwin32.cpp @@ -81,10 +81,6 @@ const S32 BITS_PER_PIXEL = 32; const S32 MAX_NUM_RESOLUTIONS = 32; const F32 ICON_FLASH_TIME = 0.5f; -#ifndef WM_DPICHANGED -#define WM_DPICHANGED 0x02E0 -#endif - #ifndef USER_DEFAULT_SCREEN_DPI #define USER_DEFAULT_SCREEN_DPI 96 // Win7 #endif @@ -2958,6 +2954,11 @@ LRESULT CALLBACK LLWindowWin32::mainWindowProc(HWND h_wnd, UINT u_msg, WPARAM w_ return 0; } + case WM_DISPLAYCHANGE: + { + WINDOW_IMP_POST(window_imp->mCallbacks->handleDisplayChanged()); + } + case WM_SETFOCUS: { LL_PROFILE_ZONE_NAMED_CATEGORY_WIN32("mwp - WM_SETFOCUS"); diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 1ba3a6c74a..0370604117 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -167,6 +167,7 @@ set(viewer_SOURCE_FILES lldrawpooltree.cpp lldrawpoolwater.cpp lldrawpoolwlsky.cpp + lldrawpoolwaterexclusion.cpp lldynamictexture.cpp llemote.cpp llenvironment.cpp @@ -840,6 +841,7 @@ set(viewer_HEADER_FILES lldrawpooltree.h lldrawpoolwater.h lldrawpoolwlsky.h + lldrawpoolwaterexclusion.h lldynamictexture.h llemote.h llenvironment.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 4739728bee..1aec56447d 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -12783,7 +12783,7 @@ <key>UpdaterWillingToTest</key> <map> <key>Comment</key> - <string>Whether or not the updater should offer test candidate upgrades.</string> + <string>Whether or not the updater should offer Beta upgrades.</string> <key>Persist</key> <integer>1</integer> <key>Type</key> diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredTonemap.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredTonemap.glsl index fc6d4d7727..c4610bffac 100644 --- a/indra/newview/app_settings/shaders/class1/deferred/postDeferredTonemap.glsl +++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredTonemap.glsl @@ -28,138 +28,11 @@ out vec4 frag_color; uniform sampler2D diffuseRect; -uniform sampler2D exposureMap; -uniform vec2 screen_res; in vec2 vary_fragcoord; vec3 linear_to_srgb(vec3 cl); - -//=============================================================== -// tone mapping taken from Khronos sample implementation -//=============================================================== - -// sRGB => XYZ => D65_2_D60 => AP1 => RRT_SAT -const mat3 ACESInputMat = mat3 -( - 0.59719, 0.07600, 0.02840, - 0.35458, 0.90834, 0.13383, - 0.04823, 0.01566, 0.83777 -); - - -// ODT_SAT => XYZ => D60_2_D65 => sRGB -const mat3 ACESOutputMat = mat3 -( - 1.60475, -0.10208, -0.00327, - -0.53108, 1.10813, -0.07276, - -0.07367, -0.00605, 1.07602 -); - -// ACES tone map (faster approximation) -// see: https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/ -vec3 toneMapACES_Narkowicz(vec3 color) -{ - const float A = 2.51; - const float B = 0.03; - const float C = 2.43; - const float D = 0.59; - const float E = 0.14; - return clamp((color * (A * color + B)) / (color * (C * color + D) + E), 0.0, 1.0); -} - - -// ACES filmic tone map approximation -// see https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl -vec3 RRTAndODTFit(vec3 color) -{ - vec3 a = color * (color + 0.0245786) - 0.000090537; - vec3 b = color * (0.983729 * color + 0.4329510) + 0.238081; - return a / b; -} - - -// tone mapping -vec3 toneMapACES_Hill(vec3 color) -{ - color = ACESInputMat * color; - - // Apply RRT and ODT - color = RRTAndODTFit(color); - - color = ACESOutputMat * color; - - // Clamp to [0, 1] - color = clamp(color, 0.0, 1.0); - - return color; -} - -// Khronos Neutral tonemapping -// https://github.com/KhronosGroup/ToneMapping/tree/main -// Input color is non-negative and resides in the Linear Rec. 709 color space. -// Output color is also Linear Rec. 709, but in the [0, 1] range. -vec3 PBRNeutralToneMapping( vec3 color ) -{ - const float startCompression = 0.8 - 0.04; - const float desaturation = 0.15; - - float x = min(color.r, min(color.g, color.b)); - float offset = x < 0.08 ? x - 6.25 * x * x : 0.04; - color -= offset; - - float peak = max(color.r, max(color.g, color.b)); - if (peak < startCompression) return color; - - const float d = 1. - startCompression; - float newPeak = 1. - d * d / (peak + d - startCompression); - color *= newPeak / peak; - - float g = 1. - 1. / (desaturation * (peak - newPeak) + 1.); - return mix(color, newPeak * vec3(1, 1, 1), g); -} - -uniform float exposure; -uniform float tonemap_mix; -uniform int tonemap_type; - -vec3 toneMap(vec3 color) -{ -#ifndef NO_POST - float exp_scale = texture(exposureMap, vec2(0.5,0.5)).r; - - color *= exposure * exp_scale; - - vec3 clamped_color = clamp(color.rgb, vec3(0.0), vec3(1.0)); - - switch(tonemap_type) - { - case 0: - color = PBRNeutralToneMapping(color); - break; - case 1: - color = toneMapACES_Hill(color); - break; - } - - // mix tonemapped and linear here to provide adjustment - color = mix(clamped_color, color, tonemap_mix); -#endif - - return color; -} - -//=============================================================== - -void debugExposure(inout vec3 color) -{ - float exp_scale = texture(exposureMap, vec2(0.5,0.5)).r; - exp_scale *= 0.5; - if (abs(vary_fragcoord.y-exp_scale) < 0.01 && vary_fragcoord.x < 0.1) - { - color = vec3(1,0,0); - } -} +vec3 toneMap(vec3 color); void main() { diff --git a/indra/newview/app_settings/shaders/class1/deferred/tonemapUtilF.glsl b/indra/newview/app_settings/shaders/class1/deferred/tonemapUtilF.glsl new file mode 100644 index 0000000000..a63b8d7c2b --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/deferred/tonemapUtilF.glsl @@ -0,0 +1,180 @@ +/** + * @file postDeferredTonemap.glsl + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, 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$ + */ + +/*[EXTRA_CODE_HERE]*/ + +uniform sampler2D exposureMap; +uniform vec2 screen_res; +in vec2 vary_fragcoord; + +//=============================================================== +// tone mapping taken from Khronos sample implementation +//=============================================================== + +// sRGB => XYZ => D65_2_D60 => AP1 => RRT_SAT +const mat3 ACESInputMat = mat3 +( + 0.59719, 0.07600, 0.02840, + 0.35458, 0.90834, 0.13383, + 0.04823, 0.01566, 0.83777 +); + + +// ODT_SAT => XYZ => D60_2_D65 => sRGB +const mat3 ACESOutputMat = mat3 +( + 1.60475, -0.10208, -0.00327, + -0.53108, 1.10813, -0.07276, + -0.07367, -0.00605, 1.07602 +); + +// ACES tone map (faster approximation) +// see: https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/ +vec3 toneMapACES_Narkowicz(vec3 color) +{ + const float A = 2.51; + const float B = 0.03; + const float C = 2.43; + const float D = 0.59; + const float E = 0.14; + return clamp((color * (A * color + B)) / (color * (C * color + D) + E), 0.0, 1.0); +} + + +// ACES filmic tone map approximation +// see https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl +vec3 RRTAndODTFit(vec3 color) +{ + vec3 a = color * (color + 0.0245786) - 0.000090537; + vec3 b = color * (0.983729 * color + 0.4329510) + 0.238081; + return a / b; +} + + +// tone mapping +vec3 toneMapACES_Hill(vec3 color) +{ + color = ACESInputMat * color; + + // Apply RRT and ODT + color = RRTAndODTFit(color); + + color = ACESOutputMat * color; + + // Clamp to [0, 1] + color = clamp(color, 0.0, 1.0); + + return color; +} + +// Khronos Neutral tonemapping +// https://github.com/KhronosGroup/ToneMapping/tree/main +// Input color is non-negative and resides in the Linear Rec. 709 color space. +// Output color is also Linear Rec. 709, but in the [0, 1] range. +vec3 PBRNeutralToneMapping( vec3 color ) +{ + const float startCompression = 0.8 - 0.04; + const float desaturation = 0.15; + + float x = min(color.r, min(color.g, color.b)); + float offset = x < 0.08 ? x - 6.25 * x * x : 0.04; + color -= offset; + + float peak = max(color.r, max(color.g, color.b)); + if (peak < startCompression) return color; + + const float d = 1. - startCompression; + float newPeak = 1. - d * d / (peak + d - startCompression); + color *= newPeak / peak; + + float g = 1. - 1. / (desaturation * (peak - newPeak) + 1.); + return mix(color, newPeak * vec3(1, 1, 1), g); +} + +uniform float exposure; +uniform float tonemap_mix; +uniform int tonemap_type; + +vec3 toneMap(vec3 color) +{ +#ifndef NO_POST + float exp_scale = texture(exposureMap, vec2(0.5,0.5)).r; + + color *= exposure * exp_scale; + + vec3 clamped_color = clamp(color.rgb, vec3(0.0), vec3(1.0)); + + switch(tonemap_type) + { + case 0: + color = PBRNeutralToneMapping(color); + break; + case 1: + color = toneMapACES_Hill(color); + break; + } + + // mix tonemapped and linear here to provide adjustment + color = mix(clamped_color, color, tonemap_mix); +#endif + + return color; +} + + +vec3 toneMapNoExposure(vec3 color) +{ +#ifndef NO_POST + vec3 clamped_color = clamp(color.rgb, vec3(0.0), vec3(1.0)); + + switch(tonemap_type) + { + case 0: + color = PBRNeutralToneMapping(color); + break; + case 1: + color = toneMapACES_Hill(color); + break; + } + + // mix tonemapped and linear here to provide adjustment + color = mix(clamped_color, color, tonemap_mix); +#endif + + return color; +} + + +//=============================================================== + +void debugExposure(inout vec3 color) +{ + float exp_scale = texture(exposureMap, vec2(0.5,0.5)).r; + exp_scale *= 0.5; + if (abs(vary_fragcoord.y-exp_scale) < 0.01 && vary_fragcoord.x < 0.1) + { + color = vec3(1,0,0); + } +} diff --git a/indra/newview/app_settings/shaders/class1/environment/srgbF.glsl b/indra/newview/app_settings/shaders/class1/environment/srgbF.glsl index d7f6d20547..bf8737615f 100644 --- a/indra/newview/app_settings/shaders/class1/environment/srgbF.glsl +++ b/indra/newview/app_settings/shaders/class1/environment/srgbF.glsl @@ -41,6 +41,26 @@ vec3 srgb_to_linear(vec3 cs) } + +vec4 srgb_to_linear4(vec4 cs) +{ + vec4 low_range = cs / vec4(12.92); + vec4 high_range = pow((cs+vec4(0.055))/vec4(1.055), vec4(2.4)); + bvec4 lte = lessThanEqual(cs,vec4(0.04045)); + +#ifdef OLD_SELECT + vec4 result; + result.r = lte.r ? low_range.r : high_range.r; + result.g = lte.g ? low_range.g : high_range.g; + result.b = lte.b ? low_range.b : high_range.b; + result.a = lte.a ? low_range.a : high_range.a; + return result; +#else + return mix(high_range, low_range, lte); +#endif + +} + vec3 linear_to_srgb(vec3 cl) { cl = clamp(cl, vec3(0), vec3(1)); diff --git a/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl b/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl index 20b61e9302..44a979e565 100644 --- a/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl +++ b/indra/newview/app_settings/shaders/class1/environment/waterFogF.glsl @@ -66,11 +66,11 @@ vec4 getWaterFogViewNoClip(vec3 pos) float t2 = kd + ks * es; float t3 = pow(F, t2*l) - 1.0; - float L = min(t1/t2*t3, 1.0); + float L = pow(min(t1/t2*t3, 1.0), 1.0/1.7); float D = pow(0.98, l*kd); - return vec4(srgb_to_linear(kc.rgb*L), D); + return vec4(srgb_to_linear(kc.rgb)*L, D); } vec4 getWaterFogView(vec3 pos) diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleColorF.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleColorF.glsl new file mode 100644 index 0000000000..dea76da5a5 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/objects/simpleColorF.glsl @@ -0,0 +1,57 @@ +/** + * @file simpleColorF.glsl + * + * $LicenseInfo:firstyear=2025&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +out vec4 frag_color; + +in vec4 vertex_color; +in vec4 vertex_position; + +uniform vec4 waterPlane; +uniform float waterSign; + +void waterClip(vec3 pos) +{ + // TODO: make this less branchy + if (waterSign > 0) + { + if ((dot(pos.xyz, waterPlane.xyz) + waterPlane.w) < 0.0) + { + discard; + } + } + else + { + if ((dot(pos.xyz, waterPlane.xyz) + waterPlane.w) > 0.0) + { + discard; + } + } +} + +void main() +{ + + frag_color = vertex_color; +} diff --git a/indra/newview/app_settings/shaders/class1/objects/simpleNoAtmosV.glsl b/indra/newview/app_settings/shaders/class1/objects/simpleNoAtmosV.glsl new file mode 100644 index 0000000000..4564e56313 --- /dev/null +++ b/indra/newview/app_settings/shaders/class1/objects/simpleNoAtmosV.glsl @@ -0,0 +1,43 @@ +/** + * @file simpleNoAtmosV.glsl + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2007, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +uniform mat4 modelview_matrix; +uniform mat4 modelview_projection_matrix; + +uniform vec4 color; + +in vec3 position; + +out vec4 vertex_color; +out vec4 vertex_position; + +void main() +{ + //transform vertex + vec4 pos = (modelview_matrix * vec4(position.xyz, 1.0)); + vertex_position = modelview_projection_matrix * vec4(position.xyz, 1.0); + gl_Position = vertex_position; + vertex_color = color; +} diff --git a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl index 6df0403198..2f577f8459 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/reflectionProbeF.glsl @@ -789,9 +789,6 @@ void sampleReflectionProbesWater(inout vec3 ambenv, inout vec3 glossenv, probeIndex[probeInfluences++] = 0; doProbeSample(ambenv, glossenv, tc, pos, norm, glossiness, false, amblit); - - // fudge factor to get PBR water at a similar luminance ot legacy water - glossenv *= 0.4; } void debugTapRefMap(vec3 pos, vec3 dir, float depth, int i, inout vec4 col) diff --git a/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl b/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl index 2bf785e773..091c25d15e 100644 --- a/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl +++ b/indra/newview/app_settings/shaders/class3/deferred/waterHazeF.glsl @@ -35,13 +35,25 @@ vec4 getWaterFogView(vec3 pos); uniform int above_water; +uniform sampler2D exclusionTex; + void main() { vec2 tc = vary_fragcoord.xy/vary_fragcoord.w*0.5+0.5; float depth = getDepth(tc.xy); + float mask = texture(exclusionTex, tc.xy).r; if (above_water > 0) { + // Just discard if we're in the exclusion mask. + // The previous invisiprim hack we're replacing would also crank up water fog desntiy. + // But doing that makes exclusion surfaces very slow as we'd need to render even more into the mask. + // - Geenz 2025-02-06 + if (mask < 1) + { + discard; + } + // we want to depth test when the camera is above water, but some GPUs have a hard time // with depth testing against render targets that are bound for sampling in the same shader // so we do it manually here @@ -51,11 +63,13 @@ void main() { discard; } + } vec4 pos = getPositionWithDepth(tc, depth); vec4 fogged = getWaterFogView(pos.xyz); + fogged.a = max(pow(fogged.a, 1.7), 0); frag_color = max(fogged, vec4(0)); //output linear since local lights will be added to this shader's results diff --git a/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl b/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl index 1c02dc764d..fa410e9f11 100644 --- a/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl +++ b/indra/newview/app_settings/shaders/class3/environment/underWaterF.glsl @@ -26,6 +26,7 @@ out vec4 frag_color; uniform sampler2D bumpMap; +uniform sampler2D exclusionTex; #ifdef TRANSPARENT_WATER uniform sampler2D screenTex; @@ -59,6 +60,9 @@ void mirrorClip(vec3 position); void main() { mirrorClip(vary_position); + vec2 screen_tc = (refCoord.xy/refCoord.z) * 0.5 + 0.5; + float water_mask = texture(exclusionTex, screen_tc).r; + vec4 color; //get detail normals @@ -68,8 +72,8 @@ void main() vec3 wavef = normalize(wave1+wave2+wave3); //figure out distortion vector (ripply) - vec2 distort = (refCoord.xy/refCoord.z) * 0.5 + 0.5; - distort = distort+wavef.xy*refScale; + vec2 distort = screen_tc; + distort = mix(distort, distort+wavef.xy*refScale, water_mask); #ifdef TRANSPARENT_WATER vec4 fb = texture(screenTex, distort); diff --git a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl index 84c287fc50..028813ef23 100644 --- a/indra/newview/app_settings/shaders/class3/environment/waterF.glsl +++ b/indra/newview/app_settings/shaders/class3/environment/waterF.glsl @@ -25,6 +25,8 @@ // class3/environment/waterF.glsl +#define WATER_MINIMAL 1 + out vec4 frag_color; #ifdef HAS_SUN_SHADOW @@ -86,23 +88,17 @@ uniform sampler2D screenTex; uniform sampler2D depthMap; #endif -uniform sampler2D refTex; +uniform sampler2D exclusionTex; -uniform float sunAngle; -uniform float sunAngle2; +uniform int classic_mode; uniform vec3 lightDir; uniform vec3 specular; -uniform float lightExp; +uniform float blurMultiplier; uniform float refScale; uniform float kd; -uniform vec2 screenRes; uniform vec3 normScale; uniform float fresnelScale; uniform float fresnelOffset; -uniform float blurMultiplier; -uniform vec4 waterFogColor; -uniform vec3 waterFogColorLinear; - //bigWave is (refCoord.w, view.w); in vec4 refCoord; @@ -122,6 +118,10 @@ vec3 BlendNormal(vec3 bump1, vec3 bump2) vec3 srgb_to_linear(vec3 col); vec3 linear_to_srgb(vec3 col); +vec3 atmosLighting(vec3 light); +vec3 scaleSoftClip(vec3 light); +vec3 toneMapNoExposure(vec3 color); + vec3 vN, vT, vB; vec3 transform_normal(vec3 vNt) @@ -132,59 +132,107 @@ vec3 transform_normal(vec3 vNt) void sampleReflectionProbesWater(inout vec3 ambenv, inout vec3 glossenv, vec2 tc, vec3 pos, vec3 norm, float glossiness, vec3 amblit_linear); +void sampleReflectionProbes(inout vec3 ambenv, inout vec3 glossenv, + vec2 tc, vec3 pos, vec3 norm, float glossiness, bool transparent, vec3 amblit_linear); + +void sampleReflectionProbesLegacy(inout vec3 ambenv, inout vec3 glossenv, inout vec3 legacyenv, + vec2 tc, vec3 pos, vec3 norm, float glossiness, float envIntensity, bool transparent, vec3 amblit); + + vec3 getPositionWithNDC(vec3 ndc); +void generateWaveNormals(out vec3 wave1, out vec3 wave2, out vec3 wave3) +{ + // Generate all of our wave normals. + // We layer these back and forth. + + vec2 bigwave = vec2(refCoord.w, view.w); + + vec3 wave1_a = texture(bumpMap, bigwave).xyz * 2.0 - 1.0; + vec3 wave2_a = texture(bumpMap, littleWave.xy).xyz * 2.0 - 1.0; + vec3 wave3_a = texture(bumpMap, littleWave.zw).xyz * 2.0 - 1.0; + + vec3 wave1_b = texture(bumpMap2, bigwave).xyz * 2.0 - 1.0; + vec3 wave2_b = texture(bumpMap2, littleWave.xy).xyz * 2.0 - 1.0; + vec3 wave3_b = texture(bumpMap2, littleWave.zw).xyz * 2.0 - 1.0; + + wave1 = BlendNormal(wave1_a, wave1_b); + wave2 = BlendNormal(wave2_a, wave2_b); + wave3 = BlendNormal(wave3_a, wave3_b); +} + +void calculateFresnelFactors(out vec3 df3, out vec2 df2, vec3 viewVec, vec3 wave1, vec3 wave2, vec3 wave3, vec3 wavef) +{ + // We calculate the fresnel here. + // We do this by getting the dot product for each sets of waves, and applying scale and offset. + + df3 = max(vec3(0), vec3( + dot(viewVec, wave1), + dot(viewVec, (wave2 + wave3) * 0.5), + dot(viewVec, wave3) + ) * fresnelScale + fresnelOffset); + + df3 *= df3; + + df2 = max(vec2(0), vec2( + df3.x + df3.y + df3.z, + dot(viewVec, wavef) * fresnelScale + fresnelOffset + )); +} + void main() { mirrorClip(vary_position); + vN = vary_normal; vT = vary_tangent; vB = cross(vN, vT); vec3 pos = vary_position.xyz; + float linear_depth = 1.0 / -pos.z; float dist = length(pos.xyz); //normalize view vector vec3 viewVec = normalize(pos.xyz); - //get wave normals - vec2 bigwave = vec2(refCoord.w, view.w); - vec3 wave1_a = texture(bumpMap, bigwave, -2.0 ).xyz*2.0-1.0; - vec3 wave2_a = texture(bumpMap, littleWave.xy).xyz*2.0-1.0; - vec3 wave3_a = texture(bumpMap, littleWave.zw).xyz*2.0-1.0; + // Setup our waves. - vec3 wave1_b = texture(bumpMap2, bigwave ).xyz*2.0-1.0; - vec3 wave2_b = texture(bumpMap2, littleWave.xy).xyz*2.0-1.0; - vec3 wave3_b = texture(bumpMap2, littleWave.zw).xyz*2.0-1.0; + vec3 wave1 = vec3(0, 0, 1); + vec3 wave2 = vec3(0, 0, 1); + vec3 wave3 = vec3(0, 0, 1); - //wave1_a = wave2_a = wave3_a = wave1_b = wave2_b = wave3_b = vec3(0,0,1); - - vec3 wave1 = BlendNormal(wave1_a, wave1_b); - vec3 wave2 = BlendNormal(wave2_a, wave2_b); - vec3 wave3 = BlendNormal(wave3_a, wave3_b); + generateWaveNormals(wave1, wave2, wave3); + float dmod = sqrt(dist); vec2 distort = (refCoord.xy/refCoord.z) * 0.5 + 0.5; - //wave1 = transform_normal(wave1); - //wave2 = transform_normal(wave2); - //wave3 = transform_normal(wave3); - vec3 wavef = (wave1 + wave2 * 0.4 + wave3 * 0.6) * 0.5; + vec3 df3 = vec3(0); + vec2 df2 = vec2(0); + + vec3 sunlit; + vec3 amblit; + vec3 additive; + vec3 atten; + calcAtmosphericVarsLinear(pos.xyz, wavef, vary_light_dir, sunlit, amblit, additive, atten); + + calculateFresnelFactors(df3, df2, normalize(view.xyz), wave1, wave2, wave3, wavef); + vec3 waver = wavef*3.0; vec3 up = transform_normal(vec3(0,0,1)); float vdu = -dot(viewVec, up)*2.0; - vec3 wave_ibl = wavef; + vec3 wave_ibl = wavef * normScale; wave_ibl.z *= 2.0; wave_ibl = transform_normal(normalize(wave_ibl)); vec3 norm = transform_normal(normalize(wavef)); vdu = clamp(vdu, 0.0, 1.0); - wavef.z *= max(vdu*vdu*vdu, 0.1); + //wavef.z *= max(vdu*vdu*vdu, 0.1); wavef = normalize(wavef); @@ -194,62 +242,66 @@ void main() float dist2 = dist; dist = max(dist, 5.0); - float dmod = sqrt(dist); - //figure out distortion vector (ripply) - vec2 distort2 = distort + waver.xy * refScale / max(dmod, 1.0); + vec2 distort2 = distort + waver.xy * refScale / max(dmod, 1.0) * 2.0; distort2 = clamp(distort2, vec2(0), vec2(0.999)); - vec3 sunlit; - vec3 amblit; - vec3 additive; - vec3 atten; - float shadow = 1.0f; + float water_mask = texture(exclusionTex, distort).r; + #ifdef HAS_SUN_SHADOW shadow = sampleDirectionalShadow(pos.xyz, norm.xyz, distort); #endif - calcAtmosphericVarsLinear(pos.xyz, wavef, vary_light_dir, sunlit, amblit, additive, atten); - vec3 sunlit_linear = srgb_to_linear(sunlit); - + float fade = 0.0; #ifdef TRANSPARENT_WATER - vec4 fb = texture(screenTex, distort2); - float depth = texture(depthMap, distort2).r; - vec3 refPos = getPositionWithNDC(vec3(distort2*2.0-vec2(1.0), depth*2.0-1.0)); + float depth = texture(depthMap, distort).r; + + vec3 refPos = getPositionWithNDC(vec3(distort*2.0-vec2(1.0), depth*2.0-1.0)); + + // Calculate some distance fade in the water to better assist with refraction blending and reducing the refraction texture's "disconnect". + fade = max(0.0,min(1.0, (pos.z - refPos.z) / 10.0)) * water_mask; + distort2 = mix(distort, distort2, min(1.0, fade * 10.0)); + depth = texture(depthMap, distort2).r; + + refPos = getPositionWithNDC(vec3(distort2 * 2.0 - vec2(1.0), depth * 2.0 - 1.0)); - if (refPos.z > pos.z-0.05) + if (pos.z < refPos.z - 0.05) { - //we sampled an above water sample, don't distort distort2 = distort; - fb = texture(screenTex, distort2); - depth = texture(depthMap, distort2).r; - refPos = getPositionWithNDC(vec3(distort2 * 2.0 - vec2(1.0), depth * 2.0 - 1.0)); } + vec4 fb = texture(screenTex, distort2); + #else vec4 fb = applyWaterFogViewLinear(viewVec*2048.0, vec4(1.0)); -#endif - // fudge sample on other side of water to be a tad darker - fb.rgb *= 0.75; + if (water_mask < 1.0) + discard; +#endif - float metallic = 0.0; - float perceptualRoughness = 0.05; + float metallic = 1.0; + float perceptualRoughness = blurMultiplier; float gloss = 1.0 - perceptualRoughness; vec3 irradiance = vec3(0); vec3 radiance = vec3(0); - sampleReflectionProbesWater(irradiance, radiance, distort2, pos.xyz, wave_ibl.xyz, gloss, amblit); + vec3 legacyenv = vec3(0); - irradiance = vec3(0); + // TODO: Make this an option. +#ifdef WATER_MINIMAL + sampleReflectionProbesWater(irradiance, radiance, distort2, pos.xyz, wave_ibl.xyz, gloss, amblit); +#elif WATER_MINIMAL_PLUS + sampleReflectionProbes(irradiance, radiance, distort2, pos.xyz, wave_ibl.xyz, gloss, false, amblit); +#endif vec3 diffuseColor = vec3(0); vec3 specularColor = vec3(0); - calcDiffuseSpecular(vec3(1), metallic, diffuseColor, specularColor); + vec3 specular_linear = srgb_to_linear(specular); + calcDiffuseSpecular(specular_linear, metallic, diffuseColor, specularColor); vec3 v = -normalize(pos.xyz); @@ -257,46 +309,36 @@ void main() float ao = 1.0; vec3 light_dir = transform_normal(lightDir); - perceptualRoughness = 0.0; - metallic = 1.0; - float NdotV = clamp(abs(dot(norm, v)), 0.001, 1.0); - float nl = 0; + float nl = 0.0; vec3 diffPunc = vec3(0); vec3 specPunc = vec3(0); - pbrPunctual(vec3(0), specularColor, 0.1, metallic, normalize(wavef+up*max(dist, 32.0)/32.0*(1.0-vdu)), v, normalize(light_dir), nl, diffPunc, specPunc); - - vec3 punctual = clamp(nl * (diffPunc + specPunc), vec3(0), vec3(10)); - - vec3 color = punctual * sunlit_linear * 2.75 * shadow; - vec3 iblDiff; - vec3 iblSpec; - pbrIbl(vec3(0), vec3(1), radiance, vec3(0), ao, NdotV, 0.0, iblDiff, iblSpec); - - color += iblDiff + iblSpec; + pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, normalize(wavef+up*max(dist, 32.0)/32.0*(1.0-vdu)), v, normalize(light_dir), nl, diffPunc, specPunc); - float nv = clamp(abs(dot(norm.xyz, v)), 0.001, 1.0); - vec2 brdf = BRDF(clamp(nv, 0.0, 1.0), 1.0); - float f = 1.0-brdf.y; //1.0 - (brdf.x+brdf.y); - f *= 0.9; - f *= f; + vec3 punctual = clamp(nl * (diffPunc + specPunc), vec3(0), vec3(10)) * sunlit_linear * shadow; + radiance *= df2.y; + //radiance = toneMapNoExposure(radiance); + vec3 color = vec3(0); + color = mix(fb.rgb, radiance, min(1.0, df2.x)) + punctual.rgb; - // incoming scale is [0, 1] with 0.5 being default - // shift to 0.5 to 1.5 - f *= (fresnelScale - 0.5)+1.0; + float water_haze_scale = 4.0; - // incoming offset is [0, 1] with 0.5 being default - // shift from -1 to 1 - f += (fresnelOffset - 0.5) * 2.0; + if (classic_mode > 0) + water_haze_scale = 1.0; - f = clamp(f, 0.0, 1.0); + // This looks super janky, but we do this to restore water haze in the distance. + // These values were finagled in to try and bring back some of the distant brightening on legacy water. Also works reasonably well on PBR skies such as PBR midday. + // color = mix(color, additive * water_haze_scale, (1 - atten)); - color = ((1.0 - f) * color) + fb.rgb; + // We shorten the fade here at the shoreline so it doesn't appear too soft from a distance. + fade *= 60.0; + fade = min(1.0, fade); + color = mix(fb.rgb, color, fade); - float spec = min(max(max(punctual.r, punctual.g), punctual.b), 0.05); + float spec = min(max(max(punctual.r, punctual.g), punctual.b), 0.0); - frag_color = max(vec4(color, spec), vec4(0)); + frag_color = min(vec4(1),max(vec4(color.rgb, spec * water_mask), vec4(0))); } diff --git a/indra/newview/llagentpicksinfo.cpp b/indra/newview/llagentpicksinfo.cpp index e2a2d2d8a9..265e4060ff 100644 --- a/indra/newview/llagentpicksinfo.cpp +++ b/indra/newview/llagentpicksinfo.cpp @@ -28,6 +28,7 @@ #include "llagentpicksinfo.h" #include "llagent.h" +#include "llagentbenefits.h" #include "llavatarpropertiesprocessor.h" const S32 MAX_AVATAR_PICKS = 10; @@ -85,10 +86,9 @@ private: LLAgentPicksInfo::LLAgentPicksInfo() : mAgentPicksObserver(NULL) - , mMaxNumberOfPicks(MAX_AVATAR_PICKS) // Disable Pick creation until we get number of Picks from server - in case // avatar has maximum number of Picks. - , mNumberOfPicks(mMaxNumberOfPicks) + , mNumberOfPicks(S32_MAX) { } @@ -110,7 +110,13 @@ void LLAgentPicksInfo::requestNumberOfPicks() mAgentPicksObserver->sendAgentPicksRequest(); } -bool LLAgentPicksInfo::isPickLimitReached() +// static +S32 LLAgentPicksInfo::getMaxNumberOfPicks() +{ + return LLAgentBenefitsMgr::current().getPicksLimit(); +} + +bool LLAgentPicksInfo::isPickLimitReached() const { return getNumberOfPicks() >= getMaxNumberOfPicks(); } diff --git a/indra/newview/llagentpicksinfo.h b/indra/newview/llagentpicksinfo.h index 9bc105a655..3514ade65d 100644 --- a/indra/newview/llagentpicksinfo.h +++ b/indra/newview/llagentpicksinfo.h @@ -52,17 +52,17 @@ public: /** * Returns number of Picks. */ - S32 getNumberOfPicks() { return mNumberOfPicks; } + S32 getNumberOfPicks() const { return mNumberOfPicks; } /** * Returns maximum number of Picks. */ - S32 getMaxNumberOfPicks() { return mMaxNumberOfPicks; } + static S32 getMaxNumberOfPicks(); /** * Returns true if Agent has maximum allowed number of Picks. */ - bool isPickLimitReached(); + bool isPickLimitReached() const; /** * After creating or deleting a Pick we can assume operation on server will be @@ -83,15 +83,9 @@ private: */ void setNumberOfPicks(S32 number) { mNumberOfPicks = number; } - /** - * Sets maximum number of Picks. - */ - void setMaxNumberOfPicks(S32 max_picks) { mMaxNumberOfPicks = max_picks; } - private: LLAgentPicksObserver* mAgentPicksObserver; - S32 mMaxNumberOfPicks; S32 mNumberOfPicks; }; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 435b2b7692..2c203869c7 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -382,7 +382,6 @@ const int MAX_MARKER_LENGTH = 1024; const std::string MARKER_FILE_NAME("SecondLife.exec_marker"); const std::string START_MARKER_FILE_NAME("SecondLife.start_marker"); const std::string ERROR_MARKER_FILE_NAME("SecondLife.error_marker"); -const std::string LLERROR_MARKER_FILE_NAME("SecondLife.llerror_marker"); const std::string LOGOUT_MARKER_FILE_NAME("SecondLife.logout_marker"); static bool gDoDisconnect = false; static std::string gLaunchFileOnQuit; @@ -2263,6 +2262,7 @@ bool LLAppViewer::initThreads() return true; } +// Callback for all LL_ERROR calls void errorCallback(LLError::ELevel level, const std::string &error_string) { if (level == LLError::LEVEL_ERROR) @@ -2278,9 +2278,18 @@ void errorCallback(LLError::ELevel level, const std::string &error_string) // haven't actually trashed anything yet, we can afford to write the whole // static info file. LLAppViewer::instance()->writeDebugInfo(); + + std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME); + if (!LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB)) + { + // If marker doesn't exist, create a marker with llerror code for next launch + // otherwise don't override existing file + LLAppViewer::instance()->createErrorMarker(LAST_EXEC_LLERROR_CRASH); + } } } +// Callback for LLError::LLUserWarningMsg void errorHandler(const std::string& title_string, const std::string& message_string, S32 code) { if (!message_string.empty()) @@ -3992,29 +4001,6 @@ void LLAppViewer::processMarkerFiles() } LLAPRFile::remove(logout_marker_file); } - // further refine based on whether or not a marker created during an llerr crash is found - std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME); - if(LLAPRFile::isExist(llerror_marker_file, NULL, LL_APR_RB)) - { - if (markerIsSameVersion(llerror_marker_file)) - { - if ( gLastExecEvent == LAST_EXEC_LOGOUT_FROZE ) - { - gLastExecEvent = LAST_EXEC_LOGOUT_CRASH; - LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL; - } - else - { - gLastExecEvent = LAST_EXEC_LLERROR_CRASH; - LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' crashed, setting LastExecEvent to LLERROR_CRASH" << LL_ENDL; - } - } - else - { - LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' found, but versions did not match" << LL_ENDL; - } - LLAPRFile::remove(llerror_marker_file); - } // and last refine based on whether or not a marker created during a non-llerr crash is found std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME); if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB)) diff --git a/indra/newview/llconversationmodel.cpp b/indra/newview/llconversationmodel.cpp index 0c939add95..af5a46742c 100644 --- a/indra/newview/llconversationmodel.cpp +++ b/indra/newview/llconversationmodel.cpp @@ -357,8 +357,9 @@ void LLConversationItemSession::clearParticipants() void LLConversationItemSession::clearAndDeparentModels() { - for (LLFolderViewModelItem* child : mChildren) + for (child_list_t::iterator it = mChildren.begin(); it != mChildren.end();) { + LLFolderViewModelItem* child = *it; if (child->getNumRefs() == 0) { // LLConversationItemParticipant can be created but not assigned to any view, @@ -370,8 +371,8 @@ void LLConversationItemSession::clearAndDeparentModels() // Model is still assigned to some view/widget child->setParent(NULL); } + it = mChildren.erase(it); } - mChildren.clear(); } LLConversationItemParticipant* LLConversationItemSession::findParticipant(const LLUUID& participant_id) diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp index 74d7997a8d..325c3f9b94 100644 --- a/indra/newview/lldrawpool.cpp +++ b/indra/newview/lldrawpool.cpp @@ -42,6 +42,7 @@ #include "lldrawpooltree.h" #include "lldrawpoolterrain.h" #include "lldrawpoolwater.h" +#include "lldrawpoolwaterexclusion.h" #include "llface.h" #include "llviewerobjectlist.h" // For debug listing. #include "pipeline.h" @@ -119,6 +120,9 @@ LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerTexture *tex0) case POOL_GLTF_PBR_ALPHA_MASK: poolp = new LLDrawPoolGLTFPBR(LLDrawPool::POOL_GLTF_PBR_ALPHA_MASK); break; + case POOL_WATEREXCLUSION: + poolp = new LLDrawPoolWaterExclusion(); + break; default: LL_ERRS() << "Unknown draw pool type!" << LL_ENDL; return NULL; diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h index bc412214c7..1c8864a9df 100644 --- a/indra/newview/lldrawpool.h +++ b/indra/newview/lldrawpool.h @@ -55,6 +55,7 @@ public: // based on fill rate and likelihood to occlude future passes (faster, large occluders first). // POOL_SKY = 1, + POOL_WATEREXCLUSION, POOL_WL_SKY, POOL_SIMPLE, POOL_FULLBRIGHT, @@ -140,7 +141,7 @@ public: PASS_GRASS, PASS_FULLBRIGHT, PASS_FULLBRIGHT_RIGGED, - PASS_INVISIBLE, + PASS_INVISIBLE, // Formerly, invisiprims. Now, water exclusion surfaces. PASS_INVISIBLE_RIGGED, PASS_INVISI_SHINY, PASS_INVISI_SHINY_RIGGED, diff --git a/indra/newview/lldrawpoolwater.cpp b/indra/newview/lldrawpoolwater.cpp index 53d6e528b6..32de0e5ee7 100644 --- a/indra/newview/lldrawpoolwater.cpp +++ b/indra/newview/lldrawpoolwater.cpp @@ -176,173 +176,156 @@ void LLDrawPoolWater::renderPostDeferred(S32 pass) light_diffuse *= (1.5f + (6.f * ground_proj_sq)); } - // set up normal maps filtering - for (auto norm_map : mWaterNormp) - { - if (norm_map) norm_map->setFilteringOption(has_normal_mips ? LLTexUnit::TFO_ANISOTROPIC : LLTexUnit::TFO_POINT); - } + LLTexUnit::eTextureFilterOptions filter_mode = has_normal_mips ? LLTexUnit::TFO_ANISOTROPIC : LLTexUnit::TFO_POINT; LLColor4 specular(sun_up ? psky->getSunlightColor() : psky->getMoonlightColor()); F32 phase_time = (F32) LLFrameTimer::getElapsedSeconds() * 0.5f; LLGLSLShader *shader = nullptr; - // two passes, first with standard water shader bound, second with edge water shader bound - for (int edge = 0; edge < 2; edge++) + // One pass, one of two shaders. Void water and region water share state. + // There isn't a good reason anymore to really have void water run in a separate pass. + // It also just introduced a bunch of weird state consistency stuff that we really don't need. + // Not to mention, re-binding the the same shader and state for that shader is kind of wasteful. + // - Geenz 2025-02-11 + // select shader + if (underwater) { - // select shader - if (underwater) - { - shader = &gUnderWaterProgram; - } - else - { - if (edge) - { - shader = &gWaterEdgeProgram; - } - else - { - shader = &gWaterProgram; - } - } + shader = &gUnderWaterProgram; + } + else + { + shader = &gWaterProgram; + } - gPipeline.bindDeferredShader(*shader, nullptr, &gPipeline.mWaterDis); + gPipeline.bindDeferredShader(*shader, nullptr, &gPipeline.mWaterDis); - //bind normal map - S32 bumpTex = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP); - S32 bumpTex2 = shader->enableTexture(LLViewerShaderMgr::BUMP_MAP2); + LLViewerTexture* tex_a = mWaterNormp[0]; + LLViewerTexture* tex_b = mWaterNormp[1]; - LLViewerTexture* tex_a = mWaterNormp[0]; - LLViewerTexture* tex_b = mWaterNormp[1]; + F32 blend_factor = (F32)pwater->getBlendFactor(); - F32 blend_factor = (F32)pwater->getBlendFactor(); + if (tex_a && (!tex_b || (tex_a == tex_b))) + { + shader->bindTexture(LLViewerShaderMgr::BUMP_MAP, tex_a); + tex_a->setFilteringOption(filter_mode); + blend_factor = 0; // only one tex provided, no blending + } + else if (tex_b && !tex_a) + { + shader->bindTexture(LLViewerShaderMgr::BUMP_MAP, tex_b); + tex_a->setFilteringOption(filter_mode); + blend_factor = 0; // only one tex provided, no blending + } + else if (tex_b != tex_a) + { + shader->bindTexture(LLViewerShaderMgr::BUMP_MAP, tex_a); + tex_a->setFilteringOption(filter_mode); + shader->bindTexture(LLViewerShaderMgr::BUMP_MAP2, tex_b); + tex_b->setFilteringOption(filter_mode); + } - gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE); - gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE); + shader->bindTexture(LLShaderMgr::WATER_EXCLUSIONTEX, &gPipeline.mWaterExclusionMask); - if (tex_a && (!tex_b || (tex_a == tex_b))) - { - gGL.getTexUnit(bumpTex)->bind(tex_a); - blend_factor = 0; // only one tex provided, no blending - } - else if (tex_b && !tex_a) - { - gGL.getTexUnit(bumpTex)->bind(tex_b); - blend_factor = 0; // only one tex provided, no blending - } - else if (tex_b != tex_a) - { - gGL.getTexUnit(bumpTex)->bind(tex_a); - gGL.getTexUnit(bumpTex2)->bind(tex_b); - } + shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor); - // bind reflection texture from RenderTarget - S32 screentex = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX); + F32 fog_density = pwater->getModifiedWaterFogDensity(underwater); - F32 screenRes[] = { 1.f / gGLViewport[2], 1.f / gGLViewport[3] }; + shader->bindTexture(LLShaderMgr::WATER_SCREENTEX, &gPipeline.mWaterDis); - shader->uniform2fv(LLShaderMgr::DEFERRED_SCREEN_RES, 1, screenRes); - shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor); + if (mShaderLevel == 1) + { + fog_color.mV[VALPHA] = (F32)(log(fog_density) / log(2)); + } - F32 fog_density = pwater->getModifiedWaterFogDensity(underwater); + F32 water_height = environment.getWaterHeight(); + F32 camera_height = LLViewerCamera::getInstance()->getOrigin().mV[2]; + shader->uniform1f(LLShaderMgr::WATER_WATERHEIGHT, camera_height - water_height); + shader->uniform1f(LLShaderMgr::WATER_TIME, phase_time); + shader->uniform3fv(LLShaderMgr::WATER_EYEVEC, 1, LLViewerCamera::getInstance()->getOrigin().mV); - if (screentex > -1) - { - shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, fog_density); - gGL.getTexUnit(screentex)->bind(&gPipeline.mWaterDis); - } + shader->uniform3fv(LLShaderMgr::WATER_SPECULAR, 1, light_diffuse.mV); - if (mShaderLevel == 1) - { - fog_color.mV[VALPHA] = (F32)(log(fog_density) / log(2)); - } + shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, pwater->getWave1Dir().mV); + shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, pwater->getWave2Dir().mV); - F32 water_height = environment.getWaterHeight(); - F32 camera_height = LLViewerCamera::getInstance()->getOrigin().mV[2]; - shader->uniform1f(LLShaderMgr::WATER_WATERHEIGHT, camera_height - water_height); - shader->uniform1f(LLShaderMgr::WATER_TIME, phase_time); - shader->uniform3fv(LLShaderMgr::WATER_EYEVEC, 1, LLViewerCamera::getInstance()->getOrigin().mV); + shader->uniform3fv(LLShaderMgr::WATER_LIGHT_DIR, 1, light_dir.mV); - shader->uniform4fv(LLShaderMgr::SPECULAR_COLOR, 1, specular.mV); - shader->uniform4fv(LLShaderMgr::WATER_FOGCOLOR, 1, fog_color.mV); - shader->uniform3fv(LLShaderMgr::WATER_FOGCOLOR_LINEAR, 1, fog_color_linear.mV); + shader->uniform3fv(LLShaderMgr::WATER_NORM_SCALE, 1, pwater->getNormalScale().mV); + shader->uniform1f(LLShaderMgr::WATER_FRESNEL_SCALE, pwater->getFresnelScale()); + shader->uniform1f(LLShaderMgr::WATER_FRESNEL_OFFSET, pwater->getFresnelOffset()); + shader->uniform1f(LLShaderMgr::WATER_BLUR_MULTIPLIER, fmaxf(0, pwater->getBlurMultiplier()) * 2); - shader->uniform3fv(LLShaderMgr::WATER_SPECULAR, 1, light_diffuse.mV); - shader->uniform1f(LLShaderMgr::WATER_SPECULAR_EXP, light_exp); + static LLStaticHashedString s_exposure("exposure"); + static LLStaticHashedString tonemap_mix("tonemap_mix"); + static LLStaticHashedString tonemap_type("tonemap_type"); - shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, pwater->getWave1Dir().mV); - shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, pwater->getWave2Dir().mV); + static LLCachedControl<F32> exposure(gSavedSettings, "RenderExposure", 1.f); - shader->uniform3fv(LLShaderMgr::WATER_LIGHT_DIR, 1, light_dir.mV); + F32 e = llclamp(exposure(), 0.5f, 4.f); - shader->uniform3fv(LLShaderMgr::WATER_NORM_SCALE, 1, pwater->getNormalScale().mV); - shader->uniform1f(LLShaderMgr::WATER_FRESNEL_SCALE, pwater->getFresnelScale()); - shader->uniform1f(LLShaderMgr::WATER_FRESNEL_OFFSET, pwater->getFresnelOffset()); - shader->uniform1f(LLShaderMgr::WATER_BLUR_MULTIPLIER, pwater->getBlurMultiplier()); + static LLCachedControl<bool> should_auto_adjust(gSavedSettings, "RenderSkyAutoAdjustLegacy", false); - F32 sunAngle = llmax(0.f, light_dir.mV[1]); - F32 scaledAngle = 1.f - sunAngle; + shader->uniform1f(s_exposure, e); + static LLCachedControl<U32> tonemap_type_setting(gSavedSettings, "RenderTonemapType", 0U); + shader->uniform1i(tonemap_type, tonemap_type_setting); + shader->uniform1f(tonemap_mix, psky->getTonemapMix(should_auto_adjust())); - shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up ? 1 : 0); - shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE, sunAngle); - shader->uniform1f(LLShaderMgr::WATER_SCALED_ANGLE, scaledAngle); - shader->uniform1f(LLShaderMgr::WATER_SUN_ANGLE2, 0.1f + 0.2f * sunAngle); - shader->uniform1i(LLShaderMgr::WATER_EDGE_FACTOR, edge ? 1 : 0); + F32 sunAngle = llmax(0.f, light_dir.mV[1]); + F32 scaledAngle = 1.f - sunAngle; - // SL-15861 This was changed from getRotatedLightNorm() as it was causing - // lightnorm in shaders\class1\windlight\atmosphericsFuncs.glsl in have inconsistent additive lighting for 180 degrees of the FOV. - LLVector4 rotated_light_direction = LLEnvironment::instance().getClampedLightNorm(); - shader->uniform3fv(LLViewerShaderMgr::LIGHTNORM, 1, rotated_light_direction.mV); + shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up ? 1 : 0); - shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV); + // SL-15861 This was changed from getRotatedLightNorm() as it was causing + // lightnorm in shaders\class1\windlight\atmosphericsFuncs.glsl in have inconsistent additive lighting for 180 degrees of the FOV. + LLVector4 rotated_light_direction = LLEnvironment::instance().getClampedLightNorm(); + shader->uniform3fv(LLViewerShaderMgr::LIGHTNORM, 1, rotated_light_direction.mV); - if (LLViewerCamera::getInstance()->cameraUnderWater()) - { - shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleBelow()); - } - else - { - shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleAbove()); - } + shader->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV); - LLGLDisable cullface(GL_CULL_FACE); + if (LLViewerCamera::getInstance()->cameraUnderWater()) + { + shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleBelow()); + } + else + { + shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleAbove()); + } - LLVOWater* water = nullptr; - for (LLFace* const& face : mDrawFace) - { - if (!face) continue; - water = static_cast<LLVOWater*>(face->getViewerObject()); - if (!water) continue; - - if ((bool)edge == (bool)water->getIsEdgePatch()) - { - face->renderIndexed(); - - // Note non-void water being drawn, updates required - if (!edge) // SL-16461 remove !LLPipeline::sUseOcclusion check - { - sNeedsReflectionUpdate = true; - sNeedsDistortionUpdate = true; - } - } - } + LLGLDisable cullface(GL_CULL_FACE); - shader->disableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP); - shader->disableTexture(LLShaderMgr::WATER_SCREENTEX); - shader->disableTexture(LLShaderMgr::BUMP_MAP); - shader->disableTexture(LLShaderMgr::WATER_REFTEX); + // Only push the water planes once. + // Previously we did this twice: once for void water and one for region water. + // However, the void water and region water shaders are the same exact shader. + // They also had the same exact state with the sole exception setting an edge water flag. + // That flag was not actually used anywhere in the shaders. + // - Geenz 2025-02-11 + pushWaterPlanes(0); - // clean up - gPipeline.unbindDeferredShader(*shader); + // clean up + gPipeline.unbindDeferredShader(*shader); - gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE); - gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE); - } + gGL.setColorMask(true, false); +} - gGL.getTexUnit(0)->activate(); - gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE); +void LLDrawPoolWater::pushWaterPlanes(int pass) +{ + LLVOWater* water = nullptr; + for (LLFace* const& face : mDrawFace) + { + water = static_cast<LLVOWater*>(face->getViewerObject()); - gGL.setColorMask(true, false); + face->renderIndexed(); + + // Note non-void water being drawn, updates required + // Previously we had some logic to determine if this pass was also our water edge pass. + // Now we only have one pass. Check if we're doing a region water plane or void water plane. + // - Geenz 2025-02-11 + if (!water->getIsEdgePatch()) + { + sNeedsReflectionUpdate = true; + sNeedsDistortionUpdate = true; + } + } } LLViewerTexture *LLDrawPoolWater::getDebugTexture() diff --git a/indra/newview/lldrawpoolwater.h b/indra/newview/lldrawpoolwater.h index f64477a059..7fc9b68bcf 100644 --- a/indra/newview/lldrawpoolwater.h +++ b/indra/newview/lldrawpoolwater.h @@ -74,6 +74,8 @@ public: void setOpaqueTexture(const LLUUID& opaqueTextureId); void setNormalMaps(const LLUUID& normalMapId, const LLUUID& nextNormalMapId); + void pushWaterPlanes(int pass); + protected: void renderOpaqueLegacyWater(); }; diff --git a/indra/newview/lldrawpoolwaterexclusion.cpp b/indra/newview/lldrawpoolwaterexclusion.cpp new file mode 100644 index 0000000000..d796bf39bf --- /dev/null +++ b/indra/newview/lldrawpoolwaterexclusion.cpp @@ -0,0 +1,79 @@ +/** + * @file lldrawpool.cpp + * @brief LLDrawPoolMaterials class implementation + * @author Jonathan "Geenz" Goodman + * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "llviewerprecompiledheaders.h" + +#include "lldrawpoolwaterexclusion.h" +#include "llviewershadermgr.h" +#include "pipeline.h" +#include "llglcommonfunc.h" +#include "llvoavatar.h" +#include "lldrawpoolwater.h" + +LLDrawPoolWaterExclusion::LLDrawPoolWaterExclusion() : LLRenderPass(LLDrawPool::POOL_WATEREXCLUSION) +{ + LL_INFOS("DPInvisible") << "Creating water exclusion draw pool" << LL_ENDL; +} + + +void LLDrawPoolWaterExclusion::render(S32 pass) +{ // render invisiprims + LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; // LL_RECORD_BLOCK_TIME(FTM_RENDER_INVISIBLE); + + if (gPipeline.shadersLoaded()) + { + gDrawColorProgram.bind(); + } + + + LLGLDepthTest depth(GL_TRUE); + gDrawColorProgram.uniform4f(LLShaderMgr::DIFFUSE_COLOR, 1, 1, 1, 1); + + LLDrawPoolWater* pwaterpool = (LLDrawPoolWater*)gPipeline.getPool(LLDrawPool::POOL_WATER); + if (pwaterpool) + { + // Just treat our water planes as double sided for the purposes of generating the exclusion mask. + LLGLDisable cullface(GL_CULL_FACE); + pwaterpool->pushWaterPlanes(0); + + // Take care of the edge water tiles. + pwaterpool->pushWaterPlanes(1); + } + + gDrawColorProgram.uniform4f(LLShaderMgr::DIFFUSE_COLOR, 0, 0, 0, 1); + + static LLStaticHashedString waterSign("waterSign"); + gDrawColorProgram.uniform1f(waterSign, 1.f); + + pushBatches(LLRenderPass::PASS_INVISIBLE, false, false); + + + if (gPipeline.shadersLoaded()) + { + gDrawColorProgram.unbind(); + } +} diff --git a/indra/newview/lldrawpoolwaterexclusion.h b/indra/newview/lldrawpoolwaterexclusion.h new file mode 100644 index 0000000000..e95721a443 --- /dev/null +++ b/indra/newview/lldrawpoolwaterexclusion.h @@ -0,0 +1,61 @@ +/** + * @file lldrawpoolwaterexclusion.h + * @brief LLDrawPoolWaterExclusion class definition + * @author Jonathan "Geenz" Goodman + * + * $LicenseInfo:firstyear=2025&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2013, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLDRAWPOOLWATEREXCLUSION_H +#define LL_LLDRAWPOOLWATEREXCLUSION_H + +#include "v4coloru.h" +#include "v2math.h" +#include "v3math.h" +#include "llvertexbuffer.h" +#include "lldrawpool.h" + +class LLViewerTexture; +class LLDrawInfo; +class LLGLSLShader; + +class LLDrawPoolWaterExclusion : public LLRenderPass +{ +public: + LLDrawPoolWaterExclusion(); + + enum + { + VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX + }; + + virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; } + + virtual void prerender() {} + + virtual void render(S32 pass = 0); + virtual void beginRenderPass(S32 pass) {} + virtual void endRenderPass(S32 pass) {} + virtual S32 getNumPasses() { return 1; } +}; + +#endif // LL_LLDRAWPOOLWATEREXCLUSION_H diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index d511171679..c103d40a38 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -4231,14 +4231,9 @@ void LLFolderBridge::staticFolderOptionsMenu() bool LLFolderBridge::checkFolderForContentsOfType(LLInventoryModel* model, LLInventoryCollectFunctor& is_type) { - LLInventoryModel::cat_array_t cat_array; - LLInventoryModel::item_array_t item_array; - model->collectDescendentsIf(mUUID, - cat_array, - item_array, + return model->hasMatchingDescendents(mUUID, LLInventoryModel::EXCLUDE_TRASH, is_type); - return !item_array.empty(); } void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items, menuentry_vec_t& disabled_items) @@ -4415,21 +4410,26 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items //Added by aura to force inventory pull on right-click to display folder options correctly. 07-17-06 mCallingCards = mWearables = false; - LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD); - if (checkFolderForContentsOfType(model, is_callingcard)) + if (gInventory.getRootFolderID() != mUUID) { - mCallingCards=true; - } + LLIsType is_callingcard(LLAssetType::AT_CALLINGCARD); + if (checkFolderForContentsOfType(model, is_callingcard)) + { + mCallingCards = true; + } - LLFindWearables is_wearable; - LLIsType is_object( LLAssetType::AT_OBJECT ); - LLIsType is_gesture( LLAssetType::AT_GESTURE ); + const std::vector<LLAssetType::EType> types = { LLAssetType::AT_CLOTHING, LLAssetType::AT_BODYPART, LLAssetType::AT_OBJECT, LLAssetType::AT_GESTURE }; + LLIsOneOfTypes is_wearable(types); - if (checkFolderForContentsOfType(model, is_wearable) || - checkFolderForContentsOfType(model, is_object) || - checkFolderForContentsOfType(model, is_gesture) ) + if (checkFolderForContentsOfType(model, is_wearable)) + { + mWearables = true; + } + } + else { - mWearables=true; + // Assume that there are wearables in the root folder + mWearables = true; } items.push_back(std::string("Set favorite folder")); @@ -4444,13 +4444,10 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t& items LLFolderType::EType type = category->getPreferredType(); const bool is_system_folder = LLFolderType::lookupIsProtectedType(type); - LLFindWearables is_wearable; - LLIsType is_object(LLAssetType::AT_OBJECT); - LLIsType is_gesture(LLAssetType::AT_GESTURE); + const std::vector<LLAssetType::EType> types = { LLAssetType::AT_CLOTHING, LLAssetType::AT_BODYPART, LLAssetType::AT_OBJECT, LLAssetType::AT_GESTURE }; + LLIsOneOfTypes is_wearable(types); - if (checkFolderForContentsOfType(model, is_wearable) || - checkFolderForContentsOfType(model, is_object) || - checkFolderForContentsOfType(model, is_gesture)) + if (checkFolderForContentsOfType(model, is_wearable)) { mWearables = true; } @@ -4573,14 +4570,11 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags, menuentry_vec_t& // wearables related functionality for folders. //is_wearable - LLFindWearables is_wearable; - LLIsType is_object( LLAssetType::AT_OBJECT ); - LLIsType is_gesture( LLAssetType::AT_GESTURE ); + const std::vector<LLAssetType::EType> types = { LLAssetType::AT_CLOTHING, LLAssetType::AT_BODYPART, LLAssetType::AT_OBJECT, LLAssetType::AT_GESTURE }; + LLIsOneOfTypes is_wearable(types); if (mWearables || - checkFolderForContentsOfType(model, is_wearable) || - checkFolderForContentsOfType(model, is_object) || - checkFolderForContentsOfType(model, is_gesture) ) + checkFolderForContentsOfType(model, is_wearable)) { // Only enable add/replace outfit for non-system folders. if (!is_system_folder) diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index dadd0590a9..1ccefa3212 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2634,6 +2634,22 @@ bool LLIsType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) return false; } +bool LLIsOneOfTypes::operator()(LLInventoryCategory* cat, LLInventoryItem* item) +{ + for (LLAssetType::EType &type : mTypes) + { + if (type == LLAssetType::AT_CATEGORY) + { + if (cat) return true; + } + if (item) + { + if (item->getType() == type) return true; + } + } + return false; +} + bool LLIsNotType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) { if(mType == LLAssetType::AT_CATEGORY) diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index a25c0d5ad6..13a64f21dc 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -246,6 +246,24 @@ protected: }; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLIsOneOfTypes +// +// Implementation of a LLInventoryCollectFunctor which returns true if +// the type is one of the types passed in during construction. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +class LLIsOneOfTypes : public LLInventoryCollectFunctor +{ +public: + LLIsOneOfTypes(const std::vector<LLAssetType::EType> &types) : mTypes(types) {} + virtual ~LLIsOneOfTypes() {} + virtual bool operator()(LLInventoryCategory* cat, + LLInventoryItem* item); +protected: + std::vector <LLAssetType::EType> mTypes; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Class LLIsNotType // // Implementation of a LLInventoryCollectFunctor which returns false if the diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 53ea02983a..b6ff31a7ed 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1305,6 +1305,47 @@ void LLInventoryModel::collectDescendentsIf(const LLUUID& id, } } +bool LLInventoryModel::hasMatchingDescendents(const LLUUID& id, + bool include_trash, + LLInventoryCollectFunctor& matches) +{ + if (!include_trash) + { + const LLUUID trash_id = findCategoryUUIDForType(LLFolderType::FT_TRASH); + if (trash_id.notNull() && (trash_id == id)) + return false; + } + cat_array_t* cat_array = get_ptr_in_map(mParentChildCategoryTree, id); + if (cat_array) + { + for (auto& cat : *cat_array) + { + if (matches(cat, NULL)) + { + return true; + } + if (hasMatchingDescendents(cat->getUUID(), include_trash, matches)) + { + return true; + } + } + } + + item_array_t* item_array = get_ptr_in_map(mParentChildItemTree, id); + + if (item_array) + { + for (auto& item : *item_array) + { + if (matches(NULL, item)) + { + return true; + } + } + } + return false; +} + void LLInventoryModel::addChangedMaskForLinks(const LLUUID& object_id, U32 mask) { const LLInventoryObject *obj = getObject(object_id); diff --git a/indra/newview/llinventorymodel.h b/indra/newview/llinventorymodel.h index 1472b705e4..d28743357e 100644 --- a/indra/newview/llinventorymodel.h +++ b/indra/newview/llinventorymodel.h @@ -287,6 +287,9 @@ public: item_array_t& items, bool include_trash, LLInventoryCollectFunctor& add); + bool hasMatchingDescendents(const LLUUID& id, + bool include_trash, + LLInventoryCollectFunctor& add); // Collect all items in inventory that are linked to item_id. // Assumes item_id is itself not a linked item. diff --git a/indra/newview/llinventorypanel.cpp b/indra/newview/llinventorypanel.cpp index bf12e6a7e0..1795de727d 100644 --- a/indra/newview/llinventorypanel.cpp +++ b/indra/newview/llinventorypanel.cpp @@ -580,7 +580,7 @@ void LLInventoryPanel::itemChanged(const LLUUID& item_id, U32 mask, const LLInve { if (model_item && view_item && viewmodel_item) { - const LLUUID& idp = viewmodel_item->getUUID(); + const LLUUID idp = viewmodel_item->getUUID(); removeItemID(idp); view_item->destroyView(); } @@ -1335,6 +1335,8 @@ void LLInventoryPanel::openStartFolderOrMyInventory() LLFolderViewFolder *fchild = dynamic_cast<LLFolderViewFolder*>(child); if (fchild && fchild->getViewModelItem() + // Is this right? Name might be localized, + // use FT_ROOT_INVENTORY or gInventory.getRootFolderID()? && fchild->getViewModelItem()->getName() == "My Inventory") { fchild->setOpen(true); diff --git a/indra/newview/llpanelgroupbulk.cpp b/indra/newview/llpanelgroupbulk.cpp index 433db74cda..8032e207cd 100644 --- a/indra/newview/llpanelgroupbulk.cpp +++ b/indra/newview/llpanelgroupbulk.cpp @@ -56,6 +56,7 @@ LLPanelGroupBulkImpl::LLPanelGroupBulkImpl(const LLUUID& group_id) : mGroupID(group_id), mBulkAgentList(NULL), mOKButton(NULL), + mAddButton(nullptr), mRemoveButton(NULL), mGroupName(NULL), mLoadingText(), @@ -79,29 +80,18 @@ LLPanelGroupBulkImpl::~LLPanelGroupBulkImpl() } } -// static -void LLPanelGroupBulkImpl::callbackClickAdd(void* userdata) +void LLPanelGroupBulkImpl::callbackClickAdd(LLPanelGroupBulk* panelp) { - if (LLPanelGroupBulk* panelp = (LLPanelGroupBulk*)userdata) - { - // Right now this is hard coded with some knowledge that it is part - // of a floater since the avatar picker needs to be added as a dependent - // floater to the parent floater. - // Soon the avatar picker will be embedded into this panel - // instead of being it's own separate floater. But that is next week. - // This will do for now. -jwolk May 10, 2006 - LLView* button = panelp->findChild<LLButton>("add_button"); - LLFloater* root_floater = gFloaterView->getParentFloater(panelp); - LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show( - [&](const uuid_vec_t& agent_ids, const std::vector<LLAvatarName>&) - { - panelp->mImplementation->addUsers(agent_ids); - }, true, false, false, root_floater->getName(), button); - if (picker) + LLFloater* root_floater = gFloaterView->getParentFloater(panelp); + LLFloaterAvatarPicker* picker = LLFloaterAvatarPicker::show( + [this](const uuid_vec_t& agent_ids, const std::vector<LLAvatarName>&) { - root_floater->addDependentFloater(picker); - LLGroupMgr::getInstance()->sendCapGroupMembersRequest(panelp->mImplementation->mGroupID); - } + addUsers(agent_ids); + }, true, false, false, root_floater->getName(), mAddButton); + if (picker) + { + root_floater->addDependentFloater(picker); + LLGroupMgr::getInstance()->sendCapGroupMembersRequest(mGroupID); } } diff --git a/indra/newview/llpanelgroupbulkban.cpp b/indra/newview/llpanelgroupbulkban.cpp index 3c764887a6..1d3edad0f3 100644 --- a/indra/newview/llpanelgroupbulkban.cpp +++ b/indra/newview/llpanelgroupbulkban.cpp @@ -68,35 +68,26 @@ bool LLPanelGroupBulkBan::postBuild() mImplementation->mBulkAgentList->setCommitCallback(LLPanelGroupBulkImpl::callbackSelect, mImplementation); } - LLButton* button = getChild<LLButton>("add_button", recurse); - if ( button ) + mImplementation->mAddButton = getChild<LLButton>("add_button", recurse); + // default to opening avatarpicker automatically + mImplementation->mAddButton->setClickedCallback( + [this](LLUICtrl* ctrl, const LLSD& param) { - // default to opening avatarpicker automatically - // (*impl::callbackClickAdd)((void*)this); - button->setClickedCallback(LLPanelGroupBulkImpl::callbackClickAdd, this); - } + mImplementation->callbackClickAdd(this); + }); mImplementation->mRemoveButton = getChild<LLButton>("remove_button", recurse); - if ( mImplementation->mRemoveButton ) - { - mImplementation->mRemoveButton->setClickedCallback(LLPanelGroupBulkImpl::callbackClickRemove, mImplementation); - mImplementation->mRemoveButton->setEnabled(false); - } + mImplementation->mRemoveButton->setClickedCallback(LLPanelGroupBulkImpl::callbackClickRemove, mImplementation); + mImplementation->mRemoveButton->setEnabled(false); mImplementation->mOKButton = getChild<LLButton>("ban_button", recurse); - if ( mImplementation->mOKButton ) - { - mImplementation->mOKButton->setClickedCallback(LLPanelGroupBulkBan::callbackClickSubmit, this); - mImplementation->mOKButton->setEnabled(false); - } + mImplementation->mOKButton->setClickedCallback(LLPanelGroupBulkBan::callbackClickSubmit, this); + mImplementation->mOKButton->setEnabled(false); - button = getChild<LLButton>("cancel_button", recurse); - if ( button ) - { - button->setClickedCallback(LLPanelGroupBulkImpl::callbackClickCancel, mImplementation); - } + LLButton* button = getChild<LLButton>("cancel_button", recurse); + button->setClickedCallback(LLPanelGroupBulkImpl::callbackClickCancel, mImplementation); mImplementation->mTooManySelected = getString("ban_selection_too_large"); mImplementation->mBanNotPermitted = getString("ban_not_permitted"); diff --git a/indra/newview/llpanelgroupbulkimpl.h b/indra/newview/llpanelgroupbulkimpl.h index 5a479f8117..5515bd6d9a 100644 --- a/indra/newview/llpanelgroupbulkimpl.h +++ b/indra/newview/llpanelgroupbulkimpl.h @@ -44,7 +44,7 @@ public: LLPanelGroupBulkImpl(const LLUUID& group_id); ~LLPanelGroupBulkImpl(); - static void callbackClickAdd(void* userdata); + void callbackClickAdd(LLPanelGroupBulk* panelp); static void callbackClickRemove(void* userdata); static void callbackClickCancel(void* userdata); @@ -70,6 +70,7 @@ public: LLNameListCtrl* mBulkAgentList; LLButton* mOKButton; + LLButton* mAddButton; LLButton* mRemoveButton; LLTextBox* mGroupName; diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp index e5b906e19b..7ef13c3a35 100644 --- a/indra/newview/llviewershadermgr.cpp +++ b/indra/newview/llviewershadermgr.cpp @@ -101,6 +101,7 @@ LLGLSLShader gReflectionProbeDisplayProgram; LLGLSLShader gCopyProgram; LLGLSLShader gCopyDepthProgram; LLGLSLShader gPBRTerrainBakeProgram; +LLGLSLShader gDrawColorProgram; //object shaders LLGLSLShader gObjectPreviewProgram; @@ -113,7 +114,6 @@ LLGLSLShader gObjectAlphaMaskNoColorProgram; //environment shaders LLGLSLShader gWaterProgram; -LLGLSLShader gWaterEdgeProgram; LLGLSLShader gUnderWaterProgram; //interface shaders @@ -409,7 +409,6 @@ void LLViewerShaderMgr::finalizeShaderList() //ONLY shaders that need WL Param management should be added here mShaderList.push_back(&gAvatarProgram); mShaderList.push_back(&gWaterProgram); - mShaderList.push_back(&gWaterEdgeProgram); mShaderList.push_back(&gAvatarEyeballProgram); mShaderList.push_back(&gImpostorProgram); mShaderList.push_back(&gObjectBumpProgram); @@ -876,6 +875,7 @@ std::string LLViewerShaderMgr::loadBasicShaders() index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/shadowUtil.glsl", 1) ); index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/aoUtil.glsl", 1) ); index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/pbrterrainUtilF.glsl", 1) ); + index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/tonemapUtilF.glsl", 1) ); index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/reflectionProbeF.glsl", has_reflection_probes ? 3 : 2) ); index_channels.push_back(-1); shaders.push_back( make_pair( "deferred/screenSpaceReflUtil.glsl", ssr ? 3 : 1) ); index_channels.push_back(-1); shaders.push_back( make_pair( "lighting/lightNonIndexedF.glsl", mShaderLevel[SHADER_LIGHTING] ) ); @@ -908,7 +908,6 @@ bool LLViewerShaderMgr::loadShadersWater() if (mShaderLevel[SHADER_WATER] == 0) { gWaterProgram.unload(); - gWaterEdgeProgram.unload(); gUnderWaterProgram.unload(); return true; } @@ -922,6 +921,7 @@ bool LLViewerShaderMgr::loadShadersWater() gWaterProgram.mFeatures.hasGamma = true; gWaterProgram.mFeatures.hasSrgb = true; gWaterProgram.mFeatures.hasReflectionProbes = true; + gWaterProgram.mFeatures.hasTonemap = true; gWaterProgram.mFeatures.hasShadows = use_sun_shadow; gWaterProgram.mShaderFiles.clear(); gWaterProgram.mShaderFiles.push_back(make_pair("environment/waterV.glsl", GL_VERTEX_SHADER)); @@ -945,36 +945,6 @@ bool LLViewerShaderMgr::loadShadersWater() if (success) { - // load water shader - gWaterEdgeProgram.mName = "Water Edge Shader"; - gWaterEdgeProgram.mFeatures.calculatesAtmospherics = true; - gWaterEdgeProgram.mFeatures.hasAtmospherics = true; - gWaterEdgeProgram.mFeatures.hasGamma = true; - gWaterEdgeProgram.mFeatures.hasSrgb = true; - gWaterEdgeProgram.mFeatures.hasReflectionProbes = true; - gWaterEdgeProgram.mFeatures.hasShadows = use_sun_shadow; - gWaterEdgeProgram.mShaderFiles.clear(); - gWaterEdgeProgram.mShaderFiles.push_back(make_pair("environment/waterV.glsl", GL_VERTEX_SHADER)); - gWaterEdgeProgram.mShaderFiles.push_back(make_pair("environment/waterF.glsl", GL_FRAGMENT_SHADER)); - gWaterEdgeProgram.clearPermutations(); - gWaterEdgeProgram.addPermutation("WATER_EDGE", "1"); - if (LLPipeline::sRenderTransparentWater) - { - gWaterEdgeProgram.addPermutation("TRANSPARENT_WATER", "1"); - } - - if (use_sun_shadow) - { - gWaterEdgeProgram.addPermutation("HAS_SUN_SHADOW", "1"); - } - gWaterEdgeProgram.mShaderGroup = LLGLSLShader::SG_WATER; - gWaterEdgeProgram.mShaderLevel = mShaderLevel[SHADER_WATER]; - success = gWaterEdgeProgram.createShader(); - llassert(success); - } - - if (success) - { //load under water vertex shader gUnderWaterProgram.mName = "Underwater Shader"; gUnderWaterProgram.mFeatures.calculatesAtmospherics = true; @@ -2483,6 +2453,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gDeferredPostTonemapProgram.mName = "Deferred Tonemap Post Process"; gDeferredPostTonemapProgram.mFeatures.hasSrgb = true; gDeferredPostTonemapProgram.mFeatures.isDeferred = true; + gDeferredPostTonemapProgram.mFeatures.hasTonemap = true; gDeferredPostTonemapProgram.mShaderFiles.clear(); gDeferredPostTonemapProgram.clearPermutations(); gDeferredPostTonemapProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER)); @@ -2497,6 +2468,7 @@ bool LLViewerShaderMgr::loadShadersDeferred() gNoPostTonemapProgram.mName = "No Post Tonemap Post Process"; gNoPostTonemapProgram.mFeatures.hasSrgb = true; gNoPostTonemapProgram.mFeatures.isDeferred = true; + gNoPostTonemapProgram.mFeatures.hasTonemap = true; gNoPostTonemapProgram.mShaderFiles.clear(); gNoPostTonemapProgram.clearPermutations(); gNoPostTonemapProgram.addPermutation("NO_POST", "1"); @@ -3355,6 +3327,17 @@ bool LLViewerShaderMgr::loadShadersInterface() success = gCopyDepthProgram.createShader(); } + if (success) + { + gDrawColorProgram.mName = "Draw Color Shader"; + gDrawColorProgram.mShaderFiles.clear(); + gDrawColorProgram.mShaderFiles.push_back(make_pair("objects/simpleNoAtmosV.glsl", GL_VERTEX_SHADER)); + gDrawColorProgram.mShaderFiles.push_back(make_pair("objects/simpleColorF.glsl", GL_FRAGMENT_SHADER)); + gDrawColorProgram.clearPermutations(); + gDrawColorProgram.mShaderLevel = mShaderLevel[SHADER_OBJECT]; + success = gDrawColorProgram.createShader(); + } + if (gSavedSettings.getBOOL("LocalTerrainPaintEnabled")) { if (success) diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h index b08796025a..7ad2da9464 100644 --- a/indra/newview/llviewershadermgr.h +++ b/indra/newview/llviewershadermgr.h @@ -175,6 +175,7 @@ extern LLGLSLShader gReflectionProbeDisplayProgram; extern LLGLSLShader gCopyProgram; extern LLGLSLShader gCopyDepthProgram; extern LLGLSLShader gPBRTerrainBakeProgram; +extern LLGLSLShader gDrawColorProgram; //output tex0[tc0] - tex1[tc1] extern LLGLSLShader gTwoTextureCompareProgram; @@ -191,7 +192,6 @@ extern LLGLSLShader gObjectAlphaMaskNoColorProgram; //environment shaders extern LLGLSLShader gWaterProgram; -extern LLGLSLShader gWaterEdgeProgram; extern LLGLSLShader gUnderWaterProgram; extern LLGLSLShader gGlowProgram; extern LLGLSLShader gGlowExtractProgram; diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp index 1084fb91da..609ad38e96 100644 --- a/indra/newview/llviewertexture.cpp +++ b/indra/newview/llviewertexture.cpp @@ -3548,18 +3548,7 @@ void LLViewerMediaTexture::setPlaying(bool playing) for(std::list< LLFace* >::iterator iter = mMediaFaceList.begin(); iter!= mMediaFaceList.end(); ++iter) { LLFace* facep = *iter; - const LLTextureEntry* te = facep->getTextureEntry(); - if (te && te->getGLTFMaterial()) - { - // PBR material, switch emissive and basecolor - switchTexture(LLRender::EMISSIVE_MAP, *iter); - switchTexture(LLRender::BASECOLOR_MAP, *iter); - } - else - { - // blinn-phong material, switch diffuse map only - switchTexture(LLRender::DIFFUSE_MAP, *iter); - } + switchTexture(LLRender::DIFFUSE_MAP, facep); } } else //stop playing this media diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 126a77ad6f..a4a001eceb 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -276,7 +276,7 @@ void LLViewerTextureList::doPrefetchImages() S32 pixel_area = imagesd["area"]; S32 texture_type = imagesd["type"]; - if(LLViewerTexture::FETCHED_TEXTURE == texture_type || LLViewerTexture::LOD_TEXTURE == texture_type) + if((LLViewerTexture::FETCHED_TEXTURE == texture_type || LLViewerTexture::LOD_TEXTURE == texture_type)) { LLViewerFetchedTexture* image = LLViewerTextureManager::getFetchedTexture(uuid, FTT_DEFAULT, MIPMAP_TRUE, LLGLTexture::BOOST_NONE, texture_type); if (image) @@ -1091,7 +1091,8 @@ F32 LLViewerTextureList::updateImagesCreateTextures(F32 max_time) imagep->mCreatePending = false; mCreateTextureList.pop(); - if (imagep->hasGLTexture() && imagep->getDiscardLevel() < imagep->getDesiredDiscardLevel()) + if (imagep->hasGLTexture() && imagep->getDiscardLevel() < imagep->getDesiredDiscardLevel() && + (imagep->getDesiredDiscardLevel() <= MAX_DISCARD_LEVEL)) { // NOTE: this may happen if the desired discard reduces while a decode is in progress and does not // necessarily indicate a problem, but if log occurrences excede that of dsiplay_stats: FPS, diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index d399cc6469..f1d406f199 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -1746,6 +1746,7 @@ bool LLViewerWindow::handleDeviceChange(LLWindow *window) bool LLViewerWindow::handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height) { + LLFontGL::sResolutionGeneration++; if (ui_scale_factor >= MIN_UI_SCALE && ui_scale_factor <= MAX_UI_SCALE) { LLViewerWindow::reshape(window_width, window_height); @@ -1759,6 +1760,12 @@ bool LLViewerWindow::handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 } } +bool LLViewerWindow::handleDisplayChanged() +{ + LLFontGL::sResolutionGeneration++; + return false; +} + bool LLViewerWindow::handleWindowDidChangeScreen(LLWindow *window) { LLCoordScreen window_rect; @@ -1927,6 +1934,7 @@ LLViewerWindow::LLViewerWindow(const Params& p) mDisplayScale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f)); mDisplayScale *= ui_scale_factor; LLUI::setScaleFactor(mDisplayScale); + LLFontGL::sResolutionGeneration++; { LLCoordWindow size; @@ -2496,6 +2504,7 @@ void LLViewerWindow::reshape(S32 width, S32 height) bool display_scale_changed = mDisplayScale != LLUI::getScaleFactor(); LLUI::setScaleFactor(mDisplayScale); + LLFontGL::sResolutionGeneration++; // update our window rectangle mWindowRectScaled.mRight = mWindowRectScaled.mLeft + ll_round((F32)width / mDisplayScale.mV[VX]); diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index 1b995ea650..fbc2c58fbf 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -225,6 +225,7 @@ public: /*virtual*/ bool handleTimerEvent(LLWindow *window); /*virtual*/ bool handleDeviceChange(LLWindow *window); /*virtual*/ bool handleDPIChanged(LLWindow *window, F32 ui_scale_factor, S32 window_width, S32 window_height); + /*virtual*/ bool handleDisplayChanged(); /*virtual*/ bool handleWindowDidChangeScreen(LLWindow *window); /*virtual*/ void handlePingWatchdog(LLWindow *window, const char * msg); diff --git a/indra/newview/llvoiceclient.cpp b/indra/newview/llvoiceclient.cpp index 3d8ffc35e7..e5eb2f8008 100644 --- a/indra/newview/llvoiceclient.cpp +++ b/indra/newview/llvoiceclient.cpp @@ -293,6 +293,7 @@ void LLVoiceClient::setNonSpatialVoiceModule(const std::string &voice_server_typ void LLVoiceClient::setHidden(bool hidden) { + LL_INFOS("Voice") << "( " << (hidden ? "true" : "false") << " )" << LL_ENDL; #if !__FreeBSD__ LLWebRTCVoiceClient::getInstance()->setHidden(hidden); #endif diff --git a/indra/newview/llvoicevivox.cpp b/indra/newview/llvoicevivox.cpp index d64c25d312..7faef8cc41 100644 --- a/indra/newview/llvoicevivox.cpp +++ b/indra/newview/llvoicevivox.cpp @@ -2014,7 +2014,7 @@ bool LLVivoxVoiceClient::waitForChannel() { recordingAndPlaybackMode(); } - else if (mProcessChannels && (mNextAudioSession == NULL) && checkParcelChanged()) + else if (mProcessChannels && ((mNextAudioSession == NULL) || checkParcelChanged())) { // the parcel is changed, or we have no pending audio sessions, // so try to request the parcel voice info diff --git a/indra/newview/llvoicewebrtc.cpp b/indra/newview/llvoicewebrtc.cpp index b2e5de5371..0bb65f7431 100644 --- a/indra/newview/llvoicewebrtc.cpp +++ b/indra/newview/llvoicewebrtc.cpp @@ -345,6 +345,8 @@ void LLWebRTCVoiceClient::updateSettings() static LLCachedControl<std::string> sOutputDevice(gSavedSettings, "VoiceOutputAudioDevice"); setRenderDevice(sOutputDevice); + LL_INFOS("Voice") << "Input device: " << std::quoted(sInputDevice()) << ", output device: " << std::quoted(sOutputDevice()) << LL_ENDL; + static LLCachedControl<F32> sMicLevel(gSavedSettings, "AudioLevelMic"); setMicGain(sMicLevel); @@ -896,7 +898,7 @@ void LLWebRTCVoiceClient::OnConnectionShutDown(const std::string &channelID, con { if (mSession && mSession->mChannelID == channelID) { - LL_DEBUGS("Voice") << "Main WebRTC Connection Shut Down." << LL_ENDL; + LL_INFOS("Voice") << "Main WebRTC Connection Shut Down." << LL_ENDL; } } mSession->removeAllParticipants(regionID); @@ -1504,6 +1506,11 @@ bool LLWebRTCVoiceClient::compareChannels(const LLSD &channelInfo1, const LLSD & // we're muting the mic, so tell each session such void LLWebRTCVoiceClient::setMuteMic(bool muted) { + if (mMuteMic != muted) + { + LL_INFOS("Voice") << "( " << (muted ? "true" : "false") << " )" << LL_ENDL; + } + mMuteMic = muted; // when you're hidden, your mic is always muted. if (!mHidden) @@ -1552,14 +1559,10 @@ void LLWebRTCVoiceClient::setVoiceEnabled(bool enabled) { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE; - LL_DEBUGS("Voice") - << "( " << (enabled ? "enabled" : "disabled") << " )" - << " was "<< (mVoiceEnabled ? "enabled" : "disabled") - << " coro "<< (mIsCoroutineActive ? "active" : "inactive") - << LL_ENDL; - if (enabled != mVoiceEnabled) { + LL_INFOS("Voice") << "( " << (enabled ? "enabled" : "disabled") << " )" + << ", coro: " << (mIsCoroutineActive ? "active" : "inactive") << LL_ENDL; // TODO: Refactor this so we don't call into LLVoiceChannel, but simply // use the status observer mVoiceEnabled = enabled; @@ -2483,7 +2486,7 @@ void LLVoiceWebRTCConnection::breakVoiceConnectionCoro(connectionPtr_t connectio { LL_PROFILE_ZONE_SCOPED_CATEGORY_VOICE; - LL_DEBUGS("Voice") << "Disconnecting voice." << LL_ENDL; + LL_INFOS("Voice") << "Disconnecting voice." << LL_ENDL; if (connection->mWebRTCDataInterface) { connection->mWebRTCDataInterface->unsetDataObserver(connection.get()); @@ -2591,6 +2594,7 @@ void LLVoiceWebRTCSpatialConnection::requestVoiceConnection() LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); + LL_INFOS("Voice") << "Voice connection request: " << (status ? "Success" : status.toString()) << LL_ENDL; if (status) { OnVoiceConnectionRequestSuccess(result); diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp index 6e946f238b..3fb7a3c156 100644 --- a/indra/newview/llvovolume.cpp +++ b/indra/newview/llvovolume.cpp @@ -5750,7 +5750,12 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group) if (is_pbr) { // tell texture streaming system to ignore blinn-phong textures - facep->setTexture(LLRender::DIFFUSE_MAP, nullptr); + // except the special case of the diffuse map containing a + // media texture that will be reused for swapping on to the pbr face + if (!facep->hasMedia()) + { + facep->setTexture(LLRender::DIFFUSE_MAP, nullptr); + } facep->setTexture(LLRender::NORMAL_MAP, nullptr); facep->setTexture(LLRender::SPECULAR_MAP, nullptr); @@ -6726,8 +6731,11 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace { //shiny if (tex->getPrimaryFormat() == GL_ALPHA) { //invisiprim+shiny - registerFace(group, facep, LLRenderPass::PASS_INVISI_SHINY); - registerFace(group, facep, LLRenderPass::PASS_INVISIBLE); + if (!facep->getViewerObject()->isAttachment() && !facep->getViewerObject()->isRiggedMesh()) + { + registerFace(group, facep, LLRenderPass::PASS_INVISI_SHINY); + registerFace(group, facep, LLRenderPass::PASS_INVISIBLE); + } } else if (!hud_group) { //deferred rendering @@ -6763,7 +6771,10 @@ U32 LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, LLFace { //not alpha and not shiny if (!is_alpha && tex->getPrimaryFormat() == GL_ALPHA) { //invisiprim - registerFace(group, facep, LLRenderPass::PASS_INVISIBLE); + if (!facep->getViewerObject()->isAttachment() && !facep->getViewerObject()->isRiggedMesh()) + { + registerFace(group, facep, LLRenderPass::PASS_INVISIBLE); + } } else if (fullbright || bake_sunlight) { //fullbright diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp index 362930a71e..e441e189ad 100644 --- a/indra/newview/pipeline.cpp +++ b/indra/newview/pipeline.cpp @@ -431,6 +431,7 @@ void LLPipeline::init() stop_glerror(); //create render pass pools + getPool(LLDrawPool::POOL_WATEREXCLUSION); getPool(LLDrawPool::POOL_ALPHA_PRE_WATER); getPool(LLDrawPool::POOL_ALPHA_POST_WATER); getPool(LLDrawPool::POOL_SIMPLE); @@ -673,6 +674,8 @@ void LLPipeline::cleanup() // don't delete wl sky pool it was handled above in the for loop //delete mWLSkyPool; mWLSkyPool = NULL; + delete mWaterExclusionPool; + mWaterExclusionPool = nullptr; releaseGLBuffers(); @@ -907,6 +910,15 @@ bool LLPipeline::allocateScreenBufferInternal(U32 resX, U32 resY) mPostMap.allocate(resX, resY, screenFormat); + // The water exclusion mask needs its own depth buffer so we can take care of the problem of multiple water planes. + // Should we ever make water not just a plane, it also aids with that as well as the water planes will be rendered into the mask. + // Why do we do this? Because it saves us some janky logic in the exclusion shader when we generate the mask. + // Regardless, this should always only be an R8 texture unless we choose to start having multiple kinds of exclusion that 8 bits can't handle. + // - Geenz 2025-02-06 + bool success = mWaterExclusionMask.allocate(resX, resY, GL_R8, true); + + assert(success); + // used to scale down textures // See LLViwerTextureList::updateImagesCreateTextures and LLImageGL::scaleDown mDownResMap.allocate(1024, 1024, GL_RGBA); @@ -1166,6 +1178,8 @@ void LLPipeline::releaseGLBuffers() mSceneMap.release(); + mWaterExclusionMask.release(); + mPostMap.release(); mFXAAMap.release(); @@ -1676,6 +1690,10 @@ LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerTexture *tex0) poolp = mPBRAlphaMaskPool; break; + case LLDrawPool::POOL_WATEREXCLUSION: + poolp = mWaterExclusionPool; + break; + default: llassert(0); LL_ERRS() << "Invalid Pool Type in LLPipeline::findPool() type=" << type << LL_ENDL; @@ -4072,6 +4090,8 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera, bool do_occlusion) #endif } +// Render all of our geometry that's required after our deferred pass. +// This is gonna be stuff like alpha, water, etc. void LLPipeline::renderGeomPostDeferred(LLCamera& camera) { LL_PROFILE_ZONE_SCOPED_CATEGORY_DRAWPOOL; @@ -4090,6 +4110,10 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera) bool done_atmospherics = LLPipeline::sRenderingHUDs; //skip atmospherics on huds bool done_water_haze = done_atmospherics; + bool done_water_exclusion = false; + + // do water exclusion just before water pass. + U32 water_exclusion_pass = LLDrawPool::POOL_WATEREXCLUSION; // do atmospheric haze just before post water alpha U32 atmospherics_pass = LLDrawPool::POOL_ALPHA_POST_WATER; @@ -4128,6 +4152,12 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera) cur_type = poolp->getType(); + if (cur_type >= water_exclusion_pass && !done_water_exclusion) + { // do water exclusion against depth buffer before rendering alpha + doWaterExclusionMask(); + done_water_exclusion = true; + } + if (cur_type >= atmospherics_pass && !done_atmospherics) { // do atmospherics against depth buffer before rendering alpha doAtmospherics(); @@ -5243,6 +5273,17 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp ) } break; + case LLDrawPool::POOL_WATEREXCLUSION: + if (mWaterExclusionPool) + { + llassert(0); + LL_WARNS() << "LLPipeline::addPool(): Ignoring duplicate Water Exclusion Pool" << LL_ENDL; + } + else + { + mWaterExclusionPool = new_poolp; + } + break; default: llassert(0); @@ -5365,6 +5406,11 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp ) mPBRAlphaMaskPool = NULL; break; + case LLDrawPool::POOL_WATEREXCLUSION: + llassert(poolp == mWaterExclusionPool); + mWaterExclusionPool = nullptr; + break; + default: llassert(0); LL_WARNS() << "Invalid Pool Type in LLPipeline::removeFromQuickLookup() type=" << poolp->getType() << LL_ENDL; @@ -8866,6 +8912,7 @@ void LLPipeline::renderDeferredLighting() LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK, LLPipeline::RENDER_TYPE_TERRAIN, LLPipeline::RENDER_TYPE_WATER, + LLPipeline::RENDER_TYPE_WATEREXCLUSION, END_RENDER_TYPES); renderGeomPostDeferred(*LLViewerCamera::getInstance()); @@ -9004,6 +9051,8 @@ void LLPipeline::doWaterHaze() static LLStaticHashedString above_water_str("above_water"); haze_shader.uniform1i(above_water_str, sUnderWaterRender ? -1 : 1); + haze_shader.bindTexture(LLShaderMgr::WATER_EXCLUSIONTEX, &mWaterExclusionMask); + if (LLPipeline::sUnderWaterRender) { LLGLDepthTest depth(GL_FALSE); @@ -9034,6 +9083,17 @@ void LLPipeline::doWaterHaze() } } +void LLPipeline::doWaterExclusionMask() +{ + mWaterExclusionMask.bindTarget(); + glClearColor(1, 1, 1, 1); + mWaterExclusionMask.clear(); + mWaterExclusionPool->render(); + + mWaterExclusionMask.flush(); + glClearColor(0, 0, 0, 0); +} + void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep) { //construct frustum diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h index 5c9b95ef4a..315e38ed8c 100644 --- a/indra/newview/pipeline.h +++ b/indra/newview/pipeline.h @@ -337,6 +337,9 @@ public: // should be called just before rendering pre-water alpha objects void doWaterHaze(); + // Generate the water exclusion surface mask. + void doWaterExclusionMask(); + void postDeferredGammaCorrect(LLRenderTarget* screen_target); void generateSunShadow(LLCamera& camera); @@ -500,6 +503,7 @@ public: RENDER_TYPE_AVATAR = LLDrawPool::POOL_AVATAR, RENDER_TYPE_CONTROL_AV = LLDrawPool::POOL_CONTROL_AV, // Animesh RENDER_TYPE_TREE = LLDrawPool::POOL_TREE, + RENDER_TYPE_WATEREXCLUSION = LLDrawPool::POOL_WATEREXCLUSION, RENDER_TYPE_VOIDWATER = LLDrawPool::POOL_VOIDWATER, RENDER_TYPE_WATER = LLDrawPool::POOL_WATER, RENDER_TYPE_GLTF_PBR = LLDrawPool::POOL_GLTF_PBR, @@ -714,6 +718,7 @@ public: LLRenderTarget mSpotShadow[2]; LLRenderTarget mPbrBrdfLut; + LLRenderTarget mWaterExclusionMask; // copy of the color/depth buffer just before gamma correction // for use by SSR @@ -953,6 +958,7 @@ protected: LLDrawPool* mWLSkyPool = nullptr; LLDrawPool* mPBROpaquePool = nullptr; LLDrawPool* mPBRAlphaMaskPool = nullptr; + LLDrawPool* mWaterExclusionPool = nullptr; // Note: no need to keep an quick-lookup to avatar pools, since there's only one per avatar diff --git a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml index 28c2d2af6e..258c49785e 100644 --- a/indra/newview/skins/default/xui/en/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/en/panel_preferences_setup.xml @@ -202,7 +202,7 @@ follows="left|top" height="14" control_name="UpdaterWillingToTest" - label="Willing to update to release candidates" + label="Willing to update to Beta" left_delta="0" mouse_opaque="true" name="update_willing_to_test" diff --git a/indra/newview/skins/default/xui/ja/panel_preferences_setup.xml b/indra/newview/skins/default/xui/ja/panel_preferences_setup.xml index f487bc32a9..959f827a61 100644 --- a/indra/newview/skins/default/xui/ja/panel_preferences_setup.xml +++ b/indra/newview/skins/default/xui/ja/panel_preferences_setup.xml @@ -30,7 +30,7 @@ <combo_box.item label="オプションのアップデートのインストール準備ができたら通知する" name="Install_ask"/> <combo_box.item label="必須アップデートのみインストールする" name="Install_manual"/> </combo_box> - <check_box label="release candidate にアップグレードします" name="update_willing_to_test"/> + <check_box label="Beta にアップグレードします" name="update_willing_to_test"/> <check_box label="更新後にリリースノートを表示する" name="update_show_release_notes"/> <text name="Proxy Settings:"> プロキシ設定: |