diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 2d471f3de..eb6c41ce5 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -149,8 +149,6 @@ void RasterizerOpenGL::DrawTriangles() { if (vertex_batch.empty()) return; - state.MakeCurrent(); - const auto& regs = Pica::g_state.regs; // Sync and bind the framebuffer surfaces @@ -247,8 +245,6 @@ void RasterizerOpenGL::DrawTriangles() { void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { const auto& regs = Pica::g_state.regs; - state.MakeCurrent(); - switch(id) { // Culling case PICA_REG_INDEX(cull_mode): @@ -612,17 +608,15 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) SurfaceType dst_type = CachedSurface::GetFormatType(dst_surface->pixel_format); - OpenGLState* old_state = OpenGLState::GetCurrentState(); - utility_state.MakeCurrent(); - - utility_state.SetDrawFramebuffer(framebuffer.handle); + OpenGLState* cur_state = OpenGLState::GetCurrentState(); + OpenGLState old_state = OpenGLState::ApplyTransferState(0, cur_state->GetReadFramebuffer(), dst_surface->texture.handle, framebuffer.handle); if (dst_type == SurfaceType::Color || dst_type == SurfaceType::Texture) { glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst_surface->texture.handle, 0); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); if (OpenGLState::CheckBoundFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - old_state->MakeCurrent(); + OpenGLState::UndoTransferState(old_state); return false; } @@ -640,7 +634,7 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) color_values[2] = config.value_24bit_b / 255.0f; break; default: - old_state->MakeCurrent(); + OpenGLState::UndoTransferState(old_state); return false; } } else if (config.fill_32bit) { @@ -654,7 +648,7 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) color_values[3] = (value & 0xFF) / 255.0f; break; default: - old_state->MakeCurrent(); + OpenGLState::UndoTransferState(old_state); return false; } } else { @@ -694,12 +688,11 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) color_values[1] = (value_16bit & 0xFF) / 255.0f; break; default: - old_state->MakeCurrent(); + OpenGLState::UndoTransferState(old_state); return false; } } - utility_state.SetColorMask(true, true, true, true); glClearBufferfv(GL_COLOR, 0, color_values); } else if (dst_type == SurfaceType::Depth) { glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); @@ -707,7 +700,7 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); if (OpenGLState::CheckBoundFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - old_state->MakeCurrent(); + OpenGLState::UndoTransferState(old_state); return false; } @@ -718,26 +711,23 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) value_float = config.value_32bit / 16777215.0f; // 2^24 - 1 } - utility_state.SetDepthWriteMask(true); glClearBufferfv(GL_DEPTH, 0, &value_float); } else if (dst_type == SurfaceType::DepthStencil) { glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, dst_surface->texture.handle, 0); if (OpenGLState::CheckBoundFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - old_state->MakeCurrent(); + OpenGLState::UndoTransferState(old_state); return false; } GLfloat value_float = (config.value_32bit & 0xFFFFFF) / 16777215.0f; // 2^24 - 1 GLint value_int = (config.value_32bit >> 24); - utility_state.SetDepthWriteMask(true); - utility_state.SetStencilWriteMask(true); glClearBufferfi(GL_DEPTH_STENCIL, 0, value_float, value_int); } - old_state->MakeCurrent(); + OpenGLState::UndoTransferState(old_state); dst_surface->dirty = true; res_cache.FlushRegion(dst_surface->addr, dst_surface->size, dst_surface, true); @@ -821,8 +811,6 @@ void RasterizerOpenGL::SetShader() { PicaShaderConfig config = PicaShaderConfig::CurrentConfig(); std::unique_ptr shader = std::make_unique(); - state.MakeCurrent(); - // Find (or generate) the GLSL shader for the current TEV state auto cached_shader = shader_cache.find(config); if (cached_shader != shader_cache.end()) { @@ -921,18 +909,20 @@ void RasterizerOpenGL::SyncBlendEnabled() { void RasterizerOpenGL::SyncBlendFuncs() { const auto& regs = Pica::g_state.regs; - state.SetBlendFunc(PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_rgb), + state.SetBlendFunc(std::make_tuple<>( + PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_rgb), PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_rgb), PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_a), - PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_a)); + PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_a))); } void RasterizerOpenGL::SyncBlendColor() { auto blend_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.output_merger.blend_const.raw); - state.SetBlendColor(blend_color[0], + state.SetBlendColor(std::make_tuple<>( + blend_color[0], blend_color[1], blend_color[2], - blend_color[3]); + blend_color[3])); } void RasterizerOpenGL::SyncAlphaTest() { @@ -954,10 +944,11 @@ void RasterizerOpenGL::SyncColorWriteMask() { return (regs.framebuffer.allow_color_write != 0 && value != 0) ? GL_TRUE : GL_FALSE; }; - state.SetColorMask(IsColorWriteEnabled(regs.output_merger.red_enable), + state.SetColorMask(std::make_tuple<>( + IsColorWriteEnabled(regs.output_merger.red_enable), IsColorWriteEnabled(regs.output_merger.green_enable), IsColorWriteEnabled(regs.output_merger.blue_enable), - IsColorWriteEnabled(regs.output_merger.alpha_enable)); + IsColorWriteEnabled(regs.output_merger.alpha_enable))); } void RasterizerOpenGL::SyncStencilWriteMask() { @@ -977,12 +968,14 @@ void RasterizerOpenGL::SyncDepthWriteMask() { void RasterizerOpenGL::SyncStencilTest() { const auto& regs = Pica::g_state.regs; state.SetStencilTestEnabled(regs.output_merger.stencil_test.enable && regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8); - state.SetStencilFunc(PicaToGL::CompareFunc(regs.output_merger.stencil_test.func), + state.SetStencilFunc(std::make_tuple<>( + PicaToGL::CompareFunc(regs.output_merger.stencil_test.func), regs.output_merger.stencil_test.reference_value, - regs.output_merger.stencil_test.input_mask); - state.SetStencilOp(PicaToGL::StencilOp(regs.output_merger.stencil_test.action_stencil_fail), + regs.output_merger.stencil_test.input_mask)); + state.SetStencilOp(std::make_tuple<>( + PicaToGL::StencilOp(regs.output_merger.stencil_test.action_stencil_fail), PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_fail), - PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_pass)); + PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_pass))); } void RasterizerOpenGL::SyncDepthTest() { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 8ed2a8a81..63ff7716d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -351,7 +351,6 @@ private: void SyncLightPosition(int light_index); OpenGLState state; - OpenGLState utility_state; RasterizerCacheOpenGL res_cache; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 5f2c79844..b59e3c607 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -105,15 +105,7 @@ static void MortonCopyPixels(CachedSurface::PixelFormat pixel_format, u32 width, bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, CachedSurface::SurfaceType type, const MathUtil::Rectangle& src_rect, const MathUtil::Rectangle& dst_rect) { using SurfaceType = CachedSurface::SurfaceType; - OpenGLState* old_state = OpenGLState::GetCurrentState(); - utility_state.MakeCurrent(); - - // Make sure textures aren't bound to texture units, since going to bind them to framebuffer components - OpenGLState::ResetTexture(src_tex); - OpenGLState::ResetTexture(dst_tex); - - utility_state.SetReadFramebuffer(transfer_framebuffers[0].handle); - utility_state.SetDrawFramebuffer(transfer_framebuffers[1].handle); + OpenGLState old_state = OpenGLState::ApplyTransferState(src_tex, transfer_framebuffers[0].handle, dst_tex, transfer_framebuffers[1].handle); u32 buffers = 0; @@ -146,12 +138,12 @@ bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, CachedS } if (OpenGLState::CheckBoundFBStatus(GL_READ_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - old_state->MakeCurrent(); + OpenGLState::UndoTransferState(old_state); return false; } if (OpenGLState::CheckBoundFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - old_state->MakeCurrent(); + OpenGLState::UndoTransferState(old_state); return false; } @@ -159,7 +151,7 @@ bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, CachedS dst_rect.left, dst_rect.top, dst_rect.right, dst_rect.bottom, buffers, buffers == GL_COLOR_BUFFER_BIT ? GL_LINEAR : GL_NEAREST); - old_state->MakeCurrent(); + OpenGLState::UndoTransferState(old_state); return true; } @@ -178,11 +170,11 @@ void RasterizerCacheOpenGL::AllocateSurfaceTexture(GLuint texture, CachedSurface // Allocate an uninitialized texture of appropriate size and format for the surface using SurfaceType = CachedSurface::SurfaceType; - OpenGLState* old_state = OpenGLState::GetCurrentState(); - utility_state.MakeCurrent(); - - utility_state.SetActiveTextureUnit(GL_TEXTURE0); - utility_state.SetTexture2D(texture); + OpenGLState* cur_state = OpenGLState::GetCurrentState(); + GLenum old_active_texture = cur_state->GetActiveTextureUnit(); + cur_state->SetActiveTextureUnit(GL_TEXTURE0); + GLuint old_texture = cur_state->GetTexture2D(); + cur_state->SetTexture2D(texture); SurfaceType type = CachedSurface::GetFormatType(pixel_format); @@ -206,7 +198,8 @@ void RasterizerCacheOpenGL::AllocateSurfaceTexture(GLuint texture, CachedSurface glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - old_state->MakeCurrent(); + cur_state->SetTexture2D(old_texture); + cur_state->SetActiveTextureUnit(old_active_texture); } MICROPROFILE_DEFINE(OpenGL_SurfaceUpload, "OpenGL", "Surface Upload", MP_RGB(128, 64, 192)); @@ -288,11 +281,11 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo Memory::RasterizerFlushRegion(params.addr, params_size); // Load data from memory to the new surface - OpenGLState* old_state = OpenGLState::GetCurrentState(); - utility_state.MakeCurrent(); - - utility_state.SetActiveTextureUnit(GL_TEXTURE0); - utility_state.SetTexture2D(new_surface->texture.handle); + OpenGLState* cur_state = OpenGLState::GetCurrentState(); + GLenum old_active_texture = cur_state->GetActiveTextureUnit(); + cur_state->SetActiveTextureUnit(GL_TEXTURE0); + GLuint old_texture = cur_state->GetTexture2D(); + cur_state->SetTexture2D(new_surface->texture.handle); glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)new_surface->stride); if (!new_surface->is_tiled) { @@ -374,7 +367,8 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - old_state->MakeCurrent(); + cur_state->SetTexture2D(old_texture); + cur_state->SetActiveTextureUnit(old_active_texture); } Memory::RasterizerMarkRegionCached(new_surface->addr, new_surface->size, 1); @@ -596,9 +590,6 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) { return; } - OpenGLState* old_state = OpenGLState::GetCurrentState(); - utility_state.MakeCurrent(); - OGLTexture unscaled_tex; GLuint texture_to_flush = surface->texture.handle; @@ -614,8 +605,11 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) { texture_to_flush = unscaled_tex.handle; } - utility_state.SetActiveTextureUnit(GL_TEXTURE0); - utility_state.SetTexture2D(texture_to_flush); + OpenGLState* cur_state = OpenGLState::GetCurrentState(); + GLenum old_active_texture = cur_state->GetActiveTextureUnit(); + cur_state->SetActiveTextureUnit(GL_TEXTURE0); + GLuint old_texture = cur_state->GetTexture2D(); + cur_state->SetTexture2D(texture_to_flush); glPixelStorei(GL_PACK_ROW_LENGTH, (GLint)surface->stride); if (!surface->is_tiled) { @@ -664,7 +658,8 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) { surface->dirty = false; - old_state->MakeCurrent(); + cur_state->SetTexture2D(old_texture); + cur_state->SetActiveTextureUnit(old_active_texture); } void RasterizerCacheOpenGL::FlushRegion(PAddr addr, u32 size, const CachedSurface* skip_surface, bool invalidate) { diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index cd91a4e70..e08099db8 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -219,8 +219,6 @@ public: private: void AllocateSurfaceTexture(GLuint texture, CachedSurface::PixelFormat pixel_format, u32 width, u32 height); - OpenGLState utility_state; - SurfaceCache surface_cache; OGLFramebuffer transfer_framebuffers[2]; }; diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index fdb345d99..79700a05e 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp @@ -82,26 +82,26 @@ void OpenGLState::MakeCurrent() { return; } - SetCullEnabled(cull.enabled); - SetCullMode(cull.mode); - SetCullFrontFace(cull.front_face); + SetCullEnabled(GetCullEnabled()); + SetCullMode(GetCullMode()); + SetCullFrontFace(GetCullFrontFace()); - SetDepthTestEnabled(depth.test_enabled); - SetDepthFunc(depth.test_func); - SetDepthWriteMask(depth.write_mask); + SetDepthTestEnabled(GetDepthTestEnabled()); + SetDepthFunc(GetDepthFunc()); + SetDepthWriteMask(GetDepthWriteMask()); - SetColorMask(color_mask.red_enabled, color_mask.green_enabled, color_mask.blue_enabled, color_mask.alpha_enabled); + SetColorMask(GetColorMask()); - SetStencilTestEnabled(stencil.test_enabled); - SetStencilFunc(stencil.test_func, stencil.test_ref, stencil.test_mask); - SetStencilOp(stencil.action_stencil_fail, stencil.action_depth_fail, stencil.action_depth_pass); - SetStencilWriteMask(stencil.write_mask); + SetStencilTestEnabled(GetStencilTestEnabled()); + SetStencilFunc(GetStencilFunc()); + SetStencilOp(GetStencilOp()); + SetStencilWriteMask(GetStencilWriteMask()); - SetBlendEnabled(blend.enabled); - SetBlendFunc(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func, blend.dst_a_func); - SetBlendColor(blend.color.red, blend.color.green, blend.color.blue, blend.color.alpha); + SetBlendEnabled(GetBlendEnabled()); + SetBlendFunc(GetBlendFunc()); + SetBlendColor(GetBlendColor()); - SetLogicOp(logic_op); + SetLogicOp(GetLogicOp()); GLenum prev_active_texture_unit = active_texture_unit; for (unsigned i = 0; i < ARRAY_SIZE(texture_units); ++i) { @@ -114,14 +114,14 @@ void OpenGLState::MakeCurrent() { active_texture_unit = prev_active_texture_unit; glActiveTexture(cur_state->active_texture_unit); - SetActiveTextureUnit(active_texture_unit); + SetActiveTextureUnit(GetActiveTextureUnit()); - SetReadFramebuffer(draw.read_framebuffer); - SetDrawFramebuffer(draw.draw_framebuffer); - SetVertexArray(draw.vertex_array); - SetVertexBuffer(draw.vertex_buffer); - SetUniformBuffer(draw.uniform_buffer); - SetShaderProgram(draw.shader_program); + SetReadFramebuffer(GetReadFramebuffer()); + SetDrawFramebuffer(GetDrawFramebuffer()); + SetVertexArray(GetVertexArray()); + SetVertexBuffer(GetVertexBuffer()); + SetUniformBuffer(GetUniformBuffer()); + SetShaderProgram(GetShaderProgram()); cur_state = this; } @@ -176,7 +176,10 @@ void OpenGLState::SetDepthWriteMask(GLboolean n_write_mask) { depth.write_mask = n_write_mask; } -void OpenGLState::SetColorMask(GLboolean n_red_enabled, GLboolean n_green_enabled, GLboolean n_blue_enabled, GLboolean n_alpha_enabled) { +void OpenGLState::SetColorMask(std::tuple n_rgba_enabled) { + GLboolean n_red_enabled, n_green_enabled, n_blue_enabled, n_alpha_enabled; + std::tie(n_red_enabled, n_green_enabled, n_blue_enabled, n_alpha_enabled) = n_rgba_enabled; + if (n_red_enabled != cur_state->color_mask.red_enabled || n_green_enabled != cur_state->color_mask.green_enabled || n_blue_enabled != cur_state->color_mask.blue_enabled || @@ -201,7 +204,11 @@ void OpenGLState::SetStencilTestEnabled(bool n_test_enabled) { stencil.test_enabled = n_test_enabled; } -void OpenGLState::SetStencilFunc(GLenum n_test_func, GLint n_test_ref, GLuint n_test_mask) { +void OpenGLState::SetStencilFunc(std::tuple n_funcs) { + GLenum n_test_func; + GLint n_test_ref, n_test_mask; + std::tie(n_test_func, n_test_ref, n_test_mask) = n_funcs; + if (n_test_func != cur_state->stencil.test_func || n_test_ref != cur_state->stencil.test_ref || n_test_mask != cur_state->stencil.test_mask) { @@ -212,7 +219,10 @@ void OpenGLState::SetStencilFunc(GLenum n_test_func, GLint n_test_ref, GLuint n_ stencil.test_mask = n_test_mask; } -void OpenGLState::SetStencilOp(GLenum n_action_stencil_fail, GLenum n_action_depth_fail, GLenum n_action_depth_pass) { +void OpenGLState::SetStencilOp(std::tuple n_actions) { + GLenum n_action_stencil_fail, n_action_depth_fail, n_action_depth_pass; + std::tie(n_action_stencil_fail, n_action_depth_fail, n_action_depth_pass) = n_actions; + if (n_action_stencil_fail != cur_state->stencil.action_stencil_fail || n_action_depth_fail != cur_state->stencil.action_depth_fail || n_action_depth_pass != cur_state->stencil.action_depth_pass) { @@ -245,7 +255,10 @@ void OpenGLState::SetBlendEnabled(bool n_enabled) { blend.enabled = n_enabled; } -void OpenGLState::SetBlendFunc(GLenum n_src_rgb_func, GLenum n_dst_rgb_func, GLenum n_src_a_func, GLenum n_dst_a_func) { +void OpenGLState::SetBlendFunc(std::tuple n_funcs) { + GLenum n_src_rgb_func, n_dst_rgb_func, n_src_a_func, n_dst_a_func; + std::tie(n_src_rgb_func, n_dst_rgb_func, n_src_a_func, n_dst_a_func) = n_funcs; + if (n_src_rgb_func != cur_state->blend.src_rgb_func || n_dst_rgb_func != cur_state->blend.dst_rgb_func || n_src_a_func != cur_state->blend.src_a_func || @@ -259,7 +272,10 @@ void OpenGLState::SetBlendFunc(GLenum n_src_rgb_func, GLenum n_dst_rgb_func, GLe blend.dst_a_func = n_dst_a_func; } -void OpenGLState::SetBlendColor(GLclampf n_red, GLclampf n_green, GLclampf n_blue, GLclampf n_alpha) { +void OpenGLState::SetBlendColor(std::tuple n_color) { + GLclampf n_red, n_green, n_blue, n_alpha; + std::tie(n_red, n_green, n_blue, n_alpha) = n_color; + if (n_red != cur_state->blend.color.red || n_green != cur_state->blend.color.green || n_blue != cur_state->blend.color.blue || @@ -477,3 +493,31 @@ GLenum OpenGLState::CheckBoundFBStatus(GLenum target) { return fb_status; } + +OpenGLState OpenGLState::ApplyTransferState(GLuint src_tex, GLuint read_framebuffer, GLuint dst_tex, GLuint draw_framebuffer) { + OpenGLState old_state = *cur_state; + + cur_state->SetColorMask(std::make_tuple<>(true, true, true, true)); + cur_state->SetDepthWriteMask(true); + cur_state->SetStencilWriteMask(true); + if (src_tex != 0) { + cur_state->ResetTexture(src_tex); + } + cur_state->SetReadFramebuffer(read_framebuffer); + if (dst_tex != 0) { + cur_state->ResetTexture(dst_tex); + } + cur_state->SetDrawFramebuffer(draw_framebuffer); + + return old_state; +} + +void OpenGLState::UndoTransferState(OpenGLState &old_state) { + cur_state->SetColorMask(old_state.GetColorMask()); + cur_state->SetDepthWriteMask(old_state.GetDepthWriteMask()); + cur_state->SetStencilWriteMask(old_state.GetStencilWriteMask()); + cur_state->SetReadFramebuffer(old_state.GetReadFramebuffer()); + cur_state->SetDrawFramebuffer(old_state.GetDrawFramebuffer()); + + // NOTE: Textures that were reset in ApplyTransferState() are NOT restored +} diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 8d10f7cdb..66a298d99 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -17,39 +17,74 @@ public: /// Apply this state as the current OpenGL state void MakeCurrent(); - /// Setter functions for OpenGL state + /// Getter and setter functions for OpenGL state + inline bool GetCullEnabled() { return cull.enabled; } void SetCullEnabled(bool n_enabled); + inline GLenum GetCullMode() { return cull.mode; } void SetCullMode(GLenum n_mode); + inline GLenum GetCullFrontFace() { return cull.front_face; } void SetCullFrontFace(GLenum n_front_face); + inline bool GetDepthTestEnabled() { return depth.test_enabled; } void SetDepthTestEnabled(bool n_test_enabled); + inline GLenum GetDepthFunc() { return depth.test_func; } void SetDepthFunc(GLenum n_test_func); + inline GLboolean GetDepthWriteMask() { return depth.write_mask; } void SetDepthWriteMask(GLboolean n_write_mask); - void SetColorMask(GLboolean n_red_enabled, GLboolean n_green_enabled, GLboolean n_blue_enabled, GLboolean n_alpha_enabled); + inline std::tuple GetColorMask() { + return std::make_tuple(color_mask.red_enabled, color_mask.green_enabled, color_mask.blue_enabled, color_mask.alpha_enabled); + } + void SetColorMask(std::tuple n_rgba_enabled); + inline bool GetStencilTestEnabled() { return stencil.test_enabled; } void SetStencilTestEnabled(bool n_test_enabled); - void SetStencilFunc(GLenum n_test_func, GLint n_test_ref, GLuint n_test_mask); - void SetStencilOp(GLenum n_action_stencil_fail, GLenum n_action_depth_fail, GLenum n_action_depth_pass); + inline std::tuple GetStencilFunc() { + return std::make_tuple(stencil.test_func, stencil.test_ref, stencil.test_mask); + } + void SetStencilFunc(std::tuple n_funcs); + inline std::tuple GetStencilOp() { + return std::make_tuple(stencil.action_stencil_fail, stencil.action_depth_fail, stencil.action_depth_pass); + } + void SetStencilOp(std::tuple n_actions); + inline GLuint GetStencilWriteMask() { return stencil.write_mask; } void SetStencilWriteMask(GLuint n_write_mask); + inline bool GetBlendEnabled() { return blend.enabled; } void SetBlendEnabled(bool n_enabled); - void SetBlendFunc(GLenum n_src_rgb_func, GLenum n_dst_rgb_func, GLenum n_src_a_func, GLenum n_dst_a_func); - void SetBlendColor(GLclampf n_red, GLclampf n_green, GLclampf n_blue, GLclampf n_alpha); + inline std::tuple GetBlendFunc() { + return std::make_tuple(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func, blend.dst_a_func); + } + void SetBlendFunc(std::tuple n_funcs); + inline std::tuple GetBlendColor() { + return std::make_tuple(blend.color.red, blend.color.green, blend.color.blue, blend.color.alpha); + } + void SetBlendColor(std::tuple n_color); + inline GLenum GetLogicOp() { return logic_op; } void SetLogicOp(GLenum n_logic_op); + inline GLuint GetTexture1D() { return texture_units[active_texture_unit - GL_TEXTURE0].texture_1d; } void SetTexture1D(GLuint n_texture_1d); + inline GLuint GetTexture2D() { return texture_units[active_texture_unit - GL_TEXTURE0].texture_2d; } void SetTexture2D(GLuint n_texture_2d); + inline GLuint GetSampler() { return texture_units[active_texture_unit - GL_TEXTURE0].sampler; } void SetSampler(GLuint n_sampler); + inline GLenum GetActiveTextureUnit() { return active_texture_unit; } void SetActiveTextureUnit(GLenum n_active_texture_unit); + inline GLuint GetReadFramebuffer() { return draw.read_framebuffer; } void SetReadFramebuffer(GLuint n_read_framebuffer); + inline GLuint GetDrawFramebuffer() { return draw.draw_framebuffer; } void SetDrawFramebuffer(GLuint n_draw_framebuffer); + inline GLuint GetVertexArray() { return draw.vertex_array; } void SetVertexArray(GLuint n_vertex_array); + inline GLuint GetVertexBuffer() { return draw.vertex_buffer; } void SetVertexBuffer(GLuint n_vertex_buffer); + inline GLuint GetUniformBuffer() { return draw.uniform_buffer; } void SetUniformBuffer(GLuint n_uniform_buffer); + inline GLuint GetShaderProgram() { return draw.shader_program; } void SetShaderProgram(GLuint n_shader_program); /// Resets and unbinds any references to the given resource across all existing states @@ -63,6 +98,12 @@ public: /// Check the status of the currently bound OpenGL read or draw framebuffer configuration static GLenum CheckBoundFBStatus(GLenum target); + /// Manipulates the current state to prepare for pixel transfer, and returns a copy of the old state + static OpenGLState ApplyTransferState(GLuint src_tex, GLuint read_framebuffer, GLuint dst_tex, GLuint draw_framebuffer); + + /// Returns the old state before transfer state changes were made + static void UndoTransferState(OpenGLState &old_state); + private: struct { bool enabled; // GL_CULL_FACE diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index b746593f8..cf5d3ff5a 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -108,6 +108,7 @@ RendererOpenGL::~RendererOpenGL() { /// Swap buffers (render frame) void RendererOpenGL::SwapBuffers() { + OpenGLState* old_state = OpenGLState::GetCurrentState(); state.MakeCurrent(); for (int i : {0, 1}) { @@ -157,6 +158,8 @@ void RendererOpenGL::SwapBuffers() { profiler.BeginFrame(); + old_state->MakeCurrent(); + RefreshRasterizerSetting(); if (Pica::g_debug_context && Pica::g_debug_context->recorder) {