From c6f20bda1887c905be4958d25007b52fbeb5b842 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 22 Aug 2022 23:30:28 +0200 Subject: [PATCH] Reimplement texture format reinterpretation --- GPU/Common/FramebufferManagerCommon.cpp | 137 ++++++++++++++++++------ GPU/Common/FramebufferManagerCommon.h | 14 +-- GPU/Common/ReinterpretFramebuffer.cpp | 99 ----------------- GPU/Common/TextureCacheCommon.cpp | 68 ++++++------ 4 files changed, 145 insertions(+), 173 deletions(-) diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 21e1d061ba..1b39540166 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -274,7 +274,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame EstimateDrawingSize(params.fb_address, params.fb_format, params.viewportWidth, params.viewportHeight, params.regionWidth, params.regionHeight, params.scissorWidth, params.scissorHeight, std::max(params.fb_stride, (u16)4), drawing_width, drawing_height); gstate_c.SetCurRTOffset(0, 0); - bool vfbFormatChanged = false; + bool vfbStrideChanged = false; if (params.fb_address == params.z_address) { // Most likely Z will not be used in this pass, as that would wreak havoc (undefined behavior for sure) @@ -289,16 +289,17 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame const u32 bpp = BufferFormatBytesPerPixel(v->fb_format); - if (params.fb_address == v->fb_address) { + if (params.fb_address == v->fb_address && params.fb_format == v->fb_format && params.fb_stride == v->fb_stride) { vfb = v; - // Update fb stride in case it changed + + // Update fb stride in case it changed. + // + // In reality, this is probably a new different framebuffer... Can't really share + // data between framebuffers with different strides! (or well, we can, with complex + // conversion shaders mapping back to and from memory addresses). if (vfb->fb_stride != params.fb_stride) { vfb->fb_stride = params.fb_stride; - vfbFormatChanged = true; - } - if (vfb->fb_format != params.fb_format) { - vfb->fb_format = params.fb_format; - vfbFormatChanged = true; + vfbStrideChanged = true; } if (vfb->z_address == 0 && vfb->z_stride == 0 && params.z_stride != 0) { @@ -392,7 +393,6 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame vfb->newHeight = drawing_height; vfb->lastFrameNewSize = gpuStats.numFlips; vfb->fb_format = params.fb_format; - vfb->drawnFormat = params.fb_format; vfb->usageFlags = FB_USAGE_RENDER_COLOR; u32 byteSize = ColorBufferByteSize(vfb); @@ -475,7 +475,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame vfb->dirtyAfterDisplay = true; if ((skipDrawReason & SKIPDRAW_SKIPFRAME) == 0) vfb->reallyDirtyAfterDisplay = true; - NotifyRenderFramebufferUpdated(vfb, vfbFormatChanged); + NotifyRenderFramebufferUpdated(vfb, vfbStrideChanged); } vfb->colorBindSeq = GetBindSeqCount(); @@ -558,8 +558,8 @@ void FramebufferManagerCommon::CopyToDepthFromOverlappingFramebuffers(VirtualFra dest->last_frame_depth_updated = gpuStats.numFlips; } else if (source.channel == RASTER_COLOR && draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported) { VirtualFramebuffer *src = source.vfb; - if (src->drawnFormat != GE_FORMAT_565) { - WARN_LOG_ONCE(not565, G3D, "Drawn fb_format of buffer at %08x not 565 as expected", src->fb_address); + if (src->fb_format != GE_FORMAT_565) { + WARN_LOG_ONCE(not565, G3D, "fb_format of buffer at %08x not 565 as expected", src->fb_address); } // Really hate to do this, but tracking the depth swizzle state across multiple @@ -582,20 +582,40 @@ void FramebufferManagerCommon::CopyToDepthFromOverlappingFramebuffers(VirtualFra gstate_c.Dirty(DIRTY_TEXTURE_IMAGE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE); } +// Can't easily dynamically create these strings, we just pass along the pointer. +static const char *reinterpretStrings[3][3] = { + { + "self_reinterpret_565", + "reinterpret_565_to_5551", + "reinterpret_565_to_4444", + }, + { + "reinterpret_5551_to_565", + "self_reinterpret_5551", + "reinterpret_5551_to_4444", + }, + { + "reinterpret_4444_to_565", + "reinterpret_4444_to_5551", + "self_reinterpret_4444", + }, +}; + // Call this after the target has been bound for rendering. For color, raster is probably always going to win over blits/copies. void FramebufferManagerCommon::CopyToColorFromOverlappingFramebuffers(VirtualFramebuffer *dst) { std::vector sources; for (auto src : vfbs_) { // Discard old and equal potential inputs. - if (src == dst || src->colorBindSeq < dst->colorBindSeq) + if (src == dst || src->colorBindSeq < dst->colorBindSeq) { continue; + } if (src->fb_address == dst->fb_address && src->fb_stride == dst->fb_stride) { // Another render target at the exact same location but gotta be a different format, otherwise // it would be the same. _dbg_assert_(src->fb_format != dst->fb_format); - WARN_LOG_ONCE(reint, G3D, "Reinterpret detected at %08x", src->fb_address); - // This is where we'll do reinterprets in the future. + // This will result in reinterpret later, if both formats are 16-bit. + sources.push_back(CopySource{ src, RASTER_COLOR, 0, 0 }); } else if (src->fb_stride == dst->fb_stride && src->fb_format == dst->fb_format) { u32 bytesPerPixel = BufferFormatBytesPerPixel(src->fb_format); @@ -631,9 +651,9 @@ void FramebufferManagerCommon::CopyToColorFromOverlappingFramebuffers(VirtualFra } } else { // Buffers not stride-aligned - ignoring for now. + // This is where we'll add the horizontal offset for GoW. continue; } - gpuStats.numColorCopies++; sources.push_back(CopySource{ src, RASTER_COLOR, xOffset, yOffset }); } } @@ -657,11 +677,38 @@ void FramebufferManagerCommon::CopyToColorFromOverlappingFramebuffers(VirtualFra int dstX2 = dstX1 + dstWidth; int dstY2 = dstY1 + dstHeight; - BlitUsingRaster(src->fbo, 0.0f, 0.0f, srcWidth, srcHeight, - dst->fbo, dstX1, dstY1, dstX2, dstY2, false, Get2DPipeline(DRAW2D_COPY_COLOR), "copy_color"); - } -} + if (source.channel == RASTER_COLOR) { + if (src->fb_format == dst->fb_format) { + gpuStats.numColorCopies++; + BlitUsingRaster(src->fbo, 0.0f, 0.0f, srcWidth, srcHeight, + dst->fbo, dstX1, dstY1, dstX2, dstY2, false, Get2DPipeline(DRAW2D_COPY_COLOR), "copy_color"); + } else if (IsBufferFormat16Bit(src->fb_format) && IsBufferFormat16Bit(dst->fb_format)) { + // Reinterpret! + // WARN_LOG(G3D, "Reinterpret detected from %08x_%s to %08x_%s", + // src->fb_address, GeBufferFormatToString(src->fb_format), + // dst->fb_address, GeBufferFormatToString(dst->fb_format)); + + Draw2DPipeline *pipeline = reinterpretFromTo_[(int)src->fb_format][(int)dst->fb_format]; + if (!pipeline) { + pipeline = draw2D_.Create2DPipeline([=](ShaderWriter &shaderWriter) -> Draw2DPipelineInfo { + return GenerateReinterpretFragmentShader(shaderWriter, src->fb_format, dst->fb_format); + }); + + reinterpretFromTo_[(int)src->fb_format][(int)dst->fb_format] = pipeline; + } + gpuStats.numReinterpretCopies++; + + // OK we have the pipeline, now just do the blit. + BlitUsingRaster(src->fbo, 0.0f, 0.0f, srcWidth, srcHeight, + dst->fbo, dstX1, dstY1, dstX2, dstY2, false, pipeline, reinterpretStrings[(int)src->fb_format][(int)dst->fb_format]); + } + } + } + + shaderManager_->DirtyLastShader(); + textureCache_->ForgetLastTexture(); +} void FramebufferManagerCommon::DestroyFramebuf(VirtualFramebuffer *v) { // Notify the texture cache of both the color and depth buffers. @@ -759,12 +806,9 @@ void FramebufferManagerCommon::NotifyRenderFramebufferCreated(VirtualFramebuffer } } -void FramebufferManagerCommon::NotifyRenderFramebufferUpdated(VirtualFramebuffer *vfb, bool vfbFormatChanged) { - if (vfbFormatChanged) { +void FramebufferManagerCommon::NotifyRenderFramebufferUpdated(VirtualFramebuffer *vfb, bool vfbStrideChanged) { + if (vfbStrideChanged) { textureCache_->NotifyFramebuffer(vfb, NOTIFY_FB_UPDATED); - if (vfb->drawnFormat != vfb->fb_format) { - ReinterpretFramebuffer(vfb, vfb->drawnFormat, vfb->fb_format); - } } // ugly... @@ -787,10 +831,6 @@ void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffe textureCache_->ForgetLastTexture(); shaderManager_->DirtyLastShader(); - if (vfb->drawnFormat != vfb->fb_format) { - ReinterpretFramebuffer(vfb, vfb->drawnFormat, vfb->fb_format); - } - if (useBufferedRendering_) { if (vfb->fbo) { shaderManager_->DirtyLastShader(); @@ -833,10 +873,9 @@ void FramebufferManagerCommon::NotifyVideoUpload(u32 addr, int size, int width, // TODO: Could possibly be an offset... VirtualFramebuffer *vfb = GetVFBAt(addr); if (vfb) { - if (vfb->fb_format != fmt || vfb->drawnFormat != fmt) { - DEBUG_LOG(ME, "Changing fb_format for %08x from %d to %d", addr, vfb->drawnFormat, fmt); + if (vfb->fb_format != fmt) { + DEBUG_LOG(ME, "Changing fb_format for %08x from %d to %d", addr, vfb->fb_format, fmt); vfb->fb_format = fmt; - vfb->drawnFormat = fmt; // Let's count this as a "render". This will also force us to use the correct format. vfb->last_frame_render = gpuStats.numFlips; @@ -1670,7 +1709,6 @@ VirtualFramebuffer *FramebufferManagerCommon::CreateRAMFramebuffer(uint32_t fbAd vfb->bufferWidth = vfb->width; vfb->bufferHeight = vfb->height; vfb->fb_format = format; - vfb->drawnFormat = GE_FORMAT_8888; vfb->usageFlags = FB_USAGE_RENDER_COLOR; SetColorUpdated(vfb, 0); char name[64]; @@ -1724,7 +1762,6 @@ VirtualFramebuffer *FramebufferManagerCommon::FindDownloadTempBuffer(VirtualFram nvfb->fb_format = vfb->fb_format; nvfb->drawnWidth = vfb->drawnWidth; nvfb->drawnHeight = vfb->drawnHeight; - nvfb->drawnFormat = vfb->fb_format; char name[64]; snprintf(name, sizeof(name), "download_temp"); @@ -2340,10 +2377,11 @@ void FramebufferManagerCommon::FlushBeforeCopy() { drawEngine_->DispatchFlush(); } +// TODO: Replace with with depal, reading the palette from the texture on the GPU directly. void FramebufferManagerCommon::DownloadFramebufferForClut(u32 fb_address, u32 loadBytes) { VirtualFramebuffer *vfb = GetVFBAt(fb_address); if (vfb && vfb->fb_stride != 0) { - const u32 bpp = BufferFormatBytesPerPixel(vfb->drawnFormat); + const u32 bpp = BufferFormatBytesPerPixel(vfb->fb_format); int x = 0; int y = 0; int pixels = loadBytes / bpp; @@ -2641,3 +2679,32 @@ void FramebufferManagerCommon::BlitUsingRaster( gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE); } + +VirtualFramebuffer *FramebufferManagerCommon::ResolveFramebufferColorToFormat(VirtualFramebuffer *src, GEBufferFormat newFormat) { + // Look for an identical framebuffer with the new format + _dbg_assert_(src->fb_format != newFormat); + + VirtualFramebuffer *vfb = nullptr; + for (auto dest : vfbs_) { + if (dest == src) { + continue; + } + + if (dest->fb_address == src->fb_address && dest->fb_stride == src->fb_stride && dest->fb_format == newFormat) { + vfb = dest; + break; + } + } + + if (!vfb) { + // Create it! + _dbg_assert_(false); + } + + // OK, now resolve it so we can texture from it. + // This will do any necessary reinterprets. + CopyToColorFromOverlappingFramebuffers(vfb); + // Now we consider the resolved one the latest at the address (though really, we could make them equivalent?). + vfb->colorBindSeq = GetBindSeqCount(); + return vfb; +} diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 23b505b772..4869748fbf 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -65,8 +65,6 @@ class ShaderWriter; // when such a situation is detected. In order to reliably detect this, we separately track depth buffers, // and they know which color buffer they were used with last. struct VirtualFramebuffer { - Draw::Framebuffer *fbo; - u32 fb_address; u32 z_address; // If 0, it's a "RAM" framebuffer. u16 fb_stride; @@ -77,6 +75,8 @@ struct VirtualFramebuffer { // when we need to interpret the bits directly (depal or buffer aliasing). GEBufferFormat fb_format; + Draw::Framebuffer *fbo; + // width/height: The detected size of the current framebuffer, in original PSP pixels. u16 width; u16 height; @@ -104,10 +104,6 @@ struct VirtualFramebuffer { // The scale factor at which we are rendering (to achieve higher resolution). u8 renderScaleFactor; - // The configured buffer format at the time of the latest/current draw. This will change first, then - // if different we'll "reinterpret" the framebuffer to match 'format' as needed. - GEBufferFormat drawnFormat; - u16 usageFlags; // These are used to track state to try to avoid buffer size shifting back and forth. @@ -373,6 +369,11 @@ public: return &draw2D_; } + // If a vfb with the target format exists, resolve it (run CopyToColorFromOverlappingFramebuffers). + // If it doesn't exist, create it and do the same. + // Returns the resolved framebuffer. + VirtualFramebuffer *ResolveFramebufferColorToFormat(VirtualFramebuffer *vfb, GEBufferFormat newFormat); + protected: virtual void PackFramebufferSync_(VirtualFramebuffer *vfb, int x, int y, int w, int h); void SetViewport2D(int x, int y, int w, int h); @@ -426,7 +427,6 @@ protected: dstBuffer->dirtyAfterDisplay = true; dstBuffer->drawnWidth = dstBuffer->width; dstBuffer->drawnHeight = dstBuffer->height; - dstBuffer->drawnFormat = dstBuffer->fb_format; if ((skipDrawReason & SKIPDRAW_SKIPFRAME) == 0) dstBuffer->reallyDirtyAfterDisplay = true; } diff --git a/GPU/Common/ReinterpretFramebuffer.cpp b/GPU/Common/ReinterpretFramebuffer.cpp index a981742aa8..16e8b3f502 100644 --- a/GPU/Common/ReinterpretFramebuffer.cpp +++ b/GPU/Common/ReinterpretFramebuffer.cpp @@ -73,102 +73,3 @@ Draw2DPipelineInfo GenerateReinterpretFragmentShader(ShaderWriter &writer, GEBuf }; } -// Can't easily dynamically create these strings, we just pass along the pointer. -static const char *reinterpretStrings[3][3] = { - { - "self_reinterpret_565", - "reinterpret_565_to_5551", - "reinterpret_565_to_4444", - }, - { - "reinterpret_5551_to_565", - "self_reinterpret_5551", - "reinterpret_5551_to_4444", - }, - { - "reinterpret_4444_to_565", - "reinterpret_4444_to_5551", - "self_reinterpret_4444", - }, -}; - -void FramebufferManagerCommon::ReinterpretFramebuffer(VirtualFramebuffer *vfb, GEBufferFormat oldFormat, GEBufferFormat newFormat) { - if (!useBufferedRendering_ || !vfb->fbo) { - return; - } - - _assert_(newFormat != oldFormat); - // The caller is responsible for updating the format. - _assert_(newFormat == vfb->fb_format); - - ShaderLanguage lang = draw_->GetShaderLanguageDesc().shaderLanguage; - - // Copy image required for now, might get rid of this later. - bool doReinterpret = PSP_CoreParameter().compat.flags().ReinterpretFramebuffers && - (lang == HLSL_D3D11 || lang == GLSL_VULKAN || lang == GLSL_3xx) && - draw_->GetDeviceCaps().framebufferCopySupported; - - if (!doReinterpret) { - // Fake reinterpret - just clear the way we always did on Vulkan. Just clear color and stencil. - if (oldFormat == GE_FORMAT_565) { - // We have to bind here instead of clear, since it can be that no framebuffer is bound. - // The backend can sometimes directly optimize it to a clear. - - // Games that are marked as doing reinterpret just ignore this - better to keep the data than to clear. - // Fixes #13717. - if (!PSP_CoreParameter().compat.flags().ReinterpretFramebuffers && !PSP_CoreParameter().compat.flags().BlueToAlpha) { - draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "FakeReinterpret"); - // Need to dirty anything that has command buffer dynamic state, in case we started a new pass above. - // Should find a way to feed that information back, maybe... Or simply correct the issue in the rendermanager. - gstate_c.Dirty(DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE); - - if (currentRenderVfb_ != vfb) { - // In case ReinterpretFramebuffer was called from the texture manager. - draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "After FakeReinterpret"); - } - } - } - return; - } - - // We only reinterpret between 16 - bit formats, for now. - if (!IsGeBufferFormat16BitColor(oldFormat) || !IsGeBufferFormat16BitColor(newFormat)) { - // 16->32 and 32->16 will require some more specialized shaders. - return; - } - - // See if we need to create a new pipeline. - - Draw2DPipeline *pipeline = reinterpretFromTo_[(int)oldFormat][(int)newFormat]; - if (!pipeline) { - pipeline = draw2D_.Create2DPipeline([=](ShaderWriter &shaderWriter) -> Draw2DPipelineInfo { - return GenerateReinterpretFragmentShader(shaderWriter, oldFormat, newFormat); - }); - - reinterpretFromTo_[(int)oldFormat][(int)newFormat] = pipeline; - } - - // Copy to a temp framebuffer. - Draw::Framebuffer *temp = GetTempFBO(TempFBO::REINTERPRET, vfb->renderWidth, vfb->renderHeight); - - // Ideally on Vulkan this should be using the original framebuffer as an input attachment, allowing it to read from - // itself while writing. - draw_->InvalidateCachedState(); - draw_->CopyFramebufferImage(vfb->fbo, 0, 0, 0, 0, temp, 0, 0, 0, 0, vfb->renderWidth, vfb->renderHeight, 1, Draw::FBChannel::FB_COLOR_BIT, "reinterpret_prep"); - - BlitUsingRaster(temp, 0.0f, 0.0f, vfb->renderWidth, vfb->renderHeight, - vfb->fbo, 0.0f, 0.0f, vfb->renderWidth, vfb->renderHeight, false, pipeline, "reinterpret"); - - // Unbind. - draw_->BindTexture(0, nullptr); - - shaderManager_->DirtyLastShader(); - textureCache_->ForgetLastTexture(); - - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); - - if (currentRenderVfb_ != vfb) { - // In case ReinterpretFramebuffer was called from the texture manager. - draw_->BindFramebufferAsRenderTarget(currentRenderVfb_->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "After reinterpret"); - } -} diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 13c3dbcc64..87746043cb 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -369,10 +369,10 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { int w = gstate.getTextureWidth(level); int h = gstate.getTextureHeight(level); - GETextureFormat format = gstate.getTextureFormat(); - if (format >= 11) { + GETextureFormat texFormat = gstate.getTextureFormat(); + if (texFormat >= 11) { // TODO: Better assumption? Doesn't really matter, these are invalid. - format = GE_TFMT_5650; + texFormat = GE_TFMT_5650; } bool hasClut = gstate.isTextureFormatIndexed(); @@ -386,9 +386,9 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { } else { cluthash = 0; } - u64 cachekey = TexCacheEntry::CacheKey(texaddr, format, dim, cluthash); + u64 cachekey = TexCacheEntry::CacheKey(texaddr, texFormat, dim, cluthash); - int bufw = GetTextureBufw(0, texaddr, format); + int bufw = GetTextureBufw(0, texaddr, texFormat); u8 maxLevel = gstate.getTextureMaxLevel(); u32 minihash = MiniHash((const u32 *)Memory::GetPointerUnchecked(texaddr)); @@ -408,7 +408,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { if (entryIter != cache_.end()) { entry = entryIter->second.get(); // Validate the texture still matches the cache entry. - bool match = entry->Matches(dim, format, maxLevel); + bool match = entry->Matches(dim, texFormat, maxLevel); const char *reason = "different params"; // Check for FBO changes. @@ -502,7 +502,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { gstate_c.SetTextureIs3D((entry->status & TexCacheEntry::STATUS_3D) != 0); if (rehash) { // Update in case any of these changed. - entry->sizeInRAM = (textureBitsPerPixel[format] * bufw * h / 2) / 8; + entry->sizeInRAM = (textureBitsPerPixel[texFormat] * bufw * h / 2) / 8; entry->bufw = bufw; entry->cluthash = cluthash; } @@ -529,7 +529,7 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { TextureDefinition def{}; def.addr = texaddr; def.dim = dim; - def.format = format; + def.format = texFormat; def.bufw = bufw; std::vector candidates = GetFramebufferCandidates(def, 0); @@ -594,12 +594,12 @@ TexCacheEntry *TextureCacheCommon::SetTexture() { entry->addr = texaddr; entry->minihash = minihash; entry->dim = dim; - entry->format = format; + entry->format = texFormat; entry->maxLevel = maxLevel; // This would overestimate the size in many case so we underestimate instead // to avoid excessive clearing caused by cache invalidations. - entry->sizeInRAM = (textureBitsPerPixel[format] * bufw * h / 2) / 8; + entry->sizeInRAM = (textureBitsPerPixel[texFormat] * bufw * h / 2) / 8; entry->bufw = bufw; entry->cluthash = cluthash; @@ -638,7 +638,7 @@ std::vector TextureCacheCommon::GetFramebufferCandidates(const if (candidates.size() > 1) { std::string cands; for (auto &candidate : candidates) { - cands += candidate.ToString() + " "; + cands += candidate.ToString() + "\n"; } WARN_LOG_REPORT_ONCE(multifbcandidate, G3D, "GetFramebufferCandidates: Multiple (%d) candidate framebuffers. texaddr: %08x offset: %d (%dx%d stride %d, %s):\n%s", @@ -908,18 +908,18 @@ bool TextureCacheCommon::MatchFramebuffer( // If they match "exactly", it's non-CLUT and from the top left. if (exactMatch) { if (fb_stride != entry.bufw) { - WARN_LOG_ONCE(diffStrides1, G3D, "Texturing from framebuffer with different strides %d != %d", entry.bufw, (int)fb_stride); + WARN_LOG_ONCE(diffStrides1, G3D, "Found matching framebuffer with different strides %d != %d", entry.bufw, (int)fb_stride); } // NOTE: This check is okay because the first texture formats are the same as the buffer formats. if (IsTextureFormatBufferCompatible(entry.format)) { if (TextureFormatMatchesBufferFormat(entry.format, fb_format) || (framebuffer->usageFlags & FB_USAGE_BLUE_TO_ALPHA)) { return true; } else if (IsTextureFormat16Bit(entry.format) && IsBufferFormat16Bit(fb_format) && channel == RASTER_COLOR) { - WARN_LOG_ONCE(diffFormat1, G3D, "Texturing from framebuffer with reinterpretable fb_format: %s != %s", GeTextureFormatToString(entry.format), GeBufferFormatToString(fb_format)); + WARN_LOG_ONCE(diffFormat1, G3D, "Found matching framebuffer with reinterpretable fb_format: %s != %s", GeTextureFormatToString(entry.format), GeBufferFormatToString(fb_format)); *matchInfo = FramebufferMatchInfo{ 0, 0, true, TextureFormatToBufferFormat(entry.format) }; return true; } else { - WARN_LOG_ONCE(diffFormat2, G3D, "Not texturing from framebuffer with incompatible formats %s != %s", GeTextureFormatToString(entry.format), GeBufferFormatToString(fb_format)); + WARN_LOG_ONCE(diffFormat2, G3D, "Rejecting framebuffer with incompatible formats %s != %s", GeTextureFormatToString(entry.format), GeBufferFormatToString(fb_format)); return false; } } else { @@ -954,7 +954,7 @@ bool TextureCacheCommon::MatchFramebuffer( if (fb_stride != entry.bufw) { if (noOffset) { - WARN_LOG_ONCE(diffStrides2, G3D, "Texturing from framebuffer (matching_clut=%s) different strides %d != %d", matchingClutFormat ? "yes" : "no", entry.bufw, fb_stride); + WARN_LOG_ONCE(diffStrides2, G3D, "Matching framebuffer(matching_clut = % s) different strides % d != % d", matchingClutFormat ? "yes" : "no", entry.bufw, fb_stride); // Continue on with other checks. // Not actually sure why we even try here. There's no way it'll go well if the strides are different. } else { @@ -980,7 +980,7 @@ bool TextureCacheCommon::MatchFramebuffer( // 3rd Birthday (and a bunch of other games) render to a 16 bit clut texture. if (matchingClutFormat) { if (!noOffset) { - WARN_LOG_ONCE(subareaClut, G3D, "Texturing from framebuffer (%s) using %s with offset at %08x +%dx%d", channel == RASTER_DEPTH ? "DEPTH" : "COLOR", GeTextureFormatToString(entry.format), fb_address, matchInfo->xOffset, matchInfo->yOffset); + WARN_LOG_ONCE(subareaClut, G3D, "Matching framebuffer (%s) using %s with offset at %08x +%dx%d", channel == RASTER_DEPTH ? "DEPTH" : "COLOR", GeTextureFormatToString(entry.format), fb_address, matchInfo->xOffset, matchInfo->yOffset); } return true; } else if (IsClutFormat((GETextureFormat)(entry.format)) || IsDXTFormat((GETextureFormat)(entry.format))) { @@ -991,15 +991,15 @@ bool TextureCacheCommon::MatchFramebuffer( // This is either normal or we failed to generate a shader to depalettize if ((int)fb_format == (int)entry.format || matchingClutFormat) { if ((int)fb_format != (int)entry.format) { - WARN_LOG_ONCE(diffFormat2, G3D, "Texturing from framebuffer with different formats %s != %s at %08x", + WARN_LOG_ONCE(diffFormat2, G3D, "Matching framebuffer with different formats %s != %s at %08x", GeTextureFormatToString(entry.format), GeBufferFormatToString(fb_format), fb_address); return true; } else { - WARN_LOG_ONCE(subarea, G3D, "Texturing from framebuffer at %08x +%dx%d", fb_address, matchInfo->xOffset, matchInfo->yOffset); + WARN_LOG_ONCE(subarea, G3D, "Matching from framebuffer at %08x +%dx%d", fb_address, matchInfo->xOffset, matchInfo->yOffset); return true; } } else { - WARN_LOG_ONCE(diffFormat2, G3D, "Texturing from framebuffer with incompatible format %s != %s at %08x", + WARN_LOG_ONCE(diffFormat2, G3D, "Ignoring possible texturing from framebuffer with incompatible format %s != %s at %08x", GeTextureFormatToString(entry.format), GeBufferFormatToString(fb_format), fb_address); return false; } @@ -1009,11 +1009,10 @@ bool TextureCacheCommon::MatchFramebuffer( void TextureCacheCommon::SetTextureFramebuffer(const AttachCandidate &candidate) { VirtualFramebuffer *framebuffer = candidate.fb; FramebufferMatchInfo fbInfo = candidate.match; + RasterChannel channel = candidate.channel; if (candidate.match.reinterpret) { - GEBufferFormat oldFormat = candidate.fb->fb_format; - candidate.fb->fb_format = candidate.match.reinterpretTo; - framebufferManager_->ReinterpretFramebuffer(candidate.fb, oldFormat, candidate.match.reinterpretTo); + framebuffer = framebufferManager_->ResolveFramebufferColorToFormat(candidate.fb, candidate.match.reinterpretTo); } _dbg_assert_msg_(framebuffer != nullptr, "Framebuffer must not be null."); @@ -1043,7 +1042,7 @@ void TextureCacheCommon::SetTextureFramebuffer(const AttachCandidate &candidate) gstate_c.SetNeedShaderTexclamp(true); } - if (candidate.channel == RASTER_DEPTH && !gstate_c.Supports(GPU_SUPPORTS_DEPTH_TEXTURE)) { + if (channel == RASTER_DEPTH && !gstate_c.Supports(GPU_SUPPORTS_DEPTH_TEXTURE)) { WARN_LOG_ONCE(ndepthtex, G3D, "Depth textures not supported, not binding"); // Flag to bind a null texture if we can't support depth textures. // Should only happen on old OpenGL. @@ -1051,7 +1050,7 @@ void TextureCacheCommon::SetTextureFramebuffer(const AttachCandidate &candidate) failedTexture_ = true; } else { nextFramebufferTexture_ = framebuffer; - nextFramebufferTextureChannel_ = candidate.channel; + nextFramebufferTextureChannel_ = channel; } nextTexture_ = nullptr; } else { @@ -1152,7 +1151,7 @@ void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) { const std::vector &framebuffers = framebufferManager_->Framebuffers(); for (VirtualFramebuffer *framebuffer : framebuffers) { const u32 fb_address = framebuffer->fb_address & 0x3FFFFFFF; - const u32 bpp = BufferFormatBytesPerPixel(framebuffer->drawnFormat); + const u32 bpp = BufferFormatBytesPerPixel(framebuffer->fb_format); u32 offset = clutFramebufAddr - fb_address; // Is this inside the framebuffer at all? @@ -1833,7 +1832,7 @@ void TextureCacheCommon::ApplyTexture() { gstate_c.SetTextureIs3D((entry->status & TexCacheEntry::STATUS_3D) != 0); } -bool CanDepalettize(GETextureFormat texFormat, GEBufferFormat bufferFormat) { +static bool CanDepalettize(GETextureFormat texFormat, GEBufferFormat bufferFormat) { if (IsClutFormat(texFormat)) { switch (bufferFormat) { case GE_FORMAT_4444: @@ -1890,7 +1889,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer uint32_t clutMode = gstate.clutformat & 0xFFFFFF; bool depth = channel == RASTER_DEPTH; - bool need_depalettize = CanDepalettize(texFormat, depth ? GE_FORMAT_DEPTH16 : framebuffer->drawnFormat); + bool need_depalettize = CanDepalettize(texFormat, depth ? GE_FORMAT_DEPTH16 : framebuffer->fb_format); // Shader depal is not supported during 3D texturing or depth texturing, and requires 32-bit integer instructions in the shader. bool useShaderDepal = framebufferManager_->GetCurrentRenderVFB() != framebuffer && @@ -1914,7 +1913,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer if (need_depalettize && !g_Config.bDisableSlowFramebufEffects) { clutTexture = textureShaderCache_->GetClutTexture(clutFormat, clutHash_, clutBufRaw_); - smoothedDepal = CanUseSmoothDepal(gstate, framebuffer->drawnFormat, clutTexture.rampLength); + smoothedDepal = CanUseSmoothDepal(gstate, framebuffer->fb_format, clutTexture.rampLength); if (useShaderDepal) { // Very icky conflation here of native and thin3d rendering. This will need careful work per backend in BindAsClutTexture. @@ -1932,9 +1931,9 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer // Since we started/ended render passes, might need these. gstate_c.Dirty(DIRTY_DEPAL); - gstate_c.SetUseShaderDepal(true, smoothedDepal); - gstate_c.depalFramebufferFormat = framebuffer->drawnFormat; + gstate_c.depalFramebufferFormat = framebuffer->fb_format; + const u32 bytesPerColor = clutFormat == GE_CMODE_32BIT_ABGR8888 ? sizeof(u32) : sizeof(u16); const u32 clutTotalColors = clutMaxBytes_ / bytesPerColor; CheckAlphaResult alphaStatus = CheckCLUTAlpha((const uint8_t *)clutBufRaw_, clutFormat, clutTotalColors); @@ -1945,7 +1944,7 @@ void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer return; } - textureShader = textureShaderCache_->GetDepalettizeShader(clutMode, texFormat, depth ? GE_FORMAT_DEPTH16 : framebuffer->drawnFormat, smoothedDepal); + textureShader = textureShaderCache_->GetDepalettizeShader(clutMode, texFormat, depth ? GE_FORMAT_DEPTH16 : framebuffer->fb_format, smoothedDepal); gstate_c.SetUseShaderDepal(false, false); } @@ -2204,7 +2203,12 @@ void TextureCacheCommon::ClearNextFrame() { } std::string AttachCandidate::ToString() const { - return StringFromFormat("[%s seq:%d C:%08x/%d Z:%08x/%d X:%d Y:%d reint: %s]", this->channel == RASTER_COLOR ? "COLOR" : "DEPTH", this->seqCount, this->fb->fb_address, this->fb->fb_stride, this->fb->z_address, this->fb->z_stride, this->match.xOffset, this->match.yOffset, this->match.reinterpret ? "true" : "false"); + return StringFromFormat("[%s seq:%d C:%08x/%d(%s) Z:%08x/%d X:%d Y:%d reint: %s]", + this->channel == RASTER_COLOR ? "COLOR" : "DEPTH", + this->seqCount, + this->fb->fb_address, this->fb->fb_stride, GeBufferFormatToString(this->fb->fb_format), + this->fb->z_address, this->fb->z_stride, + this->match.xOffset, this->match.yOffset, this->match.reinterpret ? "true" : "false"); } bool TextureCacheCommon::PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEntry *entry) {