From 16d7a8098045057fa83fef7f5799b8f9d36f8b8c Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Thu, 30 Aug 2018 21:00:21 -0700 Subject: [PATCH] GPU: Clear alpha more consistently from 565. Before, the backends all did different things. Now they are more in sync, but Vulkan still behaves slightly differently. Fixes #11326. --- GPU/D3D11/FramebufferManagerD3D11.cpp | 38 +++++++++++++++++++++------ GPU/D3D11/FramebufferManagerD3D11.h | 3 +++ GPU/Directx9/FramebufferDX9.cpp | 29 +++++++++++++++----- GPU/Directx9/FramebufferDX9.h | 2 ++ GPU/GLES/FramebufferManagerGLES.cpp | 11 +++----- GPU/Vulkan/FramebufferVulkan.cpp | 8 +++--- 6 files changed, 65 insertions(+), 26 deletions(-) diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index f2910cbec622..bb6ee6b660cd 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -129,6 +129,21 @@ FramebufferManagerD3D11::FramebufferManagerD3D11(Draw::DrawContext *draw) vb.BindFlags = D3D11_BIND_CONSTANT_BUFFER; ASSERT_SUCCESS(device_->CreateBuffer(&vb, nullptr, &postConstants_)); + D3D11_TEXTURE2D_DESC desc{}; + desc.CPUAccessFlags = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.ArraySize = 1; + desc.SampleDesc.Count = 1; + desc.Width = 1; + desc.Height = 1; + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; + desc.MipLevels = 1; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + ASSERT_SUCCESS(device_->CreateTexture2D(&desc, nullptr, &nullTexture_)); + ASSERT_SUCCESS(device_->CreateShaderResourceView(nullTexture_, nullptr, &nullTextureView_)); + uint32_t nullData[1]{}; + context_->UpdateSubresource(nullTexture_, 0, nullptr, nullData, 1, 0); + ShaderTranslationInit(); CompilePostShader(); @@ -178,6 +193,11 @@ FramebufferManagerD3D11::~FramebufferManagerD3D11() { stencilUploadInputLayout_->Release(); if (stencilValueBuffer_) stencilValueBuffer_->Release(); + + if (nullTextureView_) + nullTextureView_->Release(); + if (nullTexture_) + nullTexture_->Release(); } void FramebufferManagerD3D11::SetTextureCache(TextureCacheD3D11 *tc) { @@ -437,31 +457,33 @@ void FramebufferManagerD3D11::ReformatFramebufferFrom(VirtualFramebuffer *vfb, G // Technically, we should at this point re-interpret the bytes of the old format to the new. // That might get tricky, and could cause unnecessary slowness in some games. // For now, we just clear alpha/stencil from 565, which fixes shadow issues in Kingdom Hearts. - // (it uses 565 to write zeros to the buffer, than 4444 to actually render the shadow.) + // (it uses 565 to write zeros to the buffer, then 4444 to actually render the shadow.) // // The best way to do this may ultimately be to create a new FBO (combine with any resize?) // and blit with a shader to that, then replace the FBO on vfb. Stencil would still be complex // to exactly reproduce in 4444 and 8888 formats. if (old == GE_FORMAT_565) { - draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::KEEP, Draw::RPAction::KEEP }); + draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }); - // TODO: There's no way this does anything useful :( - context_->OMSetDepthStencilState(stockD3D11.depthDisabledStencilWrite, 0xFF); - context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0], nullptr, 0xFFFFFFFF); + context_->OMSetDepthStencilState(stockD3D11.depthStencilDisabled, 0xFF); + context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[D3D11_COLOR_WRITE_ENABLE_ALPHA], nullptr, 0xFFFFFFFF); context_->RSSetState(stockD3D11.rasterStateNoCull); context_->IASetInputLayout(quadInputLayout_); context_->PSSetShader(quadPixelShader_, nullptr, 0); context_->VSSetShader(quadVertexShader_, nullptr, 0); context_->IASetVertexBuffers(0, 1, &fsQuadBuffer_, &quadStride_, &quadOffset_); + context_->PSSetSamplers(0, 1, &stockD3D11.samplerPoint2DClamp); + context_->PSSetShaderResources(0, 1, &nullTextureView_); shaderManagerD3D11_->DirtyLastShader(); D3D11_VIEWPORT vp{ 0.0f, 0.0f, (float)vfb->renderWidth, (float)vfb->renderHeight, 0.0f, 1.0f }; context_->RSSetViewports(1, &vp); context_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); context_->Draw(4, 0); - } - RebindFramebuffer(); - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE); + textureCache_->ForgetLastTexture(); + + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE); + } } static void CopyPixelDepthOnly(u32 *dstp, const u32 *srcp, size_t c) { diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h index d73b772b6201..33f9bdbf36d0 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.h +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -107,6 +107,9 @@ class FramebufferManagerD3D11 : public FramebufferManagerCommon { ID3D11Buffer *stencilValueBuffer_ = nullptr; ID3D11DepthStencilState *stencilMaskStates_[256]{}; + ID3D11Texture2D *nullTexture_ = nullptr; + ID3D11ShaderResourceView *nullTextureView_ = nullptr; + TextureCacheD3D11 *textureCacheD3D11_; ShaderManagerD3D11 *shaderManagerD3D11_; DrawEngineD3D11 *drawEngineD3D11_; diff --git a/GPU/Directx9/FramebufferDX9.cpp b/GPU/Directx9/FramebufferDX9.cpp index a66faf39d175..88bddb3beeb0 100644 --- a/GPU/Directx9/FramebufferDX9.cpp +++ b/GPU/Directx9/FramebufferDX9.cpp @@ -100,6 +100,19 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { } device_->CreateVertexDeclaration(g_FramebufferVertexElements, &pFramebufferVertexDecl); + + + int usage = 0; + D3DPOOL pool = D3DPOOL_MANAGED; + if (deviceEx_) { + pool = D3DPOOL_DEFAULT; + usage = D3DUSAGE_DYNAMIC; + } + HRESULT hr = device_->CreateTexture(1, 1, 1, usage, D3DFMT_A8R8G8B8, pool, &nullTex_, nullptr); + D3DLOCKED_RECT rect; + nullTex_->LockRect(0, &rect, nullptr, D3DLOCK_DISCARD); + memset(rect.pBits, 0, 4); + nullTex_->UnlockRect(0); } FramebufferManagerDX9::~FramebufferManagerDX9() { @@ -125,6 +138,8 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { if (stencilUploadVS_) { stencilUploadVS_->Release(); } + if (nullTex_) + nullTex_->Release(); } void FramebufferManagerDX9::SetTextureCache(TextureCacheDX9 *tc) { @@ -307,24 +322,24 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { return; } - draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::KEEP, Draw::RPAction::KEEP }); - // Technically, we should at this point re-interpret the bytes of the old format to the new. // That might get tricky, and could cause unnecessary slowness in some games. // For now, we just clear alpha/stencil from 565, which fixes shadow issues in Kingdom Hearts. - // (it uses 565 to write zeros to the buffer, than 4444 to actually render the shadow.) + // (it uses 565 to write zeros to the buffer, then 4444 to actually render the shadow.) // // The best way to do this may ultimately be to create a new FBO (combine with any resize?) // and blit with a shader to that, then replace the FBO on vfb. Stencil would still be complex // to exactly reproduce in 4444 and 8888 formats. if (old == GE_FORMAT_565) { + draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }); + dxstate.scissorTest.disable(); dxstate.depthWrite.set(FALSE); dxstate.colorMask.set(false, false, false, true); dxstate.stencilFunc.set(D3DCMP_ALWAYS, 0, 0); dxstate.stencilMask.set(0xFF); - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE); + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_PARAMS | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE); float coord[20] = { -1.0f,-1.0f,0, 0,0, @@ -338,7 +353,7 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { device_->SetPixelShader(pFramebufferPixelShader); device_->SetVertexShader(pFramebufferVertexShader); shaderManagerDX9_->DirtyLastShader(); - device_->SetTexture(0, nullptr); + device_->SetTexture(0, nullTex_); D3DVIEWPORT9 vp{ 0, 0, (DWORD)vfb->renderWidth, (DWORD)vfb->renderHeight, 0.0f, 1.0f }; device_->SetViewport(&vp); @@ -349,9 +364,9 @@ static const D3DVERTEXELEMENT9 g_FramebufferVertexElements[] = { ERROR_LOG_REPORT(G3D, "ReformatFramebufferFrom() failed: %08x", hr); } dxstate.viewport.restore(); - } - RebindFramebuffer(); + textureCache_->ForgetLastTexture(); + } } static void CopyPixelDepthOnly(u32 *dstp, const u32 *srcp, size_t c) { diff --git a/GPU/Directx9/FramebufferDX9.h b/GPU/Directx9/FramebufferDX9.h index 4c1498b7861e..5a67b34bf65c 100644 --- a/GPU/Directx9/FramebufferDX9.h +++ b/GPU/Directx9/FramebufferDX9.h @@ -104,6 +104,8 @@ class FramebufferManagerDX9 : public FramebufferManagerCommon { LPDIRECT3DVERTEXSHADER9 stencilUploadVS_ = nullptr; bool stencilUploadFailed_ = false; + LPDIRECT3DTEXTURE9 nullTex_ = nullptr; + TextureCacheDX9 *textureCacheDX9_; ShaderManagerDX9 *shaderManagerDX9_; DrawEngineDX9 *drawEngineD3D9_; diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 81b2498346b3..6ddf06b3bddd 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -466,20 +466,17 @@ void FramebufferManagerGLES::ReformatFramebufferFrom(VirtualFramebuffer *vfb, GE // Technically, we should at this point re-interpret the bytes of the old format to the new. // That might get tricky, and could cause unnecessary slowness in some games. // For now, we just clear alpha/stencil from 565, which fixes shadow issues in Kingdom Hearts. - // (it uses 565 to write zeros to the buffer, than 4444 to actually render the shadow.) + // (it uses 565 to write zeros to the buffer, then 4444 to actually render the shadow.) // // The best way to do this may ultimately be to create a new FBO (combine with any resize?) // and blit with a shader to that, then replace the FBO on vfb. Stencil would still be complex // to exactly reproduce in 4444 and 8888 formats. if (old == GE_FORMAT_565) { - draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }); - gstate_c.Dirty(DIRTY_BLEND_STATE); - } else { - draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }); + // Clear alpha and stencil. + draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }); + render_->Clear(0, 0.0f, 0, GL_COLOR_BUFFER_BIT, 0x8, 0, 0, 0, 0); } - - RebindFramebuffer(); } void FramebufferManagerGLES::BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) { diff --git a/GPU/Vulkan/FramebufferVulkan.cpp b/GPU/Vulkan/FramebufferVulkan.cpp index 9665019ffad0..78512380909a 100644 --- a/GPU/Vulkan/FramebufferVulkan.cpp +++ b/GPU/Vulkan/FramebufferVulkan.cpp @@ -364,16 +364,16 @@ void FramebufferManagerVulkan::ReformatFramebufferFrom(VirtualFramebuffer *vfb, // Technically, we should at this point re-interpret the bytes of the old format to the new. // That might get tricky, and could cause unnecessary slowness in some games. // For now, we just clear alpha/stencil from 565, which fixes shadow issues in Kingdom Hearts. - // (it uses 565 to write zeros to the buffer, than 4444 to actually render the shadow.) + // (it uses 565 to write zeros to the buffer, then 4444 to actually render the shadow.) // // The best way to do this may ultimately be to create a new FBO (combine with any resize?) // and blit with a shader to that, then replace the FBO on vfb. Stencil would still be complex // to exactly reproduce in 4444 and 8888 formats. if (old == GE_FORMAT_565) { - draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::CLEAR, Draw::RPAction::CLEAR }); - } else { - draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }); + // TODO: To match other backends, would be ideal to clear alpha only and not color. + // But probably doesn't matter that much... + draw_->BindFramebufferAsRenderTarget(vfb->fbo, { Draw::RPAction::CLEAR, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }); } }