diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp index 6bf212ec7..cc658a45d 100644 --- a/src/core/hle/service/gsp_gpu.cpp +++ b/src/core/hle/service/gsp_gpu.cpp @@ -355,8 +355,8 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { // GX request DMA - typically used for copying memory from GSP heap to VRAM case CommandId::REQUEST_DMA: - VideoCore::g_renderer->hw_rasterizer->NotifyPreCopy(Memory::VirtualToPhysicalAddress(command.dma_request.source_address), - command.dma_request.size); + VideoCore::g_renderer->hw_rasterizer->NotifyPreRead(Memory::VirtualToPhysicalAddress(command.dma_request.source_address), + command.dma_request.size); memcpy(Memory::GetPointer(command.dma_request.dest_address), Memory::GetPointer(command.dma_request.source_address), diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index 9fa5f9e65..291b78d2b 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp @@ -131,10 +131,10 @@ inline void Write(u32 addr, const T data) { u32 output_width = config.output_width / horizontal_scale; u32 output_height = config.output_height / vertical_scale; - u32 input_size = config.input_height.Value() * config.input_width.Value() * GPU::Regs::BytesPerPixel(config.input_format.Value()); - u32 output_size = output_height * output_width * GPU::Regs::BytesPerPixel(config.output_format.Value()); + u32 input_size = config.input_height * config.input_width * GPU::Regs::BytesPerPixel(config.input_format); + u32 output_size = output_height * output_width * GPU::Regs::BytesPerPixel(config.output_format); - VideoCore::g_renderer->hw_rasterizer->NotifyPreCopy(config.GetPhysicalInputAddress(), input_size); + VideoCore::g_renderer->hw_rasterizer->NotifyPreRead(config.GetPhysicalInputAddress(), input_size); if (config.raw_copy) { // Raw copies do not perform color conversion nor tiled->linear / linear->tiled conversions diff --git a/src/video_core/hwrasterizer_base.h b/src/video_core/hwrasterizer_base.h index 7bc0b8b8d..08e77562b 100644 --- a/src/video_core/hwrasterizer_base.h +++ b/src/video_core/hwrasterizer_base.h @@ -15,10 +15,7 @@ public: /// Initialize API-specific GPU objects virtual void InitObjects() = 0; - /// Set the window (context) to draw with - virtual void SetWindow(EmuWindow* window) = 0; - - /// Converts the triangle verts to hardware data format and adds them to the current batch + /// Queues the primitive formed by the given vertices for rendering virtual void AddTriangle(const Pica::VertexShader::OutputVertex& v0, const Pica::VertexShader::OutputVertex& v1, const Pica::VertexShader::OutputVertex& v2) = 0; @@ -26,9 +23,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 - virtual void NotifyPreCopy(u32 src_paddr, u32 size) = 0; + /// Notify rasterizer that the specified 3DS memory region will be read from after this notification + virtual void NotifyPreRead(u32 paddr, u32 size) = 0; /// Notify rasterizer that a 3DS memory region has been changed - virtual void NotifyFlush(u32 paddr, u32 size) = 0; + virtual void NotifyFlush(u32 addr, u32 size) = 0; }; diff --git a/src/video_core/pica.h b/src/video_core/pica.h index e9bc7fb3b..c1d83348d 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -500,6 +500,23 @@ struct Regs { RGBA4 = 4, }; + // Returns the number of bytes in the specified color format + static unsigned BytesPerColorPixel(u32 format) { + switch (format) { + case ColorFormat::RGBA8: + return 4; + case ColorFormat::RGB8: + return 3; + case ColorFormat::RGB5A1: + case ColorFormat::RGB565: + case ColorFormat::RGBA4: + return 2; + default: + LOG_CRITICAL(HW_GPU, "Unknown color format %u", format); + UNIMPLEMENTED(); + } + } + INSERT_PADDING_WORDS(0x6); DepthFormat depth_format; 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 70dd32afb..9fe24db09 100644 --- a/src/video_core/renderer_opengl/gl_pica_to_gl.h +++ b/src/video_core/renderer_opengl/gl_pica_to_gl.h @@ -12,83 +12,86 @@ namespace PicaToGL { -static GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) { - switch (mode) { - case Pica::Regs::TextureConfig::WrapMode::ClampToEdge: +inline GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) { + static const GLenum wrap_mode_table[] = { + GL_CLAMP_TO_EDGE, // WrapMode::ClampToEdge + 0, // Unknown + GL_REPEAT, // WrapMode::Repeat + GL_MIRRORED_REPEAT // WrapMode::MirroredRepeat + }; + + // Range check table for input + if (mode >= sizeof(wrap_mode_table) / sizeof(GLenum)) { + LOG_CRITICAL(Render_OpenGL, "Unknown texture wrap mode %d", mode); + UNREACHABLE(); + return GL_CLAMP_TO_EDGE; - case Pica::Regs::TextureConfig::WrapMode::Repeat: - return GL_REPEAT; - case Pica::Regs::TextureConfig::WrapMode::MirroredRepeat: - return GL_MIRRORED_REPEAT; - default: + } + + GLenum gl_mode = wrap_mode_table[mode]; + + // Check for dummy values indicating an unknown mode + if (gl_mode == 0) { LOG_CRITICAL(Render_OpenGL, "Unknown texture wrap mode %d", mode); UNIMPLEMENTED(); + return GL_CLAMP_TO_EDGE; } + + return gl_mode; } -static GLenum BlendFunc(u32 factor) { - switch (factor) { - case Pica::registers.output_merger.alpha_blending.Zero: - return GL_ZERO; - case Pica::registers.output_merger.alpha_blending.One: - return GL_ONE; - case Pica::registers.output_merger.alpha_blending.SourceColor: - return GL_SRC_COLOR; - case Pica::registers.output_merger.alpha_blending.OneMinusSourceColor: - return GL_ONE_MINUS_SRC_COLOR; - case Pica::registers.output_merger.alpha_blending.DestColor: - return GL_DST_COLOR; - case Pica::registers.output_merger.alpha_blending.OneMinusDestColor: - return GL_ONE_MINUS_DST_COLOR; - case Pica::registers.output_merger.alpha_blending.SourceAlpha: - return GL_SRC_ALPHA; - case Pica::registers.output_merger.alpha_blending.OneMinusSourceAlpha: - return GL_ONE_MINUS_SRC_ALPHA; - case Pica::registers.output_merger.alpha_blending.DestAlpha: - return GL_DST_ALPHA; - case Pica::registers.output_merger.alpha_blending.OneMinusDestAlpha: - return GL_ONE_MINUS_DST_ALPHA; - case Pica::registers.output_merger.alpha_blending.ConstantColor: - return GL_CONSTANT_COLOR; - case Pica::registers.output_merger.alpha_blending.OneMinusConstantColor: - return GL_ONE_MINUS_CONSTANT_COLOR; - case Pica::registers.output_merger.alpha_blending.ConstantAlpha: - return GL_CONSTANT_ALPHA; - case Pica::registers.output_merger.alpha_blending.OneMinusConstantAlpha: - return GL_ONE_MINUS_CONSTANT_ALPHA; - case Pica::registers.output_merger.alpha_blending.SourceAlphaSaturate: - return GL_SRC_ALPHA_SATURATE; - default: +inline GLenum BlendFunc(u32 factor) { + static const GLenum blend_func_table[] = { + GL_ZERO, // BlendFactor::Zero + GL_ONE, // BlendFactor::One + GL_SRC_COLOR, // BlendFactor::SourceColor + GL_ONE_MINUS_SRC_COLOR, // BlendFactor::OneMinusSourceColor + GL_DST_COLOR, // BlendFactor::DestColor + GL_ONE_MINUS_DST_COLOR, // BlendFactor::OneMinusDestColor + GL_SRC_ALPHA, // BlendFactor::SourceAlpha + GL_ONE_MINUS_SRC_ALPHA, // BlendFactor::OneMinusSourceAlpha + GL_DST_ALPHA, // BlendFactor::DestAlpha + GL_ONE_MINUS_DST_ALPHA, // BlendFactor::OneMinusDestAlpha + GL_CONSTANT_COLOR, // BlendFactor::ConstantColor + GL_ONE_MINUS_CONSTANT_COLOR, // BlendFactor::OneMinusConstantColor + GL_CONSTANT_ALPHA, // BlendFactor::ConstantAlpha + GL_ONE_MINUS_CONSTANT_ALPHA, // BlendFactor::OneMinusConstantAlpha + GL_SRC_ALPHA_SATURATE, // BlendFactor::SourceAlphaSaturate + }; + + // Range check table for input + if (factor >= sizeof(blend_func_table) / sizeof(GLenum)) { LOG_CRITICAL(Render_OpenGL, "Unknown blend factor %d", factor); - UNIMPLEMENTED(); + UNREACHABLE(); + return GL_ONE; } + + return blend_func_table[factor]; } -static GLenum CompareFunc(u32 func) { - switch (func) { - case Pica::registers.output_merger.Never: - return GL_NEVER; - case Pica::registers.output_merger.Always: - return GL_ALWAYS; - case Pica::registers.output_merger.Equal: - return GL_EQUAL; - case Pica::registers.output_merger.NotEqual: - return GL_NOTEQUAL; - case Pica::registers.output_merger.LessThan: - return GL_LESS; - case Pica::registers.output_merger.LessThanOrEqual: - return GL_LEQUAL; - case Pica::registers.output_merger.GreaterThan: - return GL_GREATER; - case Pica::registers.output_merger.GreaterThanOrEqual: - return GL_GEQUAL; - default: +inline GLenum CompareFunc(u32 func) { + static const GLenum compare_func_table[] = { + GL_NEVER, // CompareFunc::Never + GL_ALWAYS, // CompareFunc::Always + GL_EQUAL, // CompareFunc::Equal + GL_NOTEQUAL, // CompareFunc::NotEqual + GL_LESS, // CompareFunc::LessThan + GL_LEQUAL, // CompareFunc::LessThanOrEqual + GL_GREATER, // CompareFunc::GreaterThan + GL_GEQUAL, // CompareFunc::GreaterThanOrEqual + }; + + // Range check table for input + if (func >= sizeof(compare_func_table) / sizeof(GLenum)) { LOG_CRITICAL(Render_OpenGL, "Unknown compare function %d", func); - UNIMPLEMENTED(); + UNREACHABLE(); + return GL_ALWAYS; } + + return compare_func_table[func]; } } // namespace diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index 591324a6f..ae450f4f4 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -17,32 +17,12 @@ #include -u32 ColorFormatBytesPerPixel(u32 format) { - switch (format) { - case Pica::registers.framebuffer.RGBA8: - return 4; - case Pica::registers.framebuffer.RGB8: - return 3; - case Pica::registers.framebuffer.RGB5A1: - case Pica::registers.framebuffer.RGB565: - case Pica::registers.framebuffer.RGBA4: - return 2; - default: - LOG_CRITICAL(Render_OpenGL, "Unknown framebuffer color format %x", format); - UNIMPLEMENTED(); - break; - } - - return 0; -} - RasterizerOpenGL::RasterizerOpenGL() : last_fb_color_addr(0), last_fb_depth_addr(0) { } RasterizerOpenGL::~RasterizerOpenGL() { - // Set context for automatic resource destruction - render_window->MakeCurrent(); + } void RasterizerOpenGL::InitObjects() { @@ -109,7 +89,7 @@ void RasterizerOpenGL::InitObjects() { // Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation fb_color_texture.texture.Create(); - ReconfigColorTexture(fb_color_texture, Pica::registers.framebuffer.RGBA8, 1, 1); + ReconfigureColorTexture(fb_color_texture, Pica::registers.framebuffer.RGBA8, 1, 1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -117,7 +97,7 @@ void RasterizerOpenGL::InitObjects() { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); fb_depth_texture.texture.Create(); - ReconfigDepthTexture(fb_depth_texture, Pica::Regs::DepthFormat::D16, 1, 1); + ReconfigureDepthTexture(fb_depth_texture, Pica::Regs::DepthFormat::D16, 1, 1); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -138,13 +118,8 @@ void RasterizerOpenGL::InitObjects() { glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb_color_texture.texture.GetHandle(), 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, fb_depth_texture.texture.GetHandle(), 0); - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - LOG_CRITICAL(Render_OpenGL, "Framebuffer setup failed, status %X", glCheckFramebufferStatus(GL_FRAMEBUFFER)); - } -} - -void RasterizerOpenGL::SetWindow(EmuWindow* window) { - render_window = window; + ASSERT_MSG(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, + "OpenGL rasterizer framebuffer setup failed, status %X", glCheckFramebufferStatus(GL_FRAMEBUFFER)); } void RasterizerOpenGL::AddTriangle(const Pica::VertexShader::OutputVertex& v0, @@ -156,8 +131,6 @@ void RasterizerOpenGL::AddTriangle(const Pica::VertexShader::OutputVertex& v0, } void RasterizerOpenGL::DrawTriangles() { - render_window->MakeCurrent(); - state.Apply(); SyncFramebuffer(); @@ -169,16 +142,14 @@ void RasterizerOpenGL::DrawTriangles() { vertex_batch.clear(); } -void RasterizerOpenGL::NotifyPreCopy(PAddr src_addr, u32 size) { +void RasterizerOpenGL::NotifyPreRead(PAddr addr, u32 size) { if (!Settings::values.use_hw_renderer) return; - render_window->MakeCurrent(); - state.Apply(); PAddr cur_fb_color_addr = Pica::registers.framebuffer.GetColorBufferPhysicalAddress(); - u32 cur_fb_color_size = ColorFormatBytesPerPixel(Pica::registers.framebuffer.color_format) + u32 cur_fb_color_size = Pica::registers.framebuffer.BytesPerColorPixel(Pica::registers.framebuffer.color_format) * Pica::registers.framebuffer.GetWidth() * Pica::registers.framebuffer.GetHeight(); PAddr cur_fb_depth_addr = Pica::registers.framebuffer.GetDepthBufferPhysicalAddress(); @@ -186,18 +157,18 @@ void RasterizerOpenGL::NotifyPreCopy(PAddr src_addr, u32 size) { * Pica::registers.framebuffer.GetWidth() * Pica::registers.framebuffer.GetHeight(); // 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); + 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_low_addr_bound <= min_hi_addr_bound) { - CommitFramebuffer(); + CommitColorBuffer(); } - 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); + 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_low_addr_bound <= min_hi_addr_bound) { - CommitFramebuffer(); + CommitDepthBuffer(); } } @@ -205,12 +176,10 @@ void RasterizerOpenGL::NotifyFlush(PAddr addr, u32 size) { if (!Settings::values.use_hw_renderer) return; - render_window->MakeCurrent(); - state.Apply(); PAddr cur_fb_color_addr = Pica::registers.framebuffer.GetColorBufferPhysicalAddress(); - u32 cur_fb_color_size = ColorFormatBytesPerPixel(Pica::registers.framebuffer.color_format) + u32 cur_fb_color_size = Pica::registers.framebuffer.BytesPerColorPixel(Pica::registers.framebuffer.color_format) * Pica::registers.framebuffer.GetWidth() * Pica::registers.framebuffer.GetHeight(); PAddr cur_fb_depth_addr = Pica::registers.framebuffer.GetDepthBufferPhysicalAddress(); @@ -236,7 +205,7 @@ void RasterizerOpenGL::NotifyFlush(PAddr addr, u32 size) { res_cache.NotifyFlush(addr, size); } -void RasterizerOpenGL::ReconfigColorTexture(TextureInfo& texture, u32 format, u32 width, u32 height) { +void RasterizerOpenGL::ReconfigureColorTexture(TextureInfo& texture, u32 format, u32 width, u32 height) { GLint internal_format; texture.format = format; @@ -293,7 +262,7 @@ void RasterizerOpenGL::ReconfigColorTexture(TextureInfo& texture, u32 format, u3 texture.gl_format, texture.gl_type, nullptr); } -void RasterizerOpenGL::ReconfigDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height) { +void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height) { GLint internal_format; texture.format = format; @@ -351,15 +320,16 @@ void RasterizerOpenGL::SyncFramebuffer() { // Commit if fb modified in any way if (fb_modified) { - CommitFramebuffer(); + CommitColorBuffer(); + CommitDepthBuffer(); } // Reconfigure framebuffer textures if any property has changed if (fb_prop_changed) { - ReconfigColorTexture(fb_color_texture, new_fb_color_format, + ReconfigureColorTexture(fb_color_texture, new_fb_color_format, Pica::registers.framebuffer.GetWidth(), Pica::registers.framebuffer.GetHeight()); - ReconfigDepthTexture(fb_depth_texture, new_fb_depth_format, + ReconfigureDepthTexture(fb_depth_texture, new_fb_depth_format, Pica::registers.framebuffer.GetWidth(), Pica::registers.framebuffer.GetHeight()); // Only attach depth buffer as stencil if it supports stencil @@ -385,10 +355,6 @@ void RasterizerOpenGL::SyncFramebuffer() { last_fb_color_addr = cur_fb_color_addr; last_fb_depth_addr = cur_fb_depth_addr; - // Currently not needed b/c of reloading buffers below, but will be needed for high-res rendering - //glDepthMask(GL_TRUE); - //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - ReloadColorBuffer(); ReloadDepthBuffer(); } @@ -549,7 +515,7 @@ void RasterizerOpenGL::ReloadColorBuffer() { if (color_buffer == nullptr) return; - u32 bytes_per_pixel = ColorFormatBytesPerPixel(fb_color_texture.format); + u32 bytes_per_pixel = Pica::registers.framebuffer.BytesPerColorPixel(fb_color_texture.format); std::unique_ptr temp_fb_color_buffer(new u8[fb_color_texture.width * fb_color_texture.height * bytes_per_pixel]); @@ -626,12 +592,12 @@ void RasterizerOpenGL::ReloadDepthBuffer() { fb_depth_texture.gl_format, fb_depth_texture.gl_type, temp_fb_depth_buffer.get()); } -void RasterizerOpenGL::CommitFramebuffer() { +void RasterizerOpenGL::CommitColorBuffer() { 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); + u32 bytes_per_pixel = Pica::registers.framebuffer.BytesPerColorPixel(fb_color_texture.format); std::unique_ptr temp_gl_color_buffer(new u8[fb_color_texture.width * fb_color_texture.height * bytes_per_pixel]); @@ -656,7 +622,9 @@ void RasterizerOpenGL::CommitFramebuffer() { } } } +} +void RasterizerOpenGL::CommitDepthBuffer() { 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); diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index e41950ffa..f6de10a1d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h @@ -18,10 +18,7 @@ public: /// Initialize API-specific GPU objects void InitObjects() override; - /// Set the window (context) to draw with - void SetWindow(EmuWindow* window) override; - - /// Converts the triangle verts to hardware data format and adds them to the current batch + /// Queues the primitive formed by the given vertices for rendering void AddTriangle(const Pica::VertexShader::OutputVertex& v0, const Pica::VertexShader::OutputVertex& v1, const Pica::VertexShader::OutputVertex& v2) override; @@ -29,8 +26,8 @@ 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(PAddr src_addr, u32 size) override; + /// Notify rasterizer that the specified 3DS memory region will be read from after this notification + void NotifyPreRead(PAddr addr, u32 size) override; /// Notify rasterizer that a 3DS memory region has been changed void NotifyFlush(PAddr addr, u32 size) override; @@ -95,10 +92,10 @@ private: }; /// Reconfigure the OpenGL color texture to use the given format and dimensions - void ReconfigColorTexture(TextureInfo& texture, u32 format, u32 width, u32 height); + void ReconfigureColorTexture(TextureInfo& texture, u32 format, u32 width, u32 height); /// Reconfigure the OpenGL depth texture to use the given format and dimensions - void ReconfigDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height); + void ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height); /// Syncs the state and contents of the OpenGL framebuffer to match the current PICA framebuffer void SyncFramebuffer(); @@ -113,13 +110,19 @@ private: void ReloadDepthBuffer(); /** - * Save the current OpenGL framebuffer to the current PICA framebuffer in 3ds memory + * Save the current OpenGL color 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(); + void CommitColorBuffer(); + + /** + * Save the current OpenGL depth 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 CommitDepthBuffer(); - EmuWindow* render_window; RasterizerCacheOpenGL res_cache; std::vector vertex_batch; diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 581061a02..9b7a40aa8 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -2,7 +2,10 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/make_unique.h" + #include "core/memory.h" + #include "video_core/renderer_opengl/gl_pica_to_gl.h" #include "video_core/renderer_opengl/gl_rasterizer_cache.h" #include "video_core/debug_utils/debug_utils.h" @@ -21,7 +24,7 @@ void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, int texture_u state.texture_units[texture_unit].texture_2d = cached_texture->second->texture.GetHandle(); state.Apply(); } else { - std::unique_ptr new_texture(new CachedTexture()); + std::unique_ptr new_texture = Common::make_unique(); new_texture->texture.Create(); state.texture_units[texture_unit].texture_2d = new_texture->texture.GetHandle(); @@ -31,8 +34,8 @@ void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, int texture_u 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, PicaToGL::WrapMode(config.config.wrap_s.Value())); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, PicaToGL::WrapMode(config.config.wrap_t.Value())); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, PicaToGL::WrapMode(config.config.wrap_s)); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, PicaToGL::WrapMode(config.config.wrap_t)); const auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format); @@ -40,11 +43,12 @@ void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, int texture_u new_texture->height = info.height; new_texture->size = info.width * info.height * Pica::Regs::NibblesPerPixel(info.format); + u8* texture_src_data = Memory::GetPhysicalPointer(texture_addr); std::unique_ptr[]> temp_texture_buffer_rgba(new Math::Vec4[info.width * info.height]); 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); + temp_texture_buffer_rgba[x + info.width * y] = Pica::DebugUtils::LookupTexture(texture_src_data, x, info.height - 1 - y, info); } } @@ -56,7 +60,7 @@ void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, int texture_u 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();) { + for (auto it = texture_cache.begin(); it != texture_cache.upper_bound(addr + 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); diff --git a/src/video_core/renderer_opengl/gl_resource_manager.cpp b/src/video_core/renderer_opengl/gl_resource_manager.cpp index 8edc9bc54..8e57d9877 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.cpp +++ b/src/video_core/renderer_opengl/gl_resource_manager.cpp @@ -5,20 +5,11 @@ #include "video_core/renderer_opengl/gl_resource_manager.h" #include "video_core/renderer_opengl/gl_shader_util.h" -// OGLResource base class -OGLResource::OGLResource() : handle(0) { - -} - -OGLResource::~OGLResource() { - -} - -void OGLResource::Release() { - -} - // Textures +OGLTexture::OGLTexture() : handle(0) { + +} + OGLTexture::~OGLTexture() { Release(); } @@ -37,6 +28,10 @@ void OGLTexture::Release() { } // Shaders +OGLShader::OGLShader() : handle(0) { + +} + OGLShader::~OGLShader() { Release(); } @@ -55,6 +50,10 @@ void OGLShader::Release() { } // Buffer objects +OGLBuffer::OGLBuffer() : handle(0) { + +} + OGLBuffer::~OGLBuffer() { Release(); } @@ -73,6 +72,10 @@ void OGLBuffer::Release() { } // Vertex array objects +OGLVertexArray::OGLVertexArray() : handle(0) { + +} + OGLVertexArray::~OGLVertexArray() { Release(); } @@ -91,6 +94,10 @@ void OGLVertexArray::Release() { } // Framebuffers +OGLFramebuffer::OGLFramebuffer() : handle(0) { + +} + OGLFramebuffer::~OGLFramebuffer() { Release(); } diff --git a/src/video_core/renderer_opengl/gl_resource_manager.h b/src/video_core/renderer_opengl/gl_resource_manager.h index 9d50e4e60..12dacedff 100644 --- a/src/video_core/renderer_opengl/gl_resource_manager.h +++ b/src/video_core/renderer_opengl/gl_resource_manager.h @@ -8,74 +8,102 @@ #include "generated/gl_3_2_core.h" -class OGLResource : NonCopyable { +class OGLTexture : public NonCopyable { public: - OGLResource(); - virtual ~OGLResource(); + OGLTexture(); + ~OGLTexture(); /// Returns the internal OpenGL resource handle for this resource inline GLuint GetHandle() { return handle; } + /// Creates a new internal OpenGL resource and stores the handle + void Create(); + /// Deletes the internal OpenGL resource - virtual void Release(); + void Release(); protected: GLuint handle; }; -class OGLTexture : public OGLResource { +class OGLShader : public NonCopyable { public: - ~OGLTexture() override; + OGLShader(); + ~OGLShader(); - /// Creates a new internal OpenGL resource and stores the handle - void Create(); - - /// Deletes the internal OpenGL resource - void Release() override; -}; - -class OGLShader : public OGLResource { -public: - ~OGLShader() override; + /// Returns the internal OpenGL resource handle for this resource + inline GLuint GetHandle() { + return handle; + } /// Creates a new internal OpenGL resource and stores the handle void Create(const char* vert_shader, const char* frag_shader); /// Deletes the internal OpenGL resource - void Release() override; + void Release(); + +protected: + GLuint handle; }; -class OGLBuffer : public OGLResource { +class OGLBuffer : public NonCopyable { public: - ~OGLBuffer() override; + OGLBuffer(); + ~OGLBuffer(); + + /// Returns the internal OpenGL resource handle for this resource + inline GLuint GetHandle() { + return handle; + } /// Creates a new internal OpenGL resource and stores the handle void Create(); /// Deletes the internal OpenGL resource - void Release() override; + void Release(); + +protected: + GLuint handle; }; -class OGLVertexArray : public OGLResource { +class OGLVertexArray : public NonCopyable { public: - ~OGLVertexArray() override; + OGLVertexArray(); + ~OGLVertexArray(); + + /// Returns the internal OpenGL resource handle for this resource + inline GLuint GetHandle() { + return handle; + } /// Creates a new internal OpenGL resource and stores the handle void Create(); /// Deletes the internal OpenGL resource - void Release() override; + void Release(); + +protected: + GLuint handle; }; -class OGLFramebuffer : public OGLResource { +class OGLFramebuffer : public NonCopyable { public: - ~OGLFramebuffer() override; + OGLFramebuffer(); + ~OGLFramebuffer(); + + /// Returns the internal OpenGL resource handle for this resource + inline GLuint GetHandle() { + return handle; + } /// Creates a new internal OpenGL resource and stores the handle void Create(); /// Deletes the internal OpenGL resource - void Release() override; + void Release(); + +protected: + GLuint handle; }; diff --git a/src/video_core/renderer_opengl/gl_shaders.h b/src/video_core/renderer_opengl/gl_shaders.h index 72bafc2a9..34d3ac28d 100644 --- a/src/video_core/renderer_opengl/gl_shaders.h +++ b/src/video_core/renderer_opengl/gl_shaders.h @@ -191,33 +191,33 @@ vec4 GetSource(int source) { return g_last_tex_env_out; } - return vec4(0.0, 0.0, 0.0, 0.0); + return vec4(0.0); } vec3 GetColorModifier(int factor, vec4 color) { if (factor == COLORMODIFIER_SOURCECOLOR) { return color.rgb; } else if (factor == COLORMODIFIER_ONEMINUSSOURCECOLOR) { - return vec3(1.0, 1.0, 1.0) - color.rgb; + return vec3(1.0) - color.rgb; } else if (factor == COLORMODIFIER_SOURCEALPHA) { return color.aaa; } else if (factor == COLORMODIFIER_ONEMINUSSOURCEALPHA) { - return vec3(1.0, 1.0, 1.0) - color.aaa; + return vec3(1.0) - color.aaa; } else if (factor == COLORMODIFIER_SOURCERED) { return color.rrr; } else if (factor == COLORMODIFIER_ONEMINUSSOURCERED) { - return vec3(1.0, 1.0, 1.0) - color.rrr; + return vec3(1.0) - color.rrr; } else if (factor == COLORMODIFIER_SOURCEGREEN) { return color.ggg; } else if (factor == COLORMODIFIER_ONEMINUSSOURCEGREEN) { - return vec3(1.0, 1.0, 1.0) - color.ggg; + return vec3(1.0) - color.ggg; } else if (factor == COLORMODIFIER_SOURCEBLUE) { return color.bbb; } else if (factor == COLORMODIFIER_ONEMINUSSOURCEBLUE) { - return vec3(1.0, 1.0, 1.0) - color.bbb; + return vec3(1.0) - color.bbb; } - return vec3(0.0, 0.0, 0.0); + return vec3(0.0); } float GetAlphaModifier(int factor, vec4 color) { @@ -250,9 +250,9 @@ vec3 ColorCombine(int op, vec3 color[3]) { } else if (op == OPERATION_ADD) { return min(color[0] + color[1], 1.0); } else if (op == OPERATION_ADDSIGNED) { - return clamp(color[0] + color[1] - vec3(0.5, 0.5, 0.5), 0.0, 1.0); + return clamp(color[0] + color[1] - vec3(0.5), 0.0, 1.0); } else if (op == OPERATION_LERP) { - return color[0] * color[2] + color[1] * (vec3(1.0, 1.0, 1.0) - color[2]); + return color[0] * color[2] + color[1] * (vec3(1.0) - color[2]); } else if (op == OPERATION_SUBTRACT) { return max(color[0] - color[1], 0.0); } else if (op == OPERATION_MULTIPLYTHENADD) { @@ -261,7 +261,7 @@ vec3 ColorCombine(int op, vec3 color[3]) { return min(color[0] + color[1], 1.0) * color[2]; } - return vec3(0.0, 0.0, 0.0); + return vec3(0.0); } float AlphaCombine(int op, float alpha[3]) { diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index a01a661f7..c70d0df12 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp @@ -42,7 +42,7 @@ OpenGLState::OpenGLState() { draw.shader_program = 0; } -void OpenGLState::Apply() { +const void OpenGLState::Apply() { // Culling if (cull.enabled) { if (cull.enabled != cur_state.cull.enabled) { diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index bdd1c7841..a56d31371 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -42,6 +42,7 @@ public: } color; // GL_BLEND_COLOR } blend; + // 3 texture units - one for each that is used in PICA fragment shader emulation struct { bool enabled_2d; // GL_TEXTURE_2D GLuint texture_2d; // GL_TEXTURE_BINDING_2D @@ -57,12 +58,12 @@ public: OpenGLState(); /// Get the currently active OpenGL state - static OpenGLState GetCurState() { + static const OpenGLState& GetCurState() { return cur_state; } /// Apply this state as the current OpenGL state - void Apply(); + const void Apply(); private: 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 5e232b4c6..8b48f80d9 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -348,7 +348,6 @@ void RendererOpenGL::UpdateFramerate() { */ void RendererOpenGL::SetWindow(EmuWindow* window) { render_window = window; - hw_rasterizer->SetWindow(window); } /// Initialize the renderer