fix(gfx): generate cloud mipmaps after unbinding the render FBO (#4344)

Found while investigating the jak2/jak3 one-frame sky flicker (see the
fog CLUT inline payload PR: `#4343`).

## Problem

`TextureAnimator::run_clouds` calls `glGenerateMipmap` on the final
cloud texture while that texture is still attached to the currently
bound draw framebuffer (the `FramebufferTexturePairContext` is still in
scope). Reading a texture that is attached to the bound framebuffer is a
driver hazard even outside a draw call.

Every other site in this file already avoids this: `run_slime` and
`opengl_upload_resize_texture` both close the FBO context scope before
generating mipmaps. `run_clouds` is the one outlier, presumably an
oversight.

## Fix

Scope the `FramebufferTexturePairContext` in braces and generate the
mipmaps after it restores the previous framebuffer binding, matching the
established pattern in the rest of the file.

## Test plan

- [ ] jak2/jak3 clouds render identically (hires and normal cloud modes)

(AI-assisted)
This commit is contained in:
Alexander J. Semenuk
2026-07-19 14:59:17 -04:00
committed by GitHub
parent eaf48bb2f3
commit eddd6fb019
@@ -2910,17 +2910,21 @@ GLint TextureAnimator::run_clouds(const SkyInput& input, bool hires) {
}
}
FramebufferTexturePairContext ctxt(final_tex);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glUniform1i(m_uniforms.enable_tex, 2);
glBindTexture(GL_TEXTURE_2D, blend_tex.texture());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glUniform1f(m_uniforms.minimum, input.cloud_min);
glUniform1f(m_uniforms.maximum, input.cloud_max);
glDisable(GL_BLEND);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
{
FramebufferTexturePairContext ctxt(final_tex);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
glUniform1i(m_uniforms.enable_tex, 2);
glBindTexture(GL_TEXTURE_2D, blend_tex.texture());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glUniform1f(m_uniforms.minimum, input.cloud_min);
glUniform1f(m_uniforms.maximum, input.cloud_max);
glDisable(GL_BLEND);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
// generate mipmaps only after final_tex is no longer attached to the bound
// framebuffer, matching run_slime and opengl_upload_resize_texture.
glBindTexture(GL_TEXTURE_2D, final_tex.texture());
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);