From 9bead443c399fc6bbaf3f91077b8ed8f301fc105 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 20 Jul 2022 11:09:32 +0200 Subject: [PATCH] Unify stencil buffer upload using Draw. Only OpenGL tested yet (shaders need adaptation). --- CMakeLists.txt | 4 - Common/GPU/D3D11/thin3d_d3d11.cpp | 1 + Common/GPU/OpenGL/thin3d_gl.cpp | 2 +- Common/GPU/thin3d.h | 8 +- GPU/Common/FramebufferManagerCommon.cpp | 4 + GPU/Common/FramebufferManagerCommon.h | 9 +- GPU/Common/StencilCommon.cpp | 264 +++++++++++++++++++++++- GPU/Common/StencilCommon.h | 4 - GPU/D3D11/FramebufferManagerD3D11.h | 2 - GPU/D3D11/StencilBufferD3D11.cpp | 245 ---------------------- GPU/Directx9/FramebufferManagerDX9.h | 2 - GPU/Directx9/StencilBufferDX9.cpp | 259 ----------------------- GPU/GLES/FramebufferManagerGLES.cpp | 8 +- GPU/GLES/FramebufferManagerGLES.h | 6 +- GPU/GPU.vcxproj | 11 +- GPU/GPU.vcxproj.filters | 14 +- GPU/Vulkan/FramebufferManagerVulkan.h | 2 - GPU/Vulkan/StencilBufferVulkan.cpp | 229 -------------------- android/jni/Android.mk | 1 - libretro/Makefile.common | 4 - 20 files changed, 287 insertions(+), 792 deletions(-) delete mode 100644 GPU/D3D11/StencilBufferD3D11.cpp delete mode 100644 GPU/Directx9/StencilBufferDX9.cpp delete mode 100644 GPU/Vulkan/StencilBufferVulkan.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ecfece342d..670e5f437c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1455,7 +1455,6 @@ set(GPU_GLES GPU/GLES/ShaderManagerGLES.h GPU/GLES/StateMappingGLES.cpp GPU/GLES/StateMappingGLES.h - GPU/GLES/StencilBufferGLES.cpp GPU/GLES/TextureCacheGLES.cpp GPU/GLES/TextureCacheGLES.h GPU/GLES/DrawEngineGLES.cpp @@ -1479,7 +1478,6 @@ set(GPU_VULKAN GPU/Vulkan/ShaderManagerVulkan.h GPU/Vulkan/StateMappingVulkan.cpp GPU/Vulkan/StateMappingVulkan.h - GPU/Vulkan/StencilBufferVulkan.cpp GPU/Vulkan/TextureCacheVulkan.cpp GPU/Vulkan/TextureCacheVulkan.h GPU/Vulkan/VulkanUtil.cpp @@ -1499,7 +1497,6 @@ set(GPU_D3D9 GPU/Directx9/ShaderManagerDX9.h GPU/Directx9/StateMappingDX9.cpp GPU/Directx9/StateMappingDX9.h - GPU/Directx9/StencilBufferDX9.cpp GPU/Directx9/TextureCacheDX9.cpp GPU/Directx9/TextureCacheDX9.h ) @@ -1519,7 +1516,6 @@ set(GPU_D3D11 GPU/D3D11/ShaderManagerD3D11.h GPU/D3D11/StateMappingD3D11.cpp GPU/D3D11/StateMappingD3D11.h - GPU/D3D11/StencilBufferD3D11.cpp GPU/D3D11/TextureCacheD3D11.cpp GPU/D3D11/TextureCacheD3D11.h ) diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index 7dc6e7e17c..d3a33d85fe 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -249,6 +249,7 @@ private: uint8_t stencilRef_ = 0; uint8_t stencilWriteMask_ = 0xFF; uint8_t stencilCompareMask_ = 0xFF; + bool stencilDirty_ = true; // Temporaries diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index f25fe16ef9..77e1d822cc 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -1112,7 +1112,7 @@ void OpenGLContext::ApplySamplers() { const OpenGLSamplerState *samp = boundSamplers_[i]; const GLRTexture *tex = boundTextures_[i]; if (tex) { - _assert_(samp); + _assert_msg_(samp, "Sampler missing"); } else { continue; } diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 185d8929fc..c832d6cc2e 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -25,7 +25,7 @@ namespace Draw { // Useful in UBOs typedef int bool32; -enum class Comparison : int { +enum class Comparison : uint8_t { NEVER, LESS, EQUAL, @@ -37,7 +37,7 @@ enum class Comparison : int { }; // Had to prefix with LOGIC, too many clashes -enum class LogicOp : int { +enum class LogicOp : uint8_t { LOGIC_CLEAR, LOGIC_SET, LOGIC_COPY, @@ -56,7 +56,7 @@ enum class LogicOp : int { LOGIC_OR_INVERTED, }; -enum class BlendOp : int { +enum class BlendOp : uint8_t { ADD, SUBTRACT, REV_SUBTRACT, @@ -96,7 +96,7 @@ enum class StencilOp { DECREMENT_AND_WRAP = 7, }; -enum class TextureFilter : int { +enum class TextureFilter : uint8_t { NEAREST = 0, LINEAR = 1, }; diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 46b8255ea5..6d7f0446ee 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -2488,6 +2488,10 @@ void FramebufferManagerCommon::DeviceLost() { DoRelease(reinterpretVBuf_); DoRelease(reinterpretSampler_); DoRelease(reinterpretVS_); + DoRelease(stencilUploadFs_); + DoRelease(stencilUploadVs_); + DoRelease(stencilUploadSampler_); + DoRelease(stencilUploadPipeline_); presentation_->DeviceLost(); draw_ = nullptr; } diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index 04e2683e0f..18e99fd559 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -253,7 +253,7 @@ public: void NotifyVideoUpload(u32 addr, int size, int width, GEBufferFormat fmt); void UpdateFromMemory(u32 addr, int size, bool safe); void ApplyClearToMemory(int x1, int y1, int x2, int y2, u32 clearColor); - virtual bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) = 0; + bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR); // Returns true if it's sure this is a direct FBO->FBO transfer and it has already handle it. // In that case we hardly need to actually copy the bytes in VRAM, they will be wrong anyway (unless // read framebuffers is on, in which case this should always return false). @@ -467,4 +467,11 @@ protected: Draw::ShaderModule *reinterpretVS_ = nullptr; Draw::SamplerState *reinterpretSampler_ = nullptr; Draw::Buffer *reinterpretVBuf_ = nullptr; + + // Common implementation of stencil buffer upload. Also not 100% optimal, but not perforamnce + // critical either. + Draw::Pipeline *stencilUploadPipeline_ = nullptr; + Draw::ShaderModule *stencilUploadVs_ = nullptr; + Draw::ShaderModule *stencilUploadFs_ = nullptr; + Draw::SamplerState *stencilUploadSampler_ = nullptr; }; diff --git a/GPU/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp index 29af15c020..94b7373952 100644 --- a/GPU/Common/StencilCommon.cpp +++ b/GPU/Common/StencilCommon.cpp @@ -15,9 +15,18 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include "Common/GPU/Shader.h" +#include "Common/GPU/OpenGL/GLSLProgram.h" +#include "Core/Config.h" +#include "Core/ConfigValues.h" +#include "Core/Reporting.h" #include "GPU/Common/StencilCommon.h" +#include "GPU/GLES/DrawEngineGLES.h" +#include "GPU/GLES/FramebufferManagerGLES.h" +#include "GPU/GLES/ShaderManagerGLES.h" +#include "GPU/GLES/TextureCacheGLES.h" -u8 StencilBits5551(const u8 *ptr8, u32 numPixels) { +static u8 StencilBits5551(const u8 *ptr8, u32 numPixels) { const u32 *ptr = (const u32 *)ptr8; for (u32 i = 0; i < numPixels / 2; ++i) { @@ -28,7 +37,7 @@ u8 StencilBits5551(const u8 *ptr8, u32 numPixels) { return 0; } -u8 StencilBits4444(const u8 *ptr8, u32 numPixels) { +static u8 StencilBits4444(const u8 *ptr8, u32 numPixels) { const u32 *ptr = (const u32 *)ptr8; u32 bits = 0; @@ -39,7 +48,7 @@ u8 StencilBits4444(const u8 *ptr8, u32 numPixels) { return ((bits >> 12) & 0xF) | (bits >> 28); } -u8 StencilBits8888(const u8 *ptr8, u32 numPixels) { +static u8 StencilBits8888(const u8 *ptr8, u32 numPixels) { const u32 *ptr = (const u32 *)ptr8; u32 bits = 0; @@ -49,3 +58,252 @@ u8 StencilBits8888(const u8 *ptr8, u32 numPixels) { return bits >> 24; } + +struct StencilUB { + float stencilValue; +}; + +const UniformBufferDesc stencilUBDesc { sizeof(StencilUB), { + { "stencilValue", 0, -1, UniformType::FLOAT1, 0 }, +} }; + +static const char *stencil_fs = R"( +#ifdef GL_ES +#ifdef GL_FRAGMENT_PRECISION_HIGH +precision highp float; +#else +precision mediump float; // just hope it's enough.. +#endif +#endif +#if __VERSION__ >= 130 +#define varying in +#define texture2D texture +#define gl_FragColor fragColor0 +out vec4 fragColor0; +#endif +varying vec2 v_texcoord0; +uniform float stencilValue; +uniform sampler2D tex; +float roundAndScaleTo255f(in float x) { return floor(x * 255.99); } +void main() { + vec4 index = texture2D(tex, v_texcoord0); + gl_FragColor = vec4(v_texcoord0.x, v_texcoord0.y, 0.0, index.a); + float shifted = roundAndScaleTo255f(index.a) / roundAndScaleTo255f(stencilValue); + // Bitwise operations on floats, ugh. + if (mod(floor(shifted), 2.0) < 0.99) discard; +} +)"; + +static const char *stencil_vs = R"( +#ifdef GL_ES +precision highp float; +#endif +#if __VERSION__ >= 130 +#define attribute in +#define varying out +#endif +attribute vec2 a_position; +varying vec2 v_texcoord0; +void main() { + v_texcoord0 = a_position * 2.0; // yes, this should be right. Should be 2.0 in the far corners. + gl_Position = vec4(v_texcoord0 * 2.0 - vec2(1.0, 1.0), 0.0, 1.0); +} +)"; + + +static const std::vector fsStencilSources = { + {ShaderLanguage::GLSL_1xx, stencil_fs} +}; + +static const std::vector vsStencilSources = { + {ShaderLanguage::GLSL_1xx, stencil_vs} +}; + +bool FramebufferManagerCommon::NotifyStencilUpload(u32 addr, int size, StencilUpload flags) { + using namespace Draw; + + addr &= 0x3FFFFFFF; + if (!MayIntersectFramebuffer(addr)) { + return false; + } + + VirtualFramebuffer *dstBuffer = 0; + for (size_t i = 0; i < vfbs_.size(); ++i) { + VirtualFramebuffer *vfb = vfbs_[i]; + if (vfb->fb_address == addr) { + dstBuffer = vfb; + } + } + if (!dstBuffer) { + return false; + } + + int values = 0; + u8 usedBits = 0; + + const u8 *src = Memory::GetPointer(addr); + if (!src) + return false; + + switch (dstBuffer->format) { + case GE_FORMAT_565: + // Well, this doesn't make much sense. + return false; + case GE_FORMAT_5551: + usedBits = StencilBits5551(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); + values = 2; + break; + case GE_FORMAT_4444: + usedBits = StencilBits4444(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); + values = 16; + break; + case GE_FORMAT_8888: + usedBits = StencilBits8888(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); + values = 256; + break; + case GE_FORMAT_INVALID: + case GE_FORMAT_DEPTH16: + // Inconceivable. + _assert_(false); + break; + } + + if (usedBits == 0) { + if (flags == StencilUpload::STENCIL_IS_ZERO) { + // Common when creating buffers, it's already 0. We're done. + return false; + } + shaderManager_->DirtyLastShader(); + + // Let's not bother with the shader if it's just zero. + if (dstBuffer->fbo) { + draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "NotifyStencilUpload_Clear"); + } + + // Clear destination alpha. + // render_->Clear(0, 0, 0, GL_COLOR_BUFFER_BIT, 0x8, 0, 0, 0, 0); + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE); + return true; + } + + shaderManager_->DirtyLastShader(); + textureCache_->ForgetLastTexture(); + + if (!stencilUploadPipeline_) { + stencilUploadFs_ = CreateShader(draw_, ShaderStage::Fragment, fsStencilSources); + stencilUploadVs_ = CreateShader(draw_, ShaderStage::Vertex, vsStencilSources); + + _assert_(stencilUploadFs_ && stencilUploadVs_); + + InputLayoutDesc desc = { + { + { 8, false }, + }, + { + { 0, SEM_POSITION, DataFormat::R32G32_FLOAT, 0 }, + }, + }; + InputLayout *inputLayout = draw_->CreateInputLayout(desc); + + BlendState *blendOff = draw_->CreateBlendState({ false, 0x8 }); + DepthStencilStateDesc dsDesc{}; + dsDesc.stencilEnabled = true; + dsDesc.stencil.compareOp = Comparison::ALWAYS; + dsDesc.stencil.depthFailOp = StencilOp::REPLACE; + dsDesc.stencil.failOp = StencilOp::REPLACE; + dsDesc.stencil.passOp = StencilOp::REPLACE; + DepthStencilState *stencilWrite = draw_->CreateDepthStencilState(dsDesc); + RasterState *rasterNoCull = draw_->CreateRasterState({}); + + PipelineDesc stencilWriteDesc{ + Primitive::TRIANGLE_LIST, + { stencilUploadVs_, stencilUploadFs_ }, + inputLayout, stencilWrite, blendOff, rasterNoCull, &stencilUBDesc, + }; + stencilUploadPipeline_ = draw_->CreateGraphicsPipeline(stencilWriteDesc); + _assert_(stencilUploadPipeline_); + + rasterNoCull->Release(); + blendOff->Release(); + stencilWrite->Release(); + inputLayout->Release(); + + SamplerStateDesc descNearest{}; + stencilUploadSampler_ = draw_->CreateSamplerState(descNearest); + } + + // Fullscreen triangle + const float positions[6] = { + 0.0, 0.0, + 1.0, 0.0, + 0.0, 1.0, + }; + + bool useBlit = draw_->GetDeviceCaps().framebufferDepthBlitSupported; + + // Our fragment shader (and discard) is slow. Since the source is 1x, we can stencil to 1x. + // Then after we're done, we'll just blit it across and stretch it there. Not worth doing + // if already at 1x size though, of course. + if (dstBuffer->width == dstBuffer->renderWidth || !dstBuffer->fbo) { + useBlit = false; + } + + u16 w = useBlit ? dstBuffer->width : dstBuffer->renderWidth; + u16 h = useBlit ? dstBuffer->height : dstBuffer->renderHeight; + + Draw::Framebuffer *blitFBO = nullptr; + if (useBlit) { + blitFBO = GetTempFBO(TempFBO::STENCIL, w, h); + draw_->BindFramebufferAsRenderTarget(blitFBO, { Draw::RPAction::DONT_CARE, Draw::RPAction::DONT_CARE, Draw::RPAction::CLEAR }, "NotifyStencilUpload_Blit"); + } else if (dstBuffer->fbo) { + draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::CLEAR }, "NotifyStencilUpload_NoBlit"); + } + + Draw::Viewport viewport = { 0.0f, 0.0f, (float)w, (float)h, 0.0f, 1.0f }; + draw_->SetViewports(1, &viewport); + + // TODO: Switch the format to a single channel format? + Draw::Texture *tex = MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->width, dstBuffer->height); + if (!tex) { + // Bad! + return false; + } + + draw_->BindTextures(TEX_SLOT_PSP_TEXTURE, 1, &tex); + draw_->BindSamplerStates(TEX_SLOT_PSP_TEXTURE, 1, &stencilUploadSampler_); + + // We must bind the program after starting the render pass, and set the color mask after clearing. + draw_->SetScissorRect(0, 0, w, h); + draw_->BindPipeline(stencilUploadPipeline_); + + for (int i = 1; i < values; i += i) { + if (!(usedBits & i)) { + // It's already zero, let's skip it. + continue; + } + StencilUB ub; + if (dstBuffer->format == GE_FORMAT_4444) { + draw_->SetStencilParams(0xFF, (i << 4) | i, 0xFF); + ub.stencilValue = i * (16.0f / 255.0f); + } else if (dstBuffer->format == GE_FORMAT_5551) { + draw_->SetStencilParams(0xFF, 0xFF, 0xFF); + ub.stencilValue = i * (128.0f / 255.0f); + } else { + draw_->SetStencilParams(0xFF, i, 0xFF); + ub.stencilValue = i * (1.0f / 255.0f); + } + draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub)); + draw_->DrawUP(positions, 3); + } + + if (useBlit) { + // Note that scissors don't affect blits on other APIs than OpenGL, so might want to try to get rid of this. + draw_->SetScissorRect(0, 0, dstBuffer->renderWidth, dstBuffer->renderHeight); + draw_->BlitFramebuffer(blitFBO, 0, 0, w, h, dstBuffer->fbo, 0, 0, dstBuffer->renderWidth, dstBuffer->renderHeight, Draw::FB_STENCIL_BIT, Draw::FB_BLIT_NEAREST, "NotifyStencilUpload_Blit"); + } + + tex->Release(); + RebindFramebuffer("RebindFramebuffer - Stencil"); + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); + return true; +} diff --git a/GPU/Common/StencilCommon.h b/GPU/Common/StencilCommon.h index ee26b4412e..3a22336b5f 100644 --- a/GPU/Common/StencilCommon.h +++ b/GPU/Common/StencilCommon.h @@ -1,7 +1,3 @@ #pragma once #include "Common/CommonTypes.h" - -u8 StencilBits8888(const u8 *ptr8, u32 numPixels); -u8 StencilBits4444(const u8 *ptr8, u32 numPixels); -u8 StencilBits5551(const u8 *ptr8, u32 numPixels); diff --git a/GPU/D3D11/FramebufferManagerD3D11.h b/GPU/D3D11/FramebufferManagerD3D11.h index 0a389f6dc3..db843c1a02 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.h +++ b/GPU/D3D11/FramebufferManagerD3D11.h @@ -43,8 +43,6 @@ public: void EndFrame(); - virtual bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override; - // TODO: Remove ID3D11Buffer *GetDynamicQuadBuffer() { return quadBuffer_; diff --git a/GPU/D3D11/StencilBufferD3D11.cpp b/GPU/D3D11/StencilBufferD3D11.cpp deleted file mode 100644 index eee531b55f..0000000000 --- a/GPU/D3D11/StencilBufferD3D11.cpp +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright (c) 2014- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#include - -#include "Common/GPU/thin3d.h" - -#include "Common/Log.h" -#include "Core/Reporting.h" -#include "GPU/Common/StencilCommon.h" -#include "GPU/D3D11/FramebufferManagerD3D11.h" -#include "GPU/D3D11/ShaderManagerD3D11.h" -#include "GPU/D3D11/TextureCacheD3D11.h" -#include "GPU/D3D11/D3D11Util.h" - -struct StencilValueUB { - uint32_t u_stencilValue[4]; -}; - -static const char *stencil_ps = R"( -SamplerState samp : register(s0); -Texture2D tex : register(t0); -cbuffer base : register(b0) { - int4 u_stencilValue; -}; -struct PS_IN { - float2 v_texcoord0 : TEXCOORD0; -}; -float4 main(PS_IN In) : SV_Target { - float4 index = tex.Sample(samp, In.v_texcoord0); - int indexBits = int(index.a * 255.99); - if ((indexBits & u_stencilValue.x) == 0) - discard; - return index.aaaa; -} -)"; - -// static const char *stencil_ps_fast; - -static const char *stencil_vs = R"( -struct VS_IN { - float4 a_position : POSITION; - float2 a_texcoord0 : TEXCOORD0; -}; -struct VS_OUT { - float2 v_texcoord0 : TEXCOORD0; - float4 position : SV_Position; -}; -VS_OUT main(VS_IN In) { - VS_OUT Out; - Out.position = In.a_position; - Out.v_texcoord0 = In.a_texcoord0; - return Out; -} -)"; - -// TODO : If SV_StencilRef is available (D3D11.3) then this can be done in a single pass. -bool FramebufferManagerD3D11::NotifyStencilUpload(u32 addr, int size, StencilUpload flags) { - addr &= 0x3FFFFFFF; - if (!MayIntersectFramebuffer(addr)) { - return false; - } - - VirtualFramebuffer *dstBuffer = 0; - for (size_t i = 0; i < vfbs_.size(); ++i) { - VirtualFramebuffer *vfb = vfbs_[i]; - if (vfb->fb_address == addr) { - dstBuffer = vfb; - } - } - if (!dstBuffer) { - return false; - } - - int values = 0; - u8 usedBits = 0; - - const u8 *src = Memory::GetPointer(addr); - if (!src) { - return false; - } - - switch (dstBuffer->format) { - case GE_FORMAT_565: - // Well, this doesn't make much sense. - return false; - case GE_FORMAT_5551: - usedBits = StencilBits5551(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 2; - break; - case GE_FORMAT_4444: - usedBits = StencilBits4444(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 16; - break; - case GE_FORMAT_8888: - usedBits = StencilBits8888(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 256; - break; - case GE_FORMAT_INVALID: - // Impossible. - break; - } - - if (usedBits == 0) { - if (flags == StencilUpload::STENCIL_IS_ZERO) { - // Common when creating buffers, it's already 0. We're done. - return false; - } - - // Clear stencil+alpha but not color. Only way is to draw a quad. - context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0x8], nullptr, 0xFFFFFFFF); - context_->RSSetState(stockD3D11.rasterStateNoCull); - context_->OMSetDepthStencilState(stockD3D11.depthDisabledStencilWrite, 0); - context_->IASetVertexBuffers(0, 1, &fsQuadBuffer_, &quadStride_, &quadOffset_); - context_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - context_->Draw(4, 0); - - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE); - return true; - } - - // TODO: Helper with logging? - if (!stencilUploadPS_) { - std::string errorMessage; - stencilUploadPS_ = CreatePixelShaderD3D11(device_, stencil_ps, strlen(stencil_ps), featureLevel_); - } - if (!stencilUploadVS_) { - std::string errorMessage; - std::vector byteCode; - stencilUploadVS_ = CreateVertexShaderD3D11(device_, stencil_vs, strlen(stencil_vs), &byteCode, featureLevel_); - ASSERT_SUCCESS(device_->CreateInputLayout(g_QuadVertexElements, 2, byteCode.data(), byteCode.size(), &stencilUploadInputLayout_)); - } - if (!stencilValueBuffer_) { - D3D11_BUFFER_DESC desc{}; - desc.ByteWidth = sizeof(StencilValueUB); - desc.Usage = D3D11_USAGE_DYNAMIC; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; - ASSERT_SUCCESS(device_->CreateBuffer(&desc, nullptr, &stencilValueBuffer_)); - } - - shaderManager_->DirtyLastShader(); - - u16 w = dstBuffer->renderWidth; - u16 h = dstBuffer->renderHeight; - Draw::Texture *tex = MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->bufferWidth, dstBuffer->bufferHeight); - if (!tex) - return false; - if (dstBuffer->fbo) { - // Typically, STENCIL_IS_ZERO means it's already bound. - Draw::RPAction stencilAction = flags == StencilUpload::STENCIL_IS_ZERO ? Draw::RPAction::KEEP : Draw::RPAction::CLEAR; - draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, stencilAction }, "Stencil"); - } else { - // something is wrong... - } - D3D11_VIEWPORT vp{ 0.0f, 0.0f, (float)w, (float)h, 0.0f, 1.0f }; - context_->RSSetViewports(1, &vp); - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE); - - float coord[20] = { - -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, - 1.0f, 1.0f, 0.0f, 1.0, 0.0f, - -1.0f, -1.0f, 0.0f, 0.0f, 1.0, - 1.0f, -1.0f, 0.0f, 1.0, 1.0, - }; - - D3D11_MAPPED_SUBRESOURCE map; - context_->Map(quadBuffer_, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - memcpy(map.pData, coord, sizeof(float) * 4 * 5); - context_->Unmap(quadBuffer_, 0); - - shaderManager_->DirtyLastShader(); - textureCache_->ForgetLastTexture(); - - context_->OMSetBlendState(stockD3D11.blendStateDisabledWithColorMask[0], nullptr, 0xFFFFFFFF); - context_->IASetInputLayout(stencilUploadInputLayout_); - context_->PSSetShader(stencilUploadPS_, nullptr, 0); - context_->VSSetShader(stencilUploadVS_, nullptr, 0); - draw_->BindTextures(0, 1, &tex); - context_->RSSetState(stockD3D11.rasterStateNoCull); - context_->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - context_->IASetVertexBuffers(0, 1, &quadBuffer_, &quadStride_, &quadOffset_); - context_->PSSetSamplers(0, 1, &stockD3D11.samplerPoint2DClamp); - context_->OMSetDepthStencilState(stockD3D11.depthDisabledStencilWrite, 0xFF); - - for (int i = 1; i < values; i += i) { - if (!(usedBits & i)) { - // It's already zero, let's skip it. - continue; - } - uint8_t mask = 0; - uint8_t value = 0; - if (dstBuffer->format == GE_FORMAT_4444) { - mask = i | (i << 4); - value = i * 16; - } else if (dstBuffer->format == GE_FORMAT_5551) { - mask = 0xFF; - value = i * 128; - } else { - mask = i; - value = i; - } - if (!stencilMaskStates_[mask]) { - D3D11_DEPTH_STENCIL_DESC desc{}; - desc.DepthEnable = false; - desc.StencilEnable = true; - desc.StencilReadMask = 0xFF; - desc.StencilWriteMask = mask; - desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_REPLACE; - desc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_REPLACE; - desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_REPLACE; - desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; - desc.BackFace = desc.FrontFace; - device_->CreateDepthStencilState(&desc, &stencilMaskStates_[mask]); - } - context_->OMSetDepthStencilState(stencilMaskStates_[mask], 0xFF); - - D3D11_MAPPED_SUBRESOURCE map; - context_->Map(stencilValueBuffer_, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); - StencilValueUB ub{ (uint32_t)value }; - memcpy(map.pData, &ub, sizeof(ub)); - context_->Unmap(stencilValueBuffer_, 0); - context_->PSSetConstantBuffers(0, 1, &stencilValueBuffer_); - context_->Draw(4, 0); - } - - tex->Release(); - RebindFramebuffer("RebindFramebuffer stencil"); - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); - return true; -} diff --git a/GPU/Directx9/FramebufferManagerDX9.h b/GPU/Directx9/FramebufferManagerDX9.h index 0d715d75f1..c8dbbe249a 100644 --- a/GPU/Directx9/FramebufferManagerDX9.h +++ b/GPU/Directx9/FramebufferManagerDX9.h @@ -48,8 +48,6 @@ public: void EndFrame(); - virtual bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override; - bool GetFramebuffer(u32 fb_address, int fb_stride, GEBufferFormat format, GPUDebugBuffer &buffer, int maxRes) override; bool GetDepthbuffer(u32 fb_address, int fb_stride, u32 z_address, int z_stride, GPUDebugBuffer &buffer) override; bool GetStencilbuffer(u32 fb_address, int fb_stride, GPUDebugBuffer &buffer) override; diff --git a/GPU/Directx9/StencilBufferDX9.cpp b/GPU/Directx9/StencilBufferDX9.cpp deleted file mode 100644 index 31ae6aa17d..0000000000 --- a/GPU/Directx9/StencilBufferDX9.cpp +++ /dev/null @@ -1,259 +0,0 @@ -// Copyright (c) 2014- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#include - -#include "Common/GPU/D3D9/D3D9StateCache.h" -#include "Common/GPU/thin3d.h" -#include "Core/Reporting.h" -#include "GPU/Common/StencilCommon.h" -#include "GPU/Directx9/FramebufferManagerDX9.h" -#include "GPU/Directx9/ShaderManagerDX9.h" -#include "GPU/Directx9/TextureCacheDX9.h" - -namespace DX9 { - -#define STR_HELPER(x) #x -#define STR(x) STR_HELPER(x) - -static const char *stencil_ps = R"( -sampler tex: register(s0); -// TODO: Don't use fixed registers? Or don't overlap? -float4 u_stencilValue : register(c)" STR(CONST_PS_STENCILVALUE) R"(); -struct PS_IN { - float2 v_texcoord0 : TEXCOORD0; -}; -float roundAndScaleTo255f(in float x) { return floor(x * 255.99); } -float4 main(PS_IN In) : COLOR { - float4 index = tex2D(tex, In.v_texcoord0); - float shifted = roundAndScaleTo255f(index.a) / roundAndScaleTo255f(u_stencilValue.x); - clip(fmod(floor(shifted), 2.0) - 0.99); - return index.aaaa; -} -)"; - -static const char *stencil_vs = R"( -struct VS_IN { - float4 a_position : POSITION; - float2 a_texcoord0 : TEXCOORD0; -}; -struct VS_OUT { - float4 position : POSITION; - float2 v_texcoord0 : TEXCOORD0; -}; -VS_OUT main(VS_IN In) { - VS_OUT Out; - Out.position = In.a_position; - Out.v_texcoord0 = In.a_texcoord0; - return Out; -} -)"; - -bool FramebufferManagerDX9::NotifyStencilUpload(u32 addr, int size, StencilUpload flags) { - addr &= 0x3FFFFFFF; - if (!MayIntersectFramebuffer(addr)) { - return false; - } - - VirtualFramebuffer *dstBuffer = 0; - for (size_t i = 0; i < vfbs_.size(); ++i) { - VirtualFramebuffer *vfb = vfbs_[i]; - if (vfb->fb_address == addr) { - dstBuffer = vfb; - } - } - if (!dstBuffer) { - return false; - } - - int values = 0; - u8 usedBits = 0; - - const u8 *src = Memory::GetPointer(addr); - if (!src) { - return false; - } - - switch (dstBuffer->format) { - case GE_FORMAT_565: - // Well, this doesn't make much sense. - return false; - case GE_FORMAT_5551: - usedBits = StencilBits5551(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 2; - break; - case GE_FORMAT_4444: - usedBits = StencilBits4444(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 16; - break; - case GE_FORMAT_8888: - usedBits = StencilBits8888(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 256; - break; - case GE_FORMAT_INVALID: - // Impossible. - break; - } - - if (usedBits == 0) { - if (flags == StencilUpload::STENCIL_IS_ZERO) { - // Common when creating buffers, it's already 0. We're done. - return false; - } - - // Let's not bother with the shader if it's just zero. - dxstate.scissorTest.disable(); - dxstate.colorMask.set(0x8); - // TODO: Verify this clears only stencil/alpha. - device_->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_STENCIL, D3DCOLOR_RGBA(0, 0, 0, 0), 0.0f, 0); - - gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE); - return true; - } - - if (stencilUploadFailed_) { - return false; - } - - // TODO: Helper with logging? - if (!stencilUploadPS_) { - std::string errorMessage; - bool success = CompilePixelShaderD3D9(device_, stencil_ps, &stencilUploadPS_, &errorMessage); - if (!errorMessage.empty()) { - if (success) { - ERROR_LOG(G3D, "Warnings in shader compilation!"); - } else { - ERROR_LOG(G3D, "Error in shader compilation!"); - } - ERROR_LOG(G3D, "Messages: %s", errorMessage.c_str()); - ERROR_LOG(G3D, "Shader source:\n%s", stencil_ps); - OutputDebugStringUTF8("Messages:\n"); - OutputDebugStringUTF8(errorMessage.c_str()); - Reporting::ReportMessage("D3D error in shader compilation: info: %s / code: %s", errorMessage.c_str(), stencil_ps); - } - if (!success) { - if (stencilUploadPS_) { - stencilUploadPS_->Release(); - } - stencilUploadPS_ = nullptr; - } - } - if (!stencilUploadVS_) { - std::string errorMessage; - bool success = CompileVertexShaderD3D9(device_, stencil_vs, &stencilUploadVS_, &errorMessage); - if (!errorMessage.empty()) { - if (success) { - ERROR_LOG(G3D, "Warnings in shader compilation!"); - } else { - ERROR_LOG(G3D, "Error in shader compilation!"); - } - ERROR_LOG(G3D, "Messages: %s", errorMessage.c_str()); - ERROR_LOG(G3D, "Shader source:\n%s", stencil_vs); - OutputDebugStringUTF8("Messages:\n"); - OutputDebugStringUTF8(errorMessage.c_str()); - Reporting::ReportMessage("D3D error in shader compilation: info: %s / code: %s", errorMessage.c_str(), stencil_vs); - } - if (!success) { - if (stencilUploadVS_) { - stencilUploadVS_->Release(); - } - stencilUploadVS_ = nullptr; - } - } - if (!stencilUploadPS_ || !stencilUploadVS_) { - stencilUploadFailed_ = true; - return false; - } - - shaderManager_->DirtyLastShader(); - - dxstate.colorMask.set(0x8); - dxstate.stencilTest.enable(); - dxstate.stencilOp.set(D3DSTENCILOP_REPLACE, D3DSTENCILOP_REPLACE, D3DSTENCILOP_REPLACE); - - u16 w = dstBuffer->renderWidth; - u16 h = dstBuffer->renderHeight; - - if (dstBuffer->fbo) { - // Typically, STENCIL_IS_ZERO means it's already bound. - Draw::RPAction stencilAction = flags == StencilUpload::STENCIL_IS_ZERO ? Draw::RPAction::KEEP : Draw::RPAction::CLEAR; - draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, stencilAction }, "StencilUpload"); - } - D3DVIEWPORT9 vp{ 0, 0, w, h, 0.0f, 1.0f }; - device_->SetViewport(&vp); - - Draw::Texture *tex = MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->bufferWidth, dstBuffer->bufferHeight); - if (!tex) - return false; - - // TODO: Ideally, we should clear alpha to zero here (but not RGB.) - - dxstate.stencilFunc.set(D3DCMP_ALWAYS); - dxstate.stencilRef.set(0xFF); - dxstate.stencilCompareMask.set(0xFF); - - float coord[20] = { - -1.0f, 1.0f, 0.0f, 0.0f, 0.0f, - 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, - -1.0f, -1.0f, 0.0f, 0.0f, 1.0f, - 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, - }; - - device_->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); - - device_->SetVertexDeclaration(pFramebufferVertexDecl); - device_->SetPixelShader(stencilUploadPS_); - device_->SetVertexShader(stencilUploadVS_); - - draw_->BindTextures(0, 1, &tex); - - shaderManager_->DirtyLastShader(); - textureCache_->ForgetLastTexture(); - - for (int i = 1; i < values; i += i) { - if (!(usedBits & i)) { - // It's already zero, let's skip it. - continue; - } - if (dstBuffer->format == GE_FORMAT_4444) { - dxstate.stencilWriteMask.set(i | (i << 4)); - const float f[4] = {i * (16.0f / 255.0f)}; - device_->SetPixelShaderConstantF(CONST_PS_STENCILVALUE, f, 1); - } else if (dstBuffer->format == GE_FORMAT_5551) { - dxstate.stencilWriteMask.set(0xFF); - const float f[4] = {i * (128.0f / 255.0f)}; - device_->SetPixelShaderConstantF(CONST_PS_STENCILVALUE, f, 1); - } else { - dxstate.stencilWriteMask.set(i); - const float f[4] = {i * (1.0f / 255.0f)}; - device_->SetPixelShaderConstantF(CONST_PS_STENCILVALUE, f, 1); - } - HRESULT hr = device_->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, coord, 5 * sizeof(float)); - if (FAILED(hr)) { - ERROR_LOG_REPORT(G3D, "Failed to draw stencil bit %x: %08x", i, (uint32_t)hr); - } - } - - tex->Release(); - dxstate.stencilWriteMask.set(0xFF); - dxstate.viewport.restore(); - RebindFramebuffer("RebindFramebuffer stencil"); - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); - return true; -} - -} // namespace DX9 diff --git a/GPU/GLES/FramebufferManagerGLES.cpp b/GPU/GLES/FramebufferManagerGLES.cpp index 983e3dc7c4..42245c4d2e 100644 --- a/GPU/GLES/FramebufferManagerGLES.cpp +++ b/GPU/GLES/FramebufferManagerGLES.cpp @@ -144,10 +144,12 @@ void FramebufferManagerGLES::DestroyDeviceObjects() { render_->DeleteProgram(draw2dprogram_); draw2dprogram_ = nullptr; } - if (stencilUploadProgram_) { - render_->DeleteProgram(stencilUploadProgram_); - stencilUploadProgram_ = nullptr; + + if (stencilUploadPipeline_) { + stencilUploadPipeline_->Release(); + stencilUploadPipeline_ = nullptr; } + if (depthDownloadProgram_) { render_->DeleteProgram(depthDownloadProgram_); depthDownloadProgram_ = nullptr; diff --git a/GPU/GLES/FramebufferManagerGLES.h b/GPU/GLES/FramebufferManagerGLES.h index 7e558772d2..8347f059a2 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -50,7 +50,7 @@ public: void DeviceLost() override; void DeviceRestore(Draw::DrawContext *draw) override; - bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override; + bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR); bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; @@ -76,10 +76,6 @@ private: GLRProgram *draw2dprogram_ = nullptr; - GLRProgram *stencilUploadProgram_ = nullptr; - int u_stencilUploadTex = -1; - int u_stencilValue = -1; - GLRProgram *depthDownloadProgram_ = nullptr; int u_depthDownloadTex = -1; int u_depthDownloadFactor = -1; diff --git a/GPU/GPU.vcxproj b/GPU/GPU.vcxproj index 49db8ec9c4..ae899f0cd2 100644 --- a/GPU/GPU.vcxproj +++ b/GPU/GPU.vcxproj @@ -513,7 +513,6 @@ - @@ -525,7 +524,6 @@ - @@ -572,12 +570,6 @@ true true - - true - true - true - true - true true @@ -616,7 +608,6 @@ - @@ -675,4 +666,4 @@ - \ No newline at end of file + diff --git a/GPU/GPU.vcxproj.filters b/GPU/GPU.vcxproj.filters index 2f26b61aa6..9c8d6b0f93 100644 --- a/GPU/GPU.vcxproj.filters +++ b/GPU/GPU.vcxproj.filters @@ -356,9 +356,6 @@ Common - - DirectX9 - Common @@ -416,9 +413,6 @@ GLES - - GLES - GLES @@ -455,9 +449,6 @@ D3D11 - - D3D11 - Common @@ -473,9 +464,6 @@ Debugger - - Vulkan - Common @@ -547,4 +535,4 @@ Shaders - \ No newline at end of file + diff --git a/GPU/Vulkan/FramebufferManagerVulkan.h b/GPU/Vulkan/FramebufferManagerVulkan.h index 6e8725398a..45a07ef9ed 100644 --- a/GPU/Vulkan/FramebufferManagerVulkan.h +++ b/GPU/Vulkan/FramebufferManagerVulkan.h @@ -52,8 +52,6 @@ public: void DeviceLost() override; void DeviceRestore(Draw::DrawContext *draw) override; - bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override; - // If within a render pass, this will just issue a regular clear. If beginning a new render pass, // do that. void NotifyClear(bool clearColor, bool clearAlpha, bool clearDepth, uint32_t color, float depth); diff --git a/GPU/Vulkan/StencilBufferVulkan.cpp b/GPU/Vulkan/StencilBufferVulkan.cpp deleted file mode 100644 index 6998455aef..0000000000 --- a/GPU/Vulkan/StencilBufferVulkan.cpp +++ /dev/null @@ -1,229 +0,0 @@ -// Copyright (c) 2014- PPSSPP Project. - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, version 2.0 or later versions. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License 2.0 for more details. - -// A copy of the GPL 2.0 should have been included with the program. -// If not, see http://www.gnu.org/licenses/ - -// Official git repository and contact information can be found at -// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. - -#include "Common/GPU/thin3d.h" -#include "Common/GPU/Vulkan/VulkanRenderManager.h" - -#include "Common/Log.h" -#include "Core/Config.h" -#include "Core/Reporting.h" -#include "GPU/Common/StencilCommon.h" -#include "GPU/Vulkan/FramebufferManagerVulkan.h" -#include "GPU/Vulkan/ShaderManagerVulkan.h" -#include "GPU/Vulkan/TextureCacheVulkan.h" -#include "GPU/Vulkan/VulkanUtil.h" - -// This shader references gl_FragDepth to prevent early fragment tests. -// They shouldn't happen since it uses discard, but Adreno detects that incorrectly - see #10634. -// This only affected the 5xx generation and was fixed sometime before driver version 512.384.0.0 (whatever that means). -// Strangely, this same code appears to fix a different issue on Exynos instead so now it's enabled on Mali as well. -static const char *stencil_fs_adreno = R"(#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_ARB_shading_language_420pack : enable -#extension GL_ARB_conservative_depth : enable -layout (depth_unchanged) out float gl_FragDepth; -layout (binding = 0) uniform sampler2D tex; -layout (push_constant) uniform params { - int u_stencilValue; -}; -layout (location = 0) in vec2 v_texcoord0; -layout (location = 0) out vec4 fragColor0; - -void main() { - gl_FragDepth = gl_FragCoord.z; - - if (u_stencilValue == 0) { - fragColor0 = vec4(0.0); - } else { - vec4 index = texture(tex, v_texcoord0); - int indexBits = int(floor(index.a * 255.99)) & 0xFF; - if ((indexBits & u_stencilValue) == 0) - discard; - fragColor0 = index.aaaa; - } -} -)"; - -static const char *stencil_fs = R"(#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_ARB_shading_language_420pack : enable -layout (binding = 0) uniform sampler2D tex; -layout (push_constant) uniform params { - int u_stencilValue; -}; -layout (location = 0) in vec2 v_texcoord0; -layout (location = 0) out vec4 fragColor0; - -void main() { - if (u_stencilValue == 0) { - fragColor0 = vec4(0.0); - } else { - vec4 index = texture(tex, v_texcoord0); - int indexBits = int(floor(index.a * 255.99)) & 0xFF; - if ((indexBits & u_stencilValue) == 0) - discard; - fragColor0 = index.aaaa; - } -} -)"; - - -static const char stencil_vs[] = R"(#version 450 -#extension GL_ARB_separate_shader_objects : enable -#extension GL_ARB_shading_language_420pack : enable -layout (location = 0) out vec2 v_texcoord0; -out gl_PerVertex { vec4 gl_Position; }; -void main() { - int id = gl_VertexIndex; - v_texcoord0.x = (id == 2) ? 2.0 : 0.0; - v_texcoord0.y = (id == 1) ? 2.0 : 0.0; - gl_Position = vec4(v_texcoord0 * vec2(2.0, 2.0) + vec2(-1.0, -1.0), 0.0, 1.0); -} -)"; - -// In Vulkan we should be able to simply copy the stencil data directly to a stencil buffer without -// messing about with bitplane textures and the like. Or actually, maybe not... Let's start with -// the traditional approach. -bool FramebufferManagerVulkan::NotifyStencilUpload(u32 addr, int size, StencilUpload flags) { - addr &= 0x3FFFFFFF; - if (!MayIntersectFramebuffer(addr)) { - return false; - } - - VirtualFramebuffer *dstBuffer = 0; - for (size_t i = 0; i < vfbs_.size(); ++i) { - VirtualFramebuffer *vfb = vfbs_[i]; - if (vfb->fb_address == addr) { - dstBuffer = vfb; - } - } - if (!dstBuffer) { - return false; - } - - int values = 0; - u8 usedBits = 0; - - const u8 *src = Memory::GetPointer(addr); - if (!src) { - return false; - } - - switch (dstBuffer->format) { - case GE_FORMAT_565: - // Well, this doesn't make much sense. - return false; - case GE_FORMAT_5551: - usedBits = StencilBits5551(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 2; - break; - case GE_FORMAT_4444: - usedBits = StencilBits4444(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 16; - break; - case GE_FORMAT_8888: - usedBits = StencilBits8888(src, dstBuffer->fb_stride * dstBuffer->bufferHeight); - values = 256; - break; - case GE_FORMAT_INVALID: - case GE_FORMAT_DEPTH16: - // Inconceivable. - _assert_(false); - break; - } - - std::string error; - if (!stencilVs_) { - VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT); - - const char *stencil_fs_source = stencil_fs; - // See comment above the stencil_fs_adreno definition. - u32 vendorID = vulkan->GetPhysicalDeviceProperties().properties.vendorID; - if (g_Config.bVendorBugChecksEnabled && (draw_->GetBugs().Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL) || vendorID == VULKAN_VENDOR_ARM)) - stencil_fs_source = stencil_fs_adreno; - - stencilVs_ = CompileShaderModule(vulkan, VK_SHADER_STAGE_VERTEX_BIT, stencil_vs, &error); - stencilFs_ = CompileShaderModule(vulkan, VK_SHADER_STAGE_FRAGMENT_BIT, stencil_fs_source, &error); - } - VkRenderPass rp = (VkRenderPass)draw_->GetNativeObject(Draw::NativeObject::FRAMEBUFFER_RENDERPASS); - - VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); - - shaderManager_->DirtyLastShader(); - textureCache_->ForgetLastTexture(); - - u16 w = dstBuffer->renderWidth; - u16 h = dstBuffer->renderHeight; - Draw::Texture *tex = MakePixelTexture(src, dstBuffer->format, dstBuffer->fb_stride, dstBuffer->bufferWidth, dstBuffer->bufferHeight); - if (!tex) - return false; - - if (dstBuffer->fbo) { - // Typically, STENCIL_IS_ZERO means it's already bound, so this bind will be optimized away. - draw_->BindFramebufferAsRenderTarget(dstBuffer->fbo, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::DONT_CARE }, "Stencil"); - } else { - // something is wrong... - } - - VkPipeline pipeline = vulkan2D_->GetPipeline(rp, stencilVs_, stencilFs_, false, Vulkan2D::VK2DDepthStencilMode::STENCIL_REPLACE_ALWAYS); - renderManager->BindPipeline(pipeline, PIPELINE_FLAG_USES_DEPTH_STENCIL); - renderManager->SetViewport({ 0.0f, 0.0f, (float)w, (float)h, 0.0f, 1.0f }); - renderManager->SetScissor(0, 0, (int)w, (int)h); - - draw_->BindTextures(0, 1, &tex); - VkImageView drawPixelsImageView = (VkImageView)draw_->GetNativeObject(Draw::NativeObject::BOUND_TEXTURE0_IMAGEVIEW); - VkDescriptorSet descSet = vulkan2D_->GetDescriptorSet(drawPixelsImageView, nearestSampler_, VK_NULL_HANDLE, VK_NULL_HANDLE); - - // Note: Even with skipZero, we don't necessarily start framebuffers at 0 in Vulkan. Clear anyway. - // Not an actual clear, because we need to draw to alpha only as well. - uint32_t value = 0; - renderManager->PushConstants(vulkan2D_->GetPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT|VK_SHADER_STAGE_FRAGMENT_BIT, 0, 4, &value); - renderManager->SetStencilParams(0xFF, 0xFF, 0x00); - renderManager->Draw(vulkan2D_->GetPipelineLayout(), descSet, 0, nullptr, VK_NULL_HANDLE, 0, 3); // full screen triangle - - for (int i = 1; i < values; i += i) { - if (!(usedBits & i)) { - // It's already zero, let's skip it. - continue; - } - - // These are the stencil bits that will be written. We discard when the bit doesn't match. - uint8_t writeMask = 0; - // This is the value to test the texture alpha against in the shader. - uint32_t value = 0; - if (dstBuffer->format == GE_FORMAT_4444) { - writeMask = i | (i << 4); - value = i * 16; - } else if (dstBuffer->format == GE_FORMAT_5551) { - writeMask = 0xFF; - value = i * 128; - } else { - writeMask = i; - value = i; - } - renderManager->SetStencilParams(writeMask, 0xFF, 0xFF); - // Need to specify both VERTEX and FRAGMENT bits here since that's what we set up in the pipeline layout, and we need - // that for the post shaders. There's probably not really a cost to this. - renderManager->PushConstants(vulkan2D_->GetPipelineLayout(), VK_SHADER_STAGE_VERTEX_BIT|VK_SHADER_STAGE_FRAGMENT_BIT, 0, 4, &value); - renderManager->Draw(vulkan2D_->GetPipelineLayout(), descSet, 0, nullptr, VK_NULL_HANDLE, 0, 3); // full screen triangle - } - - tex->Release(); - RebindFramebuffer("RebindFramebuffer - NotifyStencilUpload"); - gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS); - return true; -} diff --git a/android/jni/Android.mk b/android/jni/Android.mk index ae109b91d1..246278cf05 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -351,7 +351,6 @@ EXEC_AND_LIB_FILES := \ $(SRC)/GPU/GLES/DepalettizeShaderGLES.cpp \ $(SRC)/GPU/GLES/DepthBufferGLES.cpp \ $(SRC)/GPU/GLES/GPU_GLES.cpp.arm \ - $(SRC)/GPU/GLES/StencilBufferGLES.cpp \ $(SRC)/GPU/GLES/TextureCacheGLES.cpp.arm \ $(SRC)/GPU/GLES/DrawEngineGLES.cpp.arm \ $(SRC)/GPU/GLES/StateMappingGLES.cpp.arm \ diff --git a/libretro/Makefile.common b/libretro/Makefile.common index 696987c6fd..dc7c0bc987 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -369,7 +369,6 @@ SOURCES_CXX += \ $(GPUDIR)/GLES/TextureCacheGLES.cpp \ $(GPUDIR)/GLES/ShaderManagerGLES.cpp \ $(GPUDIR)/GLES/StateMappingGLES.cpp \ - $(GPUDIR)/GLES/StencilBufferGLES.cpp \ $(EXTDIR)/glslang/OGLCompilersDLL/InitializeDll.cpp \ $(EXTDIR)/glslang/glslang/GenericCodeGen/CodeGen.cpp \ $(EXTDIR)/glslang/glslang/GenericCodeGen/Link.cpp \ @@ -732,7 +731,6 @@ SOURCES_CXX += \ $(GPUDIR)/Vulkan/PipelineManagerVulkan.cpp \ $(GPUDIR)/Vulkan/ShaderManagerVulkan.cpp \ $(GPUDIR)/Vulkan/StateMappingVulkan.cpp \ - $(GPUDIR)/Vulkan/StencilBufferVulkan.cpp \ $(GPUDIR)/Vulkan/TextureCacheVulkan.cpp \ $(GPUDIR)/Vulkan/VulkanUtil.cpp \ $(LIBRETRODIR)/LibretroVulkanContext.cpp \ @@ -747,7 +745,6 @@ SOURCES_CXX += \ $(GPUDIR)/Directx9/GPU_DX9.cpp \ $(GPUDIR)/Directx9/ShaderManagerDX9.cpp \ $(GPUDIR)/Directx9/StateMappingDX9.cpp \ - $(GPUDIR)/Directx9/StencilBufferDX9.cpp \ $(GPUDIR)/Directx9/TextureCacheDX9.cpp SOURCES_CXX += \ @@ -758,7 +755,6 @@ SOURCES_CXX += \ $(GPUDIR)/D3D11/D3D11Util.cpp \ $(GPUDIR)/D3D11/ShaderManagerD3D11.cpp \ $(GPUDIR)/D3D11/StateMappingD3D11.cpp \ - $(GPUDIR)/D3D11/StencilBufferD3D11.cpp \ $(GPUDIR)/D3D11/TextureCacheD3D11.cpp \ $(LIBRETRODIR)/LibretroD3D11Context.cpp