Skip to content

Commit

Permalink
Support virtual readbacks for detected-memcpy framebuffer copies, del…
Browse files Browse the repository at this point in the history
…ete MotoGP hack.
  • Loading branch information
hrydgard committed Nov 11, 2018
1 parent 32dad39 commit 999bdbb
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 49 deletions.
96 changes: 49 additions & 47 deletions GPU/Common/FramebufferCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -908,14 +908,6 @@ void FramebufferManagerCommon::CopyDisplayToOutput() {
if (!vfb) {
if (Memory::IsValidAddress(displayFramebufPtr_)) {
// The game is displaying something directly from RAM. In GTA, it's decoded video.

// First check that it's not a known RAM copy of a VRAM framebuffer though, as in MotoGP
for (auto iter = knownFramebufferRAMCopies_.begin(); iter != knownFramebufferRAMCopies_.end(); ++iter) {
if (iter->second == displayFramebufPtr_) {
vfb = GetVFBAt(iter->first);
}
}

if (!vfb) {
shaderManager_->DirtyLastShader();
if (useBufferedRendering_) {
Expand Down Expand Up @@ -1222,6 +1214,8 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w,
}
}

// This is called from detected memcopies only. Not block transfers.
// MotoGP goes this path so we need to catch those copies here.
bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, bool isMemset, u32 skipDrawReason) {
if (size == 0) {
return false;
Expand Down Expand Up @@ -1282,23 +1276,21 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
}
}

if (srcBuffer && srcY == 0 && srcH == srcBuffer->height && !dstBuffer) {
// MotoGP workaround - it copies a framebuffer to memory and then displays it.
// TODO: It's rare anyway, but the game could modify the RAM and then we'd display the wrong thing.
// Unfortunately, that would force 1x render resolution.
// NOTE: With the BlockTransferAllowCreateFB hack, we might be able to remove this.
if (Memory::IsRAMAddress(dst)) {
knownFramebufferRAMCopies_.insert(std::pair<u32, u32>(src, dst));
}
}

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_)) {
return false;
}
}

if (!dstBuffer && srcBuffer && PSP_CoreParameter().compat.flags().BlockTransferAllowCreateFB) {
dstBuffer = CreateRAMFramebuffer(dst, srcBuffer->width, srcBuffer->height, srcBuffer->fb_stride, srcBuffer->format);
dstY = 0;
}
if (dstBuffer) {
dstBuffer->last_frame_used = gpuStats.numFlips;
}

if (dstBuffer && srcBuffer && !isMemset) {
if (srcBuffer == dstBuffer) {
WARN_LOG_REPORT_ONCE(dstsrccpy, G3D, "Intra-buffer memcpy (not supported) %08x -> %08x", src, dst);
Expand Down Expand Up @@ -1424,36 +1416,14 @@ void FramebufferManagerCommon::FindTransferFramebuffers(VirtualFramebuffer *&dst
}

if (!dstBuffer && PSP_CoreParameter().compat.flags().BlockTransferAllowCreateFB) {
float renderWidthFactor = renderWidth_ / 480.0f;
float renderHeightFactor = renderHeight_ / 272.0f;
// A target for the destination is missing - so just create one!
// Make sure this one would be found by the algorithm above so we wouldn't
// create a new one each frame.
VirtualFramebuffer *vfb = new VirtualFramebuffer{};
vfb->fbo = nullptr;
vfb->fb_address = dstBasePtr; // NOTE - not necessarily in VRAM!
vfb->fb_stride = dstStride;
vfb->z_address = 0;
vfb->z_stride =0;
vfb->width = std::max(dstWidth, dstStride);
vfb->height = dstHeight;
vfb->newWidth = vfb->width;
vfb->newHeight = vfb->height;
vfb->lastFrameNewSize = gpuStats.numFlips;
vfb->renderWidth = (u16)(vfb->width * renderWidthFactor);
vfb->renderHeight = (u16)(vfb->height * renderHeightFactor);
vfb->bufferWidth = vfb->width;
vfb->bufferHeight = vfb->height;
vfb->format = bpp == 4 ? GE_FORMAT_8888 : GE_FORMAT_5551; // TODO: We don't really know the 16-bit format here.. at all. Can only guess when it gets used later!
vfb->drawnFormat = GE_FORMAT_8888;
vfb->usageFlags = FB_USAGE_RENDERTARGET;
SetColorUpdated(vfb, 0);
textureCache_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_CREATED);
vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, (Draw::FBColorDepth)vfb->colorDepth });
vfbs_.push_back(vfb);
dstBuffer = vfb;
GEBufferFormat ramFormat = bpp == 4 ? GE_FORMAT_8888 : GE_FORMAT_5551;
// TODO: We don't really know the 16-bit format here.. at all. Can only guess when it gets used later!
// But actually, the format of the source buffer is probably not a bad guess..
dstBuffer = CreateRAMFramebuffer(dstBasePtr, dstWidth, dstHeight, dstStride, ramFormat);
}
dstBuffer->last_frame_used = gpuStats.numFlips;

if (dstBuffer)
dstBuffer->last_frame_used = gpuStats.numFlips;

if (dstYOffset != (u32)-1) {
dstY += dstYOffset;
Expand All @@ -1465,6 +1435,38 @@ void FramebufferManagerCommon::FindTransferFramebuffers(VirtualFramebuffer *&dst
}
}

VirtualFramebuffer *FramebufferManagerCommon::CreateRAMFramebuffer(uint32_t fbAddress, int width, int height, int stride, GEBufferFormat format) {
float renderWidthFactor = renderWidth_ / 480.0f;
float renderHeightFactor = renderHeight_ / 272.0f;

// A target for the destination is missing - so just create one!
// Make sure this one would be found by the algorithm above so we wouldn't
// create a new one each frame.
VirtualFramebuffer *vfb = new VirtualFramebuffer{};
vfb->fbo = nullptr;
vfb->fb_address = fbAddress; // NOTE - not necessarily in VRAM!
vfb->fb_stride = stride;
vfb->z_address = 0; // marks that if anyone tries to render to this framebuffer, it should be dropped and recreated.
vfb->z_stride = 0;
vfb->width = std::max(width, stride);
vfb->height = height;
vfb->newWidth = vfb->width;
vfb->newHeight = vfb->height;
vfb->lastFrameNewSize = gpuStats.numFlips;
vfb->renderWidth = (u16)(vfb->width * renderWidthFactor);
vfb->renderHeight = (u16)(vfb->height * renderHeightFactor);
vfb->bufferWidth = vfb->width;
vfb->bufferHeight = vfb->height;
vfb->format = format;
vfb->drawnFormat = GE_FORMAT_8888;
vfb->usageFlags = FB_USAGE_RENDERTARGET;
SetColorUpdated(vfb, 0);
textureCache_->NotifyFramebuffer(vfb->fb_address, vfb, NOTIFY_FB_CREATED);
vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, 1, true, (Draw::FBColorDepth)vfb->colorDepth });
vfbs_.push_back(vfb);
return vfb;
}

// 1:1 pixel sides buffers, we resize buffers to these before we read them back.
VirtualFramebuffer *FramebufferManagerCommon::FindDownloadTempBuffer(VirtualFramebuffer *vfb) {
// For now we'll keep these on the same struct as the ones that can get displayed
Expand Down
3 changes: 2 additions & 1 deletion GPU/Common/FramebufferCommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,8 @@ class FramebufferManagerCommon {
VirtualFramebuffer *FindDownloadTempBuffer(VirtualFramebuffer *vfb);
virtual bool CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) = 0;
virtual void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) = 0;

VirtualFramebuffer *CreateRAMFramebuffer(uint32_t fbAddress, int width, int height, int stride, GEBufferFormat format);
void OptimizeDownloadRange(VirtualFramebuffer *vfb, int &x, int &y, int &w, int &h);

void UpdateFramebufUsage(VirtualFramebuffer *vfb);
Expand Down Expand Up @@ -392,7 +394,6 @@ class FramebufferManagerCommon {

std::vector<VirtualFramebuffer *> vfbs_;
std::vector<VirtualFramebuffer *> bvfbs_; // blitting framebuffers (for download)
std::set<std::pair<u32, u32>> knownFramebufferRAMCopies_;

bool gameUsesSequentialCopies_ = false;

Expand Down
2 changes: 1 addition & 1 deletion assets/compat.ini
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ ULUS10323 = true # SR2
ULES00940 = true # SR2

[BlockTransferAllowCreateFB]
NPJH50686 = true # Digimon Adventures (JP)
NPJH50686 = true # Digimon Adventures (JP, and English patches...)
ULJS00078 = true # MotoGP
ULUS10153 = true # MotoGP
UCES00373 = true # MotoGP

0 comments on commit 999bdbb

Please sign in to comment.