From b2457b1865cc5db987259efd6374892bff2fdb1a Mon Sep 17 00:00:00 2001 From: Nils Schimmelmann Date: Tue, 20 Oct 2026 09:48:40 -0700 Subject: [PATCH] optimize atmosphere fragment shader for Intel GPUs (#260) - Replace dynamic textureSize() lookups with WEATHER_INV_NOISE_SIZE constant multiplier - Fully unroll the 4-octave fbm() function --- src/display/Textures.cpp | 4 +-- src/opengl/Weather.h | 2 ++ src/opengl/legacy/ShaderUtils.cpp | 7 +++++- .../legacy/weather/atmosphere/frag.glsl | 25 +++++++++++-------- 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/display/Textures.cpp b/src/display/Textures.cpp index 11e6473cc..4362e1420 100644 --- a/src/display/Textures.cpp +++ b/src/display/Textures.cpp @@ -480,8 +480,8 @@ void MapCanvas::initTextures() textures.white_pixel = MMTexture::alloc(std::vector{whitePixel}, true); } { - // weather noise is 256 - QImage noiseImage = createTileableValueNoiseImage(256); + // weather noise texture + QImage noiseImage = createTileableValueNoiseImage(WeatherConstants::WEATHER_NOISE_SIZE); textures.noise = MMTexture::alloc(std::vector{noiseImage}, false); } diff --git a/src/opengl/Weather.h b/src/opengl/Weather.h index cf3757f11..44a631b8b 100644 --- a/src/opengl/Weather.h +++ b/src/opengl/Weather.h @@ -40,6 +40,8 @@ constexpr float WEATHER_EXTENT = 28.0f; constexpr float WEATHER_MASK_RADIUS_OUTER = 12.0f; constexpr float WEATHER_MASK_RADIUS_INNER = 8.0f; constexpr float TRANSITION_DURATION = 2.0f; +constexpr int WEATHER_NOISE_SIZE = 256; +constexpr float WEATHER_INV_NOISE_SIZE = 1.0f / static_cast(WEATHER_NOISE_SIZE); } // namespace WeatherConstants /** diff --git a/src/opengl/legacy/ShaderUtils.cpp b/src/opengl/legacy/ShaderUtils.cpp index 0fe8ad8dd..4edf8cf03 100644 --- a/src/opengl/legacy/ShaderUtils.cpp +++ b/src/opengl/legacy/ShaderUtils.cpp @@ -239,13 +239,18 @@ NODISCARD static GLuint compileShader(Functions &gl, const GLenum type, const So + text_utils::formatFloatClassic( WeatherConstants::WEATHER_MASK_RADIUS_INNER) + "\n"; + std::string defineWeatherInvNoiseSize = "#define WEATHER_INV_NOISE_SIZE " + + text_utils::formatFloatClassic( + WeatherConstants::WEATHER_INV_NOISE_SIZE) + + "\n"; - std::array ptrs = {gl.getShaderVersion(), + std::array ptrs = {gl.getShaderVersion(), defineNamedColors.c_str(), defineWeatherRadius.c_str(), defineWeatherExtent.c_str(), defineWeatherMaskOuter.c_str(), defineWeatherMaskInner.c_str(), + defineWeatherInvNoiseSize.c_str(), "#line 1\n", source.source.c_str()}; gl.glShaderSource(shaderId, static_cast(ptrs.size()), ptrs.data(), nullptr); diff --git a/src/resources/shaders/legacy/weather/atmosphere/frag.glsl b/src/resources/shaders/legacy/weather/atmosphere/frag.glsl index c895941c0..92488cc5d 100644 --- a/src/resources/shaders/legacy/weather/atmosphere/frag.glsl +++ b/src/resources/shaders/legacy/weather/atmosphere/frag.glsl @@ -11,7 +11,7 @@ layout(std140) uniform NamedColorsBlock layout(std140) uniform CameraBlock { mat4 uViewProj; - vec4 uPlayerPos; // xyz, w=zScale + vec4 uPlayerPos; // xyz, w=zScale }; layout(std140) uniform TimeBlock @@ -32,22 +32,22 @@ uniform sampler2D uTexture; in vec3 vWorldPos; out vec4 vFragmentColor; +// Avoid dynamic textureSize queries in fragment loop on Intel GPUs; WEATHER_INV_NOISE_SIZE is injected at shader compile time float get_noise(vec2 p) { - vec2 size = vec2(textureSize(uTexture, 0)); - return texture(uTexture, p / size).r; + return texture(uTexture, p * WEATHER_INV_NOISE_SIZE).r; } float fbm(vec2 p) { - float v = 0.0; - float a = 0.5; vec2 shift = vec2(100.0); - for (int i = 0; i < 4; ++i) { - v += a * get_noise(p); - p = p * 2.0 + shift; - a *= 0.5; - } + float v = 0.5 * get_noise(p); + p = p * 2.0 + shift; + v += 0.25 * get_noise(p); + p = p * 2.0 + shift; + v += 0.125 * get_noise(p); + p = p * 2.0 + shift; + v += 0.0625 * get_noise(p); return v; } @@ -56,7 +56,10 @@ void main() vec3 worldPos = vWorldPos; float distToPlayer = distance(worldPos.xy, uPlayerPos.xy); - float localMask = 1.0 - smoothstep(WEATHER_MASK_RADIUS_INNER, WEATHER_MASK_RADIUS_OUTER, distToPlayer); + float localMask = 1.0 + - smoothstep(WEATHER_MASK_RADIUS_INNER, + WEATHER_MASK_RADIUS_OUTER, + distToPlayer); float uCurrentTime = uTime.x; float uWeatherStartTime = uConfig.x;