diff --git a/Common/GPU/OpenGL/GLQueueRunner.cpp b/Common/GPU/OpenGL/GLQueueRunner.cpp index 63f75af330..519939a2d8 100644 --- a/Common/GPU/OpenGL/GLQueueRunner.cpp +++ b/Common/GPU/OpenGL/GLQueueRunner.cpp @@ -1615,7 +1615,7 @@ void GLQueueRunner::PerformBindFramebufferAsRenderTarget(const GLRStep &pass) { CHECK_GL_ERROR_IF_DEBUG(); } -void GLQueueRunner::CopyReadbackBuffer(int width, int height, Draw::DataFormat srcFormat, Draw::DataFormat destFormat, int pixelStride, uint8_t *pixels) { +void GLQueueRunner::CopyFromReadbackBuffer(GLRFramebuffer *framebuffer, int width, int height, Draw::DataFormat srcFormat, Draw::DataFormat destFormat, int pixelStride, uint8_t *pixels) { // TODO: Maybe move data format conversion here, and always read back 8888. Drivers // don't usually provide very optimized conversion implementations, though some do. // Just need to be careful about dithering, which may break Danganronpa. diff --git a/Common/GPU/OpenGL/GLQueueRunner.h b/Common/GPU/OpenGL/GLQueueRunner.h index b91648a1fa..b79ff6b6ae 100644 --- a/Common/GPU/OpenGL/GLQueueRunner.h +++ b/Common/GPU/OpenGL/GLQueueRunner.h @@ -373,7 +373,7 @@ public: return (int)depth * 3 + (int)color; } - void CopyReadbackBuffer(int width, int height, Draw::DataFormat srcFormat, Draw::DataFormat destFormat, int pixelStride, uint8_t *pixels); + void CopyFromReadbackBuffer(GLRFramebuffer *framebuffer, int width, int height, Draw::DataFormat srcFormat, Draw::DataFormat destFormat, int pixelStride, uint8_t *pixels); void Resize(int width, int height) { targetWidth_ = width; diff --git a/Common/GPU/OpenGL/GLRenderManager.cpp b/Common/GPU/OpenGL/GLRenderManager.cpp index f0a1cce354..1c45abd7e3 100644 --- a/Common/GPU/OpenGL/GLRenderManager.cpp +++ b/Common/GPU/OpenGL/GLRenderManager.cpp @@ -360,7 +360,7 @@ void GLRenderManager::BlitFramebuffer(GLRFramebuffer *src, GLRect2D srcRect, GLR steps_.push_back(step); } -bool GLRenderManager::CopyFramebufferToMemorySync(GLRFramebuffer *src, int aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag) { +bool GLRenderManager::CopyFramebufferToMemory(GLRFramebuffer *src, int aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, Draw::ReadbackMode mode, const char *tag) { _assert_(pixels); GLRStep *step = new GLRStep{ GLRStepType::READBACK }; @@ -387,7 +387,7 @@ bool GLRenderManager::CopyFramebufferToMemorySync(GLRFramebuffer *src, int aspec } else { return false; } - queueRunner_.CopyReadbackBuffer(w, h, srcFormat, destFormat, pixelStride, pixels); + queueRunner_.CopyFromReadbackBuffer(src, w, h, srcFormat, destFormat, pixelStride, pixels); return true; } @@ -404,7 +404,7 @@ void GLRenderManager::CopyImageToMemorySync(GLRTexture *texture, int mipLevel, i curRenderStep_ = nullptr; FlushSync(); - queueRunner_.CopyReadbackBuffer(w, h, Draw::DataFormat::R8G8B8A8_UNORM, destFormat, pixelStride, pixels); + queueRunner_.CopyFromReadbackBuffer(nullptr, w, h, Draw::DataFormat::R8G8B8A8_UNORM, destFormat, pixelStride, pixels); } void GLRenderManager::BeginFrame() { diff --git a/Common/GPU/OpenGL/GLRenderManager.h b/Common/GPU/OpenGL/GLRenderManager.h index 2d213be8b8..fe0b42aafd 100644 --- a/Common/GPU/OpenGL/GLRenderManager.h +++ b/Common/GPU/OpenGL/GLRenderManager.h @@ -570,7 +570,7 @@ public: // Binds a framebuffer as a texture, for the following draws. void BindFramebufferAsTexture(GLRFramebuffer *fb, int binding, int aspectBit); - bool CopyFramebufferToMemorySync(GLRFramebuffer *src, int aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag); + bool CopyFramebufferToMemory(GLRFramebuffer *src, int aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, Draw::ReadbackMode mode, const char *tag); void CopyImageToMemorySync(GLRTexture *texture, int mipLevel, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag); void CopyFramebuffer(GLRFramebuffer *src, GLRect2D srcRect, GLRFramebuffer *dst, GLOffset2D dstPos, int aspectMask, const char *tag); diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index 77297a4452..95f43d9217 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -1001,7 +1001,7 @@ bool OpenGLContext::CopyFramebufferToMemory(Framebuffer *src, int channelBits, i aspect |= GL_DEPTH_BUFFER_BIT; if (channelBits & FB_STENCIL_BIT) aspect |= GL_STENCIL_BUFFER_BIT; - renderManager_.CopyFramebufferToMemorySync(fb ? fb->framebuffer_ : nullptr, aspect, x, y, w, h, dataFormat, (uint8_t *)pixels, pixelStride, tag); + renderManager_.CopyFramebufferToMemory(fb ? fb->framebuffer_ : nullptr, aspect, x, y, w, h, dataFormat, (uint8_t *)pixels, pixelStride, mode, tag); return true; } diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 3f1d047f85..a28f54ba0a 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -2074,7 +2074,7 @@ void VulkanQueueRunner::PerformReadbackImage(const VKRStep &step, VkCommandBuffe // Doing that will also act like a heavyweight barrier ensuring that device writes are visible on the host. } -void VulkanQueueRunner::CopyReadbackBuffer(int width, int height, Draw::DataFormat srcFormat, Draw::DataFormat destFormat, int pixelStride, uint8_t *pixels) { +void VulkanQueueRunner::CopyReadbackBuffer(VKRFramebuffer *src, int width, int height, Draw::DataFormat srcFormat, Draw::DataFormat destFormat, int pixelStride, uint8_t *pixels) { if (!readbackBuffer_) return; // Something has gone really wrong. @@ -2082,15 +2082,16 @@ void VulkanQueueRunner::CopyReadbackBuffer(int width, int height, Draw::DataForm void *mappedData; const size_t srcPixelSize = DataFormatSizeInBytes(srcFormat); VkResult res = vmaMapMemory(vulkan_->Allocator(), readbackAllocation_, &mappedData); - if (!readbackBufferIsCoherent_) { - vmaInvalidateAllocation(vulkan_->Allocator(), readbackAllocation_, 0, width * height * srcPixelSize); - } if (res != VK_SUCCESS) { ERROR_LOG(G3D, "CopyReadbackBuffer: vkMapMemory failed! result=%d", (int)res); return; } + if (!readbackBufferIsCoherent_) { + vmaInvalidateAllocation(vulkan_->Allocator(), readbackAllocation_, 0, width * height * srcPixelSize); + } + // TODO: Perform these conversions in a compute shader on the GPU. if (srcFormat == Draw::DataFormat::R8G8B8A8_UNORM) { ConvertFromRGBA8888(pixels, (const uint8_t *)mappedData, pixelStride, width, width, height, destFormat); diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.h b/Common/GPU/Vulkan/VulkanQueueRunner.h index bdfe9aad95..9567a8f243 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.h +++ b/Common/GPU/Vulkan/VulkanQueueRunner.h @@ -252,7 +252,8 @@ public: return (int)depth * 3 + (int)color; } - void CopyReadbackBuffer(int width, int height, Draw::DataFormat srcFormat, Draw::DataFormat destFormat, int pixelStride, uint8_t *pixels); + // src == 0 means to copy from the sync readback buffer. + void CopyReadbackBuffer(VKRFramebuffer *src, int width, int height, Draw::DataFormat srcFormat, Draw::DataFormat destFormat, int pixelStride, uint8_t *pixels); VKRRenderPass *GetRenderPass(const RPKey &key); diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 40ecd8514a..fbe6b72c7d 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -912,8 +912,9 @@ void VulkanRenderManager::BindFramebufferAsRenderTarget(VKRFramebuffer *fb, VKRR } } -bool VulkanRenderManager::CopyFramebufferToMemorySync(VKRFramebuffer *src, VkImageAspectFlags aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag) { +bool VulkanRenderManager::CopyFramebufferToMemory(VKRFramebuffer *src, VkImageAspectFlags aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, Draw::ReadbackMode mode, const char *tag) { _dbg_assert_(insideFrame_); + for (int i = (int)steps_.size() - 1; i >= 0; i--) { if (steps_[i]->stepType == VKRStepType::RENDER && steps_[i]->render.framebuffer == src) { steps_[i]->render.numReads++; @@ -971,7 +972,7 @@ bool VulkanRenderManager::CopyFramebufferToMemorySync(VKRFramebuffer *src, VkIma } // Need to call this after FlushSync so the pixels are guaranteed to be ready in CPU-accessible VRAM. - queueRunner_.CopyReadbackBuffer(w, h, srcFormat, destFormat, pixelStride, pixels); + queueRunner_.CopyReadbackBuffer(src, w, h, srcFormat, destFormat, pixelStride, pixels); return true; } @@ -991,7 +992,7 @@ void VulkanRenderManager::CopyImageToMemorySync(VkImage image, int mipLevel, int FlushSync(); // Need to call this after FlushSync so the pixels are guaranteed to be ready in CPU-accessible VRAM. - queueRunner_.CopyReadbackBuffer(w, h, destFormat, destFormat, pixelStride, pixels); + queueRunner_.CopyReadbackBuffer(nullptr, w, h, destFormat, destFormat, pixelStride, pixels); } static void RemoveDrawCommands(std::vector *cmds) { diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index 4536fcf932..812128b906 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -217,7 +217,7 @@ public: void BindCurrentFramebufferAsInputAttachment0(VkImageAspectFlags aspectBits); - bool CopyFramebufferToMemorySync(VKRFramebuffer *src, VkImageAspectFlags aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag); + bool CopyFramebufferToMemory(VKRFramebuffer *src, VkImageAspectFlags aspectBits, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, Draw::ReadbackMode mode, const char *tag); void CopyImageToMemorySync(VkImage image, int mipLevel, int x, int y, int w, int h, Draw::DataFormat destFormat, uint8_t *pixels, int pixelStride, const char *tag); void CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, VKRFramebuffer *dst, VkOffset2D dstPos, VkImageAspectFlags aspectMask, const char *tag); diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index f65bb1ed2f..14c1c0e502 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -1640,7 +1640,7 @@ bool VKContext::CopyFramebufferToMemory(Framebuffer *srcfb, int channelBits, int if (channelBits & FBChannel::FB_DEPTH_BIT) aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT; if (channelBits & FBChannel::FB_STENCIL_BIT) aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT; - return renderManager_.CopyFramebufferToMemorySync(src ? src->GetFB() : nullptr, aspectMask, x, y, w, h, format, (uint8_t *)pixels, pixelStride, tag); + return renderManager_.CopyFramebufferToMemory(src ? src->GetFB() : nullptr, aspectMask, x, y, w, h, format, (uint8_t *)pixels, pixelStride, mode, tag); } DataFormat VKContext::PreferredFramebufferReadbackFormat(Framebuffer *src) { diff --git a/GPU/Common/DepthBufferCommon.cpp b/GPU/Common/DepthBufferCommon.cpp index c628b61ee6..96ec6c95bd 100644 --- a/GPU/Common/DepthBufferCommon.cpp +++ b/GPU/Common/DepthBufferCommon.cpp @@ -164,7 +164,7 @@ Draw::Pipeline *CreateReadbackPipeline(Draw::DrawContext *draw, const char *tag, return pipeline; } -bool FramebufferManagerCommon::ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride, int destW, int destH) { +bool FramebufferManagerCommon::ReadbackDepthbuffer(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride, int destW, int destH, Draw::ReadbackMode mode) { using namespace Draw; if (!fbo) { @@ -244,13 +244,13 @@ bool FramebufferManagerCommon::ReadbackDepthbufferSync(Draw::Framebuffer *fbo, i draw_->CopyFramebufferToMemory(blitFBO, FB_COLOR_BIT, x * scaleX, y * scaleY, w * scaleX, h * scaleY, - DataFormat::R8G8B8A8_UNORM, convBuf_, destW, ReadbackMode::BLOCK, "ReadbackDepthbufferSync"); + DataFormat::R8G8B8A8_UNORM, convBuf_, destW, mode, "ReadbackDepthbufferSync"); textureCache_->ForgetLastTexture(); // TODO: Use 4444 (or better, R16_UNORM) so we can copy lines directly (instead of 32 -> 16 on CPU)? format16Bit = true; } else { - draw_->CopyFramebufferToMemory(fbo, FB_DEPTH_BIT, x, y, w, h, DataFormat::D32F, convBuf_, w, ReadbackMode::BLOCK, "ReadbackDepthbufferSync"); + draw_->CopyFramebufferToMemory(fbo, FB_DEPTH_BIT, x, y, w, h, DataFormat::D32F, convBuf_, w, mode, "ReadbackDepthbufferSync"); format16Bit = false; } diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 91d3f3c69b..e04cf5d98a 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -1018,7 +1018,7 @@ void FramebufferManagerCommon::DownloadFramebufferOnSwitch(VirtualFramebuffer *v // TODO: This type of download could be made async, for less stutter on framebuffer creation. if (!g_Config.bSkipGPUReadbacks && !PSP_CoreParameter().compat.flags().DisableFirstFrameReadback) { - ReadFramebufferToMemory(vfb, 0, 0, vfb->safeWidth, vfb->safeHeight, RASTER_COLOR); + ReadFramebufferToMemory(vfb, 0, 0, vfb->safeWidth, vfb->safeHeight, RASTER_COLOR, Draw::ReadbackMode::BLOCK); vfb->usageFlags = (vfb->usageFlags | FB_USAGE_DOWNLOAD | FB_USAGE_FIRST_FRAME_SAVED) & ~FB_USAGE_DOWNLOAD_CLEAR; vfb->safeWidth = 0; vfb->safeHeight = 0; @@ -1042,14 +1042,15 @@ bool FramebufferManagerCommon::ShouldDownloadFramebufferDepth(const VirtualFrame void FramebufferManagerCommon::NotifyRenderFramebufferSwitched(VirtualFramebuffer *prevVfb, VirtualFramebuffer *vfb, bool isClearingDepth) { // TODO: Isn't this wrong? Shouldn't we download the prevVfb if anything? if (ShouldDownloadFramebufferColor(vfb) && !vfb->memoryUpdated) { - ReadFramebufferToMemory(vfb, 0, 0, vfb->width, vfb->height, RASTER_COLOR); + ReadFramebufferToMemory(vfb, 0, 0, vfb->width, vfb->height, RASTER_COLOR, Draw::ReadbackMode::BLOCK); vfb->usageFlags = (vfb->usageFlags | FB_USAGE_DOWNLOAD | FB_USAGE_FIRST_FRAME_SAVED) & ~FB_USAGE_DOWNLOAD_CLEAR; } else { DownloadFramebufferOnSwitch(prevVfb); } if (prevVfb && ShouldDownloadFramebufferDepth(prevVfb)) { - ReadFramebufferToMemory(prevVfb, 0, 0, prevVfb->width, prevVfb->height, RasterChannel::RASTER_DEPTH); + // Allow old data here to avoid blocking, if possible - no uses cases for this depend on data being super fresh. + ReadFramebufferToMemory(prevVfb, 0, 0, prevVfb->width, prevVfb->height, RasterChannel::RASTER_DEPTH, Draw::ReadbackMode::OLD_DATA_OK); } textureCache_->ForgetLastTexture(); @@ -1586,7 +1587,7 @@ void FramebufferManagerCommon::DecimateFBOs() { int age = frameLastFramebufUsed_ - std::max(vfb->last_frame_render, vfb->last_frame_used); if (ShouldDownloadFramebufferColor(vfb) && age == 0 && !vfb->memoryUpdated) { - ReadFramebufferToMemory(vfb, 0, 0, vfb->width, vfb->height, RASTER_COLOR); + ReadFramebufferToMemory(vfb, 0, 0, vfb->width, vfb->height, RASTER_COLOR, Draw::ReadbackMode::BLOCK); vfb->usageFlags = (vfb->usageFlags | FB_USAGE_DOWNLOAD | FB_USAGE_FIRST_FRAME_SAVED) & ~FB_USAGE_DOWNLOAD_CLEAR; } @@ -1895,7 +1896,7 @@ bool FramebufferManagerCommon::NotifyFramebufferCopy(u32 src, u32 dst, int size, 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.bSkipGPUReadbacks && (!srcBuffer->memoryUpdated || channel == RASTER_DEPTH)) { - ReadFramebufferToMemory(srcBuffer, 0, srcY, srcBuffer->width, srcH, channel); + ReadFramebufferToMemory(srcBuffer, 0, srcY, srcBuffer->width, srcH, channel, Draw::ReadbackMode::BLOCK); srcBuffer->usageFlags = (srcBuffer->usageFlags | FB_USAGE_DOWNLOAD) & ~FB_USAGE_DOWNLOAD_CLEAR; } return false; @@ -2365,7 +2366,7 @@ bool FramebufferManagerCommon::NotifyBlockTransferBefore(u32 dstBasePtr, int dst if (tooTall) { WARN_LOG_ONCE(btdheight, G3D, "Block transfer download %08x -> %08x dangerous, %d+%d is taller than %d", srcBasePtr, dstBasePtr, srcRect.y, srcRect.h, srcRect.vfb->bufferHeight); } - ReadFramebufferToMemory(srcRect.vfb, static_cast(srcX * srcXFactor), srcY, static_cast(srcRect.w_bytes * srcXFactor), srcRect.h, RASTER_COLOR); + ReadFramebufferToMemory(srcRect.vfb, static_cast(srcX * srcXFactor), srcY, static_cast(srcRect.w_bytes * srcXFactor), srcRect.h, RASTER_COLOR, Draw::ReadbackMode::BLOCK); srcRect.vfb->usageFlags = (srcRect.vfb->usageFlags | FB_USAGE_DOWNLOAD) & ~FB_USAGE_DOWNLOAD_CLEAR; } } @@ -2662,25 +2663,18 @@ bool FramebufferManagerCommon::GetDepthbuffer(u32 fb_address, int fb_stride, u32 bool flipY = (GetGPUBackend() == GPUBackend::OPENGL && !useBufferedRendering_) ? true : false; - bool retval; - if (true) { - // Always use ReadbackDepthbufferSync (while we debug it) - buffer.Allocate(w, h, GPU_DBG_FORMAT_16BIT, flipY); - retval = ReadbackDepthbufferSync(vfb->fbo, 0, 0, w, h, (uint16_t *)buffer.GetData(), w, w, h); + // Old code + if (gstate_c.Use(GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT)) { + buffer.Allocate(w, h, GPU_DBG_FORMAT_FLOAT_DIV_256, flipY); } else { - // Old code - if (gstate_c.Use(GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT)) { - buffer.Allocate(w, h, GPU_DBG_FORMAT_FLOAT_DIV_256, flipY); - } else { - buffer.Allocate(w, h, GPU_DBG_FORMAT_FLOAT, flipY); - } - // No need to free on failure, that's the caller's job (it likely will reuse a buffer.) - retval = draw_->CopyFramebufferToMemory(vfb->fbo, Draw::FB_DEPTH_BIT, 0, 0, w, h, Draw::DataFormat::D32F, buffer.GetData(), w, Draw::ReadbackMode::BLOCK, "GetDepthBuffer"); - if (!retval) { - // Try ReadbackDepthbufferSync, in case GLES. - buffer.Allocate(w, h, GPU_DBG_FORMAT_16BIT, flipY); - retval = ReadbackDepthbufferSync(vfb->fbo, 0, 0, w, h, (uint16_t *)buffer.GetData(), w, w, h); - } + buffer.Allocate(w, h, GPU_DBG_FORMAT_FLOAT, flipY); + } + // No need to free on failure, that's the caller's job (it likely will reuse a buffer.) + bool retval = draw_->CopyFramebufferToMemory(vfb->fbo, Draw::FB_DEPTH_BIT, 0, 0, w, h, Draw::DataFormat::D32F, buffer.GetData(), w, Draw::ReadbackMode::BLOCK, "GetDepthBuffer"); + if (!retval) { + // Try ReadbackDepthbufferSync, in case GLES. + buffer.Allocate(w, h, GPU_DBG_FORMAT_16BIT, flipY); + retval = ReadbackDepthbuffer(vfb->fbo, 0, 0, w, h, (uint16_t *)buffer.GetData(), w, w, h, Draw::ReadbackMode::BLOCK); } // After a readback we'll have flushed and started over, need to dirty a bunch of things to be safe. @@ -2718,8 +2712,7 @@ bool FramebufferManagerCommon::GetStencilbuffer(u32 fb_address, int fb_stride, G buffer.Allocate(w, h, GPU_DBG_FORMAT_8BIT, flipY); bool retval = draw_->CopyFramebufferToMemory(vfb->fbo, Draw::FB_STENCIL_BIT, 0, 0, w,h, Draw::DataFormat::S8, buffer.GetData(), w, Draw::ReadbackMode::BLOCK, "GetStencilbuffer"); if (!retval) { - // Try ReadbackStencilbufferSync, in case GLES. - retval = ReadbackStencilbufferSync(vfb->fbo, 0, 0, w, h, buffer.GetData(), w); + retval = ReadbackStencilbuffer(vfb->fbo, 0, 0, w, h, buffer.GetData(), w, Draw::ReadbackMode::BLOCK); } // That may have unbound the framebuffer, rebind to avoid crashes when debugging. RebindFramebuffer("RebindFramebuffer - GetStencilbuffer"); @@ -2746,7 +2739,7 @@ bool FramebufferManagerCommon::GetOutputFramebuffer(GPUDebugBuffer &buffer) { // (Except using the GPU might cause problems because of various implementations' // dithering behavior and games that expect exact colors like Danganronpa, so we // can't entirely be rid of the CPU path.) -- unknown -void FramebufferManagerCommon::ReadbackFramebufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel) { +void FramebufferManagerCommon::ReadbackFramebuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel, Draw::ReadbackMode mode) { if (w <= 0 || h <= 0) { ERROR_LOG(G3D, "Bad inputs to ReadbackFramebufferSync: %d %d %d %d", x, y, w, h); return; @@ -2788,11 +2781,11 @@ void FramebufferManagerCommon::ReadbackFramebufferSync(VirtualFramebuffer *vfb, if (channel == RASTER_DEPTH) { _assert_msg_(vfb && vfb->z_address != 0 && vfb->z_stride != 0, "Depth buffer invalid"); - ReadbackDepthbufferSync(vfb->fbo, + ReadbackDepthbuffer(vfb->fbo, x * vfb->renderScaleFactor, y * vfb->renderScaleFactor, - w * vfb->renderScaleFactor, h * vfb->renderScaleFactor, (uint16_t *)destPtr, stride, w, h); + w * vfb->renderScaleFactor, h * vfb->renderScaleFactor, (uint16_t *)destPtr, stride, w, h, mode); } else { - draw_->CopyFramebufferToMemory(vfb->fbo, channel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, x, y, w, h, destFormat, destPtr, stride, Draw::ReadbackMode::BLOCK, "ReadbackFramebufferSync"); + draw_->CopyFramebufferToMemory(vfb->fbo, channel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, x, y, w, h, destFormat, destPtr, stride, mode, "ReadbackFramebufferSync"); } char tag[128]; @@ -2802,11 +2795,11 @@ void FramebufferManagerCommon::ReadbackFramebufferSync(VirtualFramebuffer *vfb, gpuStats.numReadbacks++; } -bool FramebufferManagerCommon::ReadbackStencilbufferSync(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint8_t *pixels, int pixelsStride) { - return draw_->CopyFramebufferToMemory(fbo, Draw::FB_DEPTH_BIT, x, y, w, h, Draw::DataFormat::S8, pixels, pixelsStride, Draw::ReadbackMode::BLOCK, "ReadbackStencilbufferSync"); +bool FramebufferManagerCommon::ReadbackStencilbuffer(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint8_t *pixels, int pixelsStride, Draw::ReadbackMode mode) { + return draw_->CopyFramebufferToMemory(fbo, Draw::FB_DEPTH_BIT, x, y, w, h, Draw::DataFormat::S8, pixels, pixelsStride, mode, "ReadbackStencilbufferSync"); } -void FramebufferManagerCommon::ReadFramebufferToMemory(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel) { +void FramebufferManagerCommon::ReadFramebufferToMemory(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel, Draw::ReadbackMode mode) { // Clamp to bufferWidth. Sometimes block transfers can cause this to hit. if (x + w >= vfb->bufferWidth) { w = vfb->bufferWidth - x; @@ -2843,7 +2836,7 @@ void FramebufferManagerCommon::ReadFramebufferToMemory(VirtualFramebuffer *vfb, } // This handles any required stretching internally. - ReadbackFramebufferSync(vfb, x, y, w, h, channel); + ReadbackFramebuffer(vfb, x, y, w, h, channel, mode); draw_->Invalidate(InvalidationFlags::CACHED_RENDER_STATE); textureCache_->ForgetLastTexture(); @@ -2895,7 +2888,7 @@ void FramebufferManagerCommon::DownloadFramebufferForClut(u32 fb_address, u32 lo vfb->clutUpdatedBytes = loadBytes; // This function now handles scaling down internally. - ReadbackFramebufferSync(vfb, x, y, w, h, RASTER_COLOR); + ReadbackFramebuffer(vfb, x, y, w, h, RASTER_COLOR, Draw::ReadbackMode::BLOCK); textureCache_->ForgetLastTexture(); RebindFramebuffer("RebindFramebuffer - DownloadFramebufferForClut"); diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index df4a67bb27..37650a57ba 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -328,7 +328,7 @@ public: void NotifyBlockTransferAfter(u32 dstBasePtr, int dstStride, int dstX, int dstY, u32 srcBasePtr, int srcStride, int srcX, int srcY, int w, int h, int bpp, u32 skipDrawReason); bool BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags, int layer); - void ReadFramebufferToMemory(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel); + void ReadFramebufferToMemory(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel, Draw::ReadbackMode mode); void DownloadFramebufferForClut(u32 fb_address, u32 loadBytes); void DrawFramebufferToOutput(const u8 *srcPixels, int srcStride, GEBufferFormat srcPixelFormat); @@ -457,10 +457,10 @@ public: } protected: - virtual void ReadbackFramebufferSync(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel); + virtual void ReadbackFramebuffer(VirtualFramebuffer *vfb, int x, int y, int w, int h, RasterChannel channel, Draw::ReadbackMode mode); // Used for when a shader is required, such as GLES. - virtual bool ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride, int destW, int destH); - virtual bool ReadbackStencilbufferSync(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint8_t *pixels, int pixelsStride); + virtual bool ReadbackDepthbuffer(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride, int destW, int destH, Draw::ReadbackMode mode); + virtual bool ReadbackStencilbuffer(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint8_t *pixels, int pixelsStride, Draw::ReadbackMode mode); 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); diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index 40824ecd49..e6c29e8264 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -1238,158 +1238,163 @@ void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) { clutTotalBytes_ = loadBytes; clutRenderAddress_ = 0xFFFFFFFF; - if (Memory::IsValidAddress(clutAddr)) { - if (Memory::IsVRAMAddress(clutAddr)) { - // Clear the uncached and mirror bits, etc. to match framebuffers. - const u32 clutLoadAddr = clutAddr & 0x041FFFFF; - const u32 clutLoadEnd = clutLoadAddr + loadBytes; - static const u32 MAX_CLUT_OFFSET = 4096; + if (!Memory::IsValidAddress(clutAddr)) { + memset(clutBufRaw_, 0x00, loadBytes); + // Reload the clut next time (should we really do it in this case?) + clutLastFormat_ = 0xFFFFFFFF; + clutMaxBytes_ = std::max(clutMaxBytes_, loadBytes); + return; + } - clutRenderOffset_ = MAX_CLUT_OFFSET; - const std::vector &framebuffers = framebufferManager_->Framebuffers(); + if (Memory::IsVRAMAddress(clutAddr)) { + // Clear the uncached and mirror bits, etc. to match framebuffers. + const u32 clutLoadAddr = clutAddr & 0x041FFFFF; + const u32 clutLoadEnd = clutLoadAddr + loadBytes; + static const u32 MAX_CLUT_OFFSET = 4096; - u32 bestClutAddress = 0xFFFFFFFF; + clutRenderOffset_ = MAX_CLUT_OFFSET; + const std::vector &framebuffers = framebufferManager_->Framebuffers(); - VirtualFramebuffer *chosenFramebuffer = nullptr; - for (VirtualFramebuffer *framebuffer : framebuffers) { - // Let's not deal with divide by zero. - if (framebuffer->fb_stride == 0) - continue; + u32 bestClutAddress = 0xFFFFFFFF; - const u32 fb_address = framebuffer->fb_address; - const u32 fb_bpp = BufferFormatBytesPerPixel(framebuffer->fb_format); - int offset = clutLoadAddr - fb_address; + VirtualFramebuffer *chosenFramebuffer = nullptr; + for (VirtualFramebuffer *framebuffer : framebuffers) { + // Let's not deal with divide by zero. + if (framebuffer->fb_stride == 0) + continue; - // Is this inside the framebuffer at all? Note that we only check the first line here, this should - // be changed. - bool matchRange = offset >= 0 && offset < (int)(framebuffer->fb_stride * fb_bpp); - if (matchRange) { - // And is it inside the rendered area? Sometimes games pack data in the margin between width and stride. - // If the framebuffer width was detected as 512, we're gonna assume it's really 480. - int fbMatchWidth = framebuffer->width; - if (fbMatchWidth == 512) { - fbMatchWidth = 480; - } - bool inMargin = ((offset / fb_bpp) % framebuffer->fb_stride) == fbMatchWidth; + const u32 fb_address = framebuffer->fb_address; + const u32 fb_bpp = BufferFormatBytesPerPixel(framebuffer->fb_format); + int offset = clutLoadAddr - fb_address; - // The offset check here means, in the context of the loop, that we'll pick - // the framebuffer with the smallest offset. This is yet another framebuffer matching - // loop with its own rules, eventually we'll probably want to do something - // more systematic. - if (matchRange && !inMargin && offset < (int)clutRenderOffset_) { - WARN_LOG_N_TIMES(clutfb, 5, G3D, "Detected LoadCLUT(%d bytes) from framebuffer %08x (%s), byte offset %d", loadBytes, fb_address, GeBufferFormatToString(framebuffer->fb_format), offset); - framebuffer->last_frame_clut = gpuStats.numFlips; - // Also mark used so it's not decimated. - framebuffer->last_frame_used = gpuStats.numFlips; - framebuffer->usageFlags |= FB_USAGE_CLUT; - bestClutAddress = framebuffer->fb_address; - clutRenderOffset_ = (u32)offset; - chosenFramebuffer = framebuffer; - if (offset == 0) { - // Not gonna find a better match according to the smallest-offset rule, so we'll go with this one. - break; - } + // Is this inside the framebuffer at all? Note that we only check the first line here, this should + // be changed. + bool matchRange = offset >= 0 && offset < (int)(framebuffer->fb_stride * fb_bpp); + if (matchRange) { + // And is it inside the rendered area? Sometimes games pack data in the margin between width and stride. + // If the framebuffer width was detected as 512, we're gonna assume it's really 480. + int fbMatchWidth = framebuffer->width; + if (fbMatchWidth == 512) { + fbMatchWidth = 480; + } + bool inMargin = ((offset / fb_bpp) % framebuffer->fb_stride) == fbMatchWidth; + + // The offset check here means, in the context of the loop, that we'll pick + // the framebuffer with the smallest offset. This is yet another framebuffer matching + // loop with its own rules, eventually we'll probably want to do something + // more systematic. + if (matchRange && !inMargin && offset < (int)clutRenderOffset_) { + WARN_LOG_N_TIMES(clutfb, 5, G3D, "Detected LoadCLUT(%d bytes) from framebuffer %08x (%s), byte offset %d", loadBytes, fb_address, GeBufferFormatToString(framebuffer->fb_format), offset); + framebuffer->last_frame_clut = gpuStats.numFlips; + // Also mark used so it's not decimated. + framebuffer->last_frame_used = gpuStats.numFlips; + framebuffer->usageFlags |= FB_USAGE_CLUT; + bestClutAddress = framebuffer->fb_address; + clutRenderOffset_ = (u32)offset; + chosenFramebuffer = framebuffer; + if (offset == 0) { + // Not gonna find a better match according to the smallest-offset rule, so we'll go with this one. + break; } } } - - // To turn off dynamic CLUT (for demonstration or testing purposes), add "false &&" to this check. - if (chosenFramebuffer && chosenFramebuffer->fbo) { - clutRenderAddress_ = bestClutAddress; - - if (!dynamicClutTemp_) { - Draw::FramebufferDesc desc{}; - desc.width = 512; - desc.height = 1; - desc.depth = 1; - desc.z_stencil = false; - desc.numLayers = 1; - desc.multiSampleLevel = 0; - desc.tag = "dynamic_clut"; - dynamicClutFbo_ = draw_->CreateFramebuffer(desc); - desc.tag = "dynamic_clut_temp"; - dynamicClutTemp_ = draw_->CreateFramebuffer(desc); - } - - // We'll need to copy from the offset. - const u32 fb_bpp = BufferFormatBytesPerPixel(chosenFramebuffer->fb_format); - const int totalPixelsOffset = clutRenderOffset_ / fb_bpp; - const int clutYOffset = totalPixelsOffset / chosenFramebuffer->fb_stride; - const int clutXOffset = totalPixelsOffset % chosenFramebuffer->fb_stride; - const int scale = chosenFramebuffer->renderScaleFactor; - - // Copy the pixels to our temp clut, scaling down if needed and wrapping. - framebufferManager_->BlitUsingRaster( - chosenFramebuffer->fbo, clutXOffset * scale, clutYOffset * scale, (clutXOffset + 512.0f) * scale, (clutYOffset + 1.0f) * scale, - dynamicClutTemp_, 0.0f, 0.0f, 512.0f, 1.0f, - false, scale, framebufferManager_->Get2DPipeline(DRAW2D_COPY_COLOR_RECT2LIN), "copy_clut_to_temp"); - - framebufferManager_->RebindFramebuffer("after_copy_clut_to_temp"); - clutRenderFormat_ = chosenFramebuffer->fb_format; - } - NotifyMemInfo(MemBlockFlags::ALLOC, clutAddr, loadBytes, "CLUT"); } - // It's possible for a game to load CLUT outside valid memory without crashing, should result in zeroes. - u32 bytes = Memory::ValidSize(clutAddr, loadBytes); - _assert_(bytes <= 2048); - bool performDownload = PSP_CoreParameter().compat.flags().AllowDownloadCLUT; - if (GPURecord::IsActive()) - performDownload = true; - if (clutRenderAddress_ != 0xFFFFFFFF && performDownload) { - framebufferManager_->DownloadFramebufferForClut(clutRenderAddress_, clutRenderOffset_ + bytes); - Memory::MemcpyUnchecked(clutBufRaw_, clutAddr, bytes); - if (bytes < loadBytes) { - memset((u8 *)clutBufRaw_ + bytes, 0x00, loadBytes - bytes); + // To turn off dynamic CLUT (for demonstration or testing purposes), add "false &&" to this check. + if (chosenFramebuffer && chosenFramebuffer->fbo) { + clutRenderAddress_ = bestClutAddress; + + if (!dynamicClutTemp_) { + Draw::FramebufferDesc desc{}; + desc.width = 512; + desc.height = 1; + desc.depth = 1; + desc.z_stencil = false; + desc.numLayers = 1; + desc.multiSampleLevel = 0; + desc.tag = "dynamic_clut"; + dynamicClutFbo_ = draw_->CreateFramebuffer(desc); + desc.tag = "dynamic_clut_temp"; + dynamicClutTemp_ = draw_->CreateFramebuffer(desc); } - } else { - // Here we could check for clutRenderAddress_ != 0xFFFFFFFF and zero the CLUT or something, - // but choosing not to for now. Though the results of loading the CLUT from RAM here is - // almost certainly going to be bogus. -#ifdef _M_SSE - if (bytes == loadBytes) { - const __m128i *source = (const __m128i *)Memory::GetPointerUnchecked(clutAddr); - __m128i *dest = (__m128i *)clutBufRaw_; - int numBlocks = bytes / 32; - for (int i = 0; i < numBlocks; i++, source += 2, dest += 2) { - __m128i data1 = _mm_loadu_si128(source); - __m128i data2 = _mm_loadu_si128(source + 1); - _mm_store_si128(dest, data1); - _mm_store_si128(dest + 1, data2); - } - } else { - Memory::MemcpyUnchecked(clutBufRaw_, clutAddr, bytes); - if (bytes < loadBytes) { - memset((u8 *)clutBufRaw_ + bytes, 0x00, loadBytes - bytes); - } - } -#elif PPSSPP_ARCH(ARM_NEON) - if (bytes == loadBytes) { - const uint32_t *source = (const uint32_t *)Memory::GetPointerUnchecked(clutAddr); - uint32_t *dest = (uint32_t *)clutBufRaw_; - int numBlocks = bytes / 32; - for (int i = 0; i < numBlocks; i++, source += 8, dest += 8) { - uint32x4_t data1 = vld1q_u32(source); - uint32x4_t data2 = vld1q_u32(source + 4); - vst1q_u32(dest, data1); - vst1q_u32(dest + 4, data2); - } - } else { - Memory::MemcpyUnchecked(clutBufRaw_, clutAddr, bytes); - if (bytes < loadBytes) { - memset((u8 *)clutBufRaw_ + bytes, 0x00, loadBytes - bytes); - } - } -#else - Memory::MemcpyUnchecked(clutBufRaw_, clutAddr, bytes); - if (bytes < loadBytes) { - memset((u8 *)clutBufRaw_ + bytes, 0x00, loadBytes - bytes); - } -#endif + + // We'll need to copy from the offset. + const u32 fb_bpp = BufferFormatBytesPerPixel(chosenFramebuffer->fb_format); + const int totalPixelsOffset = clutRenderOffset_ / fb_bpp; + const int clutYOffset = totalPixelsOffset / chosenFramebuffer->fb_stride; + const int clutXOffset = totalPixelsOffset % chosenFramebuffer->fb_stride; + const int scale = chosenFramebuffer->renderScaleFactor; + + // Copy the pixels to our temp clut, scaling down if needed and wrapping. + framebufferManager_->BlitUsingRaster( + chosenFramebuffer->fbo, clutXOffset * scale, clutYOffset * scale, (clutXOffset + 512.0f) * scale, (clutYOffset + 1.0f) * scale, + dynamicClutTemp_, 0.0f, 0.0f, 512.0f, 1.0f, + false, scale, framebufferManager_->Get2DPipeline(DRAW2D_COPY_COLOR_RECT2LIN), "copy_clut_to_temp"); + + framebufferManager_->RebindFramebuffer("after_copy_clut_to_temp"); + clutRenderFormat_ = chosenFramebuffer->fb_format; + } + NotifyMemInfo(MemBlockFlags::ALLOC, clutAddr, loadBytes, "CLUT"); + } + + // It's possible for a game to load CLUT outside valid memory without crashing, should result in zeroes. + u32 bytes = Memory::ValidSize(clutAddr, loadBytes); + _assert_(bytes <= 2048); + bool performDownload = PSP_CoreParameter().compat.flags().AllowDownloadCLUT; + if (GPURecord::IsActive()) + performDownload = true; + if (clutRenderAddress_ != 0xFFFFFFFF && performDownload) { + framebufferManager_->DownloadFramebufferForClut(clutRenderAddress_, clutRenderOffset_ + bytes); + Memory::MemcpyUnchecked(clutBufRaw_, clutAddr, bytes); + if (bytes < loadBytes) { + memset((u8 *)clutBufRaw_ + bytes, 0x00, loadBytes - bytes); } } else { - memset(clutBufRaw_, 0x00, loadBytes); + // Here we could check for clutRenderAddress_ != 0xFFFFFFFF and zero the CLUT or something, + // but choosing not to for now. Though the results of loading the CLUT from RAM here is + // almost certainly going to be bogus. +#ifdef _M_SSE + if (bytes == loadBytes) { + const __m128i *source = (const __m128i *)Memory::GetPointerUnchecked(clutAddr); + __m128i *dest = (__m128i *)clutBufRaw_; + int numBlocks = bytes / 32; + for (int i = 0; i < numBlocks; i++, source += 2, dest += 2) { + __m128i data1 = _mm_loadu_si128(source); + __m128i data2 = _mm_loadu_si128(source + 1); + _mm_store_si128(dest, data1); + _mm_store_si128(dest + 1, data2); + } + } else { + Memory::MemcpyUnchecked(clutBufRaw_, clutAddr, bytes); + if (bytes < loadBytes) { + memset((u8 *)clutBufRaw_ + bytes, 0x00, loadBytes - bytes); + } + } +#elif PPSSPP_ARCH(ARM_NEON) + if (bytes == loadBytes) { + const uint32_t *source = (const uint32_t *)Memory::GetPointerUnchecked(clutAddr); + uint32_t *dest = (uint32_t *)clutBufRaw_; + int numBlocks = bytes / 32; + for (int i = 0; i < numBlocks; i++, source += 8, dest += 8) { + uint32x4_t data1 = vld1q_u32(source); + uint32x4_t data2 = vld1q_u32(source + 4); + vst1q_u32(dest, data1); + vst1q_u32(dest + 4, data2); + } + } else { + Memory::MemcpyUnchecked(clutBufRaw_, clutAddr, bytes); + if (bytes < loadBytes) { + memset((u8 *)clutBufRaw_ + bytes, 0x00, loadBytes - bytes); + } + } +#else + Memory::MemcpyUnchecked(clutBufRaw_, clutAddr, bytes); + if (bytes < loadBytes) { + memset((u8 *)clutBufRaw_ + bytes, 0x00, loadBytes - bytes); + } +#endif } + // Reload the clut next time. clutLastFormat_ = 0xFFFFFFFF; clutMaxBytes_ = std::max(clutMaxBytes_, loadBytes); diff --git a/GPU/Directx9/FramebufferManagerDX9.cpp b/GPU/Directx9/FramebufferManagerDX9.cpp index a3a37eea4c..364bafbdf8 100644 --- a/GPU/Directx9/FramebufferManagerDX9.cpp +++ b/GPU/Directx9/FramebufferManagerDX9.cpp @@ -50,10 +50,7 @@ FramebufferManagerDX9::FramebufferManagerDX9(Draw::DrawContext *draw) preferredPixelsFormat_ = Draw::DataFormat::B8G8R8A8_UNORM; } -FramebufferManagerDX9::~FramebufferManagerDX9() { -} - -bool FramebufferManagerDX9::ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride, int destW, int destH) { +bool FramebufferManagerDX9::ReadbackDepthbuffer(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride, int destW, int destH, Draw::ReadbackMode mode) { // Don't yet support stretched readbacks here. if (destW != w || destH != h) { return false; diff --git a/GPU/Directx9/FramebufferManagerDX9.h b/GPU/Directx9/FramebufferManagerDX9.h index 5ac924e4e1..37458526fd 100644 --- a/GPU/Directx9/FramebufferManagerDX9.h +++ b/GPU/Directx9/FramebufferManagerDX9.h @@ -31,9 +31,8 @@ class ShaderManagerDX9; class FramebufferManagerDX9 : public FramebufferManagerCommon { public: FramebufferManagerDX9(Draw::DrawContext *draw); - ~FramebufferManagerDX9(); protected: // TODO: The non-color path of FramebufferManagerCommon::ReadbackDepthbufferSync seems to work just as well. - bool ReadbackDepthbufferSync(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride, int destW, int destH) override; + bool ReadbackDepthbuffer(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint16_t *pixels, int pixelsStride, int destW, int destH, Draw::ReadbackMode mode) override; }; diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index 15c123a1e5..bdfaa27e8d 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -36,5 +36,5 @@ public: protected: void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) override; - bool ReadbackStencilbufferSync(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint8_t *pixels, int pixelsStride) override; + bool ReadbackStencilbuffer(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint8_t *pixels, int pixelsStride, Draw::ReadbackMode mode) override; }; diff --git a/GPU/GLES/StencilBufferGLES.cpp b/GPU/GLES/StencilBufferGLES.cpp index 0097e34c59..110d2d94f7 100644 --- a/GPU/GLES/StencilBufferGLES.cpp +++ b/GPU/GLES/StencilBufferGLES.cpp @@ -98,7 +98,7 @@ void main() { Draw::Pipeline *CreateReadbackPipeline(Draw::DrawContext *draw, const char *tag, const UniformBufferDesc *ubDesc, const char *fs, const char *fsTag, const char *vs, const char *vsTag); // Well, this is not depth, but it's depth/stencil related. -bool FramebufferManagerGLES::ReadbackStencilbufferSync(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint8_t *pixels, int pixelsStride) { +bool FramebufferManagerGLES::ReadbackStencilbuffer(Draw::Framebuffer *fbo, int x, int y, int w, int h, uint8_t *pixels, int pixelsStride, Draw::ReadbackMode mode) { using namespace Draw; if (!fbo) { @@ -150,7 +150,7 @@ bool FramebufferManagerGLES::ReadbackStencilbufferSync(Draw::Framebuffer *fbo, i }; draw_->DrawUP(positions, 3); - draw_->CopyFramebufferToMemory(blitFBO, FB_COLOR_BIT, x, y, w, h, DataFormat::R8G8B8A8_UNORM, convBuf_, w, ReadbackMode::BLOCK, "ReadbackStencilbufferSync"); + draw_->CopyFramebufferToMemory(blitFBO, FB_COLOR_BIT, x, y, w, h, DataFormat::R8G8B8A8_UNORM, convBuf_, w, mode, "ReadbackStencilbufferSync"); textureCache_->ForgetLastTexture();