mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-19 09:19:05 +02:00
Merge pull request #11531 from hrydgard/virtual-readbacks
WIP: Virtual readbacks
This commit is contained in:
5 files changed
+74
-23
No files matched your search
@@ -59,6 +59,7 @@ void Compatibility::CheckSettings(IniFile &iniFile, const std::string &gameID) {
|
||||
CheckSetting(iniFile, gameID, "DisableAccurateDepth", &flags_.DisableAccurateDepth);
|
||||
CheckSetting(iniFile, gameID, "MGS2AcidHack", &flags_.MGS2AcidHack);
|
||||
CheckSetting(iniFile, gameID, "SonicRivalsHack", &flags_.SonicRivalsHack);
|
||||
CheckSetting(iniFile, gameID, "BlockTransferAllowCreateFB", &flags_.BlockTransferAllowCreateFB);
|
||||
}
|
||||
|
||||
void Compatibility::CheckSetting(IniFile &iniFile, const std::string &gameID, const char *option, bool *flag) {
|
||||
|
||||
@@ -59,6 +59,7 @@ struct CompatFlags {
|
||||
bool DisableAccurateDepth;
|
||||
bool MGS2AcidHack;
|
||||
bool SonicRivalsHack;
|
||||
bool BlockTransferAllowCreateFB;
|
||||
};
|
||||
|
||||
class IniFile;
|
||||
|
||||
@@ -342,6 +342,13 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
|
||||
vfb->fb_stride = params.fb_stride;
|
||||
vfb->format = params.fmt;
|
||||
}
|
||||
|
||||
if (vfb->z_address == 0 && vfb->z_stride == 0) {
|
||||
// Got one that was created by CreateRAMFramebuffer. Since it has no depth buffer,
|
||||
// we just recreate it immediately.
|
||||
ResizeFramebufFBO(vfb, vfb->width, vfb->height, true);
|
||||
}
|
||||
|
||||
// Keep track, but this isn't really used.
|
||||
vfb->z_stride = params.z_stride;
|
||||
// Heuristic: In throughmode, a higher height could be used. Let's avoid shrinking the buffer.
|
||||
@@ -412,8 +419,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame
|
||||
|
||||
// None found? Create one.
|
||||
if (!vfb) {
|
||||
vfb = new VirtualFramebuffer();
|
||||
memset(vfb, 0, sizeof(VirtualFramebuffer));
|
||||
vfb = new VirtualFramebuffer{};
|
||||
vfb->fbo = nullptr;
|
||||
vfb->fb_address = params.fb_address;
|
||||
vfb->fb_stride = params.fb_stride;
|
||||
@@ -904,14 +910,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_) {
|
||||
@@ -1218,6 +1216,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;
|
||||
@@ -1278,15 +1278,6 @@ 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.
|
||||
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_)) {
|
||||
@@ -1294,6 +1285,14 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -1337,7 +1336,8 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size,
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferManagerCommon::FindTransferFramebuffers(VirtualFramebuffer *&dstBuffer, VirtualFramebuffer *&srcBuffer, u32 dstBasePtr, int dstStride, int &dstX, int &dstY, u32 srcBasePtr, int srcStride, int &srcX, int &srcY, int &srcWidth, int &srcHeight, int &dstWidth, int &dstHeight, int bpp) const {
|
||||
// Can't be const, in case it has to create a vfb unfortunately.
|
||||
void FramebufferManagerCommon::FindTransferFramebuffers(VirtualFramebuffer *&dstBuffer, VirtualFramebuffer *&srcBuffer, u32 dstBasePtr, int dstStride, int &dstX, int &dstY, u32 srcBasePtr, int srcStride, int &srcX, int &srcY, int &srcWidth, int &srcHeight, int &dstWidth, int &dstHeight, int bpp) {
|
||||
u32 dstYOffset = -1;
|
||||
u32 dstXOffset = -1;
|
||||
u32 srcYOffset = -1;
|
||||
@@ -1417,6 +1417,16 @@ void FramebufferManagerCommon::FindTransferFramebuffers(VirtualFramebuffer *&dst
|
||||
}
|
||||
}
|
||||
|
||||
if (!dstBuffer && PSP_CoreParameter().compat.flags().BlockTransferAllowCreateFB) {
|
||||
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);
|
||||
}
|
||||
|
||||
if (dstBuffer)
|
||||
dstBuffer->last_frame_used = gpuStats.numFlips;
|
||||
|
||||
if (dstYOffset != (u32)-1) {
|
||||
dstY += dstYOffset;
|
||||
dstX += dstXOffset;
|
||||
@@ -1427,6 +1437,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
|
||||
|
||||
@@ -344,10 +344,12 @@ protected:
|
||||
|
||||
bool ShouldDownloadFramebuffer(const VirtualFramebuffer *vfb) const;
|
||||
void DownloadFramebufferOnSwitch(VirtualFramebuffer *vfb);
|
||||
void FindTransferFramebuffers(VirtualFramebuffer *&dstBuffer, VirtualFramebuffer *&srcBuffer, u32 dstBasePtr, int dstStride, int &dstX, int &dstY, u32 srcBasePtr, int srcStride, int &srcX, int &srcY, int &srcWidth, int &srcHeight, int &dstWidth, int &dstHeight, int bpp) const;
|
||||
void FindTransferFramebuffers(VirtualFramebuffer *&dstBuffer, VirtualFramebuffer *&srcBuffer, u32 dstBasePtr, int dstStride, int &dstX, int &dstY, u32 srcBasePtr, int srcStride, int &srcX, int &srcY, int &srcWidth, int &srcHeight, int &dstWidth, int &dstHeight, int bpp);
|
||||
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);
|
||||
@@ -391,7 +393,6 @@ protected:
|
||||
|
||||
std::vector<VirtualFramebuffer *> vfbs_;
|
||||
std::vector<VirtualFramebuffer *> bvfbs_; // blitting framebuffers (for download)
|
||||
std::set<std::pair<u32, u32>> knownFramebufferRAMCopies_;
|
||||
|
||||
bool gameUsesSequentialCopies_ = false;
|
||||
|
||||
|
||||
+7
-1
@@ -339,4 +339,10 @@ ULUS10077 = true
|
||||
ULES00622 = true # SR1
|
||||
ULUS10195 = true # SR1
|
||||
ULUS10323 = true # SR2
|
||||
ULES00940 = true # SR2
|
||||
ULES00940 = true # SR2
|
||||
|
||||
[BlockTransferAllowCreateFB]
|
||||
NPJH50686 = true # Digimon Adventures (JP, and English patches...)
|
||||
ULJS00078 = true # MotoGP
|
||||
ULUS10153 = true # MotoGP
|
||||
UCES00373 = true # MotoGP
|
||||
Reference in new issue
Block a user