Skip to content

Commit a4c484a

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

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
@@ -1358,6 +1358,15 @@ CGSH_OpenGL::BitmapPtr CGSH_OpenGL::FindOrCreateBitmap(const FramebufferPtr& fra
13581358
return sharedPtr;
13591359
}
13601360

1361+
CGSH_OpenGL::FramebufferPtr CGSH_OpenGL::FindFramebufferAtPtr(uint32 ptr, uint32 psm) const
1362+
{
1363+
auto framebufferIterator = std::find_if(m_framebuffers.begin(), m_framebuffers.end(),
1364+
[ptr, psm](const FramebufferPtr& framebuffer) {
1365+
return framebuffer->m_psm == psm && framebuffer->m_basePtr == ptr;
1366+
});
1367+
return (framebufferIterator != std::end(m_framebuffers)) ? *(framebufferIterator) : FramebufferPtr();
1368+
}
1369+
13611370
/////////////////////////////////////////////////////////////
13621371
// Individual Primitives Implementations
13631372
/////////////////////////////////////////////////////////////
@@ -1643,6 +1652,15 @@ void CGSH_OpenGL::FlushVertexBuffer()
16431652
}
16441653
DoRenderPass();
16451654
m_vertexBuffer.clear();
1655+
1656+
auto handle = m_renderState.framebufferHandle;
1657+
auto framebufferIterator = std::find_if(m_framebuffers.begin(), m_framebuffers.end(),
1658+
[handle](const FramebufferPtr& framebuffer) {
1659+
return (framebuffer->m_framebuffer == handle);
1660+
});
1661+
const auto& framebuffer = (*framebufferIterator);
1662+
1663+
framebuffer->copiedToRam = false;
16461664
}
16471665

16481666
void CGSH_OpenGL::DoRenderPass()
@@ -1897,6 +1915,90 @@ void CGSH_OpenGL::WriteRegisterImpl(uint8 nRegister, uint64 nData)
18971915
}
18981916
}
18991917

1918+
void CGSH_OpenGL::SyncCLUT(const TEX0& tex0)
1919+
{
1920+
if(!ProcessCLD(tex0)) return;
1921+
1922+
// If we use a CLUT based texture, its possible that the memory
1923+
// referenced is inside a framebuffer. In that case, we need
1924+
// to persist the framebuffer content into the GS RAM.
1925+
1926+
if(CGsPixelFormats::IsPsmIDTEX(tex0.nPsm))
1927+
{
1928+
const uint32 ptr = tex0.GetCLUTPtr();
1929+
1930+
FramebufferPtr framebuffer = FindFramebufferAtPtr(ptr, PSMCT32);
1931+
if(framebuffer)
1932+
{
1933+
WriteFramebufferToMemory(framebuffer, true);
1934+
}
1935+
}
1936+
1937+
CGSHandler::SyncCLUT(tex0);
1938+
}
1939+
1940+
void CGSH_OpenGL::WriteFramebufferToMemory(const FramebufferPtr& framebuffer, bool downSample)
1941+
{
1942+
// If the framebuffer has already been persisted to RAM,
1943+
// we don't need to do that again.
1944+
if(framebuffer->copiedToRam)
1945+
{
1946+
return;
1947+
}
1948+
1949+
FramebufferPtr targetFramebuffer = framebuffer;
1950+
uint32 scale = m_fbScale;
1951+
1952+
if(downSample && m_fbScale != 1)
1953+
{
1954+
auto dstFramebuffer = FramebufferPtr(new CFramebuffer(
1955+
framebuffer->m_basePtr,
1956+
framebuffer->m_width,
1957+
framebuffer->m_height,
1958+
framebuffer->m_psm,
1959+
1,
1960+
m_multisampleEnabled));
1961+
PopulateFramebuffer(dstFramebuffer);
1962+
1963+
glBindFramebuffer(GL_FRAMEBUFFER, dstFramebuffer->m_framebuffer);
1964+
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer->m_framebuffer);
1965+
1966+
//Copy buffers
1967+
glBlitFramebuffer(
1968+
0, 0, framebuffer->m_width * m_fbScale, framebuffer->m_height * m_fbScale,
1969+
0, 0, dstFramebuffer->m_width, dstFramebuffer->m_height,
1970+
GL_COLOR_BUFFER_BIT, GL_NEAREST);
1971+
CHECKGLERROR();
1972+
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
1973+
1974+
targetFramebuffer = dstFramebuffer;
1975+
scale = 1;
1976+
}
1977+
1978+
glBindFramebuffer(GL_FRAMEBUFFER, targetFramebuffer->m_framebuffer);
1979+
1980+
// ----------------------
1981+
1982+
// Read data into ram
1983+
1984+
auto imgbuffer = FindOrCreateBitmap(targetFramebuffer, scale);
1985+
glReadPixels(0, 0, targetFramebuffer->m_width * scale, targetFramebuffer->m_height * scale, GL_RGBA, GL_UNSIGNED_BYTE, imgbuffer->GetPixels());
1986+
1987+
CGsPixelFormats::CPixelIndexorPSMCT32 indexor(m_pRAM, targetFramebuffer->m_basePtr, targetFramebuffer->m_width / 64);
1988+
for(uint32 y = 0; y < targetFramebuffer->m_height; y++)
1989+
{
1990+
for(uint32 x = 0; x < targetFramebuffer->m_width; x++)
1991+
{
1992+
auto pixel = imgbuffer->GetPixel(x * scale, y * scale);
1993+
indexor.SetPixel(x, y, MakeColor(pixel.r, pixel.g, pixel.b, pixel.a));
1994+
}
1995+
}
1996+
1997+
framebuffer->copiedToRam = true;
1998+
1999+
glBindFramebuffer(GL_FRAMEBUFFER, m_renderState.framebufferHandle);
2000+
}
2001+
19002002
void CGSH_OpenGL::VertexKick(uint8 nRegister, uint64 nValue)
19012003
{
19022004
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
@@ -247,6 +247,8 @@ class CGSH_OpenGL : public CGSHandler
247247
bool m_resolveNeeded = false;
248248
GLuint m_colorBufferMs = 0;
249249

250+
bool copiedToRam = false;
251+
250252
CGsCachedArea m_cachedArea;
251253
};
252254
typedef std::shared_ptr<CFramebuffer> FramebufferPtr;
@@ -312,6 +314,7 @@ class CGSH_OpenGL : public CGSHandler
312314
typedef std::vector<PRIM_VERTEX> VertexBuffer;
313315

314316
void WriteRegisterImpl(uint8, uint64) override;
317+
void SyncCLUT(const TEX0&) override;
315318

316319
void InitializeRC();
317320
void CheckExtensions();
@@ -373,6 +376,8 @@ class CGSH_OpenGL : public CGSHandler
373376
FramebufferPtr FindFramebuffer(const FRAME&) const;
374377
DepthbufferPtr FindDepthbuffer(const ZBUF&, const FRAME&) const;
375378
BitmapPtr FindOrCreateBitmap(const FramebufferPtr&, uint32);
379+
FramebufferPtr FindFramebufferAtPtr(uint32, uint32) const;
380+
void WriteFramebufferToMemory(const FramebufferPtr&, bool);
376381

377382
void DumpTexture(unsigned int, unsigned int, uint32);
378383

0 commit comments

Comments
 (0)