Skip to content

Commit 5a32f9e

Browse files
committed
Persist CLUT framebuffer to GS memory
Required by DBZ Budokai Tenkaichi 2 for CLUT rendering of characters
1 parent a59a9c0 commit 5a32f9e

File tree

2 files changed

+107
-0
lines changed

2 files changed

+107
-0
lines changed

Source/gs/GSH_OpenGL/GSH_OpenGL.cpp

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1352,6 +1352,15 @@ CGSH_OpenGL::BitmapPtr CGSH_OpenGL::FindOrCreateBitmap(const FramebufferPtr& fra
13521352
return sharedPtr;
13531353
}
13541354

1355+
CGSH_OpenGL::FramebufferPtr CGSH_OpenGL::FindFramebufferAtPtr(uint32 ptr, uint32 psm) const
1356+
{
1357+
auto framebufferIterator = std::find_if(m_framebuffers.begin(), m_framebuffers.end(),
1358+
[ptr, psm](const FramebufferPtr& framebuffer) {
1359+
return framebuffer->m_psm == psm && framebuffer->m_basePtr == ptr;
1360+
});
1361+
return (framebufferIterator != std::end(m_framebuffers)) ? *(framebufferIterator) : FramebufferPtr();
1362+
}
1363+
13551364
/////////////////////////////////////////////////////////////
13561365
// Individual Primitives Implementations
13571366
/////////////////////////////////////////////////////////////
@@ -1672,6 +1681,15 @@ void CGSH_OpenGL::FlushVertexBuffer()
16721681
}
16731682
DoRenderPass();
16741683
m_vertexBuffer.clear();
1684+
1685+
auto handle = m_renderState.framebufferHandle;
1686+
auto framebufferIterator = std::find_if(m_framebuffers.begin(), m_framebuffers.end(),
1687+
[handle](const FramebufferPtr& framebuffer) {
1688+
return (framebuffer->m_framebuffer == handle);
1689+
});
1690+
const auto& framebuffer = (*framebufferIterator);
1691+
1692+
framebuffer->copiedToRam = false;
16751693
}
16761694

16771695
void CGSH_OpenGL::DoRenderPass()
@@ -1926,6 +1944,90 @@ void CGSH_OpenGL::WriteRegisterImpl(uint8 nRegister, uint64 nData)
19261944
}
19271945
}
19281946

1947+
void CGSH_OpenGL::SyncCLUT(const TEX0& tex0)
1948+
{
1949+
if(!ProcessCLD(tex0)) return;
1950+
1951+
// If we use a CLUT based texture, its possible that the memory
1952+
// referenced is inside a framebuffer. In that case, we need
1953+
// to persist the framebuffer content into the GS RAM.
1954+
1955+
if(CGsPixelFormats::IsPsmIDTEX(tex0.nPsm))
1956+
{
1957+
const uint32 ptr = tex0.GetCLUTPtr();
1958+
1959+
FramebufferPtr framebuffer = FindFramebufferAtPtr(ptr, PSMCT32);
1960+
if(framebuffer)
1961+
{
1962+
WriteFramebufferToMemory(framebuffer, true);
1963+
}
1964+
}
1965+
1966+
CGSHandler::SyncCLUT(tex0);
1967+
}
1968+
1969+
void CGSH_OpenGL::WriteFramebufferToMemory(const FramebufferPtr& framebuffer, bool downSample)
1970+
{
1971+
// If the framebuffer has already been persisted to RAM,
1972+
// we don't need to do that again.
1973+
if(framebuffer->copiedToRam)
1974+
{
1975+
return;
1976+
}
1977+
1978+
FramebufferPtr targetFramebuffer = framebuffer;
1979+
uint32 scale = m_fbScale;
1980+
1981+
if(downSample && m_fbScale != 1)
1982+
{
1983+
auto dstFramebuffer = FramebufferPtr(new CFramebuffer(
1984+
framebuffer->m_basePtr,
1985+
framebuffer->m_width,
1986+
framebuffer->m_height,
1987+
framebuffer->m_psm,
1988+
1,
1989+
m_multisampleEnabled));
1990+
PopulateFramebuffer(dstFramebuffer);
1991+
1992+
glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer->m_framebuffer);
1993+
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer->m_framebuffer);
1994+
1995+
//Copy buffers
1996+
glBlitFramebuffer(
1997+
0, 0, framebuffer->m_width * m_fbScale, framebuffer->m_height * m_fbScale,
1998+
0, 0, dstFramebuffer->m_width, dstFramebuffer->m_height,
1999+
GL_COLOR_BUFFER_BIT, GL_NEAREST);
2000+
CHECKGLERROR();
2001+
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
2002+
2003+
targetFramebuffer = dstFramebuffer;
2004+
scale = 1;
2005+
}
2006+
2007+
glBindFramebuffer(GL_FRAMEBUFFER, targetFramebuffer->m_framebuffer);
2008+
2009+
// ----------------------
2010+
2011+
// Read data into ram
2012+
2013+
auto imgbuffer = FindOrCreateBitmap(targetFramebuffer, scale);
2014+
glReadPixels(0, 0, targetFramebuffer->m_width * scale, targetFramebuffer->m_height * scale, GL_RGBA, GL_UNSIGNED_BYTE, imgbuffer->GetPixels());
2015+
2016+
CGsPixelFormats::CPixelIndexorPSMCT32 indexor(m_pRAM, targetFramebuffer->m_basePtr, targetFramebuffer->m_width / 64);
2017+
for(uint32 y = 0; y < targetFramebuffer->m_height; y++)
2018+
{
2019+
for(uint32 x = 0; x < targetFramebuffer->m_width; x++)
2020+
{
2021+
auto pixel = imgbuffer->GetPixel(x * scale, y * scale);
2022+
indexor.SetPixel(x, y, MakeColor(pixel.r, pixel.g, pixel.b, pixel.a));
2023+
}
2024+
}
2025+
2026+
framebuffer->copiedToRam = true;
2027+
2028+
glBindFramebuffer(GL_FRAMEBUFFER, m_renderState.framebufferHandle);
2029+
}
2030+
19292031
void CGSH_OpenGL::VertexKick(uint8 nRegister, uint64 nValue)
19302032
{
19312033
if(m_nVtxCount == 0) return;

Source/gs/GSH_OpenGL/GSH_OpenGL.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,8 @@ class CGSH_OpenGL : public CGSHandler, public CGsDebuggerInterface
242242
bool m_resolveNeeded = false;
243243
GLuint m_colorBufferMs = 0;
244244

245+
bool copiedToRam = false;
246+
245247
CGsCachedArea m_cachedArea;
246248
};
247249
typedef std::shared_ptr<CFramebuffer> FramebufferPtr;
@@ -307,6 +309,7 @@ class CGSH_OpenGL : public CGSHandler, public CGsDebuggerInterface
307309
typedef std::vector<PRIM_VERTEX> VertexBuffer;
308310

309311
void WriteRegisterImpl(uint8, uint64) override;
312+
void SyncCLUT(const TEX0&) override;
310313

311314
void InitializeRC();
312315
void CheckExtensions();
@@ -368,6 +371,8 @@ class CGSH_OpenGL : public CGSHandler, public CGsDebuggerInterface
368371
FramebufferPtr FindFramebuffer(const FRAME&) const;
369372
DepthbufferPtr FindDepthbuffer(const ZBUF&, const FRAME&) const;
370373
BitmapPtr FindOrCreateBitmap(const FramebufferPtr&, uint32);
374+
FramebufferPtr FindFramebufferAtPtr(uint32, uint32) const;
375+
void WriteFramebufferToMemory(const FramebufferPtr&, bool);
371376

372377
void DumpTexture(unsigned int, unsigned int, uint32);
373378

0 commit comments

Comments
 (0)