More work on depth copies. Seems to be enough for Iron Man.

This commit is contained in:
Henrik Rydgård 2023-02-14 00:00:04 +01:00
parent 62a6f351d5
commit ae9291f3b5
2 changed files with 49 additions and 26 deletions

View file

@ -2032,8 +2032,8 @@ bool FramebufferManagerCommon::FindTransferFramebuffer(u32 basePtr, int stride_p
if (candidate->channel == best->channel) {
better = candidate->vfb->BindSeq(candidate->channel) > best->vfb->BindSeq(candidate->channel);
} else {
// Prefer color over depth.
if (candidate->channel == RASTER_COLOR && best->channel == RASTER_DEPTH) {
// Prefer depth over color if the address match is perfect.
if (candidate->channel == RASTER_DEPTH && best->channel == RASTER_COLOR && candidate->vfb->z_address == basePtr) {
better = true;
}
}
@ -2073,17 +2073,27 @@ bool FramebufferManagerCommon::FindTransferFramebuffer(u32 basePtr, int stride_p
VirtualFramebuffer *FramebufferManagerCommon::CreateRAMFramebuffer(uint32_t fbAddress, int width, int height, int stride, GEBufferFormat format) {
INFO_LOG(G3D, "Creating RAM framebuffer at %08x (%dx%d, stride %d, fb_format %d)", fbAddress, width, height, stride, format);
RasterChannel channel = format == GE_FORMAT_DEPTH16 ? RASTER_DEPTH : RASTER_COLOR;
// 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;
uint32_t mask = Memory::IsVRAMAddress(fbAddress) ? 0x041FFFFF : 0x3FFFFFFF;
vfb->fb_address = fbAddress & mask; // 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);
if (format == GE_FORMAT_DEPTH16) {
vfb->fb_address = 0xFFFFFFFF; // Invalid address
vfb->fb_stride = 0;
vfb->z_address = fbAddress; // marks that if anyone tries to render with depth to this framebuffer, it should be dropped and recreated.
vfb->z_stride = stride;
vfb->width = width;
} else {
vfb->fb_address = fbAddress & mask; // NOTE - not necessarily in VRAM!
vfb->fb_stride = stride;
vfb->z_address = 0;
vfb->z_stride = 0;
vfb->width = std::max(width, stride);
}
vfb->height = height;
vfb->newWidth = vfb->width;
vfb->newHeight = vfb->height;
@ -2093,16 +2103,19 @@ VirtualFramebuffer *FramebufferManagerCommon::CreateRAMFramebuffer(uint32_t fbAd
vfb->renderHeight = (u16)(vfb->height * renderScaleFactor_);
vfb->bufferWidth = vfb->width;
vfb->bufferHeight = vfb->height;
vfb->fb_format = format;
vfb->usageFlags = FB_USAGE_RENDER_COLOR;
SetColorUpdated(vfb, 0);
vfb->fb_format = format == GE_FORMAT_DEPTH16 ? GE_FORMAT_8888 : format;
vfb->usageFlags = format == GE_FORMAT_DEPTH16 ? FB_USAGE_RENDER_DEPTH : FB_USAGE_RENDER_COLOR;
if (format != GE_FORMAT_DEPTH16) {
SetColorUpdated(vfb, 0);
}
char name[64];
snprintf(name, sizeof(name), "%08x_color_RAM", vfb->fb_address);
snprintf(name, sizeof(name), "%08x_%s_RAM", vfb->Address(channel), RasterChannelToString(channel));
textureCache_->NotifyFramebuffer(vfb, NOTIFY_FB_CREATED);
vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), 0, false, name });
bool createDepthBuffer = format == GE_FORMAT_DEPTH16;
vfb->fbo = draw_->CreateFramebuffer({ vfb->renderWidth, vfb->renderHeight, 1, GetFramebufferLayers(), 0, createDepthBuffer, name });
vfbs_.push_back(vfb);
u32 byteSize = vfb->BufferByteSize(RASTER_COLOR);
u32 byteSize = vfb->BufferByteSize(channel);
if (fbAddress + byteSize > framebufRangeEnd_) {
framebufRangeEnd_ = fbAddress + byteSize;
}
@ -2304,22 +2317,31 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst
// No info left - just fall back to something. But this is definitely split pixel tricks.
ramFormat = GE_FORMAT_5551;
}
dstBuffer = true;
dstRect.vfb = CreateRAMFramebuffer(dstBasePtr, width, height, dstStride, ramFormat);
} else {
dstRect.vfb = CreateRAMFramebuffer(dstBasePtr, width, height, dstStride, GE_FORMAT_DEPTH16);
dstRect.x_bytes = 0;
dstRect.w_bytes = 2 * width;
dstRect.y = 0;
dstRect.h = height;
dstRect.channel = RASTER_DEPTH;
}
dstBuffer = true;
}
}
if (dstBuffer) {
dstRect.vfb->last_frame_used = gpuStats.numFlips;
// Mark the destination as fresh.
dstRect.vfb->colorBindSeq = GetBindSeqCount();
if (dstRect.channel == RASTER_COLOR) {
dstRect.vfb->colorBindSeq = GetBindSeqCount();
} else {
dstRect.vfb->depthBindSeq = GetBindSeqCount();
}
}
if (dstBuffer && srcBuffer) {
if (srcRect.vfb == dstRect.vfb) {
if (srcRect.vfb && srcRect.vfb == dstRect.vfb && srcRect.channel == dstRect.channel) {
// Transfer within the same buffer.
// This is a simple case because there will be no format conversion or similar shenanigans needed.
// However, the BPP might still mismatch, but in such a case we can convert the coordinates.
@ -2329,7 +2351,7 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst
return true;
}
int buffer_bpp = BufferFormatBytesPerPixel(srcRect.vfb->fb_format);
int buffer_bpp = BufferFormatBytesPerPixel(srcRect.vfb->Format(srcRect.channel));
if (bpp != buffer_bpp) {
WARN_LOG_ONCE(intrabpp, G3D, "Mismatched transfer bpp in intra-buffer block transfer. Was %d, expected %d.", bpp, buffer_bpp);
@ -2343,28 +2365,29 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst
dstBasePtr, dstRect.x_bytes / bpp, dstRect.y, dstStride);
FlushBeforeCopy();
// Some backends can handle blitting within a framebuffer. Others will just have to deal with it or ignore it, apparently.
BlitFramebuffer(dstRect.vfb, dstX, dstY, srcRect.vfb, srcX, srcY, dstRect.w_bytes / bpp, dstRect.h / bpp, bpp, RASTER_COLOR, "Blit_IntraBufferBlockTransfer");
BlitFramebuffer(dstRect.vfb, dstX, dstY, srcRect.vfb, srcX, srcY, dstRect.w_bytes / bpp, dstRect.h / bpp, bpp, dstRect.channel, "Blit_IntraBufferBlockTransfer");
RebindFramebuffer("rebind after intra block transfer");
SetColorUpdated(dstRect.vfb, skipDrawReason);
return true; // Skip the memory copy.
}
// Straightforward blit between two same-format framebuffers.
if (srcRect.vfb->fb_format == dstRect.vfb->fb_format) {
WARN_LOG_N_TIMES(dstnotsrc, 5, G3D, "Inter-buffer block transfer %dx%d %dbpp from %08x (x:%d y:%d stride:%d %s) -> %08x (x:%d y:%d stride:%d %s)",
if (srcRect.vfb && srcRect.channel == dstRect.channel && srcRect.vfb->Format(srcRect.channel) == dstRect.vfb->Format(dstRect.channel)) {
WARN_LOG_N_TIMES(dstnotsrc, 5, G3D, "Inter-buffer %s block transfer %dx%d %dbpp from %08x (x:%d y:%d stride:%d %s) -> %08x (x:%d y:%d stride:%d %s)",
RasterChannelToString(srcRect.channel),
width, height, bpp,
srcBasePtr, srcRect.x_bytes / bpp, srcRect.y, srcStride, GeBufferFormatToString(srcRect.vfb->fb_format),
dstBasePtr, dstRect.x_bytes / bpp, dstRect.y, dstStride, GeBufferFormatToString(dstRect.vfb->fb_format));
// Straight blit will do, but check the bpp, we might need to convert coordinates differently.
int buffer_bpp = BufferFormatBytesPerPixel(srcRect.vfb->fb_format);
int buffer_bpp = BufferFormatBytesPerPixel(srcRect.vfb->Format(srcRect.channel));
if (bpp != buffer_bpp) {
WARN_LOG_ONCE(intrabpp, G3D, "Mismatched transfer bpp in inter-buffer block transfer. Was %d, expected %d.", bpp, buffer_bpp);
// We just switch to using the buffer's bpp, since we've already converted the rectangle to byte offsets.
bpp = buffer_bpp;
}
FlushBeforeCopy();
BlitFramebuffer(dstRect.vfb, dstRect.x_bytes / bpp, dstRect.y, srcRect.vfb, srcRect.x_bytes / bpp, srcRect.y, srcRect.w_bytes / bpp, height, bpp, RASTER_COLOR, "Blit_InterBufferBlockTransfer");
BlitFramebuffer(dstRect.vfb, dstRect.x_bytes / bpp, dstRect.y, srcRect.vfb, srcRect.x_bytes / bpp, srcRect.y, srcRect.w_bytes / bpp, height, bpp, srcRect.channel, "Blit_InterBufferBlockTransfer");
RebindFramebuffer("RebindFramebuffer - Inter-buffer block transfer");
SetColorUpdated(dstRect.vfb, skipDrawReason);
return true;
@ -2372,7 +2395,7 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst
// Getting to the more complex cases. Have not actually seen much of these yet.
WARN_LOG_N_TIMES(blockformat, 5, G3D, "Mismatched buffer formats in block transfer: %s->%s (%dx%d)",
GeBufferFormatToString(srcRect.vfb->fb_format), GeBufferFormatToString(dstRect.vfb->fb_format),
GeBufferFormatToString(srcRect.vfb->Format(srcRect.channel)), GeBufferFormatToString(dstRect.vfb->Format(dstRect.channel)),
width, height);
// TODO
@ -3115,7 +3138,7 @@ void FramebufferManagerCommon::BlitFramebuffer(VirtualFramebuffer *dst, int dstX
float srcXFactor = src->renderScaleFactor;
float srcYFactor = src->renderScaleFactor;
const int srcBpp = BufferFormatBytesPerPixel(src->fb_format);
const int srcBpp = BufferFormatBytesPerPixel(src->Format(channel));
if (srcBpp != bpp && bpp != 0) {
// If we do this, we're kinda in nonsense territory since the actual formats won't match (unless intentionally blitting black or white).
srcXFactor = (srcXFactor * bpp) / srcBpp;
@ -3127,7 +3150,7 @@ void FramebufferManagerCommon::BlitFramebuffer(VirtualFramebuffer *dst, int dstX
float dstXFactor = dst->renderScaleFactor;
float dstYFactor = dst->renderScaleFactor;
const int dstBpp = BufferFormatBytesPerPixel(dst->fb_format);
const int dstBpp = BufferFormatBytesPerPixel(dst->Format(channel));
if (dstBpp != bpp && bpp != 0) {
// If we do this, we're kinda in nonsense territory since the actual formats won't match (unless intentionally blitting black or white).
dstXFactor = (dstXFactor * bpp) / dstBpp;