Skip to content
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

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

aglab2
Copy link
Contributor

@aglab2 aglab2 commented Jan 10, 2025

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.

@aglab2
Copy link
Contributor Author

aglab2 commented Jan 10, 2025

CI seems to be broken, I do not believe this PR caused any issues on Linux build.

@Jj0YzL5nvJ
Copy link
Contributor

Jj0YzL5nvJ commented Jan 12, 2025

libfreetype6-dev is missing as a dependency.

CMake Error at /usr/local/share/cmake-3.31/Modules/FindPackageHandleStandardArgs.cmake:233 (message):
  Could NOT find Freetype (missing: FREETYPE_LIBRARY)

It's not your fault =P

Edit:

Upon closer inspection, several dependencies are missing (libfreetype6-dev, libpng-dev, zlib1g-dev)... all this time the CI has been at the mercy of the ubuntu-latest image manager...

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
Copy link
Owner

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;
Copy link
Owner

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 ?

Comment on lines +816 to +817
const u32 screenWidth = VI.width;
const u32 screenHeight = VI.height;
Copy link
Owner

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)

Copy link
Contributor Author

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.

Copy link
Contributor Author

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);

Copy link
Contributor Author

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.

Copy link
Contributor Author

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
Comment on lines 869 to 871
const u32 colorSize = gDP.colorImage.size < 3 ? 2 : 4;
const u32 colorImageStart = gDP.colorImage.address;
const u32 colorImageEnd = gDP.colorImage.address + screenWidth * screenHeight * colorSize;
Copy link
Owner

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

Suggested change
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...
Copy link
Owner

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
Comment on lines 847 to 861
// 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;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// 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));

Copy link
Contributor Author

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
Comment on lines 887 to 903
{
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;
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{
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));
}

Copy link
Contributor Author

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
Comment on lines 906 to 908
for (int i = 0; i < length / 4; i++) {
*(u32*)(RDRAM + addr + i * 4) = fillColor;
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.

@aglab2
Copy link
Contributor Author

aglab2 commented Jan 26, 2025

Implementation is ready for another round of review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants