-
Notifications
You must be signed in to change notification settings - Fork 181
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
F3DEX3: support gSPMemset for graphics buffers #2895
base: master
Are you sure you want to change the base?
Conversation
CI seems to be broken, I do not believe this PR caused any issues on Linux build. |
It's not your fault =P Edit: Upon closer inspection, several dependencies are missing ( |
src/gDP.cpp
Outdated
@@ -792,6 +797,126 @@ void gDPSetScissor(u32 mode, s16 xh, s16 yh, s16 xl, s16 yl) | |||
#endif | |||
} | |||
|
|||
template<typename T> | |||
class BackupRestore |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We already have similar class: ValueKeeper in Types.h
src/gDP.cpp
Outdated
GraphicsDrawer& drawer = dwnd().getDrawer(); | ||
u32 fillColor = value | (value << 16); | ||
const u32 depthImageStart = gDP.depthImageAddress; | ||
const u32 depthImageEnd = gDP.depthImageAddress + 320 * 240 * 2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
320 * 240 * 2
Is depth buffer size hardcoded in the Ucode?
May be it should be screenWidth * screenHeight * 2 ?
const u32 screenWidth = VI.width; | ||
const u32 screenHeight = VI.height; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
VI.width and VI.height are unreliable.
If gDPMemset is used for clearing existing color or depth buffer, the "addr" should point inside some buffer.
You may find that buffer by
FrameBuffer * pBuffer = frameBufferList().findBuffer(addr);
And then use pBuffer->m_width, pBuffer->m_height
You also may use
pBuffer->m_isDepthBuffer
instead of your check (depthImageStart <= addr && addr < depthImageEnd)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, its most common use case is to clean ZB or FB. Here's an example to clear ZB in HackerOOT with respective f3dzex replacement https://github.com/HackerN64/HackerOoT/blob/e6fca950b79ec7561ac5cf52dcab14c84928a03f/src/code/z_rcp.c#L1569
I will try to implement the mentioned improvement.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also do not believe it is possible to use the same approach for ZB because of a hack I had to explicitly save the buffer
frameBufferList().saveBuffer(gDP.depthImageAddress, (u16)G_IM_FMT_RGBA, (u16)G_IM_SIZ_16b, (u16)screenWidth, false);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another issue I discovered trying to implement this is that no fb emulation mode breaks. I assume that is due to frameBufferList()
being empty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have introduced a separate branch for fb emulation enabled. Implementation should be ready for review
src/gDP.cpp
Outdated
const u32 colorSize = gDP.colorImage.size < 3 ? 2 : 4; | ||
const u32 colorImageStart = gDP.colorImage.address; | ||
const u32 colorImageEnd = gDP.colorImage.address + screenWidth * screenHeight * colorSize; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Color image can be 8bit. So, it is better
const u32 colorSize = gDP.colorImage.size < 3 ? 2 : 4; | |
const u32 colorImageStart = gDP.colorImage.address; | |
const u32 colorImageEnd = gDP.colorImage.address + screenWidth * screenHeight * colorSize; | |
const u32 colorImageStart = gDP.colorImage.address; | |
const u32 colorImageEnd = gDP.colorImage.address + ((screenWidth * screenHeight) << gDP.colorImage.size >> 1); |
src/gDP.cpp
Outdated
return; | ||
} | ||
|
||
// Either RGBA16 or RGBA32. This heavily assume "niceness" of developers to bind color buffer before memset... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you use my suggestion with
FrameBuffer * pBuffer = frameBufferList().findBuffer(addr);
your code will not depend on that assumption, and developers can use any buffer, which was bound previously with gDPSetColorImage (or with gDPSetDepthImage).
If pBuffer is null, the addr doesn't point to any buffer, so you fallback to just memory set.
src/gDP.cpp
Outdated
// Pretend that we are drawing the rectangle over ZB with fill mode | ||
BackupRestore backupColorImageAddress(gDP.colorImage.address); | ||
BackupRestore backupWidth(gDP.colorImage.width); | ||
const unsigned int backupDepthSource = gDP.otherMode.depthSource; | ||
const unsigned int backupCycleType = gDP.otherMode.cycleType; | ||
|
||
gDP.colorImage.address = gDP.depthImageAddress; | ||
gDP.colorImage.width = screenWidth; | ||
gDP.otherMode.cycleType = G_CYC_FILL; | ||
|
||
drawer.drawRect(ulx, uly, lrx, lry); | ||
frameBufferList().setBufferChanged(f32(lry)); | ||
|
||
gDP.otherMode.depthSource = backupDepthSource; | ||
gDP.otherMode.cycleType = backupCycleType; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// Pretend that we are drawing the rectangle over ZB with fill mode | |
BackupRestore backupColorImageAddress(gDP.colorImage.address); | |
BackupRestore backupWidth(gDP.colorImage.width); | |
const unsigned int backupDepthSource = gDP.otherMode.depthSource; | |
const unsigned int backupCycleType = gDP.otherMode.cycleType; | |
gDP.colorImage.address = gDP.depthImageAddress; | |
gDP.colorImage.width = screenWidth; | |
gDP.otherMode.cycleType = G_CYC_FILL; | |
drawer.drawRect(ulx, uly, lrx, lry); | |
frameBufferList().setBufferChanged(f32(lry)); | |
gDP.otherMode.depthSource = backupDepthSource; | |
gDP.otherMode.cycleType = backupCycleType; | |
// Pretend that we are drawing the rectangle over ZB with fill mode | |
ValueKeeper<u32> backupColorImageAddress(gDP.colorImage.address, gDP.depthImageAddress); | |
ValueKeeper<u32> backupWidth(gDP.colorImage.width, screenWidth); | |
ValueKeeper<u32> backupDepthSource(gDP.otherMode.depthSource, gDP.otherMode.depthSource); | |
ValueKeeper<u32> backupCycleType(gDP.otherMode.cycleType, G_CYC_FILL); | |
drawer.drawRect(ulx, uly, lrx, lry); | |
frameBufferList().setBufferChanged(f32(lry)); | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cycleType
and depthSource
are not allowed to be casted to non const references because they are bit fields so this code will not work.
src/gDP.cpp
Outdated
{ | ||
BackupRestore backupFillColor(gDP.fillColor.color); | ||
const unsigned int backupDepthSource = gDP.otherMode.depthSource; | ||
const unsigned int backupCycleType = gDP.otherMode.cycleType; | ||
|
||
gDP.fillColor.color = fillColor; | ||
gDP.otherMode.cycleType = G_CYC_FILL; | ||
|
||
drawer.drawRect(ulx, uly, lrx, lry); | ||
if (auto cur = frameBufferList().getCurrent()) | ||
cur->setBufferClearParams(gDP.fillColor.color, ulx, uly, lrx, lry); | ||
|
||
frameBufferList().setBufferChanged(f32(lry)); | ||
|
||
gDP.otherMode.depthSource = backupDepthSource; | ||
gDP.otherMode.cycleType = backupCycleType; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{ | |
BackupRestore backupFillColor(gDP.fillColor.color); | |
const unsigned int backupDepthSource = gDP.otherMode.depthSource; | |
const unsigned int backupCycleType = gDP.otherMode.cycleType; | |
gDP.fillColor.color = fillColor; | |
gDP.otherMode.cycleType = G_CYC_FILL; | |
drawer.drawRect(ulx, uly, lrx, lry); | |
if (auto cur = frameBufferList().getCurrent()) | |
cur->setBufferClearParams(gDP.fillColor.color, ulx, uly, lrx, lry); | |
frameBufferList().setBufferChanged(f32(lry)); | |
gDP.otherMode.depthSource = backupDepthSource; | |
gDP.otherMode.cycleType = backupCycleType; | |
} | |
{ | |
ValueKeeper<u32> backupFillColor(gDP.fillColor.color, fillColor); | |
ValueKeeper<u32> backupDepthSource(gDP.otherMode.depthSource, gDP.otherMode.depthSource); | |
ValueKeeper<u32> backupCycleType(gDP.otherMode.cycleType, G_CYC_FILL); | |
drawer.drawRect(ulx, uly, lrx, lry); | |
if (auto cur = frameBufferList().getCurrent()) | |
cur->setBufferClearParams(gDP.fillColor.color, ulx, uly, lrx, lry); | |
frameBufferList().setBufferChanged(f32(lry)); | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, this code will not work
src/gDP.cpp
Outdated
for (int i = 0; i < length / 4; i++) { | ||
*(u32*)(RDRAM + addr + i * 4) = fillColor; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for (int i = 0; i < length / 4; i++) { | |
*(u32*)(RDRAM + addr + i * 4) = fillColor; | |
} | |
for (int i = 0; i < length; i+=4) { | |
*(u32*)(RDRAM + addr + i ) = fillColor; | |
} |
It should be faster. Or
u32* pDest = interpret_cast<u32*>(RDRAM + addr);
length /= 4; // or length >>= 2;
for (int i = 0; i < length; i++) {
pDest[i] = fillColor;
The same below.
Implementation is ready for another round of review |
This PR implements gSPMemset to handle graphics buffers. It is heavily HLE implementation that can be further improved but at least it fixes basically ZB issues.