diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index 6d9276f66c..edc4b397ab 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -64,9 +64,10 @@ public: // A D3D11Framebuffer is a D3D11Framebuffer plus all the textures it owns. class D3D11Framebuffer : public Framebuffer { public: - D3D11Framebuffer(int width, int height) { + D3D11Framebuffer(int width, int height, bool zStencil) { width_ = width; height_ = height; + hasDepthStencil_ = zStencil; } ~D3D11Framebuffer() { } @@ -1495,7 +1496,7 @@ uint32_t D3D11DrawContext::GetDataFormatSupport(DataFormat fmt) const { Framebuffer *D3D11DrawContext::CreateFramebuffer(const FramebufferDesc &desc) { HRESULT hr; - D3D11Framebuffer *fb = new D3D11Framebuffer(desc.width, desc.height); + D3D11Framebuffer *fb = new D3D11Framebuffer(desc.width, desc.height, desc.z_stencil); // We don't (yet?) support multiview for D3D11. Not sure if there's a way to do it. // Texture arrays are supported but we don't have any other use cases yet. diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index 7df9715822..497970a3ae 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -959,6 +959,7 @@ public: OpenGLFramebuffer(GLRenderManager *render, GLRFramebuffer *framebuffer) : render_(render), framebuffer_(framebuffer) { width_ = framebuffer->width; height_ = framebuffer->height; + hasDepthStencil_ = framebuffer->z_stencil_; } ~OpenGLFramebuffer() { render_->DeleteFramebuffer(framebuffer_); @@ -1596,6 +1597,14 @@ void OpenGLContext::CopyFramebufferImage(Framebuffer *fbsrc, int srcLevel, int s OpenGLFramebuffer *src = (OpenGLFramebuffer *)fbsrc; OpenGLFramebuffer *dst = (OpenGLFramebuffer *)fbdst; + if (aspects & (Aspect::DEPTH_BIT | Aspect::STENCIL_BIT)) { + _dbg_assert_msg_(src->HasDepthStencil(), "%s", src->framebuffer_->Tag()); + _dbg_assert_msg_(dst->HasDepthStencil(), "%s", dst->framebuffer_->Tag()); + if (!src->HasDepthStencil() || !dst->HasDepthStencil()) { + return; + } + } + int glAspect = 0; if (aspects & Aspect::COLOR_BIT) { glAspect |= GL_COLOR_BUFFER_BIT; @@ -1611,6 +1620,14 @@ void OpenGLContext::CopyFramebufferImage(Framebuffer *fbsrc, int srcLevel, int s bool OpenGLContext::BlitFramebuffer(Framebuffer *fbsrc, int srcX1, int srcY1, int srcX2, int srcY2, Framebuffer *fbdst, int dstX1, int dstY1, int dstX2, int dstY2, Aspect aspects, FBBlitFilter linearFilter, const char *tag) { OpenGLFramebuffer *src = (OpenGLFramebuffer *)fbsrc; OpenGLFramebuffer *dst = (OpenGLFramebuffer *)fbdst; + if (aspects & (Aspect::DEPTH_BIT | Aspect::STENCIL_BIT)) { + _dbg_assert_msg_(src->HasDepthStencil(), "%s", src->framebuffer_->Tag()); + _dbg_assert_msg_(dst->HasDepthStencil(), "%s", dst->framebuffer_->Tag()); + if (!src->HasDepthStencil() || !dst->HasDepthStencil()) { + return false; + } + } + GLuint aspect = 0; if (aspects & Aspect::COLOR_BIT) aspect |= GL_COLOR_BUFFER_BIT; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.cpp b/Common/GPU/Vulkan/VulkanRenderManager.cpp index 77e84932a1..ee38e234a6 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.cpp +++ b/Common/GPU/Vulkan/VulkanRenderManager.cpp @@ -1440,6 +1440,16 @@ void VulkanRenderManager::CopyFramebuffer(VKRFramebuffer *src, VkRect2D srcRect, _dbg_assert_msg_(dstPos.x + srcRect.extent.width <= (uint32_t)dst->width, "dstPos + extent x > width"); _dbg_assert_msg_(dstPos.y + srcRect.extent.height <= (uint32_t)dst->height, "dstPos + extent y > height"); + if (aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { + _dbg_assert_msg_(src->depth.image != VK_NULL_HANDLE, "%s", src->Tag()); + _dbg_assert_msg_(dst->depth.image != VK_NULL_HANDLE, "%s", dst->Tag()); + + if (!src->depth.image || !dst->depth.image) { + // Something has gone wrong, but let's try to stumble along. + return; + } + } + VkImageLayout finalSrcLayoutBeforeCopy = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; if (src == dst) { // We only use the first loop before, and transition to VK_IMAGE_LAYOUT_GENERAL. diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index 38e3c10ac3..b34c4cd96c 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -1839,6 +1839,7 @@ public: height_ = fb->height; layers_ = fb->numLayers; multiSampleLevel_ = multiSampleLevel; + hasDepthStencil_ = fb->HasDepth(); } ~VKFramebuffer() { _assert_msg_(buf_, "Null buf_ in VKFramebuffer - double delete?"); diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 8f875e39f7..6c230bd385 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -450,12 +450,14 @@ public: int Height() const { return height_; } int Layers() const { return layers_; } int MultiSampleLevel() const { return multiSampleLevel_; } + bool HasDepthStencil() const { return hasDepthStencil_; } virtual void UpdateTag(const char *tag) {} virtual const char *Tag() const { return "(no name)"; } protected: int width_ = -1, height_ = -1, layers_ = 1, multiSampleLevel_ = 0; + bool hasDepthStencil_ = false; }; class Buffer : public RefCountedObject { diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index b83448104c..8a602c9f22 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -2035,9 +2035,8 @@ void FramebufferManagerCommon::ResizeFramebufFBO(VirtualFramebuffer *vfb, int w, if (vfb->usageFlags & FB_USAGE_RENDER_DEPTH) { BlitFramebuffer(vfb, 0, 0, &old, 0, 0, std::min((u16)oldWidth, std::min(vfb->bufferWidth, vfb->width)), std::min((u16)oldHeight, std::min(vfb->height, vfb->bufferHeight)), 0, RASTER_DEPTH, "BlitDepth_ResizeFramebufFBO"); } - // A color framebuffer from CreateRAMFramebuffer (no z address or stride) has no depth/stencil buffer to copy from. - const bool oldHasStencil = old.z_address != 0 || old.z_stride != 0; - if (!skipCopy && vfb->fb_format != GE_FORMAT_565 && oldHasStencil) { + // A color framebuffer from CreateRAMFramebuffer has no depth/stencil buffer to copy from. + if (!skipCopy && vfb->fb_format != GE_FORMAT_565 && old.fbo->HasDepthStencil()) { // Keep the stencil too (Need for Speed Shift stencil tests right after its framebuffer grows from 480 to // 512 wide). D3D11 has no separate stencil copy, but copies it along with the depth above. const int stencilW = std::min(old.renderWidth, vfb->renderWidth);