diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 519d81aeb..c8eed05f2 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -37,10 +37,13 @@ static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) { } RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) { + state.MakeCurrent(); + // Create sampler objects for (size_t i = 0; i < texture_samplers.size(); ++i) { texture_samplers[i].Create(); - state.texture_units[i].sampler = texture_samplers[i].sampler.handle; + state.SetActiveTextureUnit(GL_TEXTURE0 + i); + state.SetSampler(texture_samplers[i].sampler.handle); } // Generate VBO, VAO and UBO @@ -48,10 +51,9 @@ RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) { vertex_array.Create(); uniform_buffer.Create(); - state.draw.vertex_array = vertex_array.handle; - state.draw.vertex_buffer = vertex_buffer.handle; - state.draw.uniform_buffer = uniform_buffer.handle; - state.Apply(); + state.SetVertexArray(vertex_array.handle); + state.SetVertexBuffer(vertex_buffer.handle); + state.SetUniformBuffer(uniform_buffer.handle); // Bind the UBO to binding point 0 glBindBufferBase(GL_UNIFORM_BUFFER, 0, uniform_buffer.handle); @@ -88,12 +90,8 @@ RasterizerOpenGL::RasterizerOpenGL() : shader_dirty(true) { // Allocate and bind lighting lut textures for (size_t i = 0; i < lighting_luts.size(); ++i) { lighting_luts[i].Create(); - state.lighting_luts[i].texture_1d = lighting_luts[i].handle; - } - state.Apply(); - - for (size_t i = 0; i < lighting_luts.size(); ++i) { - glActiveTexture(GL_TEXTURE3 + i); + state.SetActiveTextureUnit(GL_TEXTURE3 + i); + state.SetLUTTexture1D(lighting_luts[i].handle); glTexImage1D(GL_TEXTURE_1D, 0, GL_RGBA32F, 256, 0, GL_RGBA, GL_FLOAT, nullptr); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); @@ -151,6 +149,8 @@ void RasterizerOpenGL::DrawTriangles() { if (vertex_batch.empty()) return; + state.MakeCurrent(); + const auto& regs = Pica::g_state.regs; // Sync and bind the framebuffer surfaces @@ -159,8 +159,7 @@ void RasterizerOpenGL::DrawTriangles() { MathUtil::Rectangle rect; std::tie(color_surface, depth_surface, rect) = res_cache.GetFramebufferSurfaces(regs.framebuffer); - state.draw.draw_framebuffer = framebuffer.handle; - state.Apply(); + state.SetDrawFramebuffer(framebuffer.handle); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, color_surface != nullptr ? color_surface->texture.handle : 0, 0); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth_surface != nullptr ? depth_surface->texture.handle : 0, 0); @@ -188,14 +187,16 @@ void RasterizerOpenGL::DrawTriangles() { if (texture.enabled) { texture_samplers[texture_index].SyncWithConfig(texture.config); CachedSurface* surface = res_cache.GetTextureSurface(texture); + state.SetActiveTextureUnit(GL_TEXTURE0 + texture_index); if (surface != nullptr) { - state.texture_units[texture_index].texture_2d = surface->texture.handle; + state.SetTexture2D(surface->texture.handle); } else { // Can occur when texture addr is null or its memory is unmapped/invalid - state.texture_units[texture_index].texture_2d = 0; + state.SetTexture2D(0); } } else { - state.texture_units[texture_index].texture_2d = 0; + state.SetActiveTextureUnit(GL_TEXTURE0 + texture_index); + state.SetTexture2D(0); } } @@ -219,8 +220,6 @@ void RasterizerOpenGL::DrawTriangles() { uniform_block_data.dirty = false; } - state.Apply(); - // Draw the vertex batch glBufferData(GL_ARRAY_BUFFER, vertex_batch.size() * sizeof(HardwareVertex), vertex_batch.data(), GL_STREAM_DRAW); glDrawArrays(GL_TRIANGLES, 0, (GLsizei)vertex_batch.size()); @@ -240,14 +239,16 @@ void RasterizerOpenGL::DrawTriangles() { // Unbind textures for potential future use as framebuffer attachments for (unsigned texture_index = 0; texture_index < pica_textures.size(); ++texture_index) { - state.texture_units[texture_index].texture_2d = 0; + state.SetActiveTextureUnit(GL_TEXTURE0 + texture_index); + state.SetTexture2D(0); } - state.Apply(); } void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { const auto& regs = Pica::g_state.regs; + state.MakeCurrent(); + switch(id) { // Culling case PICA_REG_INDEX(cull_mode): @@ -609,20 +610,20 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) return false; } - OpenGLState cur_state = OpenGLState::GetCurState(); - SurfaceType dst_type = CachedSurface::GetFormatType(dst_surface->pixel_format); - GLuint old_fb = cur_state.draw.draw_framebuffer; - cur_state.draw.draw_framebuffer = framebuffer.handle; - // TODO: When scissor test is implemented, need to disable scissor test in cur_state here so Clear call isn't affected - cur_state.Apply(); + OpenGLState* old_state = OpenGLState::GetCurrentState(); + utility_state.MakeCurrent(); + + utility_state.SetDrawFramebuffer(framebuffer.handle); + // TODO: When scissor test is implemented, need to disable scissor test in the state here so Clear call isn't affected 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::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + old_state->MakeCurrent(); return false; } @@ -640,6 +641,7 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) color_values[2] = config.value_24bit_b / 255.0f; break; default: + old_state->MakeCurrent(); return false; } } else if (config.fill_32bit) { @@ -653,6 +655,7 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) color_values[3] = (value & 0xFF) / 255.0f; break; default: + old_state->MakeCurrent(); return false; } } else { @@ -692,15 +695,12 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) color_values[1] = (value_16bit & 0xFF) / 255.0f; break; default: + old_state->MakeCurrent(); return false; } } - cur_state.color_mask.red_enabled = true; - cur_state.color_mask.green_enabled = true; - cur_state.color_mask.blue_enabled = true; - cur_state.color_mask.alpha_enabled = true; - cur_state.Apply(); + 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); @@ -708,6 +708,7 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0, 0); if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + old_state->MakeCurrent(); return false; } @@ -718,29 +719,26 @@ bool RasterizerOpenGL::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) value_float = config.value_32bit / 16777215.0f; // 2^24 - 1 } - cur_state.depth.write_mask = true; - cur_state.Apply(); + 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::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + old_state->MakeCurrent(); return false; } GLfloat value_float = (config.value_32bit & 0xFFFFFF) / 16777215.0f; // 2^24 - 1 GLint value_int = (config.value_32bit >> 24); - cur_state.depth.write_mask = true; - cur_state.stencil.write_mask = true; - cur_state.Apply(); + utility_state.SetDepthWriteMask(true); + utility_state.SetStencilWriteMask(true); glClearBufferfi(GL_DEPTH_STENCIL, 0, value_float, value_int); } - cur_state.draw.draw_framebuffer = old_fb; - // TODO: Return scissor test to previous value when scissor test is implemented - cur_state.Apply(); + old_state->MakeCurrent(); dst_surface->dirty = true; res_cache.FlushRegion(dst_surface->addr, dst_surface->size, dst_surface, true); @@ -824,20 +822,20 @@ 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()) { current_shader = cached_shader->second.get(); - state.draw.shader_program = current_shader->shader.handle; - state.Apply(); + state.SetShaderProgram(current_shader->shader.handle); } else { LOG_DEBUG(Render_OpenGL, "Creating new shader"); shader->shader.Create(GLShader::GenerateVertexShader().c_str(), GLShader::GenerateFragmentShader(config).c_str()); - state.draw.shader_program = shader->shader.handle; - state.Apply(); + state.SetShaderProgram(shader->shader.handle); // Set the texture samplers to correspond to different texture units GLuint uniform_tex = glGetUniformLocation(shader->shader.handle, "tex[0]"); @@ -889,17 +887,17 @@ void RasterizerOpenGL::SyncCullMode() { switch (regs.cull_mode) { case Pica::Regs::CullMode::KeepAll: - state.cull.enabled = false; + state.SetCullEnabled(false); break; case Pica::Regs::CullMode::KeepClockWise: - state.cull.enabled = true; - state.cull.front_face = GL_CW; + state.SetCullEnabled(true); + state.SetCullFrontFace(GL_CW); break; case Pica::Regs::CullMode::KeepCounterClockWise: - state.cull.enabled = true; - state.cull.front_face = GL_CCW; + state.SetCullEnabled(true); + state.SetCullFrontFace(GL_CCW); break; default: @@ -919,23 +917,23 @@ void RasterizerOpenGL::SyncDepthModifiers() { } void RasterizerOpenGL::SyncBlendEnabled() { - state.blend.enabled = (Pica::g_state.regs.output_merger.alphablend_enable == 1); + state.SetBlendEnabled(Pica::g_state.regs.output_merger.alphablend_enable == 1); } void RasterizerOpenGL::SyncBlendFuncs() { const auto& regs = Pica::g_state.regs; - state.blend.src_rgb_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_rgb); - state.blend.dst_rgb_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_rgb); - state.blend.src_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_source_a); - state.blend.dst_a_func = PicaToGL::BlendFunc(regs.output_merger.alpha_blending.factor_dest_a); + state.SetBlendFunc(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)); } void RasterizerOpenGL::SyncBlendColor() { auto blend_color = PicaToGL::ColorRGBA8(Pica::g_state.regs.output_merger.blend_const.raw); - state.blend.color.red = blend_color[0]; - state.blend.color.green = blend_color[1]; - state.blend.color.blue = blend_color[2]; - state.blend.color.alpha = blend_color[3]; + state.SetBlendColor(blend_color[0], + blend_color[1], + blend_color[2], + blend_color[3]); } void RasterizerOpenGL::SyncAlphaTest() { @@ -947,7 +945,7 @@ void RasterizerOpenGL::SyncAlphaTest() { } void RasterizerOpenGL::SyncLogicOp() { - state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.output_merger.logic_op); + state.SetLogicOp(PicaToGL::LogicOp(Pica::g_state.regs.output_merger.logic_op)); } void RasterizerOpenGL::SyncColorWriteMask() { @@ -957,43 +955,43 @@ void RasterizerOpenGL::SyncColorWriteMask() { return (regs.framebuffer.allow_color_write != 0 && value != 0) ? GL_TRUE : GL_FALSE; }; - state.color_mask.red_enabled = IsColorWriteEnabled(regs.output_merger.red_enable); - state.color_mask.green_enabled = IsColorWriteEnabled(regs.output_merger.green_enable); - state.color_mask.blue_enabled = IsColorWriteEnabled(regs.output_merger.blue_enable); - state.color_mask.alpha_enabled = IsColorWriteEnabled(regs.output_merger.alpha_enable); + state.SetColorMask(IsColorWriteEnabled(regs.output_merger.red_enable), + IsColorWriteEnabled(regs.output_merger.green_enable), + IsColorWriteEnabled(regs.output_merger.blue_enable), + IsColorWriteEnabled(regs.output_merger.alpha_enable)); } void RasterizerOpenGL::SyncStencilWriteMask() { const auto& regs = Pica::g_state.regs; - state.stencil.write_mask = (regs.framebuffer.allow_depth_stencil_write != 0) - ? static_cast(regs.output_merger.stencil_test.write_mask) - : 0; + state.SetStencilWriteMask((regs.framebuffer.allow_depth_stencil_write != 0) + ? static_cast(regs.output_merger.stencil_test.write_mask) + : 0); } void RasterizerOpenGL::SyncDepthWriteMask() { const auto& regs = Pica::g_state.regs; - state.depth.write_mask = (regs.framebuffer.allow_depth_stencil_write != 0 && regs.output_merger.depth_write_enable) - ? GL_TRUE - : GL_FALSE; + state.SetDepthWriteMask((regs.framebuffer.allow_depth_stencil_write != 0 && regs.output_merger.depth_write_enable) + ? GL_TRUE + : GL_FALSE); } void RasterizerOpenGL::SyncStencilTest() { const auto& regs = Pica::g_state.regs; - state.stencil.test_enabled = regs.output_merger.stencil_test.enable && regs.framebuffer.depth_format == Pica::Regs::DepthFormat::D24S8; - state.stencil.test_func = PicaToGL::CompareFunc(regs.output_merger.stencil_test.func); - state.stencil.test_ref = regs.output_merger.stencil_test.reference_value; - state.stencil.test_mask = regs.output_merger.stencil_test.input_mask; - state.stencil.action_stencil_fail = PicaToGL::StencilOp(regs.output_merger.stencil_test.action_stencil_fail); - state.stencil.action_depth_fail = PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_fail); - state.stencil.action_depth_pass = PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_pass); + 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), + 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), + PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_fail), + PicaToGL::StencilOp(regs.output_merger.stencil_test.action_depth_pass)); } void RasterizerOpenGL::SyncDepthTest() { const auto& regs = Pica::g_state.regs; - state.depth.test_enabled = regs.output_merger.depth_test_enable == 1 || - regs.output_merger.depth_write_enable == 1; - state.depth.test_func = regs.output_merger.depth_test_enable == 1 ? - PicaToGL::CompareFunc(regs.output_merger.depth_test_func) : GL_ALWAYS; + state.SetDepthTestEnabled(regs.output_merger.depth_test_enable == 1 || + regs.output_merger.depth_write_enable == 1); + state.SetDepthFunc(regs.output_merger.depth_test_enable == 1 ? + PicaToGL::CompareFunc(regs.output_merger.depth_test_func) : GL_ALWAYS); } void RasterizerOpenGL::SyncCombinerColor() { @@ -1032,7 +1030,7 @@ void RasterizerOpenGL::SyncLightingLUT(unsigned lut_index) { if (new_data != lighting_lut_data[lut_index]) { lighting_lut_data[lut_index] = new_data; - glActiveTexture(GL_TEXTURE3 + lut_index); + state.SetActiveTextureUnit(GL_TEXTURE3 + lut_index); glTexSubImage1D(GL_TEXTURE_1D, 0, 0, 256, GL_RGBA, GL_FLOAT, lighting_lut_data[lut_index].data()); } } diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 63ff7716d..8ed2a8a81 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -351,6 +351,7 @@ 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 7efd0038a..536a5b6d7 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -105,17 +105,15 @@ 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 cur_state = OpenGLState::GetCurState(); + 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); - // Keep track of previous framebuffer bindings - GLuint old_fbs[2] = { cur_state.draw.read_framebuffer, cur_state.draw.draw_framebuffer }; - cur_state.draw.read_framebuffer = transfer_framebuffers[0].handle; - cur_state.draw.draw_framebuffer = transfer_framebuffers[1].handle; - cur_state.Apply(); + utility_state.SetReadFramebuffer(transfer_framebuffers[0].handle); + utility_state.SetDrawFramebuffer(transfer_framebuffers[1].handle); u32 buffers = 0; @@ -148,10 +146,12 @@ bool RasterizerCacheOpenGL::BlitTextures(GLuint src_tex, GLuint dst_tex, CachedS } if (OpenGLState::CheckFBStatus(GL_READ_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + old_state->MakeCurrent(); return false; } if (OpenGLState::CheckFBStatus(GL_DRAW_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { + old_state->MakeCurrent(); return false; } @@ -159,10 +159,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); - // Restore previous framebuffer bindings - cur_state.draw.read_framebuffer = old_fbs[0]; - cur_state.draw.draw_framebuffer = old_fbs[1]; - cur_state.Apply(); + old_state->MakeCurrent(); return true; } @@ -177,17 +174,15 @@ bool RasterizerCacheOpenGL::TryBlitSurfaces(CachedSurface* src_surface, const Ma return BlitTextures(src_surface->texture.handle, dst_surface->texture.handle, CachedSurface::GetFormatType(src_surface->pixel_format), src_rect, dst_rect); } -static void AllocateSurfaceTexture(GLuint texture, CachedSurface::PixelFormat pixel_format, u32 width, u32 height) { +void RasterizerCacheOpenGL::AllocateSurfaceTexture(GLuint texture, CachedSurface::PixelFormat pixel_format, u32 width, u32 height) { // Allocate an uninitialized texture of appropriate size and format for the surface using SurfaceType = CachedSurface::SurfaceType; - OpenGLState cur_state = OpenGLState::GetCurState(); + OpenGLState* old_state = OpenGLState::GetCurrentState(); + utility_state.MakeCurrent(); - // Keep track of previous texture bindings - GLuint old_tex = cur_state.texture_units[0].texture_2d; - cur_state.texture_units[0].texture_2d = texture; - cur_state.Apply(); - glActiveTexture(GL_TEXTURE0); + utility_state.SetActiveTextureUnit(GL_TEXTURE0); + utility_state.SetTexture2D(texture); SurfaceType type = CachedSurface::GetFormatType(pixel_format); @@ -211,9 +206,7 @@ static void AllocateSurfaceTexture(GLuint texture, CachedSurface::PixelFormat pi glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - // Restore previous texture bindings - cur_state.texture_units[0].texture_2d = old_tex; - cur_state.Apply(); + old_state->MakeCurrent(); } MICROPROFILE_DEFINE(OpenGL_SurfaceUpload, "OpenGL", "Surface Upload", MP_RGB(128, 64, 192)); @@ -295,12 +288,11 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo Memory::RasterizerFlushRegion(params.addr, params_size); // Load data from memory to the new surface - OpenGLState cur_state = OpenGLState::GetCurState(); + OpenGLState* old_state = OpenGLState::GetCurrentState(); + utility_state.MakeCurrent(); - GLuint old_tex = cur_state.texture_units[0].texture_2d; - cur_state.texture_units[0].texture_2d = new_surface->texture.handle; - cur_state.Apply(); - glActiveTexture(GL_TEXTURE0); + utility_state.SetActiveTextureUnit(GL_TEXTURE0); + utility_state.SetTexture2D(new_surface->texture.handle); glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)new_surface->stride); if (!new_surface->is_tiled) { @@ -375,8 +367,6 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo new_surface->texture.Release(); new_surface->texture.handle = scaled_texture.handle; scaled_texture.handle = 0; - cur_state.texture_units[0].texture_2d = new_surface->texture.handle; - cur_state.Apply(); } glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); @@ -384,8 +374,7 @@ 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); - cur_state.texture_units[0].texture_2d = old_tex; - cur_state.Apply(); + old_state->MakeCurrent(); } Memory::RasterizerMarkRegionCached(new_surface->addr, new_surface->size, 1); @@ -607,8 +596,8 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) { return; } - OpenGLState cur_state = OpenGLState::GetCurState(); - GLuint old_tex = cur_state.texture_units[0].texture_2d; + OpenGLState* old_state = OpenGLState::GetCurrentState(); + utility_state.MakeCurrent(); OGLTexture unscaled_tex; GLuint texture_to_flush = surface->texture.handle; @@ -625,9 +614,8 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) { texture_to_flush = unscaled_tex.handle; } - cur_state.texture_units[0].texture_2d = texture_to_flush; - cur_state.Apply(); - glActiveTexture(GL_TEXTURE0); + utility_state.SetActiveTextureUnit(GL_TEXTURE0); + utility_state.SetTexture2D(texture_to_flush); glPixelStorei(GL_PACK_ROW_LENGTH, (GLint)surface->stride); if (!surface->is_tiled) { @@ -676,8 +664,7 @@ void RasterizerCacheOpenGL::FlushSurface(CachedSurface* surface) { surface->dirty = false; - cur_state.texture_units[0].texture_2d = old_tex; - cur_state.Apply(); + old_state->MakeCurrent(); } 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 225596415..cd91a4e70 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -217,6 +217,10 @@ public: void FlushAll(); 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 02cd9f417..653467a9f 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp @@ -9,7 +9,8 @@ #include "video_core/renderer_opengl/gl_state.h" -OpenGLState OpenGLState::cur_state; +static OpenGLState default_state; +OpenGLState* OpenGLState::cur_state = &default_state; OpenGLState::OpenGLState() { // These all match default OpenGL values @@ -56,6 +57,8 @@ OpenGLState::OpenGLState() { lut.texture_1d = 0; } + active_texture_unit = GL_TEXTURE0; + draw.read_framebuffer = 0; draw.draw_framebuffer = 0; draw.vertex_array = 0; @@ -64,159 +67,290 @@ OpenGLState::OpenGLState() { draw.shader_program = 0; } -void OpenGLState::Apply() const { - // Culling - if (cull.enabled != cur_state.cull.enabled) { - if (cull.enabled) { +OpenGLState* OpenGLState::GetCurrentState() { + return cur_state; +} + +void OpenGLState::SetCullEnabled(bool n_enabled) { + if (n_enabled != cur_state->cull.enabled) { + if (n_enabled) { glEnable(GL_CULL_FACE); } else { glDisable(GL_CULL_FACE); } } + cull.enabled = n_enabled; +} - if (cull.mode != cur_state.cull.mode) { - glCullFace(cull.mode); +void OpenGLState::SetCullMode(GLenum n_mode) { + if (n_mode != cur_state->cull.mode) { + glCullFace(n_mode); } + cull.mode = n_mode; +} - if (cull.front_face != cur_state.cull.front_face) { - glFrontFace(cull.front_face); +void OpenGLState::SetCullFrontFace(GLenum n_front_face) { + if (n_front_face != cur_state->cull.front_face) { + glFrontFace(n_front_face); } + cull.front_face = n_front_face; +} - // Depth test - if (depth.test_enabled != cur_state.depth.test_enabled) { - if (depth.test_enabled) { +void OpenGLState::SetDepthTestEnabled(bool n_test_enabled) { + if (n_test_enabled != cur_state->depth.test_enabled) { + if (n_test_enabled) { glEnable(GL_DEPTH_TEST); } else { glDisable(GL_DEPTH_TEST); } } + depth.test_enabled = n_test_enabled; +} - if (depth.test_func != cur_state.depth.test_func) { - glDepthFunc(depth.test_func); +void OpenGLState::SetDepthFunc(GLenum n_test_func) { + if (n_test_func != cur_state->depth.test_func) { + glDepthFunc(n_test_func); } + depth.test_func = n_test_func; +} - // Depth mask - if (depth.write_mask != cur_state.depth.write_mask) { - glDepthMask(depth.write_mask); +void OpenGLState::SetDepthWriteMask(GLboolean n_write_mask) { + if (n_write_mask != cur_state->depth.write_mask) { + glDepthMask(n_write_mask); } + depth.write_mask = n_write_mask; +} - // Color mask - if (color_mask.red_enabled != cur_state.color_mask.red_enabled || - color_mask.green_enabled != cur_state.color_mask.green_enabled || - color_mask.blue_enabled != cur_state.color_mask.blue_enabled || - color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) { - glColorMask(color_mask.red_enabled, color_mask.green_enabled, - color_mask.blue_enabled, color_mask.alpha_enabled); +void OpenGLState::SetColorMask(GLboolean n_red_enabled, GLboolean n_green_enabled, GLboolean n_blue_enabled, GLboolean n_alpha_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 || + n_alpha_enabled != cur_state->color_mask.alpha_enabled) { + glColorMask(n_red_enabled, n_green_enabled, + n_blue_enabled, n_alpha_enabled); } + color_mask.red_enabled = n_red_enabled; + color_mask.green_enabled = n_green_enabled; + color_mask.blue_enabled = n_blue_enabled; + color_mask.alpha_enabled = n_alpha_enabled; +} - // Stencil test - if (stencil.test_enabled != cur_state.stencil.test_enabled) { - if (stencil.test_enabled) { +void OpenGLState::SetStencilTestEnabled(bool n_test_enabled) { + if (n_test_enabled != cur_state->stencil.test_enabled) { + if (n_test_enabled) { glEnable(GL_STENCIL_TEST); } else { glDisable(GL_STENCIL_TEST); } } + stencil.test_enabled = n_test_enabled; +} - if (stencil.test_func != cur_state.stencil.test_func || - stencil.test_ref != cur_state.stencil.test_ref || - stencil.test_mask != cur_state.stencil.test_mask) { - glStencilFunc(stencil.test_func, stencil.test_ref, stencil.test_mask); +void OpenGLState::SetStencilFunc(GLenum n_test_func, GLint n_test_ref, GLuint n_test_mask) { + 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) { + glStencilFunc(n_test_func, n_test_ref, n_test_mask); } + stencil.test_func = n_test_func; + stencil.test_ref = n_test_ref; + stencil.test_mask = n_test_mask; +} - if (stencil.action_depth_fail != cur_state.stencil.action_depth_fail || - stencil.action_depth_pass != cur_state.stencil.action_depth_pass || - stencil.action_stencil_fail != cur_state.stencil.action_stencil_fail) { - glStencilOp(stencil.action_stencil_fail, stencil.action_depth_fail, stencil.action_depth_pass); +void OpenGLState::SetStencilOp(GLenum n_action_stencil_fail, GLenum n_action_depth_fail, GLenum n_action_depth_pass) { + if (n_action_stencil_fail != cur_state->stencil.action_depth_fail || + n_action_depth_fail != cur_state->stencil.action_depth_pass || + n_action_depth_pass != cur_state->stencil.action_stencil_fail) { + glStencilOp(n_action_stencil_fail, n_action_depth_fail, n_action_depth_pass); } + stencil.action_depth_fail = n_action_stencil_fail; + stencil.action_depth_pass = n_action_depth_fail; + stencil.action_stencil_fail = n_action_depth_pass; +} - // Stencil mask - if (stencil.write_mask != cur_state.stencil.write_mask) { - glStencilMask(stencil.write_mask); +void OpenGLState::SetStencilWriteMask(GLuint n_write_mask) { + if (n_write_mask != cur_state->stencil.write_mask) { + glStencilMask(n_write_mask); } + stencil.write_mask = n_write_mask; +} - // Blending - if (blend.enabled != cur_state.blend.enabled) { - if (blend.enabled) { +void OpenGLState::SetBlendEnabled(bool n_enabled) { + if (n_enabled != cur_state->blend.enabled) { + if (n_enabled) { glEnable(GL_BLEND); - cur_state.logic_op = GL_COPY; - glLogicOp(cur_state.logic_op); + SetLogicOp(GL_COPY); glDisable(GL_COLOR_LOGIC_OP); } else { glDisable(GL_BLEND); glEnable(GL_COLOR_LOGIC_OP); } } + blend.enabled = n_enabled; +} - if (blend.color.red != cur_state.blend.color.red || - blend.color.green != cur_state.blend.color.green || - blend.color.blue != cur_state.blend.color.blue || - blend.color.alpha != cur_state.blend.color.alpha) { - glBlendColor(blend.color.red, blend.color.green, - blend.color.blue, blend.color.alpha); +void OpenGLState::SetBlendFunc(GLenum n_src_rgb_func, GLenum n_dst_rgb_func, GLenum n_src_a_func, GLenum n_dst_a_func) { + 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 || + n_dst_a_func != cur_state->blend.dst_a_func) { + glBlendFuncSeparate(n_src_rgb_func, n_dst_rgb_func, + n_src_a_func, n_dst_a_func); + } + blend.src_rgb_func = n_src_rgb_func; + blend.dst_rgb_func = n_dst_rgb_func; + blend.src_a_func = n_src_a_func; + blend.dst_a_func = n_dst_a_func; +} + +void OpenGLState::SetBlendColor(GLclampf n_red, GLclampf n_green, GLclampf n_blue, GLclampf n_alpha) { + if (n_red != cur_state->blend.color.red || + n_green != cur_state->blend.color.green || + n_blue != cur_state->blend.color.blue || + n_alpha != cur_state->blend.color.alpha) { + glBlendColor(n_red, n_green, + n_blue, n_alpha); + } + blend.color.red = n_red; + blend.color.green = n_green; + blend.color.blue = n_blue; + blend.color.alpha = n_alpha; +} + +void OpenGLState::SetLogicOp(GLenum n_logic_op) { + if (n_logic_op != cur_state->logic_op) { + glLogicOp(n_logic_op); + } + logic_op = n_logic_op; +} + +void OpenGLState::SetTexture2D(GLuint n_texture_2d) { + unsigned unit_index = active_texture_unit - GL_TEXTURE0; + ASSERT(unit_index < ARRAY_SIZE(texture_units)); + + if (n_texture_2d != cur_state->texture_units[unit_index].texture_2d) { + glBindTexture(GL_TEXTURE_2D, n_texture_2d); + } + texture_units[unit_index].texture_2d = n_texture_2d; +} + +void OpenGLState::SetSampler(GLuint n_sampler) { + unsigned unit_index = active_texture_unit - GL_TEXTURE0; + ASSERT(unit_index < ARRAY_SIZE(texture_units)); + + if (n_sampler != cur_state->texture_units[unit_index].sampler) { + glBindSampler(unit_index, n_sampler); + } + texture_units[unit_index].sampler = n_sampler; +} + +void OpenGLState::SetLUTTexture1D(GLuint n_texture_1d) { + unsigned unit_index = active_texture_unit - GL_TEXTURE3; + ASSERT(unit_index < ARRAY_SIZE(lighting_luts)); + + if (n_texture_1d != cur_state->lighting_luts[unit_index].texture_1d) { + glBindTexture(GL_TEXTURE_1D, n_texture_1d); + } + lighting_luts[unit_index].texture_1d = n_texture_1d; +} + +void OpenGLState::SetActiveTextureUnit(GLenum n_active_texture_unit) { + if (n_active_texture_unit != cur_state->active_texture_unit) { + glActiveTexture(n_active_texture_unit); + } + active_texture_unit = n_active_texture_unit; +} + +void OpenGLState::SetReadFramebuffer(GLuint n_read_framebuffer) { + if (n_read_framebuffer != cur_state->draw.read_framebuffer) { + glBindFramebuffer(GL_READ_FRAMEBUFFER, n_read_framebuffer); + } + draw.read_framebuffer = n_read_framebuffer; +} + +void OpenGLState::SetDrawFramebuffer(GLuint n_draw_framebuffer) { + if (n_draw_framebuffer != cur_state->draw.draw_framebuffer) { + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, n_draw_framebuffer); + } + draw.draw_framebuffer = n_draw_framebuffer; +} + +void OpenGLState::SetVertexArray(GLuint n_vertex_array) { + if (n_vertex_array != cur_state->draw.vertex_array) { + glBindVertexArray(n_vertex_array); + } + draw.vertex_array = n_vertex_array; +} + +void OpenGLState::SetVertexBuffer(GLuint n_vertex_buffer) { + if (n_vertex_buffer != cur_state->draw.vertex_buffer) { + glBindBuffer(GL_ARRAY_BUFFER, n_vertex_buffer); + } + draw.vertex_buffer = n_vertex_buffer; +} + +void OpenGLState::SetUniformBuffer(GLuint n_uniform_buffer) { + if (n_uniform_buffer != cur_state->draw.uniform_buffer) { + glBindBuffer(GL_UNIFORM_BUFFER, n_uniform_buffer); + } + draw.uniform_buffer = n_uniform_buffer; +} + +void OpenGLState::SetShaderProgram(GLuint n_shader_program) { + if (n_shader_program != cur_state->draw.shader_program) { + glUseProgram(n_shader_program); + } + draw.shader_program = n_shader_program; +} + +void OpenGLState::MakeCurrent() { + if (cur_state == this) { + return; } - if (blend.src_rgb_func != cur_state.blend.src_rgb_func || - blend.dst_rgb_func != cur_state.blend.dst_rgb_func || - blend.src_a_func != cur_state.blend.src_a_func || - blend.dst_a_func != cur_state.blend.dst_a_func) { - glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, - blend.src_a_func, blend.dst_a_func); - } + SetCullEnabled(cull.enabled); + SetCullMode(cull.mode); + SetCullFrontFace(cull.front_face); - if (logic_op != cur_state.logic_op) { - glLogicOp(logic_op); - } + SetDepthTestEnabled(depth.test_enabled); + SetDepthFunc(depth.test_func); + SetDepthWriteMask(depth.write_mask); + + SetColorMask(color_mask.red_enabled, color_mask.green_enabled, color_mask.blue_enabled, color_mask.alpha_enabled); + + 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); + + 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); + + SetLogicOp(logic_op); - // Textures for (unsigned i = 0; i < ARRAY_SIZE(texture_units); ++i) { - if (texture_units[i].texture_2d != cur_state.texture_units[i].texture_2d) { - glActiveTexture(GL_TEXTURE0 + i); - glBindTexture(GL_TEXTURE_2D, texture_units[i].texture_2d); - } - if (texture_units[i].sampler != cur_state.texture_units[i].sampler) { - glBindSampler(i, texture_units[i].sampler); - } + SetActiveTextureUnit(GL_TEXTURE0 + i); + SetTexture2D(texture_units[i].texture_2d); + SetSampler(texture_units[i].sampler); } - // Lighting LUTs for (unsigned i = 0; i < ARRAY_SIZE(lighting_luts); ++i) { - if (lighting_luts[i].texture_1d != cur_state.lighting_luts[i].texture_1d) { - glActiveTexture(GL_TEXTURE3 + i); - glBindTexture(GL_TEXTURE_1D, lighting_luts[i].texture_1d); - } + SetActiveTextureUnit(GL_TEXTURE3 + i); + SetLUTTexture1D(lighting_luts[i].texture_1d); } - // Framebuffer - if (draw.read_framebuffer != cur_state.draw.read_framebuffer) { - glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer); - } - if (draw.draw_framebuffer != cur_state.draw.draw_framebuffer) { - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, draw.draw_framebuffer); - } + SetActiveTextureUnit(active_texture_unit); - // Vertex array - if (draw.vertex_array != cur_state.draw.vertex_array) { - glBindVertexArray(draw.vertex_array); - } + SetReadFramebuffer(draw.read_framebuffer); + SetDrawFramebuffer(draw.draw_framebuffer); + SetVertexArray(draw.vertex_array); + SetVertexBuffer(draw.vertex_buffer); + SetUniformBuffer(draw.uniform_buffer); + SetShaderProgram(draw.shader_program); - // Vertex buffer - if (draw.vertex_buffer != cur_state.draw.vertex_buffer) { - glBindBuffer(GL_ARRAY_BUFFER, draw.vertex_buffer); - } - - // Uniform buffer - if (draw.uniform_buffer != cur_state.draw.uniform_buffer) { - glBindBuffer(GL_UNIFORM_BUFFER, draw.uniform_buffer); - } - - // Shader program - if (draw.shader_program != cur_state.draw.shader_program) { - glUseProgram(draw.shader_program); - } - - cur_state = *this; + cur_state = this; } GLenum OpenGLState::CheckFBStatus(GLenum target) { @@ -230,47 +364,55 @@ GLenum OpenGLState::CheckFBStatus(GLenum target) { } void OpenGLState::ResetTexture(GLuint handle) { - for (auto& unit : cur_state.texture_units) { - if (unit.texture_2d == handle) { - unit.texture_2d = 0; + for (unsigned i = 0; i < ARRAY_SIZE(texture_units); ++i) { + if (cur_state->texture_units[i].texture_2d == handle) { + cur_state->SetActiveTextureUnit(GL_TEXTURE0 + i); + cur_state->SetTexture2D(0); + } + } + for (unsigned i = 0; i < ARRAY_SIZE(lighting_luts); ++i) { + if (cur_state->lighting_luts[i].texture_1d == handle) { + cur_state->SetActiveTextureUnit(GL_TEXTURE3 + i); + cur_state->SetLUTTexture1D(0); } } } void OpenGLState::ResetSampler(GLuint handle) { - for (auto& unit : cur_state.texture_units) { - if (unit.sampler == handle) { - unit.sampler = 0; + for (unsigned i = 0; i < ARRAY_SIZE(texture_units); ++i) { + if (cur_state->texture_units[i].texture_2d == handle) { + cur_state->SetActiveTextureUnit(GL_TEXTURE0 + i); + cur_state->SetSampler(0); } } } void OpenGLState::ResetProgram(GLuint handle) { - if (cur_state.draw.shader_program == handle) { - cur_state.draw.shader_program = 0; + if (cur_state->draw.shader_program == handle) { + cur_state->SetShaderProgram(0); } } void OpenGLState::ResetBuffer(GLuint handle) { - if (cur_state.draw.vertex_buffer == handle) { - cur_state.draw.vertex_buffer = 0; + if (cur_state->draw.vertex_buffer == handle) { + cur_state->SetVertexBuffer(0); } - if (cur_state.draw.uniform_buffer == handle) { - cur_state.draw.uniform_buffer = 0; + if (cur_state->draw.uniform_buffer == handle) { + cur_state->SetUniformBuffer(0); } } void OpenGLState::ResetVertexArray(GLuint handle) { - if (cur_state.draw.vertex_array == handle) { - cur_state.draw.vertex_array = 0; + if (cur_state->draw.vertex_array == handle) { + cur_state->SetVertexArray(0); } } void OpenGLState::ResetFramebuffer(GLuint handle) { - if (cur_state.draw.read_framebuffer == handle) { - cur_state.draw.read_framebuffer = 0; + if (cur_state->draw.read_framebuffer == handle) { + cur_state->SetReadFramebuffer(0); } - if (cur_state.draw.draw_framebuffer == handle) { - cur_state.draw.draw_framebuffer = 0; + if (cur_state->draw.draw_framebuffer == handle) { + cur_state->SetDrawFramebuffer(0); } } diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 24f20e47c..9b5aa5e70 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -8,6 +8,60 @@ class OpenGLState { public: + OpenGLState(); + + static OpenGLState* GetCurrentState(); + + /// Apply this state as the current OpenGL state + void MakeCurrent(); + + /// Check the status of the current OpenGL read or draw framebuffer configuration + static GLenum CheckFBStatus(GLenum target); + + /// Resets and unbinds any references to the given resource in the current OpenGL state + static void ResetTexture(GLuint handle); + static void ResetSampler(GLuint handle); + static void ResetProgram(GLuint handle); + static void ResetBuffer(GLuint handle); + static void ResetVertexArray(GLuint handle); + static void ResetFramebuffer(GLuint handle); + + void SetCullEnabled(bool n_enabled); + void SetCullMode(GLenum n_mode); + void SetCullFrontFace(GLenum n_front_face); + + void SetDepthTestEnabled(bool n_test_enabled); + void SetDepthFunc(GLenum n_test_func); + void SetDepthWriteMask(GLboolean n_write_mask); + + void SetColorMask(GLboolean n_red_enabled, GLboolean n_green_enabled, GLboolean n_blue_enabled, GLboolean n_alpha_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); + void SetStencilWriteMask(GLuint n_write_mask); + + 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); + + void SetLogicOp(GLenum n_logic_op); + + void SetTexture2D(GLuint n_texture_2d); + void SetSampler(GLuint n_sampler); + + void SetLUTTexture1D(GLuint n_texture_1d); + + void SetActiveTextureUnit(GLenum n_active_texture_unit); + + void SetReadFramebuffer(GLuint n_read_framebuffer); + void SetDrawFramebuffer(GLuint n_draw_framebuffer); + void SetVertexArray(GLuint n_vertex_array); + void SetVertexBuffer(GLuint n_vertex_buffer); + void SetUniformBuffer(GLuint n_uniform_buffer); + void SetShaderProgram(GLuint n_shader_program); + +private: struct { bool enabled; // GL_CULL_FACE GLenum mode; // GL_CULL_FACE_MODE @@ -32,10 +86,10 @@ public: GLenum test_func; // GL_STENCIL_FUNC GLint test_ref; // GL_STENCIL_REF GLuint test_mask; // GL_STENCIL_VALUE_MASK - GLuint write_mask; // GL_STENCIL_WRITEMASK GLenum action_stencil_fail; // GL_STENCIL_FAIL GLenum action_depth_fail; // GL_STENCIL_PASS_DEPTH_FAIL GLenum action_depth_pass; // GL_STENCIL_PASS_DEPTH_PASS + GLuint write_mask; // GL_STENCIL_WRITEMASK } stencil; struct { @@ -65,6 +119,8 @@ public: GLuint texture_1d; // GL_TEXTURE_BINDING_1D } lighting_luts[6]; + GLenum active_texture_unit; // GL_ACTIVE_TEXTURE + struct { GLuint read_framebuffer; // GL_READ_FRAMEBUFFER_BINDING GLuint draw_framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING @@ -74,27 +130,5 @@ public: GLuint shader_program; // GL_CURRENT_PROGRAM } draw; - OpenGLState(); - - /// Get the currently active OpenGL state - static const OpenGLState& GetCurState() { - return cur_state; - } - - /// Apply this state as the current OpenGL state - void Apply() const; - - /// Check the status of the current OpenGL read or draw framebuffer configuration - static GLenum CheckFBStatus(GLenum target); - - /// Resets and unbinds any references to the given resource in the current OpenGL state - static void ResetTexture(GLuint handle); - static void ResetSampler(GLuint handle); - static void ResetProgram(GLuint handle); - static void ResetBuffer(GLuint handle); - static void ResetVertexArray(GLuint handle); - static void ResetFramebuffer(GLuint handle); - -private: - static OpenGLState cur_state; + static OpenGLState* cur_state; }; diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 0e9a0be8b..b746593f8 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -108,9 +108,7 @@ RendererOpenGL::~RendererOpenGL() { /// Swap buffers (render frame) void RendererOpenGL::SwapBuffers() { - // Maintain the rasterizer's state as a priority - OpenGLState prev_state = OpenGLState::GetCurState(); - state.Apply(); + state.MakeCurrent(); for (int i : {0, 1}) { const auto& framebuffer = GPU::g_regs.framebuffer_config[i]; @@ -157,8 +155,6 @@ void RendererOpenGL::SwapBuffers() { render_window->PollEvents(); render_window->SwapBuffers(); - prev_state.Apply(); - profiler.BeginFrame(); RefreshRasterizerSetting(); @@ -201,10 +197,9 @@ void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& fram const u8* framebuffer_data = Memory::GetPhysicalPointer(framebuffer_addr); - state.texture_units[0].texture_2d = screen_info.texture.resource.handle; - state.Apply(); + state.SetActiveTextureUnit(GL_TEXTURE0); + state.SetTexture2D(screen_info.texture.resource.handle); - glActiveTexture(GL_TEXTURE0); glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)pixel_stride); // Update existing texture @@ -217,8 +212,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& fram glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); - state.texture_units[0].texture_2d = 0; - state.Apply(); + state.SetTexture2D(0); } } @@ -229,29 +223,28 @@ void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& fram */ void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, const TextureInfo& texture) { - state.texture_units[0].texture_2d = texture.resource.handle; - state.Apply(); + state.SetActiveTextureUnit(GL_TEXTURE0); + state.SetTexture2D(texture.resource.handle); - glActiveTexture(GL_TEXTURE0); u8 framebuffer_data[3] = { color_r, color_g, color_b }; // Update existing texture glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, framebuffer_data); - state.texture_units[0].texture_2d = 0; - state.Apply(); + state.SetTexture2D(0); } /** * Initializes the OpenGL state and creates persistent objects. */ void RendererOpenGL::InitOpenGLObjects() { + state.MakeCurrent(); + glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 0.0f); // Link shaders and get variable locations shader.Create(vertex_shader, fragment_shader); - state.draw.shader_program = shader.handle; - state.Apply(); + state.SetShaderProgram(shader.handle); uniform_modelview_matrix = glGetUniformLocation(shader.handle, "modelview_matrix"); uniform_color_texture = glGetUniformLocation(shader.handle, "color_texture"); attrib_position = glGetAttribLocation(shader.handle, "vert_position"); @@ -263,10 +256,9 @@ void RendererOpenGL::InitOpenGLObjects() { // Generate VAO vertex_array.Create(); - state.draw.vertex_array = vertex_array.handle; - state.draw.vertex_buffer = vertex_buffer.handle; - state.draw.uniform_buffer = 0; - state.Apply(); + state.SetVertexArray(vertex_array.handle); + state.SetVertexBuffer(vertex_buffer.handle); + state.SetUniformBuffer(0); // Attach vertex data to VAO glBufferData(GL_ARRAY_BUFFER, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW); @@ -282,21 +274,19 @@ void RendererOpenGL::InitOpenGLObjects() { // Allocation of storage is deferred until the first frame, when we // know the framebuffer size. - state.texture_units[0].texture_2d = screen_info.texture.resource.handle; - state.Apply(); + state.SetActiveTextureUnit(GL_TEXTURE0); + state.SetTexture2D(screen_info.texture.resource.handle); - glActiveTexture(GL_TEXTURE0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + state.SetTexture2D(0); + screen_info.display_texture = screen_info.texture.resource.handle; } - - state.texture_units[0].texture_2d = 0; - state.Apply(); } void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, @@ -347,15 +337,13 @@ void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture, UNIMPLEMENTED(); } - state.texture_units[0].texture_2d = texture.resource.handle; - state.Apply(); + state.SetActiveTextureUnit(GL_TEXTURE0); + state.SetTexture2D(texture.resource.handle); - glActiveTexture(GL_TEXTURE0); glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0, texture.gl_format, texture.gl_type, nullptr); - state.texture_units[0].texture_2d = 0; - state.Apply(); + state.SetTexture2D(0); } /** @@ -371,14 +359,13 @@ void RendererOpenGL::DrawSingleScreenRotated(const ScreenInfo& screen_info, floa ScreenRectVertex(x+w, y+h, texcoords.top, texcoords.right), }}; - state.texture_units[0].texture_2d = screen_info.display_texture; - state.Apply(); + state.SetActiveTextureUnit(GL_TEXTURE0); + state.SetTexture2D(screen_info.display_texture); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data()); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); - state.texture_units[0].texture_2d = 0; - state.Apply(); + state.SetTexture2D(0); } /** @@ -396,7 +383,7 @@ void RendererOpenGL::DrawScreens() { glUniformMatrix3x2fv(uniform_modelview_matrix, 1, GL_FALSE, ortho_matrix.data()); // Bind texture in Texture Unit 0 - glActiveTexture(GL_TEXTURE0); + state.SetActiveTextureUnit(GL_TEXTURE0); glUniform1i(uniform_color_texture, 0); DrawSingleScreenRotated(screen_infos[0], (float)layout.top_screen.left, (float)layout.top_screen.top,