diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index 85c4896a92..c4ebb5f450 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -314,12 +314,11 @@ static void CopyPixelDepthOnly(u32 *dstp, const u32 *srcp, size_t c) { } } -void FramebufferManagerD3D11::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags) { +bool FramebufferManagerD3D11::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags) { if (!framebuffer->fbo || !useBufferedRendering_) { - ID3D11ShaderResourceView *view = nullptr; - context_->PSSetShaderResources(stage, 1, &view); + draw_->BindTexture(0, nullptr); gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE; - return; + return false; } // currentRenderVfb_ will always be set when this is called, except from the GE debugger. @@ -341,15 +340,16 @@ void FramebufferManagerD3D11::BindFramebufferAsColorTexture(int stage, VirtualFr } else { draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0); } + return true; } else if (framebuffer != currentRenderVfb_ || (flags & BINDFBCOLOR_FORCE_SELF) != 0) { draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0); + return true; } else { ERROR_LOG_REPORT_ONCE(d3d11SelfTexture, G3D, "Attempting to texture from target (src=%08x / target=%08x / flags=%d)", framebuffer->fb_address, currentRenderVfb_->fb_address, flags); // Badness on D3D11 to bind the currently rendered-to framebuffer as a texture. - ID3D11ShaderResourceView *view = nullptr; - context_->PSSetShaderResources(stage, 1, &view); + draw_->BindTexture(0, nullptr); gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE; - return; + return false; } } diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h index 6f8922fbe8..497af969a1 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.h +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -44,7 +44,7 @@ public: void EndFrame(); void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) override; - void BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags); + bool BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags); virtual bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override; diff --git a/GPU/Directx9/FramebufferManagerDX9.cpp b/GPU/Directx9/FramebufferManagerDX9.cpp index a820c3ece0..b017a59f64 100644 --- a/GPU/Directx9/FramebufferManagerDX9.cpp +++ b/GPU/Directx9/FramebufferManagerDX9.cpp @@ -336,15 +336,11 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { return offscreen; } - void FramebufferManagerDX9::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags) { - if (framebuffer == NULL) { - framebuffer = currentRenderVfb_; - } - + bool FramebufferManagerDX9::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags) { if (!framebuffer->fbo || !useBufferedRendering_) { device_->SetTexture(stage, nullptr); gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE; - return; + return false; } // currentRenderVfb_ will always be set when this is called, except from the GE debugger. @@ -366,8 +362,10 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { } else { draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0); } + return true; } else { draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0); + return true; } } diff --git a/GPU/Directx9/FramebufferManagerDX9.h b/GPU/Directx9/FramebufferManagerDX9.h index 24ea2b0e28..99b93c6a62 100644 --- a/GPU/Directx9/FramebufferManagerDX9.h +++ b/GPU/Directx9/FramebufferManagerDX9.h @@ -49,7 +49,7 @@ public: void EndFrame(); void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) override; - void BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags); + bool BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags); virtual bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override; diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 8e6a8e2233..eb742f3370 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -263,11 +263,11 @@ void FramebufferManagerGLES::ReformatFramebufferFrom(VirtualFramebuffer *vfb, GE } } -void FramebufferManagerGLES::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags) { +bool FramebufferManagerGLES::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags) { if (!framebuffer->fbo || !useBufferedRendering_) { render_->BindTexture(stage, nullptr); gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE; - return; + return false; } // currentRenderVfb_ will always be set when this is called, except from the GE debugger. @@ -288,8 +288,10 @@ void FramebufferManagerGLES::BindFramebufferAsColorTexture(int stage, VirtualFra } else { draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0); } + return true; } else { draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0); + return true; } } diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index f87c707ab8..fc2e5bcbad 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -53,7 +53,7 @@ public: void ReformatFramebufferFrom(VirtualFramebuffer *vfb, GEBufferFormat old) override; // For use when texturing from a framebuffer. May create a duplicate if target. - void BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags); + bool BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags); bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override; diff --git a/GPU/Vulkan/FramebufferManagerVulkan.cpp b/GPU/Vulkan/FramebufferManagerVulkan.cpp index 1b1c5ae65c..4923da7087 100644 --- a/GPU/Vulkan/FramebufferManagerVulkan.cpp +++ b/GPU/Vulkan/FramebufferManagerVulkan.cpp @@ -268,10 +268,11 @@ void FramebufferManagerVulkan::ReformatFramebufferFrom(VirtualFramebuffer *vfb, } } -VkImageView FramebufferManagerVulkan::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags) { +bool FramebufferManagerVulkan::BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags) { if (!framebuffer->fbo || !useBufferedRendering_) { + draw_->BindTexture(0, nullptr); gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE; - return VK_NULL_HANDLE; + return false; } // currentRenderVfb_ will always be set when this is called, except from the GE debugger. @@ -293,14 +294,19 @@ VkImageView FramebufferManagerVulkan::BindFramebufferAsColorTexture(int stage, V } else { draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0); } - return (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW); + return true; } else if (framebuffer != currentRenderVfb_ || (flags & BINDFBCOLOR_FORCE_SELF) != 0) { draw_->BindFramebufferAsTexture(framebuffer->fbo, stage, Draw::FB_COLOR_BIT, 0); - return (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW); + return true; } else { ERROR_LOG_REPORT_ONCE(vulkanSelfTexture, G3D, "Attempting to texture from target (src=%08x / target=%08x / flags=%d)", framebuffer->fb_address, currentRenderVfb_->fb_address, flags); // To do this safely in Vulkan, we need to use input attachments. - return VK_NULL_HANDLE; + // Actually if the texture region and render regions don't overlap, this is safe, but we need + // to transition to GENERAL image layout which will take some trickery. + // Badness on D3D11 to bind the currently rendered-to framebuffer as a texture. + draw_->BindTexture(0, nullptr); + gstate_c.skipDrawReason |= SKIPDRAW_BAD_FB_TEXTURE; + return false; } } diff --git a/GPU/Vulkan/FramebufferManagerVulkan.h b/GPU/Vulkan/FramebufferManagerVulkan.h index 9ba0f0fb1d..96e6a74569 100644 --- a/GPU/Vulkan/FramebufferManagerVulkan.h +++ b/GPU/Vulkan/FramebufferManagerVulkan.h @@ -57,7 +57,7 @@ public: bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override; - VkImageView BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags); + bool BindFramebufferAsColorTexture(int stage, VirtualFramebuffer *framebuffer, int flags); // If within a render pass, this will just issue a regular clear. If beginning a new render pass, // do that. diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 19e232bb93..cf3f6d1758 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -558,7 +558,11 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer TexCacheEntry::TexStatus alphaStatus = CheckAlpha(clutBuf_, getClutDestFormatVulkan(clutFormat), clutTotalColors, clutTotalColors, 1); gstate_c.SetTextureFullAlpha(alphaStatus == TexCacheEntry::STATUS_ALPHA_FULL); curSampler_ = samplerCache_.GetOrCreateSampler(samplerKey); - imageView_ = framebufferManagerVulkan_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET); + if (framebufferManagerVulkan_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET)) { + imageView_ = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW); + } else { + imageView_ = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::NULL_IMAGEVIEW); + } return; } else { depalShader = depalShaderCache_->GetDepalettizeShader(clutMode, depth ? GE_FORMAT_DEPTH16 : framebuffer->drawnFormat); @@ -667,7 +671,12 @@ void TextureCacheVulkan::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer // Since we may have switched render targets, we need to re-set depth/stencil etc states. gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE); } else { - imageView_ = framebufferManagerVulkan_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET); + if (framebufferManagerVulkan_->BindFramebufferAsColorTexture(0, framebuffer, BINDFBCOLOR_MAY_COPY_WITH_UV | BINDFBCOLOR_APPLY_TEX_OFFSET)) { + imageView_ = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW); + } else { + imageView_ = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::NULL_IMAGEVIEW); + } + drawEngine_->SetDepalTexture(VK_NULL_HANDLE); gstate_c.SetUseShaderDepal(false);