From 070e23398524de11ade4a6375797b1cb3d88271e Mon Sep 17 00:00:00 2001 From: Alex <7569514+ManDude@users.noreply.github.com> Date: Fri, 1 Aug 2025 00:46:15 +0100 Subject: [PATCH] Replace PCRTC framebuffer blit with screen quad draw (#3980) Taking the suggestion from @Calinou (https://github.com/open-goal/jak-project/pull/3943#issuecomment-3017359144), this replaces the resolve/render framebuffer -> window framebuffer blit with an actual drawn tri-strip which covers the entire viewport, which the PCRTC blackout already does. It appears we have no guarantee what state the internal window framebuffer will be in, so drawing an actual primitive and letting the fragment shader do all the work seems to be the more compatible/functional solution here. Thanks for the suggestion! --- .../opengl_renderer/OpenGLRenderer.cpp | 73 ++++++++++++++----- .../graphics/opengl_renderer/OpenGLRenderer.h | 4 + 2 files changed, 58 insertions(+), 19 deletions(-) diff --git a/game/graphics/opengl_renderer/OpenGLRenderer.cpp b/game/graphics/opengl_renderer/OpenGLRenderer.cpp index 5b38618f90..e58e943566 100644 --- a/game/graphics/opengl_renderer/OpenGLRenderer.cpp +++ b/game/graphics/opengl_renderer/OpenGLRenderer.cpp @@ -81,7 +81,7 @@ OpenGLRenderer::OpenGLRenderer(std::shared_ptr texture_pool, glEnable(GL_DEBUG_OUTPUT); glDebugMessageCallback(opengl_error_callback, nullptr); // disable specific errors - const GLuint gl_error_ignores_api_other[1] = {0x20071}; + const GLuint gl_error_ignores_api_other[1] = {0x20071}; // some annoying nvidia message glDebugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_OTHER, GL_DONT_CARE, 1, &gl_error_ignores_api_other[0], GL_FALSE); #endif @@ -92,6 +92,38 @@ OpenGLRenderer::OpenGLRenderer(std::shared_ptr texture_pool, lg::info("OpenGL context shading language version: {}", (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION)); + // set up screen draw + + glGenVertexArrays(1, &screen_vao); + glGenBuffers(1, &screen_vbo); + + struct Vertex { + float x, y; + }; + constexpr std::array vertices = { + Vertex{-1, -1}, + Vertex{-1, 1}, + Vertex{1, -1}, + Vertex{1, 1}, + }; + + glBindVertexArray(screen_vao); + glBindBuffer(GL_ARRAY_BUFFER, screen_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * 4, vertices.data(), GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, // location 0 in the shader + 2, // 2 floats per vert + GL_FLOAT, // floats + GL_TRUE, // normalized, ignored, + sizeof(Vertex), // + nullptr // + ); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + + // end set up screen draw + const tfrag3::Level* common_level = nullptr; { auto p = scoped_prof("load-common"); @@ -1595,30 +1627,33 @@ void OpenGLRenderer::do_pcrtc_effects(float alp, window_blit_src = &m_fbo_state.resources.render_buffer; } - glBindFramebuffer(GL_READ_FRAMEBUFFER, window_blit_src->fbo_id); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - glBlitFramebuffer(0, // srcX0 - 0, // srcY0 - window_blit_src->width, // srcX1 - window_blit_src->height, // srcY1 - render_state->draw_offset_x, // dstX0 - render_state->draw_offset_y, // dstY0 - render_state->draw_offset_x + render_state->draw_region_w, // dstX1 - render_state->draw_offset_y + render_state->draw_region_h, // dstY1 - GL_COLOR_BUFFER_BIT, // mask - GL_LINEAR // filter - ); + glDisable(GL_DEPTH_TEST); + glDisable(GL_BLEND); + glViewport(render_state->draw_offset_x, render_state->draw_offset_y, render_state->draw_region_w, + render_state->draw_region_h); + glBindTexture(GL_TEXTURE_2D, *window_blit_src->tex_id); glBindFramebuffer(GL_FRAMEBUFFER, 0); + glBindVertexArray(screen_vao); + glBindBuffer(GL_ARRAY_BUFFER, screen_vbo); + + auto& shader = render_state->shaders[ShaderId::PLAIN_TEXTURE]; + shader.activate(); + glUniform1i(glGetUniformLocation(shader.id(), "tex_T0"), 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glActiveTexture(GL_TEXTURE0); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + + glEnable(GL_BLEND); if (alp < 1) { - glDisable(GL_DEPTH_TEST); - glEnable(GL_BLEND); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO); glBlendEquation(GL_FUNC_ADD); - glViewport(0, 0, m_fbo_state.resources.window.width, m_fbo_state.resources.window.height); m_blackout_renderer.draw(Vector4f(0, 0, 0, 1.f - alp), render_state, prof); - - glEnable(GL_DEPTH_TEST); } + glEnable(GL_DEPTH_TEST); } diff --git a/game/graphics/opengl_renderer/OpenGLRenderer.h b/game/graphics/opengl_renderer/OpenGLRenderer.h index 667fe2fecf..773f34bbb4 100644 --- a/game/graphics/opengl_renderer/OpenGLRenderer.h +++ b/game/graphics/opengl_renderer/OpenGLRenderer.h @@ -65,6 +65,7 @@ class OpenGLRenderer { OpenGLRenderer(std::shared_ptr texture_pool, std::shared_ptr loader, GameVersion version); + // TODO delete // rendering interface: takes the dma chain from the game, and some size/debug settings from // the graphics system. @@ -135,6 +136,9 @@ class OpenGLRenderer { Fbo* render_fbo = nullptr; // the selected fbo from the three above to use for rendering } m_fbo_state; + GLuint screen_vao = 0; // vertex array object for a screen-space draw + GLuint screen_vbo = 0; // vertex buffer object for a screen-space draw + std::unique_ptr m_jak2_eye_renderer; std::unique_ptr m_jak3_eye_renderer; GameVersion m_version;