diff options
Diffstat (limited to 'indra')
60 files changed, 1093 insertions, 539 deletions
| 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:">  		プロキシ設定: | 
