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

# Conflicts:
#	indra/llcommon/llqueuedthread.cpp
master
Ansariel 2025-02-13 21:24:29 +01:00
commit 5bf1f485f3
39 changed files with 474 additions and 406 deletions

View File

@ -42,7 +42,7 @@ jobs:
needs: setup
strategy:
matrix:
runner: [windows-large, macos-12-large]
runner: [windows-large, macos-15-xlarge]
configuration: ${{ fromJSON(needs.setup.outputs.configurations) }}
runs-on: ${{ matrix.runner }}
outputs:
@ -64,7 +64,7 @@ jobs:
# autobuild-package.xml.
AUTOBUILD_VCS_INFO: "true"
AUTOBUILD_VSVER: "170"
DEVELOPER_DIR: "/Applications/Xcode_14.0.1.app/Contents/Developer"
DEVELOPER_DIR: "/Applications/Xcode_16.1.app/Contents/Developer"
# Ensure that Linden viewer builds engage Bugsplat.
BUGSPLAT_DB: ${{ needs.setup.outputs.bugsplat_db }}
build_coverity: false

View File

@ -29,6 +29,11 @@ else()
set( USE_AUTOBUILD_3P ON )
endif()
if (NOT DEFINED CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 20)
endif()
set(CMAKE_CXX_STANDARD_REQUIRED ON)
include(Variables)
include(BuildVersion)

View File

@ -68,7 +68,11 @@ public:
}
// shadow base-class string() method with UTF-8 aware method
std::string string() const { return super::u8string(); }
std::string string() const
{
auto u8 = super::u8string();
return std::string(u8.begin(), u8.end());
}
// On Posix systems, where value_type is already char, this operator
// std::string() method shadows the base class operator string_type()
// method. But on Windows, where value_type is wchar_t, the base class

View File

@ -146,7 +146,7 @@ size_t LLQueuedThread::updateQueue(F32 max_time_ms)
// schedule a call to threadedUpdate for every call to updateQueue
if (!isQuitting())
{
mRequestQueue.post([=]()
mRequestQueue.post([=, this]()
{
LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD("qt - update");
mIdleThread = false;
@ -497,7 +497,7 @@ void LLQueuedThread::processRequest(LLQueuedThread::QueuedRequest* req)
#else
using namespace std::chrono_literals;
// <FS:Beq> improve retry behaviour
// mRequestQueue.post([=]
// mRequestQueue.post([=, this]
// {
// LL_PROFILE_ZONE_NAMED("processRequest - retry");
// if (LL::WorkQueue::TimePoint::clock::now() < retry_time)

View File

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

View File

@ -812,7 +812,7 @@ void LLFontFreetype::renderGlyph(EFontGlyphType bitmap_type, U32 glyph_index, ll
if (error == FT_Err_Out_Of_Memory)
{
LLError::LLUserWarningMsg::showOutOfMemory();
LL_ERRS() << "Out of memory loading glyph for character " << wch << LL_ENDL;
LL_ERRS() << "Out of memory loading glyph for character " << llformat("U+%xu", U32(wch)) << LL_ENDL;
}
std::string message = llformat(

View File

@ -166,6 +166,7 @@ public:
void setStyle(U8 style);
U8 getStyle() const;
S32 getAddedGlyphs() const { return mAddGlyphCount; }
private:
void resetBitmapCache();

View File

@ -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.
@ -317,6 +332,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))

View File

@ -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,
@ -235,6 +236,7 @@ public:
static F32 sHorizDPI;
static F32 sScaleX;
static F32 sScaleY;
static S32 sResolutionGeneration;
static bool sDisplayFont ;
static std::string sAppDir; // For loading fonts

View File

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

View File

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

View File

@ -59,6 +59,7 @@ public:
bool attachNothing = false;
bool hasHeroProbes = false;
bool isPBRTerrain = false;
bool hasTonemap = false;
};
// ============= Structure for caching shader uniforms ===============

View File

@ -1773,7 +1773,7 @@ void LLImageGL::syncToMainThread(LLGLuint new_tex_name)
ref();
LL::WorkQueue::postMaybe(
mMainQueue,
[=]()
[=, this]()
{
LL_PROFILE_ZONE_NAMED_CATEGORY_TEXTURE("cglt - delete callback");
syncTexName(new_tex_name);

View File

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

View File

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

View File

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

View File

@ -1069,7 +1069,7 @@ F32 LLWindowMacOSX::getGamma()
&greenGamma,
&blueMin,
&blueMax,
&blueGamma) == noErr)
&blueGamma) == kCGErrorSuccess)
{
// So many choices...
// Let's just return the green channel gamma for now.
@ -1120,7 +1120,7 @@ bool LLWindowMacOSX::setGamma(const F32 gamma)
&greenGamma,
&blueMin,
&blueMax,
&blueGamma) != noErr)
&blueGamma) != kCGErrorSuccess)
{
return false;
}
@ -1135,7 +1135,7 @@ bool LLWindowMacOSX::setGamma(const F32 gamma)
gamma,
blueMin,
blueMax,
gamma) != noErr)
gamma) != kCGErrorSuccess)
{
return false;
}
@ -1187,7 +1187,7 @@ bool LLWindowMacOSX::setCursorPosition(const LLCoordWindow position)
newPosition.y = screen_pos.mY;
CGSetLocalEventsSuppressionInterval(0.0);
if(CGWarpMouseCursorPosition(newPosition) == noErr)
if(CGWarpMouseCursorPosition(newPosition) == kCGErrorSuccess)
{
result = true;
}

View File

@ -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
@ -3005,6 +3001,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");

View File

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

View File

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

View File

@ -90,21 +90,15 @@ uniform sampler2D depthMap;
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;
@ -126,6 +120,7 @@ vec3 linear_to_srgb(vec3 col);
vec3 atmosLighting(vec3 light);
vec3 scaleSoftClip(vec3 light);
vec3 toneMapNoExposure(vec3 color);
vec3 vN, vT, vB;
@ -171,18 +166,18 @@ void calculateFresnelFactors(out vec3 df3, out vec2 df2, vec3 viewVec, vec3 wave
// We calculate the fresnel here.
// We do this by getting the dot product for each sets of waves, and applying scale and offset.
df3 = vec3(
df3 = max(vec3(0), vec3(
dot(viewVec, wave1),
dot(viewVec, (wave2 + wave3) * 0.5),
dot(viewVec, wave3)
) * fresnelScale + fresnelOffset;
) * fresnelScale + fresnelOffset);
df3 *= df3;
df2 = vec2(
df2 = max(vec2(0), vec2(
df3.x + df3.y + df3.z,
dot(viewVec, wavef) * fresnelScale + fresnelOffset
);
));
}
void main()
@ -194,6 +189,7 @@ void main()
vB = cross(vN, vT);
vec3 pos = vary_position.xyz;
float linear_depth = 1 / -pos.z;
float dist = length(pos.xyz);
@ -216,6 +212,12 @@ void main()
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;
@ -230,7 +232,7 @@ void main()
vec3 norm = transform_normal(normalize(wavef));
vdu = clamp(vdu, 0, 1);
wavef.z *= max(vdu*vdu*vdu, 0.1);
//wavef.z *= max(vdu*vdu*vdu, 0.1);
wavef = normalize(wavef);
@ -245,11 +247,6 @@ void main()
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;
@ -258,8 +255,6 @@ void main()
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;
#ifdef TRANSPARENT_WATER
@ -289,8 +284,8 @@ void main()
#endif
float metallic = 1.0;
float perceptualRoughness = 0.1;
float gloss = 0.95;
float perceptualRoughness = blurMultiplier;
float gloss = 1 - perceptualRoughness;
vec3 irradiance = vec3(0);
vec3 radiance = vec3(0);
@ -300,7 +295,7 @@ void main()
#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, 1, false, amblit);
sampleReflectionProbes(irradiance, radiance, distort2, pos.xyz, wave_ibl.xyz, gloss, false, amblit);
#endif
vec3 diffuseColor = vec3(0);
@ -323,20 +318,26 @@ void main()
pbrPunctual(diffuseColor, specularColor, perceptualRoughness, metallic, normalize(wavef+up*max(dist, 32.0)/32.0*(1.0-vdu)), v, normalize(light_dir), nl, diffPunc, specPunc);
vec3 punctual = clamp(nl * (diffPunc + specPunc), vec3(0), vec3(10)) * sunlit_linear * shadow;
radiance *= df2.y;
//radiance = toneMapNoExposure(radiance);
vec3 color = vec3(0);
color = mix(fb.rgb, radiance * df2.y, df2.x * 0.99999) + punctual.rgb;
color = mix(fb.rgb, radiance, min(1, df2.x)) + punctual.rgb;
float water_haze_scale = 4;
if (classic_mode > 0)
water_haze_scale = 1;
// This looks super janky, but we do this to restore water haze in the distance.
// These values were finagled in to try and bring back some of the distant brightening on legacy water. Also works reasonably well on PBR skies such as PBR midday.
color += color * min(vec3(4),pow(1 - atten, vec3(1.35)) * 16 * fade);
// color = mix(color, additive * water_haze_scale, (1 - atten));
// We shorten the fade here at the shoreline so it doesn't appear too soft from a distance.
fade *= 60;
fade = min(1, fade);
color = mix(fb.rgb, color, fade);
float spec = min(max(max(punctual.r, punctual.g), punctual.b), 0.05);
float spec = min(max(max(punctual.r, punctual.g), punctual.b), 0);
frag_color = min(vec4(1),max(vec4(color.rgb, spec * water_mask), vec4(0)));
}

View File

@ -500,7 +500,7 @@ void GLTFSceneManager::update()
LLNewBufferedResourceUploadInfo::uploadFinish_f finish = [this, buffer](LLUUID assetId, LLSD response)
{
LLAppViewer::instance()->postToMainCoro(
[=]()
[=, this]()
{
if (mUploadingAsset)
{

View File

@ -107,10 +107,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)
{
}
@ -132,7 +131,13 @@ void LLAgentPicksInfo::requestNumberOfPicks()
mAgentPicksObserver->sendAgentPicksRequest();
}
bool LLAgentPicksInfo::isPickLimitReached()
// static
S32 LLAgentPicksInfo::getMaxNumberOfPicks()
{
return LLAgentBenefitsMgr::current().getPicksLimit();
}
bool LLAgentPicksInfo::isPickLimitReached() const
{
// <FS:Ansariel> Picks premium perks integration
//return getNumberOfPicks() >= getMaxNumberOfPicks();

View File

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

View File

@ -189,154 +189,133 @@ 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;
}
}
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];
F32 blend_factor = (F32)pwater->getBlendFactor();
gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE);
gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE);
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->bindTexture(LLShaderMgr::WATER_EXCLUSIONTEX, &gPipeline.mWaterExclusionMask);
// bind reflection texture from RenderTarget
S32 screentex = shader->enableTexture(LLShaderMgr::WATER_SCREENTEX);
F32 screenRes[] = { 1.f / gGLViewport[2], 1.f / gGLViewport[3] };
shader->uniform2fv(LLShaderMgr::DEFERRED_SCREEN_RES, 1, screenRes);
shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor);
F32 fog_density = pwater->getModifiedWaterFogDensity(underwater);
if (screentex > -1)
{
shader->uniform1f(LLShaderMgr::WATER_FOGDENSITY, fog_density);
gGL.getTexUnit(screentex)->bind(&gPipeline.mWaterDis);
}
if (mShaderLevel == 1)
{
fog_color.mV[VALPHA] = (F32)(log(fog_density) / log(2));
}
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->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_SPECULAR, 1, light_diffuse.mV);
shader->uniform1f(LLShaderMgr::WATER_SPECULAR_EXP, light_exp);
shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, pwater->getWave1Dir().mV);
shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, pwater->getWave2Dir().mV);
shader->uniform3fv(LLShaderMgr::WATER_LIGHT_DIR, 1, light_dir.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, pwater->getBlurMultiplier());
F32 sunAngle = llmax(0.f, light_dir.mV[1]);
F32 scaledAngle = 1.f - sunAngle;
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);
// 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->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV);
if (LLViewerCamera::getInstance()->cameraUnderWater())
{
shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleBelow());
}
else
{
shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleAbove());
}
LLGLDisable cullface(GL_CULL_FACE);
pushWaterPlanes(edge);
shader->disableTexture(LLShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
shader->disableTexture(LLShaderMgr::WATER_SCREENTEX);
shader->disableTexture(LLShaderMgr::BUMP_MAP);
// clean up
gPipeline.unbindDeferredShader(*shader);
gGL.getTexUnit(bumpTex)->unbind(LLTexUnit::TT_TEXTURE);
gGL.getTexUnit(bumpTex2)->unbind(LLTexUnit::TT_TEXTURE);
shader = &gUnderWaterProgram;
}
else
{
shader = &gWaterProgram;
}
gGL.getTexUnit(0)->activate();
gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
gPipeline.bindDeferredShader(*shader, nullptr, &gPipeline.mWaterDis);
LLViewerTexture* tex_a = mWaterNormp[0];
LLViewerTexture* tex_b = mWaterNormp[1];
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);
}
shader->bindTexture(LLShaderMgr::WATER_EXCLUSIONTEX, &gPipeline.mWaterExclusionMask);
shader->uniform1f(LLShaderMgr::BLEND_FACTOR, blend_factor);
F32 fog_density = pwater->getModifiedWaterFogDensity(underwater);
shader->bindTexture(LLShaderMgr::WATER_SCREENTEX, &gPipeline.mWaterDis);
if (mShaderLevel == 1)
{
fog_color.mV[VALPHA] = (F32)(log(fog_density) / log(2));
}
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_SPECULAR, 1, light_diffuse.mV);
shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR1, 1, pwater->getWave1Dir().mV);
shader->uniform2fv(LLShaderMgr::WATER_WAVE_DIR2, 1, pwater->getWave2Dir().mV);
shader->uniform3fv(LLShaderMgr::WATER_LIGHT_DIR, 1, light_dir.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);
static LLStaticHashedString s_exposure("exposure");
static LLStaticHashedString tonemap_mix("tonemap_mix");
static LLStaticHashedString tonemap_type("tonemap_type");
static LLCachedControl<F32> exposure(gSavedSettings, "RenderExposure", 1.f);
F32 e = llclamp(exposure(), 0.5f, 4.f);
static LLCachedControl<bool> should_auto_adjust(gSavedSettings, "RenderSkyAutoAdjustLegacy", false);
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()));
F32 sunAngle = llmax(0.f, light_dir.mV[1]);
F32 scaledAngle = 1.f - sunAngle;
shader->uniform1i(LLShaderMgr::SUN_UP_FACTOR, sun_up ? 1 : 0);
// 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->uniform3fv(LLShaderMgr::WL_CAMPOSLOCAL, 1, LLViewerCamera::getInstance()->getOrigin().mV);
if (LLViewerCamera::getInstance()->cameraUnderWater())
{
shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleBelow());
}
else
{
shader->uniform1f(LLShaderMgr::WATER_REFSCALE, pwater->getScaleAbove());
}
LLGLDisable cullface(GL_CULL_FACE);
// 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);
gGL.setColorMask(true, false);
}
@ -346,22 +325,18 @@ void LLDrawPoolWater::pushWaterPlanes(int pass)
LLVOWater* water = nullptr;
for (LLFace* const& face : mDrawFace)
{
if (!face)
continue;
water = static_cast<LLVOWater*>(face->getViewerObject());
if (!water)
continue;
if ((bool)pass == (bool)water->getIsEdgePatch())
face->renderIndexed();
// Note non-void water being drawn, updates required
// 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())
{
face->renderIndexed();
// Note non-void water being drawn, updates required
if (!pass) // SL-16461 remove !LLPipeline::sUseOcclusion check
{
sNeedsReflectionUpdate = true;
sNeedsDistortionUpdate = true;
}
sNeedsReflectionUpdate = true;
sNeedsDistortionUpdate = true;
}
}
}

View File

@ -647,7 +647,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();
view_item->destroyView();
removeItemID(idp);
}

View File

@ -564,8 +564,8 @@ LLViewerFetchedTexture* LLMeshUploadThread::FindViewerTexture(const LLImportMate
return ppTex ? (*ppTex).get() : NULL;
}
volatile S32 LLMeshRepoThread::sActiveHeaderRequests = 0;
volatile S32 LLMeshRepoThread::sActiveLODRequests = 0;
std::atomic<S32> LLMeshRepoThread::sActiveHeaderRequests = 0;
std::atomic<S32> LLMeshRepoThread::sActiveLODRequests = 0;
U32 LLMeshRepoThread::sMaxConcurrentRequests = 1;
S32 LLMeshRepoThread::sRequestLowWater = REQUEST2_LOW_WATER_MIN;
S32 LLMeshRepoThread::sRequestHighWater = REQUEST2_HIGH_WATER_MIN;
@ -4080,7 +4080,7 @@ void LLMeshRepository::notifyLoadedMeshes()
}
// erase from background thread
mThread->mWorkQueue.post([=]()
mThread->mWorkQueue.post([=, this]()
{
mThread->mSkinMap.erase(id);
});

View File

@ -266,8 +266,8 @@ class LLMeshRepoThread : public LLThread
{
public:
volatile static S32 sActiveHeaderRequests;
volatile static S32 sActiveLODRequests;
static std::atomic<S32> sActiveHeaderRequests;
static std::atomic<S32> sActiveLODRequests;
static U32 sMaxConcurrentRequests;
static S32 sRequestLowWater;
static S32 sRequestHighWater;

View File

@ -443,7 +443,7 @@ void LLPanelEmojiComplete::updateConstraints()
{
mRenderRect = getLocalRect();
mEmojiWidth = (U16)(mIconFont->getWidthF32(u8"\U0001F431") + mPadding * 2);
mEmojiWidth = (U16)(mIconFont->getWidthF32(LLWString(1, 0x1F431).c_str()) + mPadding * 2);
if (mVertical)
{
mEmojiHeight = mIconFont->getLineHeight() + mPadding * 2;

View File

@ -29,6 +29,7 @@
#include <iostream>
#include <map>
#include <algorithm>
#include <atomic>
#include "lltexturefetch.h"
@ -3156,7 +3157,7 @@ bool LLTextureFetch::getRequestFinished(const LLUUID& id, S32& discard_level, S3
bool LLTextureFetch::updateRequestPriority(const LLUUID& id, F32 priority)
{
LL_PROFILE_ZONE_SCOPED;
mRequestQueue.tryPost([=]()
mRequestQueue.tryPost([=, this]()
{
LLTextureFetchWorker* worker = getWorker(id);
if (worker)
@ -4274,29 +4275,30 @@ TFReqSendMetrics::doWork(LLTextureFetch * fetcher)
//if (! gViewerAssetStatsThread1)
// return true;
static volatile bool reporting_started(false);
static volatile S32 report_sequence(0);
static std::atomic<bool> reporting_started(false);
static std::atomic<S32> report_sequence(0);
// In mStatsSD, we have a copy we own of the LLSD representation
// of the asset stats. Add some additional fields and ship it off.
static const S32 metrics_data_version = 2;
bool initial_report = !reporting_started;
bool initial_report = !reporting_started.load();
mStatsSD["session_id"] = mSessionID;
mStatsSD["agent_id"] = mAgentID;
mStatsSD["message"] = "ViewerAssetMetrics";
mStatsSD["sequence"] = report_sequence;
mStatsSD["sequence"] = report_sequence.load();
mStatsSD["initial"] = initial_report;
mStatsSD["version"] = metrics_data_version;
mStatsSD["break"] = static_cast<bool>(LLTextureFetch::svMetricsDataBreak);
// Update sequence number
if (S32_MAX == ++report_sequence)
if (S32_MAX == report_sequence.fetch_add(1))
{
report_sequence = 0;
report_sequence.store(0);
}
reporting_started = true;
reporting_started.store(true);
// Limit the size of the stats report if necessary.

View File

@ -2947,14 +2947,14 @@ void LLViewerMediaImpl::update()
media_tex->ref();
main_queue->postTo(
mTexUpdateQueue, // Worker thread queue
[=]() // work done on update worker thread
[=, this]() // work done on update worker thread
{
#if LL_IMAGEGL_THREAD_CHECK
media_tex->getGLTexture()->mActiveThread = LLThread::currentID();
#endif
doMediaTexUpdate(media_tex, data, data_width, data_height, x_pos, y_pos, width, height, true);
},
[=]() // callback to main thread
[=, this]() // callback to main thread
{
#if LL_IMAGEGL_THREAD_CHECK
media_tex->getGLTexture()->mActiveThread = LLThread::currentID();

View File

@ -114,7 +114,6 @@ LLGLSLShader gObjectAlphaMaskNoColorProgram;
//environment shaders
LLGLSLShader gWaterProgram;
LLGLSLShader gWaterEdgeProgram;
LLGLSLShader gUnderWaterProgram;
//interface shaders
@ -415,7 +414,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);
@ -882,6 +880,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] ) );
@ -914,7 +913,6 @@ bool LLViewerShaderMgr::loadShadersWater()
if (mShaderLevel[SHADER_WATER] == 0)
{
gWaterProgram.unload();
gWaterEdgeProgram.unload();
gUnderWaterProgram.unload();
return true;
}
@ -928,6 +926,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));
@ -949,36 +948,6 @@ bool LLViewerShaderMgr::loadShadersWater()
llassert(success);
}
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
@ -2517,6 +2486,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));
@ -2531,6 +2501,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");

View File

@ -192,7 +192,6 @@ extern LLGLSLShader gObjectAlphaMaskNoColorProgram;
//environment shaders
extern LLGLSLShader gWaterProgram;
extern LLGLSLShader gWaterEdgeProgram;
extern LLGLSLShader gUnderWaterProgram;
extern LLGLSLShader gGlowProgram;
extern LLGLSLShader gGlowExtractProgram;

View File

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

View File

@ -778,7 +778,7 @@ public:
ypos += y_inc;
// <FS:Ansariel> Mesh debugging
addText(xpos, ypos, llformat("%d Mesh Active LOD Requests", LLMeshRepoThread::sActiveLODRequests));
addText(xpos, ypos, llformat("%d Mesh Active LOD Requests", LLMeshRepoThread::sActiveLODRequests.load()));
ypos += y_inc;
// </FS:Ansariel>
@ -1437,7 +1437,7 @@ LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *wi
// Check the whitelist, if there's media (otherwise just show it)
if (te->getMediaData() == NULL || te->getMediaData()->checkCandidateUrl(url))
{
if ( obj != mDragHoveredObject)
if ( obj != mDragHoveredObject.get())
{
// Highlight the dragged object
LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject);
@ -1852,6 +1852,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);
@ -1865,6 +1866,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;
@ -2037,6 +2044,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;
@ -2758,6 +2766,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]);

View File

@ -227,6 +227,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);

View File

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

View File

@ -556,7 +556,7 @@ void LLWebRTCVoiceClient::voiceConnectionCoro()
}
}
LL::WorkQueue::postMaybe(mMainQueue,
[=] {
[=, this] {
if (sShuttingDown)
{
return;
@ -674,7 +674,7 @@ void LLWebRTCVoiceClient::OnDevicesChanged(const llwebrtc::LLWebRTCVoiceDeviceLi
{
LL::WorkQueue::postMaybe(mMainQueue,
[=]
[=, this]
{
OnDevicesChangedImpl(render_devices, capture_devices);
});
@ -2211,7 +2211,7 @@ LLVoiceWebRTCConnection::~LLVoiceWebRTCConnection()
void LLVoiceWebRTCConnection::OnIceGatheringState(llwebrtc::LLWebRTCSignalingObserver::EIceGatheringState state)
{
LL::WorkQueue::postMaybe(mMainQueue,
[=] {
[=, this] {
LL_DEBUGS("Voice") << "Ice Gathering voice account. " << state << LL_ENDL;
switch (state)
@ -2234,7 +2234,7 @@ void LLVoiceWebRTCConnection::OnIceGatheringState(llwebrtc::LLWebRTCSignalingObs
// callback from llwebrtc
void LLVoiceWebRTCConnection::OnIceCandidate(const llwebrtc::LLWebRTCIceCandidate& candidate)
{
LL::WorkQueue::postMaybe(mMainQueue, [=] { mIceCandidates.push_back(candidate); });
LL::WorkQueue::postMaybe(mMainQueue, [=, this] { mIceCandidates.push_back(candidate); });
}
void LLVoiceWebRTCConnection::processIceUpdates()
@ -2352,7 +2352,7 @@ void LLVoiceWebRTCConnection::processIceUpdatesCoro(connectionPtr_t connection)
void LLVoiceWebRTCConnection::OnOfferAvailable(const std::string &sdp)
{
LL::WorkQueue::postMaybe(mMainQueue,
[=] {
[=, this] {
if (mShutDown)
{
return;
@ -2379,7 +2379,7 @@ void LLVoiceWebRTCConnection::OnOfferAvailable(const std::string &sdp)
void LLVoiceWebRTCConnection::OnAudioEstablished(llwebrtc::LLWebRTCAudioInterface* audio_interface)
{
LL::WorkQueue::postMaybe(mMainQueue,
[=] {
[=, this] {
if (mShutDown)
{
return;
@ -2401,7 +2401,7 @@ void LLVoiceWebRTCConnection::OnAudioEstablished(llwebrtc::LLWebRTCAudioInterfac
void LLVoiceWebRTCConnection::OnRenegotiationNeeded()
{
LL::WorkQueue::postMaybe(mMainQueue,
[=] {
[=, this] {
LL_DEBUGS("Voice") << "Voice channel requires renegotiation." << LL_ENDL;
if (!mShutDown)
{
@ -2415,7 +2415,7 @@ void LLVoiceWebRTCConnection::OnRenegotiationNeeded()
void LLVoiceWebRTCConnection::OnPeerConnectionClosed()
{
LL::WorkQueue::postMaybe(mMainQueue,
[=] {
[=, this] {
LL_DEBUGS("Voice") << "Peer connection has closed." << LL_ENDL;
if (mVoiceConnectionState == VOICE_STATE_WAIT_FOR_CLOSE)
{
@ -2890,7 +2890,7 @@ bool LLVoiceWebRTCConnection::connectionStateMachine()
// llwebrtc callback
void LLVoiceWebRTCConnection::OnDataReceived(const std::string& data, bool binary)
{
LL::WorkQueue::postMaybe(mMainQueue, [=] { LLVoiceWebRTCConnection::OnDataReceivedImpl(data, binary); });
LL::WorkQueue::postMaybe(mMainQueue, [=, this] { LLVoiceWebRTCConnection::OnDataReceivedImpl(data, binary); });
}
//
@ -3046,7 +3046,7 @@ void LLVoiceWebRTCConnection::OnDataReceivedImpl(const std::string &data, bool b
void LLVoiceWebRTCConnection::OnDataChannelReady(llwebrtc::LLWebRTCDataInterface *data_interface)
{
LL::WorkQueue::postMaybe(mMainQueue,
[=] {
[=, this] {
if (mShutDown)
{
return;

View File

@ -128,7 +128,7 @@ void LLLogin::Impl::connect(const std::string& uri, const LLSD& login_params)
// Launch a coroutine with our login_() method. Run the coroutine until
// its first wait; at that point, return here.
std::string coroname =
LLCoros::instance().launch("LLLogin::Impl::login_", [=]() { loginCoro(uri, login_params); });
LLCoros::instance().launch("LLLogin::Impl::login_", [=, this]() { loginCoro(uri, login_params); });
LL_DEBUGS("LLLogin") << " connected with uri '" << uri << "', login_params " << login_params << LL_ENDL;
}