From 4171d6e7b131c190ca26680d23d44feefbf5f18e Mon Sep 17 00:00:00 2001 From: tfarley Date: Mon, 18 May 2015 02:33:08 -0700 Subject: [PATCH] Pica reg state triggers, outmaps removed, cleanup Some state now updates when PICA registers actually change Made rast state persistent and renderer state only during swap Removed outmaps as they are only needed for hw vtx shaders Made util func for IsNotPassThroughTevStage --- src/video_core/command_processor.cpp | 2 + src/video_core/hwrasterizer_base.h | 7 +- .../renderer_opengl/gl_rasterizer.cpp | 411 ++++++++++++------ .../renderer_opengl/gl_rasterizer.h | 23 +- src/video_core/renderer_opengl/gl_shaders.h | 96 ++-- .../renderer_opengl/renderer_opengl.cpp | 3 + 6 files changed, 340 insertions(+), 202 deletions(-) diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 0081c8eb6..5c4c04408 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp @@ -358,6 +358,8 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { break; } + VideoCore::g_renderer->hw_rasterizer->NotifyPicaRegisterChanged(id); + if (g_debug_context) g_debug_context->OnEvent(DebugContext::Event::CommandProcessed, reinterpret_cast(&id)); } diff --git a/src/video_core/hwrasterizer_base.h b/src/video_core/hwrasterizer_base.h index 08e77562b..8a16db5b6 100644 --- a/src/video_core/hwrasterizer_base.h +++ b/src/video_core/hwrasterizer_base.h @@ -23,9 +23,12 @@ public: /// Draw the current batch of triangles virtual void DrawTriangles() = 0; + /// Notify rasterizer that the specified PICA register has been changed + virtual void NotifyPicaRegisterChanged(u32 id) = 0; + /// Notify rasterizer that the specified 3DS memory region will be read from after this notification - virtual void NotifyPreRead(u32 paddr, u32 size) = 0; + virtual void NotifyPreRead(PAddr addr, u32 size) = 0; /// Notify rasterizer that a 3DS memory region has been changed - virtual void NotifyFlush(u32 addr, u32 size) = 0; + virtual void NotifyFlush(PAddr addr, u32 size) = 0; }; diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 0f5102a35..fc7023c95 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -17,6 +17,17 @@ #include +static bool IsNotPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) { + return (stage.color_op != Pica::Regs::TevStageConfig::Operation::Replace || + stage.alpha_op != Pica::Regs::TevStageConfig::Operation::Replace || + stage.color_source1 != Pica::Regs::TevStageConfig::Source::Previous || + stage.alpha_source1 != Pica::Regs::TevStageConfig::Source::Previous || + stage.color_modifier1 != Pica::Regs::TevStageConfig::ColorModifier::SourceColor || + stage.alpha_modifier1 != Pica::Regs::TevStageConfig::AlphaModifier::SourceAlpha || + stage.GetColorMultiplier() != 1 || + stage.GetAlphaMultiplier() != 1); +} + RasterizerOpenGL::RasterizerOpenGL() : last_fb_color_addr(0), last_fb_depth_addr(0) { } @@ -32,6 +43,7 @@ void RasterizerOpenGL::InitObjects() { attrib_color = glGetAttribLocation(shader.GetHandle(), "vert_color"); attrib_texcoords = glGetAttribLocation(shader.GetHandle(), "vert_texcoords"); + uniform_alphatest_enabled = glGetUniformLocation(shader.GetHandle(), "alphatest_enabled"); uniform_alphatest_func = glGetUniformLocation(shader.GetHandle(), "alphatest_func"); uniform_alphatest_ref = glGetUniformLocation(shader.GetHandle(), "alphatest_ref"); @@ -54,8 +66,6 @@ void RasterizerOpenGL::InitObjects() { uniform_tev.updates_combiner_buffer_color_alpha = glGetUniformLocation(shader.GetHandle(), (tev_ref_str + ".updates_combiner_buffer_color_alpha").c_str()); } - uniform_out_maps = glGetUniformLocation(shader.GetHandle(), "out_maps"); - // Generate VBO and VAO vertex_buffer.Create(); vertex_array.Create(); @@ -132,8 +142,6 @@ void RasterizerOpenGL::AddTriangle(const Pica::VertexShader::OutputVertex& v0, } void RasterizerOpenGL::DrawTriangles() { - state.Apply(); - SyncFramebuffer(); SyncDrawState(); @@ -143,11 +151,224 @@ void RasterizerOpenGL::DrawTriangles() { vertex_batch.clear(); } -void RasterizerOpenGL::NotifyPreRead(PAddr addr, u32 size) { +void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { if (!Settings::values.use_hw_renderer) return; - state.Apply(); + switch(id) { + // Culling + case PICA_REG_INDEX(cull_mode): + { + switch (Pica::registers.cull_mode) { + case Pica::Regs::CullMode::KeepAll: + state.cull.enabled = false; + break; + + case Pica::Regs::CullMode::KeepClockWise: + state.cull.enabled = true; + state.cull.mode = GL_BACK; + break; + + case Pica::Regs::CullMode::KeepCounterClockWise: + state.cull.enabled = true; + state.cull.mode = GL_FRONT; + break; + + default: + LOG_CRITICAL(Render_OpenGL, "Unknown cull mode %d", Pica::registers.cull_mode.Value()); + UNIMPLEMENTED(); + break; + } + break; + } + + // Blending + case PICA_REG_INDEX(output_merger.alphablend_enable): + { + state.blend.enabled = Pica::registers.output_merger.alphablend_enable; + break; + } + case PICA_REG_INDEX(output_merger.alpha_blending): + { + state.blend.src_rgb_func = PicaToGL::BlendFunc(Pica::registers.output_merger.alpha_blending.factor_source_rgb); + state.blend.dst_rgb_func = PicaToGL::BlendFunc(Pica::registers.output_merger.alpha_blending.factor_dest_rgb); + state.blend.src_a_func = PicaToGL::BlendFunc(Pica::registers.output_merger.alpha_blending.factor_source_a); + state.blend.dst_a_func = PicaToGL::BlendFunc(Pica::registers.output_merger.alpha_blending.factor_dest_a); + break; + } + case PICA_REG_INDEX(output_merger.blend_const): + { + state.blend.color.red = (GLclampf)Pica::registers.output_merger.blend_const.r / 255.0f; + state.blend.color.green = (GLclampf)Pica::registers.output_merger.blend_const.g / 255.0f; + state.blend.color.blue = (GLclampf)Pica::registers.output_merger.blend_const.b / 255.0f; + state.blend.color.alpha = (GLclampf)Pica::registers.output_merger.blend_const.a / 255.0f; + break; + } + + // Alpha test + case PICA_REG_INDEX(output_merger.alpha_test): + { + glUniform1i(uniform_alphatest_enabled, Pica::registers.output_merger.alpha_test.enable); + glUniform1i(uniform_alphatest_func, Pica::registers.output_merger.alpha_test.func); + glUniform1f(uniform_alphatest_ref, Pica::registers.output_merger.alpha_test.ref / 255.0f); + break; + } + + // Stencil test + case PICA_REG_INDEX(output_merger.stencil_test): + { + // TODO: Implement stencil test, mask, and op + break; + } + + // Depth test + case PICA_REG_INDEX(output_merger.depth_test_enable): + { + state.depth.test_enabled = Pica::registers.output_merger.depth_test_enable; + state.depth.test_func = PicaToGL::CompareFunc(Pica::registers.output_merger.depth_test_func); + + if (Pica::registers.output_merger.depth_write_enable) { + state.depth.write_mask = GL_TRUE; + } else { + state.depth.write_mask = GL_FALSE; + } + + break; + } + + // TEV stage 0 + case PICA_REG_INDEX(tev_stage0.color_source1): + SyncTevSources(0, Pica::registers.tev_stage0); + break; + case PICA_REG_INDEX(tev_stage0.color_modifier1): + SyncTevModifiers(0, Pica::registers.tev_stage0); + break; + case PICA_REG_INDEX(tev_stage0.color_op): + SyncTevOps(0, Pica::registers.tev_stage0); + break; + case PICA_REG_INDEX(tev_stage0.const_r): + SyncTevColor(0, Pica::registers.tev_stage0); + break; + case PICA_REG_INDEX(tev_stage0.color_scale): + SyncTevMultipliers(0, Pica::registers.tev_stage0); + break; + + // TEV stage 1 + case PICA_REG_INDEX(tev_stage1.color_source1): + SyncTevSources(1, Pica::registers.tev_stage1); + break; + case PICA_REG_INDEX(tev_stage1.color_modifier1): + SyncTevModifiers(1, Pica::registers.tev_stage1); + break; + case PICA_REG_INDEX(tev_stage1.color_op): + SyncTevOps(1, Pica::registers.tev_stage1); + break; + case PICA_REG_INDEX(tev_stage1.const_r): + SyncTevColor(1, Pica::registers.tev_stage1); + break; + case PICA_REG_INDEX(tev_stage1.color_scale): + SyncTevMultipliers(1, Pica::registers.tev_stage1); + break; + + // TEV stage 2 + case PICA_REG_INDEX(tev_stage2.color_source1): + SyncTevSources(2, Pica::registers.tev_stage2); + break; + case PICA_REG_INDEX(tev_stage2.color_modifier1): + SyncTevModifiers(2, Pica::registers.tev_stage2); + break; + case PICA_REG_INDEX(tev_stage2.color_op): + SyncTevOps(2, Pica::registers.tev_stage2); + break; + case PICA_REG_INDEX(tev_stage2.const_r): + SyncTevColor(2, Pica::registers.tev_stage2); + break; + case PICA_REG_INDEX(tev_stage2.color_scale): + SyncTevMultipliers(2, Pica::registers.tev_stage2); + break; + + // TEV stage 3 + case PICA_REG_INDEX(tev_stage3.color_source1): + SyncTevSources(3, Pica::registers.tev_stage3); + break; + case PICA_REG_INDEX(tev_stage3.color_modifier1): + SyncTevModifiers(3, Pica::registers.tev_stage3); + break; + case PICA_REG_INDEX(tev_stage3.color_op): + SyncTevOps(3, Pica::registers.tev_stage3); + break; + case PICA_REG_INDEX(tev_stage3.const_r): + SyncTevColor(3, Pica::registers.tev_stage3); + break; + case PICA_REG_INDEX(tev_stage3.color_scale): + SyncTevMultipliers(3, Pica::registers.tev_stage3); + break; + + // TEV stage 4 + case PICA_REG_INDEX(tev_stage4.color_source1): + SyncTevSources(4, Pica::registers.tev_stage4); + break; + case PICA_REG_INDEX(tev_stage4.color_modifier1): + SyncTevModifiers(4, Pica::registers.tev_stage4); + break; + case PICA_REG_INDEX(tev_stage4.color_op): + SyncTevOps(4, Pica::registers.tev_stage4); + break; + case PICA_REG_INDEX(tev_stage4.const_r): + SyncTevColor(4, Pica::registers.tev_stage4); + break; + case PICA_REG_INDEX(tev_stage4.color_scale): + SyncTevMultipliers(4, Pica::registers.tev_stage4); + break; + + // TEV stage 5 + case PICA_REG_INDEX(tev_stage5.color_source1): + SyncTevSources(5, Pica::registers.tev_stage5); + break; + case PICA_REG_INDEX(tev_stage5.color_modifier1): + SyncTevModifiers(5, Pica::registers.tev_stage5); + break; + case PICA_REG_INDEX(tev_stage5.color_op): + SyncTevOps(5, Pica::registers.tev_stage5); + break; + case PICA_REG_INDEX(tev_stage5.const_r): + SyncTevColor(5, Pica::registers.tev_stage5); + break; + case PICA_REG_INDEX(tev_stage5.color_scale): + SyncTevMultipliers(5, Pica::registers.tev_stage5); + break; + + // TEV combiner buffer color + case PICA_REG_INDEX(tev_combiner_buffer_color): + { + GLfloat combiner_color[4] = { Pica::registers.tev_combiner_buffer_color.r / 255.0f, + Pica::registers.tev_combiner_buffer_color.g / 255.0f, + Pica::registers.tev_combiner_buffer_color.b / 255.0f, + Pica::registers.tev_combiner_buffer_color.a / 255.0f }; + + glUniform4fv(uniform_tev_combiner_buffer_color, 1, combiner_color); + break; + } + + // TEV combiner buffer write flags + case PICA_REG_INDEX(tev_combiner_buffer_input): + { + for (int tev_stage_idx = 0; tev_stage_idx < 6; ++tev_stage_idx) { + glUniform2i(uniform_tev_cfgs[tev_stage_idx].updates_combiner_buffer_color_alpha, + Pica::registers.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(tev_stage_idx), + Pica::registers.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(tev_stage_idx)); + } + break; + } + + default: + break; + } +} + +void RasterizerOpenGL::NotifyPreRead(PAddr addr, u32 size) { + if (!Settings::values.use_hw_renderer) + return; PAddr cur_fb_color_addr = Pica::registers.framebuffer.GetColorBufferPhysicalAddress(); u32 cur_fb_color_size = Pica::registers.framebuffer.BytesPerColorPixel(Pica::registers.framebuffer.color_format) @@ -177,8 +398,6 @@ void RasterizerOpenGL::NotifyFlush(PAddr addr, u32 size) { if (!Settings::values.use_hw_renderer) return; - state.Apply(); - PAddr cur_fb_color_addr = Pica::registers.framebuffer.GetColorBufferPhysicalAddress(); u32 cur_fb_color_size = Pica::registers.framebuffer.BytesPerColorPixel(Pica::registers.framebuffer.color_format) * Pica::registers.framebuffer.GetWidth() * Pica::registers.framebuffer.GetHeight(); @@ -361,6 +580,47 @@ void RasterizerOpenGL::SyncFramebuffer() { } } +void RasterizerOpenGL::SyncTevSources(int stage_index, const Pica::Regs::TevStageConfig& config) { + GLint color_srcs[3] = { (GLint)config.color_source1.Value(), + (GLint)config.color_source2.Value(), + (GLint)config.color_source3.Value() }; + GLint alpha_srcs[3] = { (GLint)config.alpha_source1.Value(), + (GLint)config.alpha_source2.Value(), + (GLint)config.alpha_source3.Value() }; + + glUniform3iv(uniform_tev_cfgs[stage_index].color_sources, 1, color_srcs); + glUniform3iv(uniform_tev_cfgs[stage_index].alpha_sources, 1, alpha_srcs); +} + +void RasterizerOpenGL::SyncTevModifiers(int stage_index, const Pica::Regs::TevStageConfig& config) { + GLint color_mods[3] = { (GLint)config.color_modifier1.Value(), + (GLint)config.color_modifier2.Value(), + (GLint)config.color_modifier3.Value() }; + GLint alpha_mods[3] = { (GLint)config.alpha_modifier1.Value(), + (GLint)config.alpha_modifier2.Value(), + (GLint)config.alpha_modifier3.Value() }; + + glUniform3iv(uniform_tev_cfgs[stage_index].color_modifiers, 1, color_mods); + glUniform3iv(uniform_tev_cfgs[stage_index].alpha_modifiers, 1, alpha_mods); +} + +void RasterizerOpenGL::SyncTevOps(int stage_index, const Pica::Regs::TevStageConfig& config) { + glUniform2i(uniform_tev_cfgs[stage_index].color_alpha_op, (GLint)config.color_op.Value(), (GLint)config.alpha_op.Value()); +} + +void RasterizerOpenGL::SyncTevColor(int stage_index, const Pica::Regs::TevStageConfig& config) { + GLfloat const_color[4] = { config.const_r / 255.0f, + config.const_g / 255.0f, + config.const_b / 255.0f, + config.const_a / 255.0f }; + + glUniform4fv(uniform_tev_cfgs[stage_index].const_color, 1, const_color); +} + +void RasterizerOpenGL::SyncTevMultipliers(int stage_index, const Pica::Regs::TevStageConfig& config) { + glUniform2i(uniform_tev_cfgs[stage_index].color_alpha_multiplier, config.GetColorMultiplier(), config.GetAlphaMultiplier()); +} + void RasterizerOpenGL::SyncDrawState() { // Sync the viewport GLsizei viewport_width = (GLsizei)Pica::float24::FromRawFloat24(Pica::registers.viewport_size_x).ToFloat32() * 2; @@ -373,63 +633,7 @@ void RasterizerOpenGL::SyncDrawState() { + Pica::registers.framebuffer.GetHeight() - viewport_height, viewport_width, viewport_height); - // Sync the cull mode - switch (Pica::registers.cull_mode) { - case Pica::Regs::CullMode::KeepAll: - state.cull.enabled = false; - break; - - case Pica::Regs::CullMode::KeepClockWise: - state.cull.enabled = true; - state.cull.mode = GL_BACK; - break; - - case Pica::Regs::CullMode::KeepCounterClockWise: - state.cull.enabled = true; - state.cull.mode = GL_FRONT; - break; - - default: - LOG_CRITICAL(Render_OpenGL, "Unknown cull mode %d", Pica::registers.cull_mode.Value()); - UNIMPLEMENTED(); - break; - } - - // Sync depth test - if (Pica::registers.output_merger.depth_test_enable) { - state.depth.test_enabled = true; - state.depth.test_func = PicaToGL::CompareFunc(Pica::registers.output_merger.depth_test_func); - } else { - state.depth.test_enabled = false; - } - - // Sync depth writing - if (Pica::registers.output_merger.depth_write_enable) { - state.depth.write_mask = GL_TRUE; - } else { - state.depth.write_mask = GL_FALSE; - } - - // TODO: Implement stencil test, mask, and op via: state.stencil.* = Pica::registers.output_merger.stencil_test.* - - // Sync blend state - if (Pica::registers.output_merger.alphablend_enable) { - state.blend.enabled = true; - - state.blend.color.red = (GLclampf)Pica::registers.output_merger.blend_const.r / 255.0f; - state.blend.color.green = (GLclampf)Pica::registers.output_merger.blend_const.g / 255.0f; - state.blend.color.blue = (GLclampf)Pica::registers.output_merger.blend_const.b / 255.0f; - state.blend.color.alpha = (GLclampf)Pica::registers.output_merger.blend_const.a / 255.0f; - - state.blend.src_rgb_func = PicaToGL::BlendFunc(Pica::registers.output_merger.alpha_blending.factor_source_rgb); - state.blend.dst_rgb_func = PicaToGL::BlendFunc(Pica::registers.output_merger.alpha_blending.factor_dest_rgb); - state.blend.src_a_func = PicaToGL::BlendFunc(Pica::registers.output_merger.alpha_blending.factor_source_a); - state.blend.dst_a_func = PicaToGL::BlendFunc(Pica::registers.output_merger.alpha_blending.factor_dest_a); - } else { - state.blend.enabled = false; - } - - // Sync bound texture(s), upload if uncached + // Sync bound texture(s), upload if not cached const auto pica_textures = Pica::registers.GetTextures(); for (int i = 0; i < 3; ++i) { @@ -443,84 +647,13 @@ void RasterizerOpenGL::SyncDrawState() { } } - state.Apply(); - - // Sync shader output register mapping to hw shader - 7 vectors with 4 components - for (int i = 0; i < 7 * 4; ++i) { - glUniform1i(uniform_out_maps + i, 0); - } - - for (int i = 0; i < 7; ++i) { - const auto& output_register_map = Pica::registers.vs_output_attributes[i]; - - u32 semantics[4] = { - output_register_map.map_x, output_register_map.map_y, - output_register_map.map_z, output_register_map.map_w - }; - - // TODO: Might only need to do this once per shader? Not sure when/if out maps are modified. - for (int comp = 0; comp < 4; ++comp) { - if (semantics[comp] != Pica::Regs::VSOutputAttributes::INVALID) { - glUniform1i(uniform_out_maps + semantics[comp], 4 * i + comp); - } - } - } - - // Sync intial combiner buffer color - GLfloat initial_combiner_color[4] = { Pica::registers.tev_combiner_buffer_color.r / 255.0f, - Pica::registers.tev_combiner_buffer_color.g / 255.0f, - Pica::registers.tev_combiner_buffer_color.b / 255.0f, - Pica::registers.tev_combiner_buffer_color.a / 255.0f }; - - glUniform4fv(uniform_tev_combiner_buffer_color, 1, initial_combiner_color); - - // Sync texture environment configurations to hw shader + // Skip processing TEV stages that simply pass the previous stage results through const auto tev_stages = Pica::registers.GetTevStages(); for (unsigned tev_stage_idx = 0; tev_stage_idx < tev_stages.size(); ++tev_stage_idx) { - const auto& stage = tev_stages[tev_stage_idx]; - const auto& uniform_tev_cfg = uniform_tev_cfgs[tev_stage_idx]; - - // No need to process the tev stage if it simply passes the previous stage results through - if (stage.color_op == Pica::Regs::TevStageConfig::Operation::Replace && - stage.alpha_op == Pica::Regs::TevStageConfig::Operation::Replace && - stage.color_source1 == Pica::Regs::TevStageConfig::Source::Previous && - stage.alpha_source1 == Pica::Regs::TevStageConfig::Source::Previous && - stage.color_modifier1 == Pica::Regs::TevStageConfig::ColorModifier::SourceColor && - stage.alpha_modifier1 == Pica::Regs::TevStageConfig::AlphaModifier::SourceAlpha && - stage.GetColorMultiplier() == 1 && - stage.GetAlphaMultiplier() == 1) { - glUniform1i(uniform_tev_cfg.enabled, 0); - } else { - GLint color_srcs[3] = { (GLint)stage.color_source1.Value(), (GLint)stage.color_source2.Value(), (GLint)stage.color_source3.Value() }; - GLint alpha_srcs[3] = { (GLint)stage.alpha_source1.Value(), (GLint)stage.alpha_source2.Value(), (GLint)stage.alpha_source3.Value() }; - GLint color_mods[3] = { (GLint)stage.color_modifier1.Value(), (GLint)stage.color_modifier2.Value(), (GLint)stage.color_modifier3.Value() }; - GLint alpha_mods[3] = { (GLint)stage.alpha_modifier1.Value(), (GLint)stage.alpha_modifier2.Value(), (GLint)stage.alpha_modifier3.Value() }; - GLfloat const_color[4] = { stage.const_r / 255.0f, - stage.const_g / 255.0f, - stage.const_b / 255.0f, - stage.const_a / 255.0f }; - - glUniform1i(uniform_tev_cfg.enabled, 1); - glUniform3iv(uniform_tev_cfg.color_sources, 1, color_srcs); - glUniform3iv(uniform_tev_cfg.alpha_sources, 1, alpha_srcs); - glUniform3iv(uniform_tev_cfg.color_modifiers, 1, color_mods); - glUniform3iv(uniform_tev_cfg.alpha_modifiers, 1, alpha_mods); - glUniform2i(uniform_tev_cfg.color_alpha_op, (GLint)stage.color_op.Value(), (GLint)stage.alpha_op.Value()); - glUniform2i(uniform_tev_cfg.color_alpha_multiplier, stage.GetColorMultiplier(), stage.GetAlphaMultiplier()); - glUniform4fv(uniform_tev_cfg.const_color, 1, const_color); - glUniform2i(uniform_tev_cfg.updates_combiner_buffer_color_alpha, - Pica::registers.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(tev_stage_idx), - Pica::registers.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(tev_stage_idx)); - } + glUniform1i(uniform_tev_cfgs[tev_stage_idx].enabled, IsNotPassThroughTevStage(tev_stages[tev_stage_idx])); } - // Sync alpha testing to hw shader - if (Pica::registers.output_merger.alpha_test.enable) { - glUniform1i(uniform_alphatest_func, Pica::registers.output_merger.alpha_test.func); - glUniform1f(uniform_alphatest_ref, Pica::registers.output_merger.alpha_test.ref / 255.0f); - } else { - glUniform1i(uniform_alphatest_func, Pica::registers.output_merger.Always); - } + state.Apply(); } void RasterizerOpenGL::ReloadColorBuffer() { diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 4cf8dc0fc..60cc1f265 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -26,6 +26,9 @@ public: /// Draw the current batch of triangles void DrawTriangles() override; + /// Notify rasterizer that the specified PICA register has been changed + void NotifyPicaRegisterChanged(u32 id) override; + /// Notify rasterizer that the specified 3DS memory region will be read from after this notification void NotifyPreRead(PAddr addr, u32 size) override; @@ -101,7 +104,22 @@ private: /// Syncs the state and contents of the OpenGL framebuffer to match the current PICA framebuffer void SyncFramebuffer(); - /// Syncs the OpenGL drawing state to match the current PICA state + /// Syncs the specified TEV stage's color and alpha sources to match the PICA register + void SyncTevSources(int stage_index, const Pica::Regs::TevStageConfig& config); + + /// Syncs the specified TEV stage's color and alpha modifiers to match the PICA register + void SyncTevModifiers(int stage_index, const Pica::Regs::TevStageConfig& config); + + /// Syncs the specified TEV stage's color and alpha combiner operations to match the PICA register + void SyncTevOps(int stage_index, const Pica::Regs::TevStageConfig& config); + + /// Syncs the specified TEV stage's constant color to match the PICA register + void SyncTevColor(int stage_index, const Pica::Regs::TevStageConfig& config); + + /// Syncs the specified TEV stage's color and alpha multipliers to match the PICA register + void SyncTevMultipliers(int stage_index, const Pica::Regs::TevStageConfig& config); + + /// Syncs the remaining OpenGL drawing state to match the current PICA state void SyncDrawState(); /// Copies the 3ds color framebuffer into the OpenGL color framebuffer texture @@ -147,11 +165,10 @@ private: GLuint attrib_texcoords; // Hardware fragment shader + GLuint uniform_alphatest_enabled; GLuint uniform_alphatest_func; GLuint uniform_alphatest_ref; GLuint uniform_tex; GLuint uniform_tev_combiner_buffer_color; TEVConfigUniforms uniform_tev_cfgs[6]; - GLuint uniform_out_maps; - GLuint uniform_tex_envs; }; diff --git a/src/video_core/renderer_opengl/gl_shaders.h b/src/video_core/renderer_opengl/gl_shaders.h index 3527f8601..8f0941230 100644 --- a/src/video_core/renderer_opengl/gl_shaders.h +++ b/src/video_core/renderer_opengl/gl_shaders.h @@ -53,25 +53,10 @@ in vec2 vert_texcoords[3]; out vec4 o[NUM_VTX_ATTR]; -uniform int out_maps[NUM_VTX_ATTR * 4]; - -void SetVal(int map_idx, float val) { - o[out_maps[map_idx] / 4][out_maps[map_idx] % 4] = val; -} - void main() { - SetVal(8, vert_color.x); - SetVal(9, vert_color.y); - SetVal(10, vert_color.z); - SetVal(11, vert_color.w); - SetVal(12, vert_texcoords[0].x); - SetVal(13, vert_texcoords[0].y); - - // TODO: These seem like the wrong map indices - SetVal(14, vert_texcoords[1].x); - SetVal(15, vert_texcoords[1].y); - SetVal(16, vert_texcoords[2].x); - SetVal(17, vert_texcoords[2].y); + o[2] = vert_color; + o[3] = vec4(vert_texcoords[0].xy, vert_texcoords[1].xy); + o[5] = vec4(0.0, 0.0, vert_texcoords[2].xy); gl_Position = vec4(vert_position.x, -vert_position.y, -vert_position.z, vert_position.w); } @@ -81,8 +66,8 @@ void main() { const char g_fragment_shader_hw[] = R"( #version 150 core -#define NUM_TEV_STAGES 6 #define NUM_VTX_ATTR 7 +#define NUM_TEV_STAGES 6 #define SOURCE_PRIMARYCOLOR 0x0 #define SOURCE_PRIMARYFRAGMENTCOLOR 0x1 @@ -135,6 +120,7 @@ const char g_fragment_shader_hw[] = R"( in vec4 o[NUM_VTX_ATTR]; out vec4 color; +uniform bool alphatest_enabled; uniform int alphatest_func; uniform float alphatest_ref; @@ -157,31 +143,23 @@ struct TEVConfig uniform TEVConfig tev_cfgs[NUM_TEV_STAGES]; -uniform int out_maps[NUM_VTX_ATTR * 4]; - vec4 g_combiner_buffer; vec4 g_last_tex_env_out; vec4 g_const_color; -float GetVal(int map_idx) { - return o[out_maps[map_idx] / 4][out_maps[map_idx] % 4]; -} - vec4 GetSource(int source) { if (source == SOURCE_PRIMARYCOLOR) { - // HACK: Should use values 8/9/10/11 but hurts framerate - // Hack assumes 9/10/11 follow directly after 8's map - return o[out_maps[8] >> 2]; + return o[2]; } else if (source == SOURCE_PRIMARYFRAGMENTCOLOR) { // HACK: Uses color value, but should really use fragment lighting output - return o[out_maps[8] >> 2]; + return o[2]; } else if (source == SOURCE_TEXTURE0) { - return texture(tex[0], vec2(GetVal(12), GetVal(13))); + return texture(tex[0], o[3].xy); } else if (source == SOURCE_TEXTURE1) { - return texture(tex[1], vec2(GetVal(14), GetVal(15))); + return texture(tex[1], o[3].zw); } else if (source == SOURCE_TEXTURE2) { // TODO: Unverified - return texture(tex[2], vec2(GetVal(16), GetVal(17))); + return texture(tex[2], o[5].zw); } else if (source == SOURCE_TEXTURE3) { // TODO: no 4th texture? } else if (source == SOURCE_PREVIOUSBUFFER) { @@ -316,33 +294,35 @@ void main(void) { } } - if (alphatest_func == COMPAREFUNC_NEVER) { - discard; - } else if (alphatest_func == COMPAREFUNC_ALWAYS) { + if (alphatest_enabled) { + if (alphatest_func == COMPAREFUNC_NEVER) { + discard; + } else if (alphatest_func == COMPAREFUNC_ALWAYS) { - } else if (alphatest_func == COMPAREFUNC_EQUAL) { - if (g_last_tex_env_out.a != alphatest_ref) { - discard; - } - } else if (alphatest_func == COMPAREFUNC_NOTEQUAL) { - if (g_last_tex_env_out.a == alphatest_ref) { - discard; - } - } else if (alphatest_func == COMPAREFUNC_LESSTHAN) { - if (g_last_tex_env_out.a >= alphatest_ref) { - discard; - } - } else if (alphatest_func == COMPAREFUNC_LESSTHANOREQUAL) { - if (g_last_tex_env_out.a > alphatest_ref) { - discard; - } - } else if (alphatest_func == COMPAREFUNC_GREATERTHAN) { - if (g_last_tex_env_out.a <= alphatest_ref) { - discard; - } - } else if (alphatest_func == COMPAREFUNC_GREATERTHANOREQUAL) { - if (g_last_tex_env_out.a < alphatest_ref) { - discard; + } else if (alphatest_func == COMPAREFUNC_EQUAL) { + if (g_last_tex_env_out.a != alphatest_ref) { + discard; + } + } else if (alphatest_func == COMPAREFUNC_NOTEQUAL) { + if (g_last_tex_env_out.a == alphatest_ref) { + discard; + } + } else if (alphatest_func == COMPAREFUNC_LESSTHAN) { + if (g_last_tex_env_out.a >= alphatest_ref) { + discard; + } + } else if (alphatest_func == COMPAREFUNC_LESSTHANOREQUAL) { + if (g_last_tex_env_out.a > alphatest_ref) { + discard; + } + } else if (alphatest_func == COMPAREFUNC_GREATERTHAN) { + if (g_last_tex_env_out.a <= alphatest_ref) { + discard; + } + } else if (alphatest_func == COMPAREFUNC_GREATERTHANOREQUAL) { + if (g_last_tex_env_out.a < alphatest_ref) { + discard; + } } } diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 8b48f80d9..1258e81cf 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -67,6 +67,7 @@ RendererOpenGL::~RendererOpenGL() { void RendererOpenGL::SwapBuffers() { render_window->MakeCurrent(); + OpenGLState prev_state = OpenGLState::GetCurState(); state.Apply(); for(int i : {0, 1}) { @@ -114,6 +115,8 @@ void RendererOpenGL::SwapBuffers() { render_window->PollEvents(); render_window->SwapBuffers(); + prev_state.Apply(); + profiler.BeginFrame(); }