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

GPU: Hook Gods Eater Burst avatar read #16184

Merged
merged 4 commits into from
Oct 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions Core/HLE/ReplaceTables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,35 @@ static int Hook_godseaterburst_blit_texture() {
return 0;
}

static int Hook_godseaterburst_depthmask_5551() {
// This function copies the 5551 framebuffer to a temporary, generating alpha based on depth.
// Depth is optional, in which case all pixels get full alpha.
// Called when your avatar changes to screenshot for save data.
uint32_t colorBuffer = currentMIPS->r[MIPS_REG_A1];
uint32_t depthBuffer = currentMIPS->r[MIPS_REG_T2];
uint32_t byteStride = currentMIPS->r[MIPS_REG_A2];
uint32_t height = currentMIPS->r[MIPS_REG_T1];
uint32_t size = byteStride * height;

if (!Memory::IsVRAMAddress(colorBuffer) || !Memory::IsValidRange(colorBuffer, size))
return 0;
if (depthBuffer != 0) {
if (!Memory::IsVRAMAddress(colorBuffer) || !Memory::IsValidRange(depthBuffer, size))
return 0;

// This is added to read from the linearized mirror.
uint32_t depthMirror = depthBuffer + 0x00200000;
// Depth download required, or it won't work and will be transparent.
gpu->PerformMemoryCopy(depthMirror, depthMirror, size, GPUCopyFlag::FORCE_DST_MEM | GPUCopyFlag::DEPTH_REQUESTED);
NotifyMemInfo(MemBlockFlags::WRITE, depthMirror, size, "godseaterburst_depthmask_5551");
}

gpu->PerformMemoryDownload(colorBuffer, size);
NotifyMemInfo(MemBlockFlags::WRITE, colorBuffer, size, "godseaterburst_depthmask_5551");

return 0;
}

static int Hook_hexyzforce_monoclome_thread() {
u32 fb_info;
if (!GetMIPSStaticAddress(fb_info, -4, 0)) {
Expand Down Expand Up @@ -1414,6 +1443,7 @@ static const ReplacementTableEntry entries[] = {
// { "vmmul_q_transp", &Replace_vmmul_q_transp, 0, REPFLAG_DISABLED },

{ "godseaterburst_blit_texture", &Hook_godseaterburst_blit_texture, 0, REPFLAG_HOOKENTER },
{ "godseaterburst_depthmask_5551", &Hook_godseaterburst_depthmask_5551, 0, REPFLAG_HOOKENTER },
{ "hexyzforce_monoclome_thread", &Hook_hexyzforce_monoclome_thread, 0, REPFLAG_HOOKENTER, 0x58 },
{ "starocean_write_stencil", &Hook_starocean_write_stencil, 0, REPFLAG_HOOKENTER, 0x260 },
{ "topx_create_saveicon", &Hook_topx_create_saveicon, 0, REPFLAG_HOOKENTER, 0x34 },
Expand Down
1 change: 1 addition & 0 deletions Core/MIPS/MIPSAnalyst.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ static const HardHashTableEntry hardcodedHashes[] = {
{ 0x70a6152b265228e8, 296, "unendingbloodycall_download_frame", }, // unENDing Bloody Call
{ 0x7245b74db370ae72, 64, "vmmul_q_transp3", },
{ 0x7259d52b21814a5a, 40, "vtfm_t_transp", },
{ 0x730f59cc6c0f5732, 452, "godseaterburst_depthmask_5551", }, // Gods Eater Burst (US)
{ 0x7354fd206796d817, 864, "flowers_download_frame", }, // Flowers
{ 0x736b34ebc702d873, 104, "vmmul_q_transp", },
{ 0x73a614c08f777d52, 792, "danganronpa2_2_download_frame", }, // Danganronpa 2
Expand Down
61 changes: 51 additions & 10 deletions GPU/Common/FramebufferManagerCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1657,13 +1657,14 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
VirtualFramebuffer *srcBuffer = nullptr;
bool ignoreDstBuffer = flags & GPUCopyFlag::FORCE_DST_MEM;
bool ignoreSrcBuffer = flags & (GPUCopyFlag::FORCE_SRC_MEM | GPUCopyFlag::MEMSET);
RasterChannel channel = flags & GPUCopyFlag::DEPTH_REQUESTED ? RASTER_DEPTH : RASTER_COLOR;

u32 dstY = (u32)-1;
u32 dstH = 0;
u32 srcY = (u32)-1;
u32 srcH = 0;
for (auto vfb : vfbs_) {
if (vfb->fb_stride == 0) {
if (vfb->fb_stride == 0 || channel != RASTER_COLOR) {
continue;
}

Expand Down Expand Up @@ -1715,14 +1716,36 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
}
}

if (channel == RASTER_DEPTH) {
srcBuffer = nullptr;
dstBuffer = nullptr;
// Let's assume exact matches only for simplicity.
for (auto vfb : vfbs_) {
if (!ignoreDstBuffer && dst == vfb->z_address && size == vfb->z_stride * 2 * vfb->height) {
if (!dstBuffer || dstBuffer->depthBindSeq < vfb->depthBindSeq) {
dstBuffer = vfb;
dstY = 0;
dstH = vfb->height;
}
}
if (!ignoreSrcBuffer && src == vfb->z_address && size == vfb->z_stride * 2 * vfb->height) {
if (!srcBuffer || srcBuffer->depthBindSeq < vfb->depthBindSeq) {
srcBuffer = vfb;
srcY = 0;
srcH = vfb->height;
}
}
}
}

if (!useBufferedRendering_) {
// If we're copying into a recently used display buf, it's probably destined for the screen.
if (srcBuffer || (dstBuffer != displayFramebuf_ && dstBuffer != prevDisplayFramebuf_)) {
if (channel == RASTER_DEPTH || srcBuffer || (dstBuffer != displayFramebuf_ && dstBuffer != prevDisplayFramebuf_)) {
return false;
}
}

if (!dstBuffer && srcBuffer) {
if (!dstBuffer && srcBuffer && channel != RASTER_DEPTH) {
// Note - if we're here, we're in a memcpy, not a block transfer. Not allowing IntraVRAMBlockTransferAllowCreateFB.
// Technically, that makes BlockTransferAllowCreateFB a bit of a misnomer.
if (PSP_CoreParameter().compat.flags().BlockTransferAllowCreateFB) {
Expand All @@ -1740,7 +1763,7 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
} else {
WARN_LOG_ONCE(dstnotsrccpy, G3D, "Inter-buffer memcpy %08x -> %08x (size: %x)", src, dst, size);
// Just do the blit!
BlitFramebuffer(dstBuffer, 0, dstY, srcBuffer, 0, srcY, srcBuffer->width, srcH, 0, RASTER_COLOR, "Blit_InterBufferMemcpy");
BlitFramebuffer(dstBuffer, 0, dstY, srcBuffer, 0, srcY, srcBuffer->width, srcH, 0, channel, "Blit_InterBufferMemcpy");
SetColorUpdated(dstBuffer, skipDrawReason);
RebindFramebuffer("RebindFramebuffer - Inter-buffer memcpy");
}
Expand All @@ -1752,7 +1775,9 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
WARN_LOG_ONCE(btucpy, G3D, "Memcpy fbo upload %08x -> %08x (size: %x)", src, dst, size);
FlushBeforeCopy();
const u8 *srcBase = Memory::GetPointerUnchecked(src);
DrawPixels(dstBuffer, 0, dstY, srcBase, dstBuffer->fb_format, dstBuffer->fb_stride, dstBuffer->width, dstH, RASTER_COLOR, "MemcpyFboUpload_DrawPixels");
GEBufferFormat srcFormat = channel == RASTER_DEPTH ? GE_FORMAT_DEPTH16 : dstBuffer->fb_format;
int srcStride = channel == RASTER_DEPTH ? dstBuffer->z_stride : dstBuffer->fb_stride;
DrawPixels(dstBuffer, 0, dstY, srcBase, srcFormat, srcStride, dstBuffer->width, dstH, channel, "MemcpyFboUpload_DrawPixels");
SetColorUpdated(dstBuffer, skipDrawReason);
RebindFramebuffer("RebindFramebuffer - Memcpy fbo upload");
// This is a memcpy, let's still copy just in case.
Expand All @@ -1762,8 +1787,8 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
FlushBeforeCopy();
if (srcH == 0 || srcY + srcH > srcBuffer->bufferHeight) {
WARN_LOG_ONCE(btdcpyheight, G3D, "Memcpy fbo download %08x -> %08x skipped, %d+%d is taller than %d", src, dst, srcY, srcH, srcBuffer->bufferHeight);
} else if (g_Config.bBlockTransferGPU && !srcBuffer->memoryUpdated) {
ReadFramebufferToMemory(srcBuffer, 0, srcY, srcBuffer->width, srcH, RASTER_COLOR);
} else if (g_Config.bBlockTransferGPU && (!srcBuffer->memoryUpdated || channel == RASTER_DEPTH)) {
ReadFramebufferToMemory(srcBuffer, 0, srcY, srcBuffer->width, srcH, channel);
srcBuffer->usageFlags = (srcBuffer->usageFlags | FB_USAGE_DOWNLOAD) & ~FB_USAGE_DOWNLOAD_CLEAR;
}
return false;
Expand Down Expand Up @@ -2580,7 +2605,7 @@ void FramebufferManagerCommon::PackFramebufferSync(VirtualFramebuffer *vfb, int
const int dstByteOffset = (y * stride + x) * dstBpp;
// Leave the gap between the end of the last line and the full stride.
// This is only used for the NotifyMemInfo range.
const int dstSize = (h * stride + w - 1) * dstBpp;
const int dstSize = ((h - 1) * stride + w) * dstBpp;

if (!Memory::IsValidRange(fb_address + dstByteOffset, dstSize)) {
ERROR_LOG_REPORT(G3D, "PackFramebufferSync would write outside of memory, ignoring");
Expand All @@ -2594,7 +2619,11 @@ void FramebufferManagerCommon::PackFramebufferSync(VirtualFramebuffer *vfb, int
DEBUG_LOG(G3D, "Reading framebuffer to mem, fb_address = %08x, ptr=%p", fb_address, destPtr);

if (destPtr) {
draw_->CopyFramebufferToMemorySync(vfb->fbo, channel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, x, y, w, h, destFormat, destPtr, vfb->fb_stride, "PackFramebufferSync");
if (channel == RASTER_DEPTH)
PackDepthbuffer(vfb, x, y, w, h);
else
draw_->CopyFramebufferToMemorySync(vfb->fbo, channel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, x, y, w, h, destFormat, destPtr, vfb->fb_stride, "PackFramebufferSync");

char tag[128];
size_t len = snprintf(tag, sizeof(tag), "FramebufferPack/%08x_%08x_%dx%d_%s", vfb->fb_address, vfb->z_address, w, h, GeBufferFormatToString(vfb->fb_format));
NotifyMemInfo(MemBlockFlags::WRITE, fb_address + dstByteOffset, dstSize, tag, len);
Expand All @@ -2605,6 +2634,17 @@ void FramebufferManagerCommon::PackFramebufferSync(VirtualFramebuffer *vfb, int
gpuStats.numReadbacks++;
}

void FramebufferManagerCommon::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h) {
_assert_msg_(vfb && vfb->z_address != 0 && vfb->z_stride != 0, "Depth buffer invalid");

Draw::DataFormat destFormat = GEFormatToThin3D(GE_FORMAT_DEPTH16);
const int dstByteOffset = (y * vfb->z_stride + x) * 2;
u8 *destPtr = Memory::GetPointerWriteUnchecked(vfb->z_address + dstByteOffset);
if (!draw_->CopyFramebufferToMemorySync(vfb->fbo, Draw::FB_DEPTH_BIT, x, y, w, h, destFormat, destPtr, vfb->fb_stride, "PackDepthbuffer")) {
WARN_LOG(G3D, "PackDepthbuffer failed");
}
}

void FramebufferManagerCommon::ReadFramebufferToMemory(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel) {
// Clamp to bufferWidth. Sometimes block transfers can cause this to hit.
if (x + w >= vfb->bufferWidth) {
Expand All @@ -2623,7 +2663,8 @@ void FramebufferManagerCommon::ReadFramebufferToMemory(VirtualFramebuffer *vfb,
vfb->usageFlags |= FB_USAGE_DOWNLOAD;
} else if (x == 0 && y == 0 && w == vfb->width && h == vfb->height) {
// Mark it as fully downloaded until next render to it.
vfb->memoryUpdated = true;
if (channel == RASTER_COLOR)
vfb->memoryUpdated = true;
vfb->usageFlags |= FB_USAGE_DOWNLOAD;
} else {
// Let's try to set the flag eventually, if the game copies a lot.
Expand Down
2 changes: 2 additions & 0 deletions GPU/Common/FramebufferManagerCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,8 @@ class FramebufferManagerCommon {

protected:
virtual void PackFramebufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel);
// Used for when a shader is required, such as GLES.
virtual void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h);
void SetViewport2D(int x, int y, int w, int h);
Draw::Texture *MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height);
void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags);
Expand Down
2 changes: 1 addition & 1 deletion GPU/Directx9/FramebufferManagerDX9.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ class FramebufferManagerDX9 : public FramebufferManagerCommon {

protected:
void DecimateFBOs() override;
void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h) override;

private:
void PackFramebufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel) override;
void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h);
bool GetRenderTargetFramebuffer(LPDIRECT3DSURFACE9 renderTarget, LPDIRECT3DSURFACE9 offscreen, int w, int h, GPUDebugBuffer &buffer);

LPDIRECT3DDEVICE9 device_;
Expand Down
3 changes: 1 addition & 2 deletions GPU/GLES/FramebufferManagerGLES.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,9 @@ class FramebufferManagerGLES : public FramebufferManagerCommon {

protected:
void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) override;
void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h) override;

private:
void PackDepthbuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h);

u8 *convBuf_ = nullptr;
u32 convBufSize_ = 0;

Expand Down
3 changes: 2 additions & 1 deletion GPU/GPUInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,8 @@ enum class GPUCopyFlag {
FORCE_DST_MEM = 2,
// Note: implies src == dst and FORCE_SRC_MEM.
MEMSET = 4,
DEBUG_NOTIFIED = 8,
DEPTH_REQUESTED = 8,
DEBUG_NOTIFIED = 16,
};
ENUM_CLASS_BITOPS(GPUCopyFlag);

Expand Down