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 a9a922cf24..eeba9d24a3 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -38,6 +38,7 @@ class D3D11Pipeline; class D3D11BlendState; class D3D11DepthStencilState; class D3D11SamplerState; +class D3D11Buffer; class D3D11RasterState; class D3D11Framebuffer; @@ -248,10 +249,12 @@ private: uint8_t stencilRef_ = 0; uint8_t stencilWriteMask_ = 0xFF; uint8_t stencilCompareMask_ = 0xFF; + bool stencilDirty_ = true; // Temporaries ID3D11Texture2D *packTexture_ = nullptr; + Buffer *upBuffer_ = nullptr; // System info D3D_FEATURE_LEVEL featureLevel_; @@ -282,8 +285,9 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de caps_.framebufferBlitSupported = false; caps_.framebufferCopySupported = true; caps_.framebufferDepthBlitSupported = false; + caps_.framebufferStencilBlitSupported = false; caps_.framebufferDepthCopySupported = true; - caps_.framebufferSeparateDepthCopySupported = false; + caps_.framebufferSeparateDepthCopySupported = false; // Though could be emulated with a draw. caps_.texture3DSupported = true; D3D11_FEATURE_DATA_D3D11_OPTIONS options{}; @@ -338,9 +342,14 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de _assert_(SUCCEEDED(hr)); shaderLanguageDesc_.Init(HLSL_D3D11); + + const size_t UP_MAX_BYTES = 65536 * 24; + + upBuffer_ = CreateBuffer(UP_MAX_BYTES, BufferUsageFlag::DYNAMIC | BufferUsageFlag::VERTEXDATA); } D3D11DrawContext::~D3D11DrawContext() { + upBuffer_->Release(); packTexture_->Release(); // Release references. @@ -756,9 +765,6 @@ public: shaderModule->Release(); } } - bool RequiresBuffer() override { - return true; - } AutoRef input; ID3D11InputLayout *il = nullptr; @@ -1248,7 +1254,13 @@ void D3D11DrawContext::DrawIndexed(int indexCount, int offset) { void D3D11DrawContext::DrawUP(const void *vdata, int vertexCount) { ApplyCurrentState(); - // TODO: Upload the data then draw.. + + int byteSize = vertexCount * curPipeline_->input->strides[0]; + + UpdateBuffer(upBuffer_, (const uint8_t *)vdata, 0, byteSize, Draw::UPDATE_DISCARD); + BindVertexBuffers(0, 1, &upBuffer_, nullptr); + int offset = 0; + Draw(vertexCount, offset); } uint32_t D3D11DrawContext::GetDataFormatSupport(DataFormat fmt) const { diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index 684b727cc5..2b0f1a0faa 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -23,6 +23,7 @@ #include "Common/Math/lin/matrix4x4.h" #include "Common/GPU/thin3d.h" #include "Common/GPU/D3D9/D3D9StateCache.h" +#include "Common/StringUtils.h" #include "Common/Log.h" @@ -272,9 +273,6 @@ public: D3D9Pipeline() {} ~D3D9Pipeline() { } - bool RequiresBuffer() override { - return false; - } D3D9ShaderModule *vshader; D3D9ShaderModule *pshader; @@ -666,6 +664,7 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID caps_.framebufferBlitSupported = true; caps_.framebufferCopySupported = false; caps_.framebufferDepthBlitSupported = true; + caps_.framebufferStencilBlitSupported = false; caps_.framebufferDepthCopySupported = false; caps_.framebufferSeparateDepthCopySupported = false; caps_.texture3DSupported = true; @@ -1065,6 +1064,10 @@ bool D3D9ShaderModule::Compile(LPDIRECT3DDEVICE9 device, const uint8_t *data, si // No D3D9-compatible shader compiler installed. error = "D3D9 shader compiler not installed"; } + + ERROR_LOG(G3D, "Compile error: %s", error); + ERROR_LOG(G3D, "%s", LineNumberString(std::string((const char *)data)).c_str()); + OutputDebugStringA(source); OutputDebugStringA(error); if (errorBuffer) diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index b48d900ab1..29c51cbeb5 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -261,9 +261,6 @@ public: ~OpenGLInputLayout(); void Compile(const InputLayoutDesc &desc); - bool RequiresBuffer() { - return false; - } GLRInputLayout *inputLayout_ = nullptr; int stride = 0; @@ -284,10 +281,6 @@ public: bool LinkShaders(); - bool RequiresBuffer() override { - return inputLayout && inputLayout->RequiresBuffer(); - } - GLuint prim = 0; std::vector shaders; AutoRef inputLayout; @@ -545,6 +538,7 @@ OpenGLContext::OpenGLContext() { caps_.framebufferCopySupported = gl_extensions.OES_copy_image || gl_extensions.NV_copy_image || gl_extensions.EXT_copy_image || gl_extensions.ARB_copy_image; caps_.framebufferBlitSupported = gl_extensions.NV_framebuffer_blit || gl_extensions.ARB_framebuffer_object || gl_extensions.GLES3; caps_.framebufferDepthBlitSupported = caps_.framebufferBlitSupported; + caps_.framebufferStencilBlitSupported = caps_.framebufferBlitSupported; caps_.depthClampSupported = gl_extensions.ARB_depth_clamp; if (gl_extensions.IsGLES) { caps_.clipDistanceSupported = gl_extensions.EXT_clip_cull_distance || gl_extensions.APPLE_clip_distance; @@ -1119,7 +1113,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/Shader.cpp b/Common/GPU/Shader.cpp index eaca068ff5..5033e55ac1 100644 --- a/Common/GPU/Shader.cpp +++ b/Common/GPU/Shader.cpp @@ -86,12 +86,14 @@ void ShaderLanguageDesc::Init(ShaderLanguage lang) { texelFetch = "texelFetch"; forceMatrix4x4 = false; coefsFromBuffers = true; + vertexIndex = true; break; case HLSL_D3D9: case HLSL_D3D11: if (lang == HLSL_D3D11) { fragColor0 = "outfragment.target"; fragColor1 = "outfragment.target1"; + vertexIndex = true; // if declared as a semantic input } else { fragColor0 = "outfragment.target"; } diff --git a/Common/GPU/Shader.h b/Common/GPU/Shader.h index 71cd26cae6..bc8c0f4e81 100644 --- a/Common/GPU/Shader.h +++ b/Common/GPU/Shader.h @@ -52,6 +52,8 @@ struct ShaderLanguageDesc { const char *framebufferFetchExtension = nullptr; const char *vsOutPrefix = ""; const char *viewportYSign = ""; + + bool vertexIndex = false; bool glslES30 = false; // really glslES30Features. TODO: Clean this up. bool bitwiseOps = false; bool forceMatrix4x4 = false; diff --git a/Common/GPU/ShaderWriter.cpp b/Common/GPU/ShaderWriter.cpp index d53f00169e..c8c64d6a72 100644 --- a/Common/GPU/ShaderWriter.cpp +++ b/Common/GPU/ShaderWriter.cpp @@ -162,6 +162,11 @@ void ShaderWriter::BeginVSMain(Slice inputs, Slice uniform if (lang_.shaderLanguage == HLSL_D3D11) { C("uint gl_VertexIndex : SV_VertexID, "); } + // List the inputs. + for (auto &input : inputs) { + F("in %s %s : %s, ", input.type, input.name, input.semantic); + } + Rewind(2); // Get rid of the last comma. C(") {\n"); C(" vec4 gl_Position;\n"); @@ -171,13 +176,23 @@ void ShaderWriter::BeginVSMain(Slice inputs, Slice uniform break; } case GLSL_VULKAN: + { + int i = 0; + for (auto &input : inputs) { + F("layout(location = %d) in %s %s;\n", i, input.type, input.name); + i++; + } for (auto &varying : varyings) { F("layout(location = %d) %s out %s %s; // %s\n", varying.index, varying.precision ? varying.precision : "", varying.type, varying.name, varying.semantic); } C("void main() {\n"); break; + } default: // OpenGL + for (auto &input : inputs) { + F("in %s %s;\n", input.type, input.name); + } for (auto &varying : varyings) { F("%s %s %s %s; // %s (%d)\n", lang_.varying_vs, varying.precision ? varying.precision : "", varying.type, varying.name, varying.semantic, varying.index); } @@ -191,10 +206,15 @@ void ShaderWriter::BeginFSMain(Slice uniforms, Slice var switch (lang_.shaderLanguage) { case HLSL_D3D11: if (!uniforms.is_empty()) { + C("cbuffer base : register(b0) {\n"); + for (auto &uniform : uniforms) { - //F(" %s %s : %s;\n", uniform.type, uniform.name, uniform.index); + F(" %s %s;\n", uniform.type, uniform.name); } + + C("};\n"); } + // Let's do the varyings as parameters to main, no struct. C("vec4 main("); for (auto &varying : varyings) { @@ -224,12 +244,23 @@ void ShaderWriter::BeginFSMain(Slice uniforms, Slice var F("layout(location = %d) %s in %s %s; // %s\n", varying.index, varying.precision ? varying.precision : "", varying.type, varying.name, varying.semantic); } C("layout(location = 0, index = 0) out vec4 fragColor0;\n"); + if (!uniforms.is_empty()) { + C("layout(std140, set = 0, binding = 0) uniform bufferVals {\n"); + for (auto &uniform : uniforms) { + F("%s %s;\n", uniform.type, uniform.name); + } + C("};\n"); + } C("\nvoid main() {\n"); break; - default: + + default: // GLSL OpenGL for (auto &varying : varyings) { F("%s %s %s %s; // %s\n", lang_.varying_fs, varying.precision ? varying.precision : "", varying.type, varying.name, varying.semantic); } + for (auto &uniform : uniforms) { + F("uniform %s %s;\n", uniform.type, uniform.name); + } if (!strcmp(lang_.fragColor0, "fragColor0")) { C("out vec4 fragColor0;\n"); } @@ -284,6 +315,7 @@ void ShaderWriter::DeclareTexture2D(const char *name, int binding) { F("Texture2D %s : register(t%d);\n", name, binding); break; case HLSL_D3D9: + F("sampler %s: register(s%d);\n", name, binding); break; case GLSL_VULKAN: // In the thin3d descriptor set layout, textures start at 1 in set 0. Hence the +1. diff --git a/Common/GPU/ShaderWriter.h b/Common/GPU/ShaderWriter.h index cb8d963be3..5e7f488723 100644 --- a/Common/GPU/ShaderWriter.h +++ b/Common/GPU/ShaderWriter.h @@ -19,6 +19,7 @@ struct InputDef { const char *type; const char *name; + const char *semantic; }; struct UniformDef { diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index e2cae4c906..1a84cb5ecb 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -271,9 +271,6 @@ public: int GetUBOSize() const { return uboSize_; } - bool RequiresBuffer() override { - return false; - } VkPipeline backbufferPipeline = VK_NULL_HANDLE; VkPipeline framebufferPipeline = VK_NULL_HANDLE; @@ -787,6 +784,7 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit) caps_.framebufferBlitSupported = true; caps_.framebufferCopySupported = true; caps_.framebufferDepthBlitSupported = vulkan->GetDeviceInfo().canBlitToPreferredDepthStencilFormat; + caps_.framebufferStencilBlitSupported = caps_.framebufferDepthBlitSupported; caps_.framebufferDepthCopySupported = true; // Will pretty much always be the case. caps_.framebufferSeparateDepthCopySupported = true; // Will pretty much always be the case. caps_.preferredDepthBufferFormat = DataFormat::D24_S8; // TODO: Ask vulkan. diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 9a618df79e..845914d344 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, }; @@ -450,7 +450,6 @@ public: class Pipeline : public RefCountedObject { public: virtual ~Pipeline() {} - virtual bool RequiresBuffer() = 0; }; class RasterState : public RefCountedObject {}; @@ -534,6 +533,7 @@ struct DeviceCaps { bool framebufferDepthCopySupported; bool framebufferSeparateDepthCopySupported; bool framebufferDepthBlitSupported; + bool framebufferStencilBlitSupported; bool framebufferFetchSupported; bool texture3DSupported; diff --git a/Common/Render/DrawBuffer.cpp b/Common/Render/DrawBuffer.cpp index 35e3f0176b..9b09e7675b 100644 --- a/Common/Render/DrawBuffer.cpp +++ b/Common/Render/DrawBuffer.cpp @@ -32,12 +32,6 @@ void DrawBuffer::Init(Draw::DrawContext *t3d, Draw::Pipeline *pipeline) { draw_ = t3d; inited_ = true; - - if (pipeline->RequiresBuffer()) { - vbuf_ = draw_->CreateBuffer(MAX_VERTS * sizeof(Vertex), BufferUsageFlag::DYNAMIC | BufferUsageFlag::VERTEXDATA); - } else { - vbuf_ = nullptr; - } } Draw::InputLayout *DrawBuffer::CreateInputLayout(Draw::DrawContext *t3d) { @@ -57,10 +51,6 @@ Draw::InputLayout *DrawBuffer::CreateInputLayout(Draw::DrawContext *t3d) { } void DrawBuffer::Shutdown() { - if (vbuf_) { - vbuf_->Release(); - vbuf_ = nullptr; - } inited_ = false; alphaStack_.clear(); drawMatrixStack_.clear(); @@ -90,14 +80,7 @@ void DrawBuffer::Flush(bool set_blend_state) { ub.tint = tint_; ub.saturation = saturation_; draw_->UpdateDynamicUniformBuffer(&ub, sizeof(ub)); - if (vbuf_) { - draw_->UpdateBuffer(vbuf_, (const uint8_t *)verts_, 0, sizeof(Vertex) * count_, Draw::UPDATE_DISCARD); - draw_->BindVertexBuffers(0, 1, &vbuf_, nullptr); - int offset = 0; - draw_->Draw(count_, offset); - } else { - draw_->DrawUP((const void *)verts_, count_); - } + draw_->DrawUP((const void *)verts_, count_); count_ = 0; } diff --git a/Common/Render/DrawBuffer.h b/Common/Render/DrawBuffer.h index e103805d2e..4a29893c15 100644 --- a/Common/Render/DrawBuffer.h +++ b/Common/Render/DrawBuffer.h @@ -199,7 +199,6 @@ private: std::vector alphaStack_; Draw::DrawContext *draw_ = nullptr; - Draw::Buffer *vbuf_ = nullptr; Draw::Pipeline *pipeline_ = nullptr; Vertex *verts_; diff --git a/GPU/Common/DrawEngineCommon.h b/GPU/Common/DrawEngineCommon.h index e5b7f952da..65391be14f 100644 --- a/GPU/Common/DrawEngineCommon.h +++ b/GPU/Common/DrawEngineCommon.h @@ -35,6 +35,16 @@ enum { DECODED_INDEX_BUFFER_SIZE = VERTEX_BUFFER_MAX * 16, }; +enum { + TEX_SLOT_PSP_TEXTURE = 0, + TEX_SLOT_SHADERBLEND_SRC = 1, + TEX_SLOT_ALPHATEST = 2, + TEX_SLOT_CLUT = 3, + TEX_SLOT_SPLINE_POINTS = 4, + TEX_SLOT_SPLINE_WEIGHTS_U = 5, + TEX_SLOT_SPLINE_WEIGHTS_V = 6, +}; + inline uint32_t GetVertTypeID(uint32_t vertType, int uvGenMode) { // As the decoder depends on the UVGenMode when we use UV prescale, we simply mash it // into the top of the verttype where there are unused bits. diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 46b8255ea5..9478bf34fd 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -469,7 +469,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame if (useBufferedRendering_ && !g_Config.bDisableSlowFramebufEffects) { gpu->PerformMemoryUpload(params.fb_address, byteSize); - NotifyStencilUpload(params.fb_address, byteSize, StencilUpload::STENCIL_IS_ZERO); + PerformStencilUpload(params.fb_address, byteSize, StencilUpload::STENCIL_IS_ZERO); // TODO: Is it worth trying to upload the depth buffer (only if it wasn't copied above..?) } @@ -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..894d7266e8 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -19,7 +19,6 @@ // Here's a list of functionality to unify into FramebufferManagerCommon: // * DrawActiveTexture // * BlitFramebuffer -// * StencilBuffer*.cpp // // Also, in TextureCache we should be able to unify texture-based depal. @@ -253,7 +252,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 PerformStencilUpload(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 +466,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/ReinterpretFramebuffer.cpp b/GPU/Common/ReinterpretFramebuffer.cpp index da2f0ef7b1..1f0f23b8c0 100644 --- a/GPU/Common/ReinterpretFramebuffer.cpp +++ b/GPU/Common/ReinterpretFramebuffer.cpp @@ -79,9 +79,10 @@ bool GenerateReinterpretVertexShader(char *buffer, const ShaderLanguageDesc &lan writer.C(" float x = -1.0 + float((gl_VertexIndex & 1) << 2);\n"); writer.C(" float y = -1.0 + float((gl_VertexIndex & 2) << 1);\n"); writer.C(" v_texcoord = (vec2(x, y) + vec2(1.0, 1.0)) * 0.5;\n"); - writer.F(" y *= %s1.0;\n", lang.viewportYSign); + if (strlen(lang.viewportYSign)) { + writer.F(" y *= %s1.0;\n", lang.viewportYSign); + } writer.C(" gl_Position = vec4(x, y, 0.0, 1.0);\n"); - writer.EndVSMain(varyings); return true; } diff --git a/GPU/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp index 29af15c020..ca661fa1f0 100644 --- a/GPU/Common/StencilCommon.cpp +++ b/GPU/Common/StencilCommon.cpp @@ -15,9 +15,17 @@ // 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/ShaderWriter.h" +#include "Core/Config.h" +#include "Core/ConfigValues.h" +#include "Core/Reporting.h" #include "GPU/Common/StencilCommon.h" +#include "GPU/Common/DrawEngineCommon.h" +#include "GPU/Common/FramebufferManagerCommon.h" +#include "GPU/Common/TextureCacheCommon.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 +36,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 +47,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 +57,273 @@ u8 StencilBits8888(const u8 *ptr8, u32 numPixels) { return bits >> 24; } + +struct StencilUB { + float stencilValue; +}; + +const UniformBufferDesc stencilUBDesc { sizeof(StencilUB), { + { "stencilValue", -1, 0, UniformType::FLOAT1, 0 }, +} }; + +// TODO: Merge this with UniformBufferDesc +static const UniformDef uniforms[1] = { + { "float", "stencilValue", 0 }, +}; + +static const InputDef inputs[1] = { + { "vec2", "a_position", "POSITION", } +}; + +static const VaryingDef varyings[1] = { + { "vec2", "v_texcoord", "TEXCOORD0", 0, "highp" }, +}; + +void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw::Bugs &bugs) { + ShaderWriter writer(buffer, lang, ShaderStage::Fragment, nullptr, 0); + writer.HighPrecisionFloat(); + + writer.DeclareSampler2D("samp", 0); + writer.DeclareTexture2D("tex", 0); + + if (bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL)) { + writer.C("layout (depth_unchanged) out float gl_FragDepth;\n"); + } + + writer.C("float roundAndScaleTo255f(in float x) { return floor(x * 255.99); }\n"); + + writer.BeginFSMain(uniforms, varyings); + + writer.C(" vec4 index = ").SampleTexture2D("tex", "samp", "v_texcoord.xy").C(";\n"); + writer.C(" vec4 outColor = index.aaaa;\n"); // Only care about a. + writer.C(" float shifted = roundAndScaleTo255f(index.a) / roundAndScaleTo255f(stencilValue);\n"); + // Bitwise operations on floats, ugh. + writer.C(" if (mod(floor(shifted), 2.0) < 0.99) DISCARD;\n"); + + if (bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL)) { + writer.C(" gl_FragDepth = gl_FragCoord.z;\n"); + } + + writer.EndFSMain("outColor"); +} + +// This can probably be shared with some other shaders, like reinterpret or the future depth upload. +void GenerateStencilVs(char *buffer, const ShaderLanguageDesc &lang) { + ShaderWriter writer(buffer, lang, ShaderStage::Vertex, nullptr, 0); + + writer.BeginVSMain(lang.vertexIndex ? Slice::empty() : inputs, Slice::empty(), varyings); + + if (lang.vertexIndex) { + writer.C(" float x = float((gl_VertexIndex & 1) << 1);\n"); + writer.C(" float y = float(gl_VertexIndex & 2);\n"); + writer.C(" v_texcoord = vec2(x, y);\n"); + } else { + writer.C(" v_texcoord = a_position * 2.0;\n"); // yes, this should be right. Should be 2.0 in the far corners. + } + writer.C(" gl_Position = vec4(v_texcoord * 2.0 - vec2(1.0, 1.0), 0.0, 1.0);\n"); + writer.F(" gl_Position.y *= %s1.0;\n", lang.viewportYSign); + + writer.EndVSMain(varyings); +} + +bool FramebufferManagerCommon::PerformStencilUpload(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"); + } + + // Here we might want to clear destination alpha by using a draw, but we haven't found a need for this yet. + // Will implement when needed... + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_DEPTHSTENCIL_STATE); + return true; + } + + shaderManager_->DirtyLastShader(); + textureCache_->ForgetLastTexture(); + + if (!stencilUploadPipeline_) { + const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc(); + + char *fsCode = new char[4000]; + char *vsCode = new char[4000]; + GenerateStencilFs(fsCode, shaderLanguageDesc, draw_->GetBugs()); + GenerateStencilVs(vsCode, shaderLanguageDesc); + + stencilUploadFs_ = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsCode, strlen(fsCode), "stencil_fs"); + stencilUploadVs_ = draw_->CreateShaderModule(ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage, (const uint8_t *)vsCode, strlen(vsCode), "stencil_vs"); + + _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_); + + delete[] fsCode; + delete[] vsCode; + + rasterNoCull->Release(); + blendOff->Release(); + stencilWrite->Release(); + inputLayout->Release(); + + SamplerStateDesc descNearest{}; + stencilUploadSampler_ = draw_->CreateSamplerState(descNearest); + } + + // Fullscreen triangle coordinates. + static const float positions[6] = { + 0.0, 0.0, + 1.0, 0.0, + 0.0, 1.0, + }; + + bool useBlit = draw_->GetDeviceCaps().framebufferStencilBlitSupported; + + // 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. + // TODO: This path means that we don't write color alpha... Ugh. + 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"); + RebindFramebuffer("RebindFramebuffer - Stencil"); + } + + tex->Release(); + gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_RASTER_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_TEXTURE_IMAGE | DIRTY_TEXTURE_PARAMS | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE); + return true; +} diff --git a/GPU/Common/StencilCommon.h b/GPU/Common/StencilCommon.h index ee26b4412e..e9746012a6 100644 --- a/GPU/Common/StencilCommon.h +++ b/GPU/Common/StencilCommon.h @@ -2,6 +2,8 @@ #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); +#include "Common/GPU/thin3d.h" + +// Exposed for automated tests +void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw::Bugs &bugs); +void GenerateStencilVs(char *buffer, const ShaderLanguageDesc &lang); diff --git a/GPU/D3D11/FramebufferManagerD3D11.cpp b/GPU/D3D11/FramebufferManagerD3D11.cpp index 6900e115d6..6d58e5caac 100644 --- a/GPU/D3D11/FramebufferManagerD3D11.cpp +++ b/GPU/D3D11/FramebufferManagerD3D11.cpp @@ -207,7 +207,7 @@ void FramebufferManagerD3D11::DrawActiveTexture(float x, float y, float w, float coord[i].pos.y = -(coord[i].pos.y * invDestH - 1.0f); } - if (g_display_rotation != DisplayRotation::ROTATE_0) { + if ((flags & DRAWTEX_TO_BACKBUFFER) && g_display_rotation != DisplayRotation::ROTATE_0) { for (int i = 0; i < 4; i++) { // backwards notation, should fix that... coord[i].pos = coord[i].pos * g_display_rot_matrix; 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/DrawEngineGLES.h b/GPU/GLES/DrawEngineGLES.h index 5554fe21e8..c016771e64 100644 --- a/GPU/GLES/DrawEngineGLES.h +++ b/GPU/GLES/DrawEngineGLES.h @@ -40,16 +40,6 @@ struct TransformedVertex; struct DecVtxFormat; -enum { - TEX_SLOT_PSP_TEXTURE = 0, - TEX_SLOT_SHADERBLEND_SRC = 1, - TEX_SLOT_ALPHATEST = 2, - TEX_SLOT_CLUT = 3, - TEX_SLOT_SPLINE_POINTS = 4, - TEX_SLOT_SPLINE_WEIGHTS_U = 5, - TEX_SLOT_SPLINE_WEIGHTS_V = 6, -}; - class TessellationDataTransferGLES : public TessellationDataTransfer { private: GLRTexture *data_tex[3]{}; 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..94b06155e0 100644 --- a/GPU/GLES/FramebufferManagerGLES.h +++ b/GPU/GLES/FramebufferManagerGLES.h @@ -50,8 +50,6 @@ public: void DeviceLost() override; void DeviceRestore(Draw::DrawContext *draw) override; - bool NotifyStencilUpload(u32 addr, int size, StencilUpload flags = StencilUpload::NEEDS_CLEAR) override; - bool GetOutputFramebuffer(GPUDebugBuffer &buffer) override; protected: @@ -76,10 +74,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/GPUCommon.cpp b/GPU/GPUCommon.cpp index 9fc627fc75..03ab2629e8 100644 --- a/GPU/GPUCommon.cpp +++ b/GPU/GPUCommon.cpp @@ -2933,7 +2933,7 @@ void GPUCommon::NotifyVideoUpload(u32 addr, int size, int width, int format) { bool GPUCommon::PerformStencilUpload(u32 dest, int size) { if (framebufferManager_->MayIntersectFramebuffer(dest)) { - framebufferManager_->NotifyStencilUpload(dest, size); + framebufferManager_->PerformStencilUpload(dest, size); return true; } return false; 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/UWP/GPU_UWP/GPU_UWP.vcxproj b/UWP/GPU_UWP/GPU_UWP.vcxproj index 0d09bebc50..81ab4c82a0 100644 --- a/UWP/GPU_UWP/GPU_UWP.vcxproj +++ b/UWP/GPU_UWP/GPU_UWP.vcxproj @@ -470,7 +470,6 @@ - diff --git a/UWP/GPU_UWP/GPU_UWP.vcxproj.filters b/UWP/GPU_UWP/GPU_UWP.vcxproj.filters index 84ab7ec547..f1f1de951b 100644 --- a/UWP/GPU_UWP/GPU_UWP.vcxproj.filters +++ b/UWP/GPU_UWP/GPU_UWP.vcxproj.filters @@ -30,7 +30,6 @@ - diff --git a/android/jni/Android.mk b/android/jni/Android.mk index ae109b91d1..b2e4e6fe37 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -133,7 +133,6 @@ VULKAN_FILES := \ $(SRC)/GPU/Vulkan/PipelineManagerVulkan.cpp \ $(SRC)/GPU/Vulkan/ShaderManagerVulkan.cpp \ $(SRC)/GPU/Vulkan/StateMappingVulkan.cpp \ - $(SRC)/GPU/Vulkan/StencilBufferVulkan.cpp \ $(SRC)/GPU/Vulkan/TextureCacheVulkan.cpp \ $(SRC)/GPU/Vulkan/DepalettizeShaderVulkan.cpp \ $(SRC)/GPU/Vulkan/VulkanUtil.cpp \ @@ -351,7 +350,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 diff --git a/unittest/TestShaderGenerators.cpp b/unittest/TestShaderGenerators.cpp index ef4116cfaf..8583a18c60 100644 --- a/unittest/TestShaderGenerators.cpp +++ b/unittest/TestShaderGenerators.cpp @@ -13,6 +13,7 @@ #include "GPU/Common/FragmentShaderGenerator.h" #include "GPU/Common/VertexShaderGenerator.h" #include "GPU/Common/ReinterpretFramebuffer.h" +#include "GPU/Common/StencilCommon.h" #if PPSSPP_PLATFORM(WINDOWS) #include "GPU/D3D11/D3D11Util.h" @@ -89,18 +90,18 @@ bool GenerateVShader(VShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs } } -bool TestCompileShader(const char *buffer, ShaderLanguage lang, bool vertex, std::string *errorMessage) { +bool TestCompileShader(const char *buffer, ShaderLanguage lang, ShaderStage stage, std::string *errorMessage) { std::vector spirv; switch (lang) { #if PPSSPP_PLATFORM(WINDOWS) case ShaderLanguage::HLSL_D3D11: { - auto output = CompileShaderToBytecodeD3D11(buffer, strlen(buffer), vertex ? "vs_4_0" : "ps_4_0", 0); + auto output = CompileShaderToBytecodeD3D11(buffer, strlen(buffer), stage == ShaderStage::Vertex ? "vs_4_0" : "ps_4_0", 0); return !output.empty(); } case ShaderLanguage::HLSL_D3D9: { - LPD3DBLOB blob = CompileShaderToByteCodeD3D9(buffer, vertex ? "vs_2_0" : "ps_2_0", errorMessage); + LPD3DBLOB blob = CompileShaderToByteCodeD3D9(buffer, stage == ShaderStage::Vertex ? "vs_2_0" : "ps_2_0", errorMessage); if (blob) { blob->Release(); return true; @@ -111,11 +112,11 @@ bool TestCompileShader(const char *buffer, ShaderLanguage lang, bool vertex, std #endif case ShaderLanguage::GLSL_VULKAN: - return GLSLtoSPV(vertex ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, buffer, GLSLVariant::VULKAN, spirv, errorMessage); + return GLSLtoSPV(stage == ShaderStage::Vertex ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, buffer, GLSLVariant::VULKAN, spirv, errorMessage); case ShaderLanguage::GLSL_1xx: - return GLSLtoSPV(vertex ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, buffer, GLSLVariant::GL140, spirv, errorMessage); + return GLSLtoSPV(stage == ShaderStage::Vertex ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, buffer, GLSLVariant::GL140, spirv, errorMessage); case ShaderLanguage::GLSL_3xx: - return GLSLtoSPV(vertex ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, buffer, GLSLVariant::GLES300, spirv, errorMessage); + return GLSLtoSPV(stage == ShaderStage::Vertex ? VK_SHADER_STAGE_VERTEX_BIT : VK_SHADER_STAGE_FRAGMENT_BIT, buffer, GLSLVariant::GLES300, spirv, errorMessage); default: return false; } @@ -159,6 +160,8 @@ const char *ShaderLanguageToString(ShaderLanguage lang) { } bool TestReinterpretShaders() { + Draw::Bugs bugs; + ShaderLanguage languages[] = { #if PPSSPP_PLATFORM(WINDOWS) ShaderLanguage::HLSL_D3D11, @@ -183,7 +186,7 @@ bool TestReinterpretShaders() { failed = true; } else { std::string errorMessage; - if (!TestCompileShader(buffer, languages[k], true, &errorMessage)) { + if (!TestCompileShader(buffer, languages[k], ShaderStage::Vertex, &errorMessage)) { printf("Error compiling fragment shader:\n\n%s\n\n%s\n", LineNumberString(buffer).c_str(), errorMessage.c_str()); failed = true; return false; @@ -197,6 +200,7 @@ bool TestReinterpretShaders() { printf("=== %s ===\n\n", ShaderLanguageToString(languages[k])); ShaderLanguageDesc desc(languages[k]); + std::string errorMessage; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { @@ -206,8 +210,7 @@ bool TestReinterpretShaders() { printf("Failed!\n%s\n", buffer); failed = true; } else { - std::string errorMessage; - if (!TestCompileShader(buffer, languages[k], false, &errorMessage)) { + if (!TestCompileShader(buffer, languages[k], ShaderStage::Fragment, &errorMessage)) { printf("Error compiling fragment shader %d:\n\n%s\n\n%s\n", (int)j, LineNumberString(buffer).c_str(), errorMessage.c_str()); failed = true; return false; @@ -217,8 +220,55 @@ bool TestReinterpretShaders() { } } } - } + + delete[] buffer; + return !failed; +} + +bool TestStencilShaders() { + Draw::Bugs bugs; + + ShaderLanguage languages[] = { +#if PPSSPP_PLATFORM(WINDOWS) + ShaderLanguage::HLSL_D3D9, + ShaderLanguage::HLSL_D3D11, +#endif + ShaderLanguage::GLSL_VULKAN, + ShaderLanguage::GLSL_3xx, + }; + + char *buffer = new char[65536]; + + bool failed = false; + + for (int k = 0; k < ARRAY_SIZE(languages); k++) { + printf("=== %s ===\n\n", ShaderLanguageToString(languages[k])); + + ShaderLanguageDesc desc(languages[k]); + std::string errorMessage; + + // Generate all despite failures - it's only 6. + GenerateStencilFs(buffer, desc, bugs); + if (!TestCompileShader(buffer, languages[k], ShaderStage::Fragment, &errorMessage)) { + printf("Error compiling stencil shader:\n\n%s\n\n%s\n", LineNumberString(buffer).c_str(), errorMessage.c_str()); + failed = true; + return false; + } else { + printf("===\n%s\n===\n", buffer); + } + + GenerateStencilVs(buffer, desc); + if (!TestCompileShader(buffer, languages[k], ShaderStage::Vertex, &errorMessage)) { + printf("Error compiling stencil shader:\n\n%s\n\n%s\n", LineNumberString(buffer).c_str(), errorMessage.c_str()); + failed = true; + return false; + } else { + printf("===\n%s\n===\n", buffer); + } + } + + delete[] buffer; return !failed; } @@ -281,7 +331,7 @@ bool TestVertexShaders() { for (int j = 0; j < numLanguages; j++) { if (generateSuccess[j]) { std::string errorMessage; - if (!TestCompileShader(buffer[j], languages[j], true, &errorMessage)) { + if (!TestCompileShader(buffer[j], languages[j], ShaderStage::Vertex, &errorMessage)) { printf("Error compiling vertex shader %d:\n\n%s\n\n%s\n", (int)j, LineNumberString(buffer[j]).c_str(), errorMessage.c_str()); return false; } @@ -343,7 +393,7 @@ bool TestFragmentShaders() { for (int j = 0; j < numLanguages; j++) { if (generateSuccess[j]) { std::string errorMessage; - if (!TestCompileShader(buffer[j], languages[j], false, &errorMessage)) { + if (!TestCompileShader(buffer[j], languages[j], ShaderStage::Fragment, &errorMessage)) { printf("Error compiling fragment shader:\n\n%s\n\n%s\n", LineNumberString(buffer[j]).c_str(), errorMessage.c_str()); return false; } @@ -369,7 +419,7 @@ bool TestShaderGenerators() { init_glslang(); #endif - if (!TestFragmentShaders()) { + if (!TestStencilShaders()) { return false; } @@ -377,6 +427,10 @@ bool TestShaderGenerators() { return false; } + if (!TestFragmentShaders()) { + return false; + } + if (!TestVertexShaders()) { return false; }