From c6c71bb9b226b6353582f599ef17d97e0fc54373 Mon Sep 17 00:00:00 2001 From: GPUCode Date: Wed, 26 Jul 2023 22:34:39 +0300 Subject: [PATCH] renderer_gl: Implement semi proper clears --- include/renderer_gl/opengl.hpp | 12 +++---- include/renderer_gl/surfaces.hpp | 8 ++++- src/core/renderer_gl/renderer_gl.cpp | 41 ++++++++++++++++++----- src/core/services/gsp_gpu.cpp | 50 ++++++++++++++-------------- 4 files changed, 71 insertions(+), 40 deletions(-) diff --git a/include/renderer_gl/opengl.hpp b/include/renderer_gl/opengl.hpp index f8328799..c1ceb4c7 100644 --- a/include/renderer_gl/opengl.hpp +++ b/include/renderer_gl/opengl.hpp @@ -333,18 +333,18 @@ namespace OpenGL { void bind(FramebufferTypes target) const { bind(static_cast(target)); } void free() { glDeleteFramebuffers(1, &m_handle); } - void createWithTexture(Texture& tex, GLenum mode = GL_FRAMEBUFFER, GLenum textureType = GL_TEXTURE_2D) { + void createWithTexture(Texture& tex, GLenum mode = GL_FRAMEBUFFER, GLenum attachment = GL_COLOR_ATTACHMENT0, GLenum textureType = GL_TEXTURE_2D) { m_textureType = textureType; create(); bind(mode); - glFramebufferTexture2D(mode, GL_COLOR_ATTACHMENT0, textureType, tex.handle(), 0); + glFramebufferTexture2D(mode, attachment, textureType, tex.handle(), 0); } - void createWithReadTexture(Texture& tex, GLenum textureType = GL_TEXTURE_2D) { - createWithTexture(tex, GL_READ_FRAMEBUFFER, textureType); + void createWithReadTexture(Texture& tex, GLenum attachment = GL_COLOR_ATTACHMENT0, GLenum textureType = GL_TEXTURE_2D) { + createWithTexture(tex, GL_READ_FRAMEBUFFER, attachment, textureType); } - void createWithDrawTexture(Texture& tex, GLenum textureType = GL_TEXTURE_2D) { - createWithTexture(tex, GL_DRAW_FRAMEBUFFER, textureType); + void createWithDrawTexture(Texture& tex, GLenum attachment = GL_COLOR_ATTACHMENT0, GLenum textureType = GL_TEXTURE_2D) { + createWithTexture(tex, GL_DRAW_FRAMEBUFFER, attachment, textureType); } void createWithTextureMSAA(Texture& tex, GLenum mode = GL_FRAMEBUFFER) { diff --git a/include/renderer_gl/surfaces.hpp b/include/renderer_gl/surfaces.hpp index 1d46e28e..a77729c4 100644 --- a/include/renderer_gl/surfaces.hpp +++ b/include/renderer_gl/surfaces.hpp @@ -86,6 +86,7 @@ struct DepthBuffer { Interval range; // OpenGL texture used for storing depth/stencil OpenGL::Texture texture; + OpenGL::Framebuffer fbo; DepthBuffer() : valid(false) {} @@ -127,6 +128,11 @@ struct DepthBuffer { texture.setMagFilter(OpenGL::Nearest); glBindTexture(GL_TEXTURE_2D, prevTexture); + + fbo.createWithDrawTexture(texture, fmt == GL_DEPTH_STENCIL ? GL_DEPTH_STENCIL_ATTACHMENT : GL_DEPTH_ATTACHMENT); + + if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) + Helpers::panic("Incomplete framebuffer"); } void free() { @@ -144,4 +150,4 @@ struct DepthBuffer { size_t sizeInBytes() { return (size_t)size.x() * (size_t)size.y() * PICA::sizePerPixel(format); } -}; \ No newline at end of file +}; diff --git a/src/core/renderer_gl/renderer_gl.cpp b/src/core/renderer_gl/renderer_gl.cpp index dc21b744..c1c79b2f 100644 --- a/src/core/renderer_gl/renderer_gl.cpp +++ b/src/core/renderer_gl/renderer_gl.cpp @@ -472,14 +472,8 @@ void RendererGL::display() { } void RendererGL::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 control) { - return; log("GPU: Clear buffer\nStart: %08X End: %08X\nValue: %08X Control: %08X\n", startAddress, endAddress, value, control); - const float r = float(getBits<24, 8>(value)) / 255.0f; - const float g = float(getBits<16, 8>(value)) / 255.0f; - const float b = float(getBits<8, 8>(value)) / 255.0f; - const float a = float(value & 0xff) / 255.0f; - if (startAddress == topScreenBuffer) { log("GPU: Cleared top screen\n"); } else if (startAddress == bottomScreenBuffer) { @@ -489,8 +483,39 @@ void RendererGL::clearBuffer(u32 startAddress, u32 endAddress, u32 value, u32 co log("GPU: Clearing some unknown buffer\n"); } - OpenGL::setClearColor(r, g, b, a); - OpenGL::clearColor(); + const auto color = colourBufferCache.findFromAddress(startAddress); + if (color) { + const float r = getBits<24, 8>(value) / 255.0f; + const float g = getBits<16, 8>(value) / 255.0f; + const float b = getBits<8, 8>(value) / 255.0f; + const float a = (value & 0xff) / 255.0f; + color->get().fbo.bind(OpenGL::DrawFramebuffer); + gl.setColourMask(true, true, true, true); + OpenGL::setClearColor(r, g, b, a); + OpenGL::clearColor(); + return; + } + const auto depth = depthBufferCache.findFromAddress(startAddress); + if (depth) { + float depthVal; + const auto format = depth->get().format; + if (format == DepthFmt::Depth16) { + depthVal = (value & 0xffff) / 65535.0f; + } else { + depthVal = (value & 0xffffff) / 16777215.0f; + } + depth->get().fbo.bind(OpenGL::DrawFramebuffer); + OpenGL::setDepthMask(true); + OpenGL::setClearDepth(depthVal); + OpenGL::clearDepth(); + if (format == DepthFmt::Depth24Stencil8) { + const u8 stencil = (value >> 24); + OpenGL::setStencilMask(0xFF); + OpenGL::setClearStencil(stencil); + } + return; + } + Helpers::warn("GPU: No buffer found!\n"); } OpenGL::Framebuffer RendererGL::getColourFBO() { diff --git a/src/core/services/gsp_gpu.cpp b/src/core/services/gsp_gpu.cpp index 5179aec8..5d4b27a4 100644 --- a/src/core/services/gsp_gpu.cpp +++ b/src/core/services/gsp_gpu.cpp @@ -299,6 +299,28 @@ void GPUService::processCommandBuffer() { } } +static u32 VaddrToPaddr(u32 addr) { + if (addr >= VirtualAddrs::VramStart && addr < (VirtualAddrs::VramStart + VirtualAddrs::VramSize)) [[likely]] { + return addr - VirtualAddrs::VramStart + PhysicalAddrs::VRAM; + } + + else if (addr >= VirtualAddrs::LinearHeapStartOld && addr < VirtualAddrs::LinearHeapEndOld) { + return addr - VirtualAddrs::LinearHeapStartOld + PhysicalAddrs::FCRAM; + } + + else if (addr >= VirtualAddrs::LinearHeapStartNew && addr < VirtualAddrs::LinearHeapEndNew) { + return addr - VirtualAddrs::LinearHeapStartNew + PhysicalAddrs::FCRAM; + } + + else if (addr == 0) { + return 0; + } + + Helpers::warn("[GSP::GPU VaddrToPaddr] Unknown virtual address %08X", addr); + // Obviously garbage address + return 0xF3310932; +} + // Fill 2 GPU framebuffers, buf0 and buf1, using a specific word value void GPUService::memoryFill(u32* cmd) { u32 control = cmd[7]; @@ -316,38 +338,16 @@ void GPUService::memoryFill(u32* cmd) { u32 control1 = control >> 16; if (start0 != 0) { - gpu.clearBuffer(start0, end0, value0, control0); + gpu.clearBuffer(VaddrToPaddr(start0), VaddrToPaddr(end0), value0, control0); requestInterrupt(GPUInterrupt::PSC0); } if (start1 != 0) { - gpu.clearBuffer(start1, end1, value1, control1); + gpu.clearBuffer(VaddrToPaddr(start1), VaddrToPaddr(end1), value1, control1); requestInterrupt(GPUInterrupt::PSC1); } } -static u32 VaddrToPaddr(u32 addr) { - if (addr >= VirtualAddrs::VramStart && addr < (VirtualAddrs::VramStart + VirtualAddrs::VramSize)) [[likely]] { - return addr - VirtualAddrs::VramStart + PhysicalAddrs::VRAM; - } - - else if (addr >= VirtualAddrs::LinearHeapStartOld && addr < VirtualAddrs::LinearHeapEndOld) { - return addr - VirtualAddrs::LinearHeapStartOld + PhysicalAddrs::FCRAM; - } - - else if (addr >= VirtualAddrs::LinearHeapStartNew && addr < VirtualAddrs::LinearHeapEndNew) { - return addr - VirtualAddrs::LinearHeapStartNew + PhysicalAddrs::FCRAM; - } - - else if (addr == 0) { - return 0; - } - - Helpers::warn("[GSP::GPU VaddrToPaddr] Unknown virtual address %08X", addr); - // Obviously garbage address - return 0xF3310932; -} - void GPUService::triggerDisplayTransfer(u32* cmd) { const u32 inputAddr = VaddrToPaddr(cmd[1]); const u32 outputAddr = VaddrToPaddr(cmd[2]); @@ -394,4 +394,4 @@ void GPUService::triggerTextureCopy(u32* cmd) { // This uses the transfer engine and thus needs to fire a PPF interrupt. // NSMB2 relies on this requestInterrupt(GPUInterrupt::PPF); -} \ No newline at end of file +}