diff --git a/src/video_core/hwrasterizer_base.h b/src/video_core/hwrasterizer_base.h index 2178b70fd..7bc0b8b8d 100644 --- a/src/video_core/hwrasterizer_base.h +++ b/src/video_core/hwrasterizer_base.h @@ -26,9 +26,9 @@ public: /// Draw the current batch of triangles virtual void DrawTriangles() = 0; - /// Notify rasterizer that a copy within 3ds memory will occur after this notification + /// Notify rasterizer that a copy within 3DS memory will occur after this notification virtual void NotifyPreCopy(u32 src_paddr, u32 size) = 0; - /// Notify rasterizer that a 3ds memory region has been changed + /// Notify rasterizer that a 3DS memory region has been changed virtual void NotifyFlush(u32 paddr, u32 size) = 0; }; diff --git a/src/video_core/renderer_opengl/gl_pica_to_gl.h b/src/video_core/renderer_opengl/gl_pica_to_gl.h index 9512b8571..70dd32afb 100644 --- a/src/video_core/renderer_opengl/gl_pica_to_gl.h +++ b/src/video_core/renderer_opengl/gl_pica_to_gl.h @@ -21,7 +21,8 @@ static GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) { case Pica::Regs::TextureConfig::WrapMode::MirroredRepeat: return GL_MIRRORED_REPEAT; default: - LOG_ERROR(Render_OpenGL, "Unknown texture wrap mode %d", mode); + LOG_CRITICAL(Render_OpenGL, "Unknown texture wrap mode %d", mode); + UNIMPLEMENTED(); return GL_CLAMP_TO_EDGE; } } @@ -59,7 +60,8 @@ static GLenum BlendFunc(u32 factor) { case Pica::registers.output_merger.alpha_blending.SourceAlphaSaturate: return GL_SRC_ALPHA_SATURATE; default: - LOG_ERROR(Render_OpenGL, "Unknown blend factor %d", factor); + LOG_CRITICAL(Render_OpenGL, "Unknown blend factor %d", factor); + UNIMPLEMENTED(); return GL_ONE; } } @@ -83,7 +85,8 @@ static GLenum CompareFunc(u32 func) { case Pica::registers.output_merger.GreaterThanOrEqual: return GL_GEQUAL; default: - LOG_ERROR(Render_OpenGL, "Unknown compare function %d", func); + LOG_CRITICAL(Render_OpenGL, "Unknown compare function %d", func); + UNIMPLEMENTED(); return GL_ALWAYS; } } diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 9100e63ed..3b25b530f 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -28,6 +28,7 @@ u32 ColorFormatBytesPerPixel(u32 format) { case Pica::registers.framebuffer.RGBA4: return 2; default: + LOG_CRITICAL(Render_OpenGL, "Unknown framebuffer color format %x", format); UNIMPLEMENTED(); break; } @@ -35,7 +36,7 @@ u32 ColorFormatBytesPerPixel(u32 format) { return 0; } -RasterizerOpenGL::RasterizerOpenGL() : last_fb_color_addr(-1), last_fb_depth_addr(-1) { +RasterizerOpenGL::RasterizerOpenGL() : last_fb_color_addr(0), last_fb_depth_addr(0) { } @@ -44,7 +45,6 @@ RasterizerOpenGL::~RasterizerOpenGL() { render_window->MakeCurrent(); } -/// Initialize API-specific GPU objects void RasterizerOpenGL::InitObjects() { // Create the hardware shader program and get attrib/uniform locations shader.Create(GLShaders::g_vertex_shader_hw, GLShaders::g_fragment_shader_hw); @@ -57,7 +57,7 @@ void RasterizerOpenGL::InitObjects() { uniform_tex = glGetUniformLocation(shader.GetHandle(), "tex"); - for (int i = 0; i < 6; i++) { + for (int i = 0; i < 6; ++i) { auto& uniform_tev = uniform_tev_cfgs[i]; std::string tev_ref_str = "tev_cfgs[" + std::to_string(i) + "]"; @@ -82,8 +82,8 @@ void RasterizerOpenGL::InitObjects() { state.draw.vertex_buffer = vertex_buffer.GetHandle(); state.draw.shader_program = shader.GetHandle(); - for (int i = 0; i < 3; i++) { - state.texture_unit[i].enabled_2d = true; + for (auto& texture_unit : state.texture_units) { + texture_unit.enabled_2d = true; } state.Apply(); @@ -128,8 +128,8 @@ void RasterizerOpenGL::InitObjects() { framebuffer.Create(); state.draw.framebuffer = framebuffer.GetHandle(); - state.texture_unit[0].enabled_2d = true; - state.texture_unit[0].texture_2d = 0; + state.texture_units[0].enabled_2d = true; + state.texture_units[0].texture_2d = 0; state.Apply(); glActiveTexture(GL_TEXTURE0); @@ -137,16 +137,14 @@ void RasterizerOpenGL::InitObjects() { glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, fb_depth_texture.texture.GetHandle(), 0); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - LOG_ERROR(Render_OpenGL, "Framebuffer setup failed, status %X", glCheckFramebufferStatus(GL_FRAMEBUFFER)); + LOG_CRITICAL(Render_OpenGL, "Framebuffer setup failed, status %X", glCheckFramebufferStatus(GL_FRAMEBUFFER)); } } -/// Set the window (context) to draw with void RasterizerOpenGL::SetWindow(EmuWindow* window) { render_window = window; } -/// Converts the triangle verts to hardware data format and adds them to the current batch void RasterizerOpenGL::AddTriangle(const Pica::VertexShader::OutputVertex& v0, const Pica::VertexShader::OutputVertex& v1, const Pica::VertexShader::OutputVertex& v2) { @@ -155,7 +153,6 @@ void RasterizerOpenGL::AddTriangle(const Pica::VertexShader::OutputVertex& v0, vertex_batch.push_back(HardwareVertex(v2)); } -/// Draw the current batch of triangles void RasterizerOpenGL::DrawTriangles() { render_window->MakeCurrent(); @@ -170,70 +167,67 @@ void RasterizerOpenGL::DrawTriangles() { vertex_batch.clear(); } -/// Notify rasterizer that a copy within 3ds memory will occur after this notification -void RasterizerOpenGL::NotifyPreCopy(u32 src_paddr, u32 size) { +void RasterizerOpenGL::NotifyPreCopy(PAddr src_addr, u32 size) { render_window->MakeCurrent(); state.Apply(); - u32 cur_fb_color_addr = Pica::registers.framebuffer.GetColorBufferPhysicalAddress(); - u32 cur_fb_color_size = ColorFormatBytesPerPixel(Pica::registers.framebuffer.color_format.Value()) + PAddr cur_fb_color_addr = Pica::registers.framebuffer.GetColorBufferPhysicalAddress(); + u32 cur_fb_color_size = ColorFormatBytesPerPixel(Pica::registers.framebuffer.color_format) * Pica::registers.framebuffer.GetWidth() * Pica::registers.framebuffer.GetHeight(); - u32 cur_fb_depth_addr = Pica::registers.framebuffer.GetDepthBufferPhysicalAddress(); + PAddr cur_fb_depth_addr = Pica::registers.framebuffer.GetDepthBufferPhysicalAddress(); u32 cur_fb_depth_size = Pica::Regs::BytesPerDepthPixel(Pica::registers.framebuffer.depth_format) * Pica::registers.framebuffer.GetWidth() * Pica::registers.framebuffer.GetHeight(); - // If source memory region overlaps 3ds framebuffers, commit them before the copy happens - u32 max_lower = std::max(src_paddr, cur_fb_color_addr); - u32 min_upper = std::min(src_paddr + size, cur_fb_color_addr + cur_fb_color_size); + // If source memory region overlaps 3DS framebuffers, commit them before the copy happens + PAddr max_low_addr_bound = std::max(src_addr, cur_fb_color_addr); + PAddr min_hi_addr_bound = std::min(src_addr + size, cur_fb_color_addr + cur_fb_color_size); - if (max_lower <= min_upper) { + if (max_low_addr_bound <= min_hi_addr_bound) { CommitFramebuffer(); } - max_lower = std::max(src_paddr, cur_fb_depth_addr); - min_upper = std::min(src_paddr + size, cur_fb_depth_addr + cur_fb_depth_size); + max_low_addr_bound = std::max(src_addr, cur_fb_depth_addr); + min_hi_addr_bound = std::min(src_addr + size, cur_fb_depth_addr + cur_fb_depth_size); - if (max_lower <= min_upper) { + if (max_low_addr_bound <= min_hi_addr_bound) { CommitFramebuffer(); } } -/// Notify rasterizer that a 3ds memory region has been changed -void RasterizerOpenGL::NotifyFlush(u32 paddr, u32 size) { +void RasterizerOpenGL::NotifyFlush(PAddr addr, u32 size) { render_window->MakeCurrent(); state.Apply(); - u32 cur_fb_color_addr = Pica::registers.framebuffer.GetColorBufferPhysicalAddress(); - u32 cur_fb_color_size = ColorFormatBytesPerPixel(Pica::registers.framebuffer.color_format.Value()) + PAddr cur_fb_color_addr = Pica::registers.framebuffer.GetColorBufferPhysicalAddress(); + u32 cur_fb_color_size = ColorFormatBytesPerPixel(Pica::registers.framebuffer.color_format) * Pica::registers.framebuffer.GetWidth() * Pica::registers.framebuffer.GetHeight(); - u32 cur_fb_depth_addr = Pica::registers.framebuffer.GetDepthBufferPhysicalAddress(); + PAddr cur_fb_depth_addr = Pica::registers.framebuffer.GetDepthBufferPhysicalAddress(); u32 cur_fb_depth_size = Pica::Regs::BytesPerDepthPixel(Pica::registers.framebuffer.depth_format) * Pica::registers.framebuffer.GetWidth() * Pica::registers.framebuffer.GetHeight(); - // If modified memory region overlaps 3ds framebuffers, reload their contents into OpenGL - u32 max_lower = std::max(paddr, cur_fb_color_addr); - u32 min_upper = std::min(paddr + size, cur_fb_color_addr + cur_fb_color_size); + // If modified memory region overlaps 3DS framebuffers, reload their contents into OpenGL + PAddr max_low_addr_bound = std::max(addr, cur_fb_color_addr); + PAddr min_hi_addr_bound = std::min(addr + size, cur_fb_color_addr + cur_fb_color_size); - if (max_lower <= min_upper) { + if (max_low_addr_bound <= min_hi_addr_bound) { ReloadColorBuffer(); } - max_lower = std::max(paddr, cur_fb_depth_addr); - min_upper = std::min(paddr + size, cur_fb_depth_addr + cur_fb_depth_size); + max_low_addr_bound = std::max(addr, cur_fb_depth_addr); + min_hi_addr_bound = std::min(addr + size, cur_fb_depth_addr + cur_fb_depth_size); - if (max_lower <= min_upper) { + if (max_low_addr_bound <= min_hi_addr_bound) { ReloadDepthBuffer(); } // Notify cache of flush in case the region touches a cached resource - res_cache.NotifyFlush(paddr, size); + res_cache.NotifyFlush(addr, size); } -/// Reconfigure the OpenGL color texture to use the given format and dimensions void RasterizerOpenGL::ReconfigColorTexture(TextureInfo& texture, u32 format, u32 width, u32 height) { GLint internal_format; @@ -277,12 +271,13 @@ void RasterizerOpenGL::ReconfigColorTexture(TextureInfo& texture, u32 format, u3 break; default: + LOG_CRITICAL(Render_OpenGL, "Unknown framebuffer texture color format %x", format); UNIMPLEMENTED(); break; } - state.texture_unit[0].enabled_2d = true; - state.texture_unit[0].texture_2d = texture.texture.GetHandle(); + state.texture_units[0].enabled_2d = true; + state.texture_units[0].texture_2d = texture.texture.GetHandle(); state.Apply(); glActiveTexture(GL_TEXTURE0); @@ -290,7 +285,6 @@ void RasterizerOpenGL::ReconfigColorTexture(TextureInfo& texture, u32 format, u3 texture.gl_format, texture.gl_type, nullptr); } -/// Reconfigure the OpenGL depth texture to use the given format and dimensions void RasterizerOpenGL::ReconfigDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height) { GLint internal_format; @@ -318,12 +312,13 @@ void RasterizerOpenGL::ReconfigDepthTexture(DepthTextureInfo& texture, Pica::Reg break; default: + LOG_CRITICAL(Render_OpenGL, "Unknown framebuffer texture depth format %x", format); UNIMPLEMENTED(); break; } - state.texture_unit[0].enabled_2d = true; - state.texture_unit[0].texture_2d = texture.texture.GetHandle(); + state.texture_units[0].enabled_2d = true; + state.texture_units[0].texture_2d = texture.texture.GetHandle(); state.Apply(); glActiveTexture(GL_TEXTURE0); @@ -331,12 +326,11 @@ void RasterizerOpenGL::ReconfigDepthTexture(DepthTextureInfo& texture, Pica::Reg texture.gl_format, texture.gl_type, nullptr); } -/// Syncs the state and contents of the OpenGL framebuffer to match the current PICA framebuffer void RasterizerOpenGL::SyncFramebuffer() { - u32 cur_fb_color_addr = Pica::registers.framebuffer.GetColorBufferPhysicalAddress(); - u32 new_fb_color_format = Pica::registers.framebuffer.color_format.Value(); + PAddr cur_fb_color_addr = Pica::registers.framebuffer.GetColorBufferPhysicalAddress(); + u32 new_fb_color_format = Pica::registers.framebuffer.color_format; - u32 cur_fb_depth_addr = Pica::registers.framebuffer.GetDepthBufferPhysicalAddress(); + PAddr cur_fb_depth_addr = Pica::registers.framebuffer.GetDepthBufferPhysicalAddress(); Pica::Regs::DepthFormat new_fb_depth_format = Pica::registers.framebuffer.depth_format; bool fb_prop_changed = (fb_color_texture.format != new_fb_color_format || @@ -372,6 +366,7 @@ void RasterizerOpenGL::SyncFramebuffer() { break; default: + LOG_CRITICAL(Render_OpenGL, "Unknown framebuffer depth format %x", new_fb_depth_format); UNIMPLEMENTED(); break; } @@ -391,21 +386,20 @@ void RasterizerOpenGL::SyncFramebuffer() { } } -/// Syncs the OpenGL drawing state to match the current PICA state void RasterizerOpenGL::SyncDrawState() { // Sync the viewport - GLsizei viewportWidth = (GLsizei)Pica::float24::FromRawFloat24(Pica::registers.viewport_size_x.Value()).ToFloat32() * 2; - GLsizei viewportHeight = (GLsizei)Pica::float24::FromRawFloat24(Pica::registers.viewport_size_y.Value()).ToFloat32() * 2; + GLsizei viewport_width = (GLsizei)Pica::float24::FromRawFloat24(Pica::registers.viewport_size_x).ToFloat32() * 2; + GLsizei viewport_height = (GLsizei)Pica::float24::FromRawFloat24(Pica::registers.viewport_size_y).ToFloat32() * 2; // OpenGL uses different y coordinates, so negate corner offset and flip origin // TODO: Ensure viewport_corner.x should not be negated or origin flipped - glViewport((GLsizei)static_cast(Pica::registers.viewport_corner.x.Value()), - -(GLsizei)static_cast(Pica::registers.viewport_corner.y.Value()) - + Pica::registers.framebuffer.GetHeight() - viewportHeight, - viewportWidth, viewportHeight); + glViewport((GLsizei)static_cast(Pica::registers.viewport_corner.x), + -(GLsizei)static_cast(Pica::registers.viewport_corner.y) + + Pica::registers.framebuffer.GetHeight() - viewport_height, + viewport_width, viewport_height); // Sync the cull mode - switch (Pica::registers.cull_mode.Value()) { + switch (Pica::registers.cull_mode) { case Pica::Regs::CullMode::KeepAll: state.cull.enabled = false; break; @@ -421,88 +415,72 @@ void RasterizerOpenGL::SyncDrawState() { break; default: - LOG_ERROR(Render_OpenGL, "Unknown cull mode %d", Pica::registers.cull_mode.Value()); + 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.Value()) { + 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.Value()); + 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.Value()) { + if (Pica::registers.output_merger.depth_write_enable) { state.depth.write_mask = GL_TRUE; } else { state.depth.write_mask = GL_FALSE; } - // Stencil functionality commented out until a good test case and verified info crop up - - // Sync stencil test - // TODO: Untested, make sure stencil_reference_value refers to this mask - //if (Pica::registers.output_merger.stencil_test.stencil_test_enable.Value()) { - // state.stencil.test_enabled = true; - // state.stencil.test_func = PicaToGL::CompareFunc(Pica::registers.output_merger.stencil_test.stencil_test_func.Value()); - // state.stencil.test_ref = Pica::registers.output_merger.stencil_test.stencil_reference_value.Value(); - // state.stencil.test_mask = Pica::registers.output_merger.stencil_test.stencil_replacement_value.Value(); - //} else { - // state.stencil.test_enabled = false; - //} - - // Sync stencil writing - // TODO: Untested, make sure stencil_mask refers to this mask - //state.stencil.write_mask = Pica::registers.output_merger.stencil_test.stencil_mask.Value(); - - // TODO: Need to sync glStencilOp() once corresponding PICA registers are discovered + // 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.Value()) { + if (Pica::registers.output_merger.alphablend_enable) { state.blend.enabled = true; - state.blend.color.red = (GLclampf)Pica::registers.output_merger.blend_const.r.Value() / 255.0f; - state.blend.color.green = (GLclampf)Pica::registers.output_merger.blend_const.g.Value() / 255.0f; - state.blend.color.blue = (GLclampf)Pica::registers.output_merger.blend_const.b.Value() / 255.0f; - state.blend.color.alpha = (GLclampf)Pica::registers.output_merger.blend_const.a.Value() / 255.0f; + 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.Value()); - state.blend.dst_rgb_func = PicaToGL::BlendFunc(Pica::registers.output_merger.alpha_blending.factor_dest_rgb.Value()); - state.blend.src_a_func = PicaToGL::BlendFunc(Pica::registers.output_merger.alpha_blending.factor_source_a.Value()); - state.blend.dst_a_func = PicaToGL::BlendFunc(Pica::registers.output_merger.alpha_blending.factor_dest_a.Value()); + 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 - auto pica_textures = Pica::registers.GetTextures(); + const auto pica_textures = Pica::registers.GetTextures(); for (int i = 0; i < 3; ++i) { const auto& texture = pica_textures[i]; if (texture.enabled) { - state.texture_unit[i].enabled_2d = true; + state.texture_units[i].enabled_2d = true; res_cache.LoadAndBindTexture(state, i, texture); } else { - state.texture_unit[i].enabled_2d = false; + state.texture_units[i].enabled_2d = false; } } state.Apply(); - // Sync shader output register mapping to hw shader + // 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 < 6; ++i) { + 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.Value(), output_register_map.map_y.Value(), - output_register_map.map_z.Value(), output_register_map.map_w.Value() + 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. @@ -514,19 +492,19 @@ void RasterizerOpenGL::SyncDrawState() { } // Sync texture environment configurations to hw shader - auto tev_stages = Pica::registers.GetTevStages(); - for (int i = 0; i < 6; i++) { - const auto& stage = tev_stages[i]; - const auto& uniform_tev_cfg = uniform_tev_cfgs[i]; + 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]; 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.Value() / 255.0f, - stage.const_g.Value() / 255.0f, - stage.const_b.Value() / 255.0f, - stage.const_a.Value() / 255.0f }; + GLfloat const_color[4] = { stage.const_r / 255.0f, + stage.const_g / 255.0f, + stage.const_b / 255.0f, + stage.const_a / 255.0f }; glUniform3iv(uniform_tev_cfg.color_sources, 1, color_srcs); glUniform3iv(uniform_tev_cfg.alpha_sources, 1, alpha_srcs); @@ -536,52 +514,51 @@ void RasterizerOpenGL::SyncDrawState() { glUniform2f(uniform_tev_cfg.color_alpha_multiplier, (GLfloat)stage.GetColorMultiplier(), (GLfloat)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(i), - Pica::registers.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(i)); + Pica::registers.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferColor(tev_stage_idx), + Pica::registers.tev_combiner_buffer_input.TevStageUpdatesCombinerBufferAlpha(tev_stage_idx)); } // Sync alpha testing to hw shader - if (Pica::registers.output_merger.alpha_test.enable.Value()) { - glUniform1i(uniform_alphatest_func, Pica::registers.output_merger.alpha_test.func.Value()); - glUniform1f(uniform_alphatest_ref, Pica::registers.output_merger.alpha_test.ref.Value() / 255.0f); + 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, 1); + glUniform1i(uniform_alphatest_func, Pica::registers.output_merger.Always); } } -/// Copies the 3ds color framebuffer into the OpenGL color framebuffer texture void RasterizerOpenGL::ReloadColorBuffer() { u8* color_buffer = Memory::GetPhysicalPointer(last_fb_color_addr); - if (color_buffer == nullptr) { + if (color_buffer == nullptr) return; - } u32 bytes_per_pixel = ColorFormatBytesPerPixel(fb_color_texture.format); - std::unique_ptr ogl_img(new u8[fb_color_texture.width * fb_color_texture.height * bytes_per_pixel]); + std::unique_ptr temp_fb_color_buffer(new u8[fb_color_texture.width * fb_color_texture.height * bytes_per_pixel]); + // Directly copy pixels. Internal OpenGL color formats are consistent so no conversion is necessary. // TODO: Evaluate whether u16/memcpy/u32 is faster for 2/3/4 bpp versus memcpy for all - for (int x = 0; x < fb_color_texture.width; ++x) { - for (int y = 0; y < fb_color_texture.height; ++y) { + for (int y = 0; y < fb_color_texture.height; ++y) { + for (int x = 0; x < fb_color_texture.width; ++x) { const u32 coarse_y = y & ~7; u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_color_texture.width * bytes_per_pixel; - u32 ogl_px_idx = x * bytes_per_pixel + y * fb_color_texture.width * bytes_per_pixel; + u32 gl_px_idx = x * bytes_per_pixel + y * fb_color_texture.width * bytes_per_pixel; u8* pixel = color_buffer + dst_offset; - memcpy(&ogl_img.get()[ogl_px_idx], pixel, bytes_per_pixel); + memcpy(&temp_fb_color_buffer[gl_px_idx], pixel, bytes_per_pixel); } } - state.texture_unit[0].enabled_2d = true; - state.texture_unit[0].texture_2d = fb_color_texture.texture.GetHandle(); + state.texture_units[0].enabled_2d = true; + state.texture_units[0].texture_2d = fb_color_texture.texture.GetHandle(); state.Apply(); glActiveTexture(GL_TEXTURE0); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fb_color_texture.width, fb_color_texture.height, fb_color_texture.gl_format, fb_color_texture.gl_type, ogl_img.get()); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fb_color_texture.width, fb_color_texture.height, + fb_color_texture.gl_format, fb_color_texture.gl_type, temp_fb_color_buffer.get()); } -/// Copies the 3ds depth framebuffer into the OpenGL depth framebuffer texture void RasterizerOpenGL::ReloadDepthBuffer() { // TODO: Appears to work, but double-check endianness of depth values and order of depth-stencil u8* depth_buffer = Memory::GetPhysicalPointer(last_fb_depth_addr); @@ -593,27 +570,27 @@ void RasterizerOpenGL::ReloadDepthBuffer() { u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(fb_depth_texture.format); // OpenGL needs 4 bpp alignment for D24 - u32 ogl_bpp = bytes_per_pixel == 3 ? 4 : bytes_per_pixel; + u32 gl_bpp = bytes_per_pixel == 3 ? 4 : bytes_per_pixel; - std::unique_ptr ogl_img(new u8[fb_depth_texture.width * fb_depth_texture.height * ogl_bpp]); + std::unique_ptr temp_fb_depth_buffer(new u8[fb_depth_texture.width * fb_depth_texture.height * gl_bpp]); - for (int x = 0; x < fb_depth_texture.width; ++x) { - for (int y = 0; y < fb_depth_texture.height; ++y) { + for (int y = 0; y < fb_depth_texture.height; ++y) { + for (int x = 0; x < fb_depth_texture.width; ++x) { const u32 coarse_y = y & ~7; u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel; - u32 ogl_px_idx = x + y * fb_depth_texture.width; + u32 gl_px_idx = x + y * fb_depth_texture.width; switch (fb_depth_texture.format) { case Pica::Regs::DepthFormat::D16: - ((u16*)ogl_img.get())[ogl_px_idx] = Color::DecodeD16(depth_buffer + dst_offset); + ((u16*)temp_fb_depth_buffer.get())[gl_px_idx] = Color::DecodeD16(depth_buffer + dst_offset); break; case Pica::Regs::DepthFormat::D24: - ((u32*)ogl_img.get())[ogl_px_idx] = Color::DecodeD24(depth_buffer + dst_offset); + ((u32*)temp_fb_depth_buffer.get())[gl_px_idx] = Color::DecodeD24(depth_buffer + dst_offset); break; case Pica::Regs::DepthFormat::D24S8: { Math::Vec2 depth_stencil = Color::DecodeD24S8(depth_buffer + dst_offset); - ((u32*)ogl_img.get())[ogl_px_idx] = depth_stencil.x << 8 | depth_stencil.y; + ((u32*)temp_fb_depth_buffer.get())[gl_px_idx] = (depth_stencil.x << 8) | depth_stencil.y; break; } default: @@ -624,49 +601,47 @@ void RasterizerOpenGL::ReloadDepthBuffer() { } } - state.texture_unit[0].enabled_2d = true; - state.texture_unit[0].texture_2d = fb_depth_texture.texture.GetHandle(); + state.texture_units[0].enabled_2d = true; + state.texture_units[0].texture_2d = fb_depth_texture.texture.GetHandle(); state.Apply(); glActiveTexture(GL_TEXTURE0); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fb_depth_texture.width, fb_depth_texture.height, fb_depth_texture.gl_format, fb_depth_texture.gl_type, ogl_img.get()); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fb_depth_texture.width, fb_depth_texture.height, + fb_depth_texture.gl_format, fb_depth_texture.gl_type, temp_fb_depth_buffer.get()); } -/** -* Save the current OpenGL framebuffer to the current PICA framebuffer in 3ds memory -* Loads the OpenGL framebuffer textures into temporary buffers -* Then copies into the 3ds framebuffer using proper Morton order -*/ void RasterizerOpenGL::CommitFramebuffer() { - if (last_fb_color_addr != -1) { + if (last_fb_color_addr != 0) { u8* color_buffer = Memory::GetPhysicalPointer(last_fb_color_addr); if (color_buffer != nullptr) { u32 bytes_per_pixel = ColorFormatBytesPerPixel(fb_color_texture.format); - std::unique_ptr ogl_img(new u8[fb_color_texture.width * fb_color_texture.height * bytes_per_pixel]); + std::unique_ptr temp_gl_color_buffer(new u8[fb_color_texture.width * fb_color_texture.height * bytes_per_pixel]); - state.texture_unit[0].enabled_2d = true; - state.texture_unit[0].texture_2d = fb_color_texture.texture.GetHandle(); + state.texture_units[0].enabled_2d = true; + state.texture_units[0].texture_2d = fb_color_texture.texture.GetHandle(); state.Apply(); glActiveTexture(GL_TEXTURE0); - glGetTexImage(GL_TEXTURE_2D, 0, fb_color_texture.gl_format, fb_color_texture.gl_type, ogl_img.get()); + glGetTexImage(GL_TEXTURE_2D, 0, fb_color_texture.gl_format, fb_color_texture.gl_type, temp_gl_color_buffer.get()); - for (int x = 0; x < fb_color_texture.width; ++x) { - for (int y = 0; y < fb_color_texture.height; ++y) { + // Directly copy pixels. Internal OpenGL color formats are consistent so no conversion is necessary. + // TODO: Evaluate whether u16/memcpy/u32 is faster for 2/3/4 bpp versus memcpy for all + for (int y = 0; y < fb_color_texture.height; ++y) { + for (int x = 0; x < fb_color_texture.width; ++x) { const u32 coarse_y = y & ~7; u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_color_texture.width * bytes_per_pixel; - u32 ogl_px_idx = x * bytes_per_pixel + y * fb_color_texture.width * bytes_per_pixel; + u32 gl_px_idx = x * bytes_per_pixel + y * fb_color_texture.width * bytes_per_pixel; u8* pixel = color_buffer + dst_offset; - memcpy(pixel, &ogl_img.get()[ogl_px_idx], bytes_per_pixel); + memcpy(pixel, &temp_gl_color_buffer[gl_px_idx], bytes_per_pixel); } } } } - if (last_fb_depth_addr != -1) { + if (last_fb_depth_addr != 0) { // TODO: Output seems correct visually, but doesn't quite match sw renderer output. One of them is wrong. u8* depth_buffer = Memory::GetPhysicalPointer(last_fb_depth_addr); @@ -674,34 +649,34 @@ void RasterizerOpenGL::CommitFramebuffer() { u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(fb_depth_texture.format); // OpenGL needs 4 bpp alignment for D24 - u32 ogl_bpp = bytes_per_pixel == 3 ? 4 : bytes_per_pixel; + u32 gl_bpp = bytes_per_pixel == 3 ? 4 : bytes_per_pixel; - std::unique_ptr ogl_img(new u8[fb_depth_texture.width * fb_depth_texture.height * ogl_bpp]); + std::unique_ptr temp_gl_depth_buffer(new u8[fb_depth_texture.width * fb_depth_texture.height * gl_bpp]); - state.texture_unit[0].enabled_2d = true; - state.texture_unit[0].texture_2d = fb_depth_texture.texture.GetHandle(); + state.texture_units[0].enabled_2d = true; + state.texture_units[0].texture_2d = fb_depth_texture.texture.GetHandle(); state.Apply(); glActiveTexture(GL_TEXTURE0); - glGetTexImage(GL_TEXTURE_2D, 0, fb_depth_texture.gl_format, fb_depth_texture.gl_type, ogl_img.get()); + glGetTexImage(GL_TEXTURE_2D, 0, fb_depth_texture.gl_format, fb_depth_texture.gl_type, temp_gl_depth_buffer.get()); - for (int x = 0; x < fb_depth_texture.width; ++x) { - for (int y = 0; y < fb_depth_texture.height; ++y) { + for (int y = 0; y < fb_depth_texture.height; ++y) { + for (int x = 0; x < fb_depth_texture.width; ++x) { const u32 coarse_y = y & ~7; u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel; - u32 ogl_px_idx = x + y * fb_depth_texture.width; + u32 gl_px_idx = x + y * fb_depth_texture.width; switch (fb_depth_texture.format) { case Pica::Regs::DepthFormat::D16: - Color::EncodeD16(((u16*)ogl_img.get())[ogl_px_idx], depth_buffer + dst_offset); + Color::EncodeD16(((u16*)temp_gl_depth_buffer.get())[gl_px_idx], depth_buffer + dst_offset); break; case Pica::Regs::DepthFormat::D24: - Color::EncodeD24(((u32*)ogl_img.get())[ogl_px_idx], depth_buffer + dst_offset); + Color::EncodeD24(((u32*)temp_gl_depth_buffer.get())[gl_px_idx], depth_buffer + dst_offset); break; case Pica::Regs::DepthFormat::D24S8: { - u32 depth_stencil = ((u32*)ogl_img.get())[ogl_px_idx]; - Color::EncodeD24S8(depth_stencil >> 8, depth_stencil & 0xFF, depth_buffer + dst_offset); + u32 depth_stencil = ((u32*)temp_gl_depth_buffer.get())[gl_px_idx]; + Color::EncodeD24S8((depth_stencil >> 8), depth_stencil & 0xFF, depth_buffer + dst_offset); break; } default: diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 8eec10abc..301233227 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -29,11 +29,11 @@ public: /// Draw the current batch of triangles void DrawTriangles() override; - /// Notify rasterizer that a copy within 3ds memory will occur after this notification - void NotifyPreCopy(u32 src_paddr, u32 size) override; + /// Notify rasterizer that a copy within 3DS memory will occur after this notification + void NotifyPreCopy(PAddr src_addr, u32 size) override; - /// Notify rasterizer that a 3ds memory region has been changed - void NotifyFlush(u32 paddr, u32 size) override; + /// Notify rasterizer that a 3DS memory region has been changed + void NotifyFlush(PAddr addr, u32 size) override; private: /// Structure used for managing texture environment states @@ -68,7 +68,7 @@ private: GLenum gl_type; }; - ///Structure that the hardware rendered vertices are composed of + /// Structure that the hardware rendered vertices are composed of struct HardwareVertex { HardwareVertex(const Pica::VertexShader::OutputVertex& v) { position[0] = v.pos.x.ToFloat32(); @@ -113,10 +113,10 @@ private: void ReloadDepthBuffer(); /** - * Save the current OpenGL framebuffer to the current PICA framebuffer in 3ds memory - * Loads the OpenGL framebuffer textures into temporary buffers - * Then copies into the 3ds framebuffer using proper Morton order - */ + * Save the current OpenGL framebuffer to the current PICA framebuffer in 3ds memory + * Loads the OpenGL framebuffer textures into temporary buffers + * Then copies into the 3ds framebuffer using proper Morton order + */ void CommitFramebuffer(); EmuWindow* render_window; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 34f5ce4e1..0dd898077 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -12,20 +12,19 @@ RasterizerCacheOpenGL::~RasterizerCacheOpenGL() { FullFlush(); } -/// Loads a texture from 3ds memory to OpenGL and caches it (if not already cached) void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, int texture_unit, const Pica::Regs::FullTextureConfig& config) { - PAddr tex_paddr = config.config.GetPhysicalAddress(); + PAddr texture_addr = config.config.GetPhysicalAddress(); - auto cached_texture = texture_cache.find(tex_paddr); + const auto cached_texture = texture_cache.find(texture_addr); if (cached_texture != texture_cache.end()) { - state.texture_unit[texture_unit].texture_2d = cached_texture->second->texture.GetHandle(); + state.texture_units[texture_unit].texture_2d = cached_texture->second->texture.GetHandle(); state.Apply(); } else { std::unique_ptr new_texture(new CachedTexture()); new_texture->texture.Create(); - state.texture_unit[texture_unit].texture_2d = new_texture->texture.GetHandle(); + state.texture_units[texture_unit].texture_2d = new_texture->texture.GetHandle(); state.Apply(); // TODO: Need to choose filters that correspond to PICA once register is declared @@ -35,36 +34,33 @@ void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, int texture_u glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, PicaToGL::WrapMode(config.config.wrap_s.Value())); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, PicaToGL::WrapMode(config.config.wrap_t.Value())); - auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format); + const auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format); new_texture->width = info.width; new_texture->height = info.height; new_texture->size = info.width * info.height * Pica::Regs::NibblesPerPixel(info.format); - Math::Vec4* rgba_tex = new Math::Vec4[info.width * info.height]; + std::unique_ptr[]> temp_texture_buffer_rgba(new Math::Vec4[info.width * info.height]); - for (int i = 0; i < info.width; i++) { - for (int j = 0; j < info.height; j++) { - rgba_tex[i + info.width * j] = Pica::DebugUtils::LookupTexture(Memory::GetPhysicalPointer(tex_paddr), i, info.height - 1 - j, info); + for (int y = 0; y < info.height; ++y) { + for (int x = 0; x < info.width; ++x) { + temp_texture_buffer_rgba[x + info.width * y] = Pica::DebugUtils::LookupTexture(Memory::GetPhysicalPointer(texture_addr), x, info.height - 1 - y, info); } } - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, info.width, info.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rgba_tex); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, info.width, info.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp_texture_buffer_rgba.get()); - delete[] rgba_tex; - - texture_cache.emplace(tex_paddr, std::move(new_texture)); + texture_cache.emplace(texture_addr, std::move(new_texture)); } } -/// Flush any cached resource that touches the flushed region -void RasterizerCacheOpenGL::NotifyFlush(u32 paddr, u32 size) { +void RasterizerCacheOpenGL::NotifyFlush(PAddr addr, u32 size) { // Flush any texture that falls in the flushed region for (auto it = texture_cache.begin(); it != texture_cache.end();) { - u32 max_lower = std::max(paddr, it->first); - u32 min_upper = std::min(paddr + size, it->first + it->second->size); + PAddr max_low_addr_bound = std::max(addr, it->first); + PAddr min_hi_addr_bound = std::min(addr + size, it->first + it->second->size); - if (max_lower <= min_upper) { + if (max_low_addr_bound <= min_hi_addr_bound) { it = texture_cache.erase(it); } else { ++it; @@ -72,9 +68,6 @@ void RasterizerCacheOpenGL::NotifyFlush(u32 paddr, u32 size) { } } -/// Flush all cached resources void RasterizerCacheOpenGL::FullFlush() { - for (auto it = texture_cache.begin(); it != texture_cache.end();) { - it = texture_cache.erase(it); - } + texture_cache.clear(); } diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 3c4a7e41e..4e3f942fb 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h @@ -15,11 +15,11 @@ class RasterizerCacheOpenGL : NonCopyable { public: ~RasterizerCacheOpenGL(); - /// Loads a texture from 3ds memory to OpenGL and caches it (if not already cached) + /// Loads a texture from 3DS memory to OpenGL and caches it (if not already cached) void LoadAndBindTexture(OpenGLState &state, int texture_unit, const Pica::Regs::FullTextureConfig& config); /// Flush any cached resource that touches the flushed region - void NotifyFlush(u32 paddr, u32 size); + void NotifyFlush(PAddr addr, u32 size); /// Flush all cached OpenGL resources tracked by this cache manager void FullFlush(); @@ -32,5 +32,5 @@ private: u32 size; }; - std::map> texture_cache; + std::map> texture_cache; }; diff --git a/src/video_core/renderer_opengl/gl_shaders.h b/src/video_core/renderer_opengl/gl_shaders.h index d7d88464c..6ccf3fe03 100644 --- a/src/video_core/renderer_opengl/gl_shaders.h +++ b/src/video_core/renderer_opengl/gl_shaders.h @@ -45,13 +45,15 @@ void main() { const char g_vertex_shader_hw[] = R"( #version 150 core +#define NUM_VTX_ATTR 7 + in vec4 vert_position; in vec4 vert_color; in vec2 vert_texcoords[3]; -out vec4 o[7]; +out vec4 o[NUM_VTX_ATTR]; -uniform int out_maps[7*4]; +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; @@ -79,7 +81,58 @@ void main() { const char g_fragment_shader_hw[] = R"( #version 150 core -in vec4 o[7]; +#define NUM_TEV_STAGES 6 +#define NUM_VTX_ATTR 7 + +#define SOURCE_PRIMARYCOLOR 0x0 +#define SOURCE_PRIMARYFRAGMENTCOLOR 0x1 +#define SOURCE_TEXTURE0 0x3 +#define SOURCE_TEXTURE1 0x4 +#define SOURCE_TEXTURE2 0x5 +#define SOURCE_TEXTURE3 0x6 +#define SOURCE_PREVIOUSBUFFER 0xd +#define SOURCE_CONSTANT 0xe +#define SOURCE_PREVIOUS 0xf + +#define COLORMODIFIER_SOURCECOLOR 0x0 +#define COLORMODIFIER_ONEMINUSSOURCECOLOR 0x1 +#define COLORMODIFIER_SOURCEALPHA 0x2 +#define COLORMODIFIER_ONEMINUSSOURCEALPHA 0x3 +#define COLORMODIFIER_SOURCERED 0x4 +#define COLORMODIFIER_ONEMINUSSOURCERED 0x5 +#define COLORMODIFIER_SOURCEGREEN 0x8 +#define COLORMODIFIER_ONEMINUSSOURCEGREEN 0x9 +#define COLORMODIFIER_SOURCEBLUE 0xc +#define COLORMODIFIER_ONEMINUSSOURCEBLUE 0xd + +#define ALPHAMODIFIER_SOURCEALPHA 0x0 +#define ALPHAMODIFIER_ONEMINUSSOURCEALPHA 0x1 +#define ALPHAMODIFIER_SOURCERED 0x2 +#define ALPHAMODIFIER_ONEMINUSSOURCERED 0x3 +#define ALPHAMODIFIER_SOURCEGREEN 0x4 +#define ALPHAMODIFIER_ONEMINUSSOURCEGREEN 0x5 +#define ALPHAMODIFIER_SOURCEBLUE 0x6 +#define ALPHAMODIFIER_ONEMINUSSOURCEBLUE 0x7 + +#define OPERATION_REPLACE 0 +#define OPERATION_MODULATE 1 +#define OPERATION_ADD 2 +#define OPERATION_ADDSIGNED 3 +#define OPERATION_LERP 4 +#define OPERATION_SUBTRACT 5 +#define OPERATION_MULTIPLYTHENADD 8 +#define OPERATION_ADDTHENMULTIPLY 9 + +#define COMPAREFUNC_NEVER 0 +#define COMPAREFUNC_ALWAYS 1 +#define COMPAREFUNC_EQUAL 2 +#define COMPAREFUNC_NOTEQUAL 3 +#define COMPAREFUNC_LESSTHAN 4 +#define COMPAREFUNC_LESSTHANOREQUAL 5 +#define COMPAREFUNC_GREATERTHAN 6 +#define COMPAREFUNC_GREATERTHANOREQUAL 7 + +in vec4 o[NUM_VTX_ATTR]; out vec4 color; uniform int alphatest_func; @@ -99,9 +152,9 @@ struct TEVConfig bvec2 updates_combiner_buffer_color_alpha; }; -uniform TEVConfig tev_cfgs[6]; +uniform TEVConfig tev_cfgs[NUM_TEV_STAGES]; -uniform int out_maps[7*4]; +uniform int out_maps[NUM_VTX_ATTR * 4]; vec4 g_combiner_buffer; vec4 g_last_tex_env_out; @@ -112,33 +165,27 @@ float GetVal(int map_idx) { } vec4 GetSource(int source) { - if (source == 0) { + 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]; - } - else if (source == 1) { + } else if (source == SOURCE_PRIMARYFRAGMENTCOLOR) { + // HACK: Uses color value, but should really use fragment lighting output return o[out_maps[8] >> 2]; - } - else if (source == 3) { + } else if (source == SOURCE_TEXTURE0) { return texture(tex[0], vec2(GetVal(12), GetVal(13))); - } - else if (source == 4) { + } else if (source == SOURCE_TEXTURE1) { return texture(tex[1], vec2(GetVal(14), GetVal(15))); - } - else if (source == 5) { + } else if (source == SOURCE_TEXTURE2) { // TODO: Unverified return texture(tex[2], vec2(GetVal(16), GetVal(17))); - } - else if (source == 6) { + } else if (source == SOURCE_TEXTURE3) { // TODO: no 4th texture? - } - else if (source == 13) { + } else if (source == SOURCE_PREVIOUSBUFFER) { return g_combiner_buffer; - } - else if (source == 14) { + } else if (source == SOURCE_CONSTANT) { return g_const_color; - } - else if (source == 15) { + } else if (source == SOURCE_PREVIOUS) { return g_last_tex_env_out; } @@ -146,34 +193,25 @@ vec4 GetSource(int source) { } vec3 GetColorModifier(int factor, vec4 color) { - if (factor == 0) { + if (factor == COLORMODIFIER_SOURCECOLOR) { return color.rgb; - } - else if (factor == 1) { + } else if (factor == COLORMODIFIER_ONEMINUSSOURCECOLOR) { return vec3(1.0, 1.0, 1.0) - color.rgb; - } - else if (factor == 2) { + } else if (factor == COLORMODIFIER_SOURCEALPHA) { return color.aaa; - } - else if (factor == 3) { + } else if (factor == COLORMODIFIER_ONEMINUSSOURCEALPHA) { return vec3(1.0, 1.0, 1.0) - color.aaa; - } - else if (factor == 4) { + } else if (factor == COLORMODIFIER_SOURCERED) { return color.rrr; - } - else if (factor == 5) { + } else if (factor == COLORMODIFIER_ONEMINUSSOURCERED) { return vec3(1.0, 1.0, 1.0) - color.rrr; - } - else if (factor == 8) { + } else if (factor == COLORMODIFIER_SOURCEGREEN) { return color.ggg; - } - else if (factor == 9) { + } else if (factor == COLORMODIFIER_ONEMINUSSOURCEGREEN) { return vec3(1.0, 1.0, 1.0) - color.ggg; - } - else if (factor == 12) { + } else if (factor == COLORMODIFIER_SOURCEBLUE) { return color.bbb; - } - else if (factor == 13) { + } else if (factor == COLORMODIFIER_ONEMINUSSOURCEBLUE) { return vec3(1.0, 1.0, 1.0) - color.bbb; } @@ -181,28 +219,21 @@ vec3 GetColorModifier(int factor, vec4 color) { } float GetAlphaModifier(int factor, vec4 color) { - if (factor == 0) { + if (factor == ALPHAMODIFIER_SOURCEALPHA) { return color.a; - } - else if (factor == 1) { + } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEALPHA) { return 1.0 - color.a; - } - else if (factor == 2) { + } else if (factor == ALPHAMODIFIER_SOURCERED) { return color.r; - } - else if (factor == 3) { + } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCERED) { return 1.0 - color.r; - } - else if (factor == 4) { + } else if (factor == ALPHAMODIFIER_SOURCEGREEN) { return color.g; - } - else if (factor == 5) { + } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEGREEN) { return 1.0 - color.g; - } - else if (factor == 6) { + } else if (factor == ALPHAMODIFIER_SOURCEBLUE) { return color.b; - } - else if (factor == 7) { + } else if (factor == ALPHAMODIFIER_ONEMINUSSOURCEBLUE) { return 1.0 - color.b; } @@ -210,28 +241,21 @@ float GetAlphaModifier(int factor, vec4 color) { } vec3 ColorCombine(int op, vec3 color[3]) { - if (op == 0) { + if (op == OPERATION_REPLACE) { return color[0]; - } - else if (op == 1) { + } else if (op == OPERATION_MODULATE) { return color[0] * color[1]; - } - else if (op == 2) { + } else if (op == OPERATION_ADD) { return min(color[0] + color[1], 1.0); - } - else if (op == 3) { + } else if (op == OPERATION_ADDSIGNED) { return color[0] + color[1] - vec3(0.5, 0.5, 0.5); - } - else if (op == 4) { + } else if (op == OPERATION_LERP) { return color[0] * color[2] + color[1] * (vec3(1.0, 1.0, 1.0) - color[2]); - } - else if (op == 5) { + } else if (op == OPERATION_SUBTRACT) { return max(color[0] - color[1], 0.0); - } - else if (op == 8) { + } else if (op == OPERATION_MULTIPLYTHENADD) { return min(color[0] * color[1] + color[2], 1.0); - } - else if (op == 9) { + } else if (op == OPERATION_ADDTHENMULTIPLY) { return min(color[0] + color[1], 1.0) * color[2]; } @@ -239,28 +263,21 @@ vec3 ColorCombine(int op, vec3 color[3]) { } float AlphaCombine(int op, float alpha[3]) { - if (op == 0) { + if (op == OPERATION_REPLACE) { return alpha[0]; - } - else if (op == 1) { + } else if (op == OPERATION_MODULATE) { return alpha[0] * alpha[1]; - } - else if (op == 2) { + } else if (op == OPERATION_ADD) { return min(alpha[0] + alpha[1], 1.0); - } - else if (op == 3) { + } else if (op == OPERATION_ADDSIGNED) { return alpha[0] + alpha[1] - 0.5; - } - else if (op == 4) { + } else if (op == OPERATION_LERP) { return alpha[0] * alpha[2] + alpha[1] * (1.0 - alpha[2]); - } - else if (op == 5) { + } else if (op == OPERATION_SUBTRACT) { return max(alpha[0] - alpha[1], 0.0); - } - else if (op == 8) { + } else if (op == OPERATION_MULTIPLYTHENADD) { return min(alpha[0] * alpha[1] + alpha[2], 1.0); - } - else if (op == 9) { + } else if (op == OPERATION_ADDTHENMULTIPLY) { return min(alpha[0] + alpha[1], 1.0) * alpha[2]; } @@ -292,39 +309,35 @@ void ProcessTexEnv(int tex_env_idx) { } void main(void) { - for (int i = 0; i < 6; ++i) { + for (int i = 0; i < NUM_TEV_STAGES; ++i) { ProcessTexEnv(i); } - if (alphatest_func == 0) { + if (alphatest_func == COMPAREFUNC_NEVER) { discard; - } - else if (alphatest_func == 2) { + } 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 == 3) { + } else if (alphatest_func == COMPAREFUNC_NOTEQUAL) { if (g_last_tex_env_out.a == alphatest_ref) { discard; } - } - else if (alphatest_func == 4) { + } else if (alphatest_func == COMPAREFUNC_LESSTHAN) { if (g_last_tex_env_out.a > alphatest_ref) { discard; } - } - else if (alphatest_func == 5) { + } else if (alphatest_func == COMPAREFUNC_LESSTHANOREQUAL) { if (g_last_tex_env_out.a >= alphatest_ref) { discard; } - } - else if (alphatest_func == 6) { + } else if (alphatest_func == COMPAREFUNC_GREATERTHAN) { if (g_last_tex_env_out.a < alphatest_ref) { discard; } - } - else if (alphatest_func == 7) { + } else if (alphatest_func == COMPAREFUNC_GREATERTHANOREQUAL) { if (g_last_tex_env_out.a <= alphatest_ref) { discard; } diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index e81a6c38f..a01a661f7 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp @@ -31,9 +31,9 @@ OpenGLState::OpenGLState() { blend.color.blue = 0.0f; blend.color.alpha = 0.0f; - for (int i = 0; i < 3; i++) { - texture_unit[i].enabled_2d = false; - texture_unit[i].texture_2d = 0; + for (auto& texture_unit : texture_units) { + texture_unit.enabled_2d = false; + texture_unit.texture_2d = 0; } draw.framebuffer = 0; @@ -42,7 +42,6 @@ OpenGLState::OpenGLState() { draw.shader_program = 0; } -/// Apply this state as the current OpenGL state void OpenGLState::Apply() { // Culling if (cull.enabled) { @@ -119,18 +118,18 @@ void OpenGLState::Apply() { } // Textures - for (int i = 0; i < 3; i++) { - if (texture_unit[i].enabled_2d) { - if (texture_unit[i].enabled_2d != texture_unit[i].enabled_2d) { + for (int i = 0; i < 3; ++i) { + if (texture_units[i].enabled_2d) { + if (texture_units[i].enabled_2d != texture_units[i].enabled_2d) { glActiveTexture(GL_TEXTURE0 + i); glEnable(GL_TEXTURE_2D); } - if (texture_unit[i].texture_2d != cur_state.texture_unit[i].texture_2d) { + if (texture_units[i].texture_2d != cur_state.texture_units[i].texture_2d) { glActiveTexture(GL_TEXTURE0 + i); - glBindTexture(GL_TEXTURE_2D, texture_unit[i].texture_2d); + glBindTexture(GL_TEXTURE_2D, texture_units[i].texture_2d); } - } else if (texture_unit[i].enabled_2d != cur_state.texture_unit[i].enabled_2d) { + } else if (texture_units[i].enabled_2d != cur_state.texture_units[i].enabled_2d) { glActiveTexture(GL_TEXTURE0 + i); glDisable(GL_TEXTURE_2D); } diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 1ca7d2b92..bdd1c7841 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -45,7 +45,7 @@ public: struct { bool enabled_2d; // GL_TEXTURE_2D GLuint texture_2d; // GL_TEXTURE_BINDING_2D - } texture_unit[3]; + } texture_units[3]; struct { GLuint framebuffer; // GL_DRAW_FRAMEBUFFER_BINDING diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 05c936879..5e232b4c6 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -143,8 +143,8 @@ void RendererOpenGL::LoadFBToActiveGLTexture(OpenGLState &state, const GPU::Regs // only allows rows to have a memory alignement of 4. ASSERT(pixel_stride % 4 == 0); - state.texture_unit[0].enabled_2d = true; - state.texture_unit[0].texture_2d = texture.handle; + state.texture_units[0].enabled_2d = true; + state.texture_units[0].texture_2d = texture.handle; state.Apply(); glActiveTexture(GL_TEXTURE0); @@ -168,8 +168,8 @@ void RendererOpenGL::LoadFBToActiveGLTexture(OpenGLState &state, const GPU::Regs */ void RendererOpenGL::LoadColorToActiveGLTexture(OpenGLState &state, u8 color_r, u8 color_g, u8 color_b, const TextureInfo& texture) { - state.texture_unit[0].enabled_2d = true; - state.texture_unit[0].texture_2d = texture.handle; + state.texture_units[0].enabled_2d = true; + state.texture_units[0].texture_2d = texture.handle; state.Apply(); glActiveTexture(GL_TEXTURE0); @@ -185,7 +185,7 @@ void RendererOpenGL::LoadColorToActiveGLTexture(OpenGLState &state, u8 color_r, void RendererOpenGL::InitOpenGLObjects() { glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue, 0.0f); state.depth.test_enabled = false; - state.texture_unit[0].enabled_2d = true; + state.texture_units[0].enabled_2d = true; // Link shaders and get variable locations program_id = ShaderUtil::LoadShaders(GLShaders::g_vertex_shader, GLShaders::g_fragment_shader); @@ -218,8 +218,8 @@ void RendererOpenGL::InitOpenGLObjects() { // Allocation of storage is deferred until the first frame, when we // know the framebuffer size. - state.texture_unit[0].enabled_2d = true; - state.texture_unit[0].texture_2d = texture.handle; + state.texture_units[0].enabled_2d = true; + state.texture_units[0].texture_2d = texture.handle; state.Apply(); glActiveTexture(GL_TEXTURE0); @@ -281,8 +281,8 @@ void RendererOpenGL::ConfigureFramebufferTexture(OpenGLState &state, TextureInfo UNIMPLEMENTED(); } - state.texture_unit[0].enabled_2d = true; - state.texture_unit[0].texture_2d = texture.handle; + state.texture_units[0].enabled_2d = true; + state.texture_units[0].texture_2d = texture.handle; state.Apply(); glActiveTexture(GL_TEXTURE0); @@ -301,8 +301,8 @@ void RendererOpenGL::DrawSingleScreenRotated(const TextureInfo& texture, float x ScreenRectVertex(x+w, y+h, 0.f, 1.f), }; - state.texture_unit[0].enabled_2d = true; - state.texture_unit[0].texture_2d = texture.handle; + state.texture_units[0].enabled_2d = true; + state.texture_units[0].texture_2d = texture.handle; state.Apply(); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data());