diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4d96d72320..a40d4334ec 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1070,6 +1070,7 @@ add_library(native STATIC
ext/native/util/text/wrap_text.h
ext/native/util/text/wrap_text.cpp
ext/native/util/const_map.h
+ ext/native/util/tiny_set.h
ext/native/ext/jpge/jpgd.cpp
ext/native/ext/jpge/jpgd.h
ext/native/ext/jpge/jpge.cpp
diff --git a/GPU/Common/FramebufferCommon.cpp b/GPU/Common/FramebufferCommon.cpp
index e3701b6d48..298f54d8ba 100644
--- a/GPU/Common/FramebufferCommon.cpp
+++ b/GPU/Common/FramebufferCommon.cpp
@@ -1351,11 +1351,10 @@ VirtualFramebuffer *FramebufferManagerCommon::CreateRAMFramebuffer(uint32_t fbAd
VirtualFramebuffer *FramebufferManagerCommon::FindDownloadTempBuffer(VirtualFramebuffer *vfb) {
// For now we'll keep these on the same struct as the ones that can get displayed
// (and blatantly copy work already done above while at it).
- VirtualFramebuffer *nvfb = 0;
+ VirtualFramebuffer *nvfb = nullptr;
// We maintain a separate vector of framebuffer objects for blitting.
- for (size_t i = 0; i < bvfbs_.size(); ++i) {
- VirtualFramebuffer *v = bvfbs_[i];
+ for (VirtualFramebuffer *v : bvfbs_) {
if (v->fb_address == vfb->fb_address && v->format == vfb->format) {
if (v->bufferWidth == vfb->bufferWidth && v->bufferHeight == vfb->bufferHeight) {
nvfb = v;
@@ -1405,6 +1404,34 @@ VirtualFramebuffer *FramebufferManagerCommon::FindDownloadTempBuffer(VirtualFram
return nvfb;
}
+bool FramebufferManagerCommon::CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) {
+ // When updating VRAM, it need to be exact format.
+ if (!gstate_c.Supports(GPU_PREFER_CPU_DOWNLOAD)) {
+ switch (nvfb->format) {
+ case GE_FORMAT_4444:
+ nvfb->colorDepth = Draw::FBO_4444;
+ break;
+ case GE_FORMAT_5551:
+ nvfb->colorDepth = Draw::FBO_5551;
+ break;
+ case GE_FORMAT_565:
+ nvfb->colorDepth = Draw::FBO_565;
+ break;
+ case GE_FORMAT_8888:
+ default:
+ nvfb->colorDepth = Draw::FBO_8888;
+ break;
+ }
+ }
+
+ nvfb->fbo = draw_->CreateFramebuffer({ nvfb->bufferWidth, nvfb->bufferHeight, 1, 1, false, (Draw::FBColorDepth)nvfb->colorDepth });
+ if (!nvfb->fbo) {
+ ERROR_LOG(FRAMEBUF, "Error creating GL FBO! %i x %i", nvfb->renderWidth, nvfb->renderHeight);
+ return false;
+ }
+ return true;
+}
+
void FramebufferManagerCommon::ApplyClearToMemory(int x1, int y1, int x2, int y2, u32 clearColor) {
if (currentRenderVfb_) {
if ((currentRenderVfb_->usageFlags & FB_USAGE_DOWNLOAD_CLEAR) != 0) {
@@ -1969,8 +1996,10 @@ void FramebufferManagerCommon::ReadFramebufferToMemory(VirtualFramebuffer *vfb,
PackFramebufferSync_(vfb, x, y, w, h);
} else {
VirtualFramebuffer *nvfb = FindDownloadTempBuffer(vfb);
- BlitFramebuffer(nvfb, x, y, vfb, x, y, w, h, 0);
- PackFramebufferSync_(nvfb, x, y, w, h);
+ if (nvfb) {
+ BlitFramebuffer(nvfb, x, y, vfb, x, y, w, h, 0);
+ PackFramebufferSync_(nvfb, x, y, w, h);
+ }
}
textureCache_->ForgetLastTexture();
@@ -2014,9 +2043,10 @@ void FramebufferManagerCommon::DownloadFramebufferForClut(u32 fb_address, u32 lo
// We'll pseudo-blit framebuffers here to get a resized version of vfb.
VirtualFramebuffer *nvfb = FindDownloadTempBuffer(vfb);
- BlitFramebuffer(nvfb, x, y, vfb, x, y, w, h, 0);
-
- PackFramebufferSync_(nvfb, x, y, w, h);
+ if (nvfb) {
+ BlitFramebuffer(nvfb, x, y, vfb, x, y, w, h, 0);
+ PackFramebufferSync_(nvfb, x, y, w, h);
+ }
textureCache_->ForgetLastTexture();
RebindFramebuffer();
diff --git a/GPU/Common/FramebufferCommon.h b/GPU/Common/FramebufferCommon.h
index f95a12670f..bf92ae189d 100644
--- a/GPU/Common/FramebufferCommon.h
+++ b/GPU/Common/FramebufferCommon.h
@@ -339,7 +339,7 @@ protected:
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);
VirtualFramebuffer *FindDownloadTempBuffer(VirtualFramebuffer *vfb);
- virtual bool CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) = 0;
+ virtual bool CreateDownloadTempBuffer(VirtualFramebuffer *nvfb);
virtual void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) = 0;
VirtualFramebuffer *CreateRAMFramebuffer(uint32_t fbAddress, int width, int height, int stride, GEBufferFormat format);
diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp
index 6bca9211b9..70e2b19bfc 100644
--- a/GPU/D3D11/FramebufferManagerD3D11.cpp
+++ b/GPU/D3D11/FramebufferManagerD3D11.cpp
@@ -366,19 +366,6 @@ void FramebufferManagerD3D11::BindFramebufferAsColorTexture(int stage, VirtualFr
}
}
-bool FramebufferManagerD3D11::CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) {
- nvfb->colorDepth = Draw::FBO_8888;
-
- nvfb->fbo = draw_->CreateFramebuffer({ nvfb->bufferWidth, nvfb->bufferHeight, 1, 1, true, (Draw::FBColorDepth)nvfb->colorDepth });
- if (!(nvfb->fbo)) {
- ERROR_LOG(FRAMEBUF, "Error creating FBO! %i x %i", nvfb->renderWidth, nvfb->renderHeight);
- return false;
- }
-
- draw_->BindFramebufferAsRenderTarget(nvfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR });
- return true;
-}
-
void FramebufferManagerD3D11::UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) {
// Nothing to do here.
}
diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h
index aa8641bb14..73b917f326 100644
--- a/GPU/D3D11/FramebufferManagerD3D11.h
+++ b/GPU/D3D11/FramebufferManagerD3D11.h
@@ -60,7 +60,6 @@ protected:
// Used by ReadFramebufferToMemory and later framebuffer block copies
void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp) override;
- bool CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) override;
void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) override;
private:
diff --git a/GPU/Directx9/FramebufferDX9.cpp b/GPU/Directx9/FramebufferDX9.cpp
index 877b196e64..0300bbf45a 100644
--- a/GPU/Directx9/FramebufferDX9.cpp
+++ b/GPU/Directx9/FramebufferDX9.cpp
@@ -379,19 +379,6 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = {
}
}
- bool FramebufferManagerDX9::CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) {
- nvfb->colorDepth = Draw::FBO_8888;
-
- nvfb->fbo = draw_->CreateFramebuffer({ nvfb->bufferWidth, nvfb->bufferHeight, 1, 1, true, (Draw::FBColorDepth)nvfb->colorDepth });
- if (!(nvfb->fbo)) {
- ERROR_LOG(FRAMEBUF, "Error creating FBO! %i x %i", nvfb->renderWidth, nvfb->renderHeight);
- return false;
- }
-
- draw_->BindFramebufferAsRenderTarget(nvfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR });
- return true;
- }
-
void FramebufferManagerDX9::UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) {
// Nothing to do here.
}
diff --git a/GPU/Directx9/FramebufferDX9.h b/GPU/Directx9/FramebufferDX9.h
index 3de91750c1..bab50d4dfc 100644
--- a/GPU/Directx9/FramebufferDX9.h
+++ b/GPU/Directx9/FramebufferDX9.h
@@ -71,7 +71,6 @@ protected:
// Used by ReadFramebufferToMemory and later framebuffer block copies
void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp) override;
- bool CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) override;
void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) override;
private:
diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp
index 0800a8b917..266b4fde93 100644
--- a/GPU/GLES/FramebufferManagerGLES.cpp
+++ b/GPU/GLES/FramebufferManagerGLES.cpp
@@ -313,39 +313,11 @@ void FramebufferManagerGLES::BindFramebufferAsColorTexture(int stage, VirtualFra
}
}
-bool FramebufferManagerGLES::CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) {
- // When updating VRAM, it need to be exact format.
- if (!gstate_c.Supports(GPU_PREFER_CPU_DOWNLOAD)) {
- switch (nvfb->format) {
- case GE_FORMAT_4444:
- nvfb->colorDepth = Draw::FBO_4444;
- break;
- case GE_FORMAT_5551:
- nvfb->colorDepth = Draw::FBO_5551;
- break;
- case GE_FORMAT_565:
- nvfb->colorDepth = Draw::FBO_565;
- break;
- case GE_FORMAT_8888:
- default:
- nvfb->colorDepth = Draw::FBO_8888;
- break;
- }
- }
-
- nvfb->fbo = draw_->CreateFramebuffer({ nvfb->bufferWidth, nvfb->bufferHeight, 1, 1, false, (Draw::FBColorDepth)nvfb->colorDepth });
- if (!nvfb->fbo) {
- ERROR_LOG(FRAMEBUF, "Error creating GL FBO! %i x %i", nvfb->renderWidth, nvfb->renderHeight);
- return false;
- }
- return true;
-}
-
void FramebufferManagerGLES::UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) {
_assert_msg_(G3D, nvfb->fbo, "Expecting a valid nvfb in UpdateDownloadTempBuffer");
// Discard the previous contents of this buffer where possible.
- if (gl_extensions.GLES3 && glInvalidateFramebuffer != nullptr) {
+ if (gl_extensions.GLES3) {
draw_->BindFramebufferAsRenderTarget(nvfb->fbo, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE });
} else if (gl_extensions.IsGLES) {
draw_->BindFramebufferAsRenderTarget(nvfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR });
diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h
index 33d364fe7b..25f541fd81 100644
--- a/GPU/GLES/FramebufferManagerGLES.h
+++ b/GPU/GLES/FramebufferManagerGLES.h
@@ -64,7 +64,6 @@ protected:
// Used by ReadFramebufferToMemory and later framebuffer block copies
void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp) override;
- bool CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) override;
void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) override;
private:
diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp
index 5bb733ddb0..dfef7d47b7 100644
--- a/GPU/Vulkan/FramebufferVulkan.cpp
+++ b/GPU/Vulkan/FramebufferVulkan.cpp
@@ -325,19 +325,6 @@ VkImageView FramebufferManagerVulkan::BindFramebufferAsColorTexture(int stage, V
}
}
-bool FramebufferManagerVulkan::CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) {
- nvfb->colorDepth = Draw::FBO_8888;
-
- nvfb->fbo = draw_->CreateFramebuffer({ nvfb->bufferWidth, nvfb->bufferHeight, 1, 1, true, (Draw::FBColorDepth)nvfb->colorDepth });
- if (!(nvfb->fbo)) {
- ERROR_LOG(FRAMEBUF, "Error creating FBO! %i x %i", nvfb->renderWidth, nvfb->renderHeight);
- return false;
- }
-
- draw_->BindFramebufferAsRenderTarget(nvfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR });
- return true;
-}
-
void FramebufferManagerVulkan::UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) {
// Nothing to do here.
}
diff --git a/GPU/Vulkan/FramebufferVulkan.h b/GPU/Vulkan/FramebufferVulkan.h
index d17d836216..bbd799e1d0 100644
--- a/GPU/Vulkan/FramebufferVulkan.h
+++ b/GPU/Vulkan/FramebufferVulkan.h
@@ -71,7 +71,6 @@ protected:
// Used by ReadFramebufferToMemory and later framebuffer block copies
void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp) override;
- bool CreateDownloadTempBuffer(VirtualFramebuffer *nvfb) override;
void UpdateDownloadTempBuffer(VirtualFramebuffer *nvfb) override;
private:
diff --git a/GPU/Vulkan/GPU_Vulkan.cpp b/GPU/Vulkan/GPU_Vulkan.cpp
index 6cd2493f5a..43de4d1078 100644
--- a/GPU/Vulkan/GPU_Vulkan.cpp
+++ b/GPU/Vulkan/GPU_Vulkan.cpp
@@ -231,6 +231,7 @@ void GPU_Vulkan::CheckGPUFeatures() {
features |= GPU_SUPPORTS_INSTANCE_RENDERING;
features |= GPU_SUPPORTS_VERTEX_TEXTURE_FETCH;
features |= GPU_SUPPORTS_TEXTURE_FLOAT;
+ features |= GPU_PREFER_CPU_DOWNLOAD;
if (vulkan_->GetDeviceFeatures().enabled.wideLines) {
features |= GPU_SUPPORTS_WIDE_LINES;
diff --git a/ext/native/native.vcxproj b/ext/native/native.vcxproj
index 80b0f68e59..60f361b959 100644
--- a/ext/native/native.vcxproj
+++ b/ext/native/native.vcxproj
@@ -489,6 +489,7 @@
+
diff --git a/ext/native/native.vcxproj.filters b/ext/native/native.vcxproj.filters
index 82e64872aa..9c6af13184 100644
--- a/ext/native/native.vcxproj.filters
+++ b/ext/native/native.vcxproj.filters
@@ -350,6 +350,9 @@
ui
+
+ util
+
diff --git a/ext/native/thin3d/GLQueueRunner.cpp b/ext/native/thin3d/GLQueueRunner.cpp
index 20c5bf7800..5a297aa974 100644
--- a/ext/native/thin3d/GLQueueRunner.cpp
+++ b/ext/native/thin3d/GLQueueRunner.cpp
@@ -827,13 +827,16 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step) {
{
GLenum attachments[3];
int count = 0;
+ bool isFBO = step.render.framebuffer != nullptr;
+ bool hasDepth = isFBO ? step.render.framebuffer->z_stencil_ : false;
if (c.clear.clearMask & GL_COLOR_BUFFER_BIT)
- attachments[count++] = GL_COLOR_ATTACHMENT0;
- if (c.clear.clearMask & GL_DEPTH_BUFFER_BIT)
- attachments[count++] = GL_DEPTH_ATTACHMENT;
- if (c.clear.clearMask & GL_STENCIL_BUFFER_BIT)
- attachments[count++] = GL_STENCIL_BUFFER_BIT;
- glInvalidateFramebuffer(GL_FRAMEBUFFER, count, attachments);
+ attachments[count++] = isFBO ? GL_COLOR_ATTACHMENT0 : GL_COLOR;
+ if (hasDepth && (c.clear.clearMask & GL_DEPTH_BUFFER_BIT))
+ attachments[count++] = isFBO ? GL_DEPTH_ATTACHMENT : GL_DEPTH;
+ if (hasDepth && (c.clear.clearMask & GL_STENCIL_BUFFER_BIT))
+ attachments[count++] = isFBO ? GL_STENCIL_ATTACHMENT : GL_STENCIL;
+ if (glInvalidateFramebuffer != nullptr && count != 0)
+ glInvalidateFramebuffer(GL_FRAMEBUFFER, count, attachments);
CHECK_GL_ERROR_IF_DEBUG();
break;
}
diff --git a/ext/native/thin3d/GLQueueRunner.h b/ext/native/thin3d/GLQueueRunner.h
index 41bceedb20..813f8c020e 100644
--- a/ext/native/thin3d/GLQueueRunner.h
+++ b/ext/native/thin3d/GLQueueRunner.h
@@ -6,6 +6,7 @@
#include "gfx/gl_common.h"
#include "thin3d/DataFormat.h"
+#include "util/tiny_set.h"
struct GLRViewport {
float x, y, w, h, minZ, maxZ;
@@ -295,9 +296,14 @@ struct GLRStep {
GLRStep(GLRStepType _type) : stepType(_type) {}
GLRStepType stepType;
std::vector commands;
+ TinySet dependencies;
union {
struct {
GLRFramebuffer *framebuffer;
+ GLRRenderPassAction color;
+ GLRRenderPassAction depth;
+ GLRRenderPassAction stencil;
+ // Note: not accurate.
int numDraws;
} render;
struct {
diff --git a/ext/native/thin3d/GLRenderManager.cpp b/ext/native/thin3d/GLRenderManager.cpp
index 670021cf93..e1d8393162 100644
--- a/ext/native/thin3d/GLRenderManager.cpp
+++ b/ext/native/thin3d/GLRenderManager.cpp
@@ -279,6 +279,9 @@ void GLRenderManager::BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRende
GLRStep *step = new GLRStep{ GLRStepType::RENDER };
// This is what queues up new passes, and can end previous ones.
step->render.framebuffer = fb;
+ step->render.color = color;
+ step->render.depth = depth;
+ step->render.stencil = stencil;
step->render.numDraws = 0;
steps_.push_back(step);
@@ -308,6 +311,12 @@ void GLRenderManager::BindFramebufferAsRenderTarget(GLRFramebuffer *fb, GLRRende
}
curRenderStep_ = step;
+ if (fb) {
+ if (color == GLRRenderPassAction::KEEP || depth == GLRRenderPassAction::KEEP || stencil == GLRRenderPassAction::KEEP) {
+ step->dependencies.insert(fb);
+ }
+ }
+
// Every step clears this state.
gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE);
}
@@ -319,6 +328,7 @@ void GLRenderManager::BindFramebufferAsTexture(GLRFramebuffer *fb, int binding,
data.bind_fb_texture.framebuffer = fb;
data.bind_fb_texture.aspect = aspectBit;
curRenderStep_->commands.push_back(data);
+ curRenderStep_->dependencies.insert(fb);
}
void GLRenderManager::CopyFramebuffer(GLRFramebuffer *src, GLRect2D srcRect, GLRFramebuffer *dst, GLOffset2D dstPos, int aspectMask) {
@@ -328,6 +338,10 @@ void GLRenderManager::CopyFramebuffer(GLRFramebuffer *src, GLRect2D srcRect, GLR
step->copy.src = src;
step->copy.dst = dst;
step->copy.aspectMask = aspectMask;
+ step->dependencies.insert(src);
+ bool fillsDst = dst && srcRect.x == 0 && srcRect.y == 0 && srcRect.w == dst->width && srcRect.h == dst->height;
+ if (dstPos.x != 0 || dstPos.y != 0 || !fillsDst)
+ step->dependencies.insert(dst);
steps_.push_back(step);
// Every step clears this state.
@@ -342,6 +356,10 @@ void GLRenderManager::BlitFramebuffer(GLRFramebuffer *src, GLRect2D srcRect, GLR
step->blit.dst = dst;
step->blit.aspectMask = aspectMask;
step->blit.filter = filter;
+ step->dependencies.insert(src);
+ bool fillsDst = dst && dstRect.x == 0 && dstRect.y == 0 && dstRect.w == dst->width && dstRect.h == dst->height;
+ if (!fillsDst)
+ step->dependencies.insert(dst);
steps_.push_back(step);
// Every step clears this state.
@@ -356,6 +374,7 @@ bool GLRenderManager::CopyFramebufferToMemorySync(GLRFramebuffer *src, int aspec
step->readback.srcRect = { x, y, w, h };
step->readback.aspectMask = aspectBits;
step->readback.dstFormat = destFormat;
+ step->dependencies.insert(src);
steps_.push_back(step);
// Every step clears this state.
diff --git a/ext/native/thin3d/VulkanQueueRunner.cpp b/ext/native/thin3d/VulkanQueueRunner.cpp
index 28aa244776..a74a679e6e 100644
--- a/ext/native/thin3d/VulkanQueueRunner.cpp
+++ b/ext/native/thin3d/VulkanQueueRunner.cpp
@@ -1,4 +1,4 @@
-#include