From a59a9c0f14e09b3187f88eb4be2e5c67c6ba1f55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gerdau?= Date: Thu, 3 Jun 2021 20:35:09 +0200 Subject: [PATCH 1/2] Implement FindOrCreateBitmap for OpenGL --- Source/gs/GSH_OpenGL/GSH_OpenGL.cpp | 22 ++++++++++++++++++++++ Source/gs/GSH_OpenGL/GSH_OpenGL.h | 5 +++++ 2 files changed, 27 insertions(+) diff --git a/Source/gs/GSH_OpenGL/GSH_OpenGL.cpp b/Source/gs/GSH_OpenGL/GSH_OpenGL.cpp index ba5668b0ca..f2ada9a5cb 100644 --- a/Source/gs/GSH_OpenGL/GSH_OpenGL.cpp +++ b/Source/gs/GSH_OpenGL/GSH_OpenGL.cpp @@ -115,6 +115,7 @@ void CGSH_OpenGL::ResetImpl() PalCache_Flush(); m_framebuffers.clear(); m_depthbuffers.clear(); + m_bitmaps.clear(); m_vertexBuffer.clear(); m_renderState.isValid = false; m_validGlState = 0; @@ -254,6 +255,7 @@ void CGSH_OpenGL::NotifyPreferencesChangedImpl() PalCache_Flush(); m_framebuffers.clear(); m_depthbuffers.clear(); + m_bitmaps.clear(); CGSHandler::NotifyPreferencesChangedImpl(); } @@ -1330,6 +1332,26 @@ CGSH_OpenGL::DepthbufferPtr CGSH_OpenGL::FindDepthbuffer(const ZBUF& zbuf, const return (depthbufferIterator != std::end(m_depthbuffers)) ? *(depthbufferIterator) : DepthbufferPtr(); } +CGSH_OpenGL::BitmapPtr CGSH_OpenGL::FindOrCreateBitmap(const FramebufferPtr& framebuffer, uint32 scale) +{ + auto bitmapIterator = std::find_if(std::begin(m_bitmaps), std::end(m_bitmaps), + [&](const BitmapPtr& bitmap) { + return ( + framebuffer->m_width * scale == bitmap->GetWidth() && + framebuffer->m_height * scale == bitmap->GetHeight() && + bitmap->GetBitsPerPixel() == 32); + }); + if(bitmapIterator != std::end(m_bitmaps)) + { + return *bitmapIterator; + } + + auto sharedPtr = std::make_shared(framebuffer->m_width * scale, framebuffer->m_height * scale, 32); + m_bitmaps.push_back(sharedPtr); + + return sharedPtr; +} + ///////////////////////////////////////////////////////////// // Individual Primitives Implementations ///////////////////////////////////////////////////////////// diff --git a/Source/gs/GSH_OpenGL/GSH_OpenGL.h b/Source/gs/GSH_OpenGL/GSH_OpenGL.h index cc95740c4a..4346b9ebc9 100644 --- a/Source/gs/GSH_OpenGL/GSH_OpenGL.h +++ b/Source/gs/GSH_OpenGL/GSH_OpenGL.h @@ -247,6 +247,9 @@ class CGSH_OpenGL : public CGSHandler, public CGsDebuggerInterface typedef std::shared_ptr FramebufferPtr; typedef std::vector FramebufferList; + typedef std::shared_ptr BitmapPtr; + typedef std::vector BitmapList; + class CDepthbuffer { public: @@ -364,6 +367,7 @@ class CGSH_OpenGL : public CGSHandler, public CGsDebuggerInterface FramebufferPtr FindFramebuffer(const FRAME&) const; DepthbufferPtr FindDepthbuffer(const ZBUF&, const FRAME&) const; + BitmapPtr FindOrCreateBitmap(const FramebufferPtr&, uint32); void DumpTexture(unsigned int, unsigned int, uint32); @@ -426,6 +430,7 @@ class CGSH_OpenGL : public CGSHandler, public CGsDebuggerInterface PaletteList m_paletteCache; FramebufferList m_framebuffers; DepthbufferList m_depthbuffers; + BitmapList m_bitmaps; Framework::OpenGl::CBuffer m_primBuffer; Framework::OpenGl::CVertexArray m_primVertexArray; From 5a32f9e15bd56a0a277f26955535fbee040ff033 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Gerdau?= Date: Thu, 3 Jun 2021 19:18:44 +0200 Subject: [PATCH 2/2] Persist CLUT framebuffer to GS memory Required by DBZ Budokai Tenkaichi 2 for CLUT rendering of characters --- Source/gs/GSH_OpenGL/GSH_OpenGL.cpp | 102 ++++++++++++++++++++++++++++ Source/gs/GSH_OpenGL/GSH_OpenGL.h | 5 ++ 2 files changed, 107 insertions(+) diff --git a/Source/gs/GSH_OpenGL/GSH_OpenGL.cpp b/Source/gs/GSH_OpenGL/GSH_OpenGL.cpp index f2ada9a5cb..5002771d05 100644 --- a/Source/gs/GSH_OpenGL/GSH_OpenGL.cpp +++ b/Source/gs/GSH_OpenGL/GSH_OpenGL.cpp @@ -1352,6 +1352,15 @@ CGSH_OpenGL::BitmapPtr CGSH_OpenGL::FindOrCreateBitmap(const FramebufferPtr& fra return sharedPtr; } +CGSH_OpenGL::FramebufferPtr CGSH_OpenGL::FindFramebufferAtPtr(uint32 ptr, uint32 psm) const +{ + auto framebufferIterator = std::find_if(m_framebuffers.begin(), m_framebuffers.end(), + [ptr, psm](const FramebufferPtr& framebuffer) { + return framebuffer->m_psm == psm && framebuffer->m_basePtr == ptr; + }); + return (framebufferIterator != std::end(m_framebuffers)) ? *(framebufferIterator) : FramebufferPtr(); +} + ///////////////////////////////////////////////////////////// // Individual Primitives Implementations ///////////////////////////////////////////////////////////// @@ -1672,6 +1681,15 @@ void CGSH_OpenGL::FlushVertexBuffer() } DoRenderPass(); m_vertexBuffer.clear(); + + auto handle = m_renderState.framebufferHandle; + auto framebufferIterator = std::find_if(m_framebuffers.begin(), m_framebuffers.end(), + [handle](const FramebufferPtr& framebuffer) { + return (framebuffer->m_framebuffer == handle); + }); + const auto& framebuffer = (*framebufferIterator); + + framebuffer->copiedToRam = false; } void CGSH_OpenGL::DoRenderPass() @@ -1926,6 +1944,90 @@ void CGSH_OpenGL::WriteRegisterImpl(uint8 nRegister, uint64 nData) } } +void CGSH_OpenGL::SyncCLUT(const TEX0& tex0) +{ + if(!ProcessCLD(tex0)) return; + + // If we use a CLUT based texture, its possible that the memory + // referenced is inside a framebuffer. In that case, we need + // to persist the framebuffer content into the GS RAM. + + if(CGsPixelFormats::IsPsmIDTEX(tex0.nPsm)) + { + const uint32 ptr = tex0.GetCLUTPtr(); + + FramebufferPtr framebuffer = FindFramebufferAtPtr(ptr, PSMCT32); + if(framebuffer) + { + WriteFramebufferToMemory(framebuffer, true); + } + } + + CGSHandler::SyncCLUT(tex0); +} + +void CGSH_OpenGL::WriteFramebufferToMemory(const FramebufferPtr& framebuffer, bool downSample) +{ + // If the framebuffer has already been persisted to RAM, + // we don't need to do that again. + if(framebuffer->copiedToRam) + { + return; + } + + FramebufferPtr targetFramebuffer = framebuffer; + uint32 scale = m_fbScale; + + if(downSample && m_fbScale != 1) + { + auto dstFramebuffer = FramebufferPtr(new CFramebuffer( + framebuffer->m_basePtr, + framebuffer->m_width, + framebuffer->m_height, + framebuffer->m_psm, + 1, + m_multisampleEnabled)); + PopulateFramebuffer(dstFramebuffer); + + glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer->m_framebuffer); + glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer->m_framebuffer); + + //Copy buffers + glBlitFramebuffer( + 0, 0, framebuffer->m_width * m_fbScale, framebuffer->m_height * m_fbScale, + 0, 0, dstFramebuffer->m_width, dstFramebuffer->m_height, + GL_COLOR_BUFFER_BIT, GL_NEAREST); + CHECKGLERROR(); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + + targetFramebuffer = dstFramebuffer; + scale = 1; + } + + glBindFramebuffer(GL_FRAMEBUFFER, targetFramebuffer->m_framebuffer); + + // ---------------------- + + // Read data into ram + + auto imgbuffer = FindOrCreateBitmap(targetFramebuffer, scale); + glReadPixels(0, 0, targetFramebuffer->m_width * scale, targetFramebuffer->m_height * scale, GL_RGBA, GL_UNSIGNED_BYTE, imgbuffer->GetPixels()); + + CGsPixelFormats::CPixelIndexorPSMCT32 indexor(m_pRAM, targetFramebuffer->m_basePtr, targetFramebuffer->m_width / 64); + for(uint32 y = 0; y < targetFramebuffer->m_height; y++) + { + for(uint32 x = 0; x < targetFramebuffer->m_width; x++) + { + auto pixel = imgbuffer->GetPixel(x * scale, y * scale); + indexor.SetPixel(x, y, MakeColor(pixel.r, pixel.g, pixel.b, pixel.a)); + } + } + + framebuffer->copiedToRam = true; + + glBindFramebuffer(GL_FRAMEBUFFER, m_renderState.framebufferHandle); +} + void CGSH_OpenGL::VertexKick(uint8 nRegister, uint64 nValue) { if(m_nVtxCount == 0) return; diff --git a/Source/gs/GSH_OpenGL/GSH_OpenGL.h b/Source/gs/GSH_OpenGL/GSH_OpenGL.h index 4346b9ebc9..4170558c73 100644 --- a/Source/gs/GSH_OpenGL/GSH_OpenGL.h +++ b/Source/gs/GSH_OpenGL/GSH_OpenGL.h @@ -242,6 +242,8 @@ class CGSH_OpenGL : public CGSHandler, public CGsDebuggerInterface bool m_resolveNeeded = false; GLuint m_colorBufferMs = 0; + bool copiedToRam = false; + CGsCachedArea m_cachedArea; }; typedef std::shared_ptr FramebufferPtr; @@ -307,6 +309,7 @@ class CGSH_OpenGL : public CGSHandler, public CGsDebuggerInterface typedef std::vector VertexBuffer; void WriteRegisterImpl(uint8, uint64) override; + void SyncCLUT(const TEX0&) override; void InitializeRC(); void CheckExtensions(); @@ -368,6 +371,8 @@ class CGSH_OpenGL : public CGSHandler, public CGsDebuggerInterface FramebufferPtr FindFramebuffer(const FRAME&) const; DepthbufferPtr FindDepthbuffer(const ZBUF&, const FRAME&) const; BitmapPtr FindOrCreateBitmap(const FramebufferPtr&, uint32); + FramebufferPtr FindFramebufferAtPtr(uint32, uint32) const; + void WriteFramebufferToMemory(const FramebufferPtr&, bool); void DumpTexture(unsigned int, unsigned int, uint32);