From 131098c4d46289e7b7192031dbdc3993cc04fe25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 8 Aug 2022 11:24:35 +0200 Subject: [PATCH 1/3] Some enum renaming, move RasterChannel to GPU.h. --- GPU/Common/FramebufferManagerCommon.cpp | 6 ++-- GPU/Common/GPUStateUtils.cpp | 2 +- GPU/Common/ShaderId.cpp | 2 +- GPU/Common/TextureCacheCommon.cpp | 38 ++++++++++++------------- GPU/Common/TextureCacheCommon.h | 12 +++----- GPU/D3D11/StateMappingD3D11.cpp | 2 +- GPU/Directx9/StateMappingDX9.cpp | 2 +- GPU/GLES/StateMappingGLES.cpp | 2 +- GPU/GPU.h | 14 +++++++-- GPU/GPUState.h | 4 +-- GPU/Vulkan/StateMappingVulkan.cpp | 2 +- 11 files changed, 45 insertions(+), 41 deletions(-) diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 505006eff9..7d5077b298 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -283,7 +283,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame WARN_LOG_ONCE(color_equal_z, G3D, "Framebuffer bound with color addr == z addr, likely will not use Z in this pass: %08x", params.fb_address); } - FramebufferRenderMode mode = FB_MODE_NORMAL; + RasterMode mode = RASTER_MODE_NORMAL; // Find a matching framebuffer VirtualFramebuffer *vfb = nullptr; @@ -331,7 +331,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame // Seems impractical to use the other 16-bit formats for this due to the limited control over alpha, // so we'll simply only support 565. if (params.fmt == GE_FORMAT_565) { - mode = FB_MODE_COLOR_TO_DEPTH; + mode = RASTER_MODE_COLOR_TO_DEPTH; break; } } else if (v->fb_stride == params.fb_stride && v->format == params.fmt) { @@ -368,7 +368,7 @@ VirtualFramebuffer *FramebufferManagerCommon::DoSetRenderFrameBuffer(const Frame } } - if (mode == FB_MODE_COLOR_TO_DEPTH) { + if (mode == RASTER_MODE_COLOR_TO_DEPTH) { // Lookup in the depth tracking to find which VFB has the latest version of this Z buffer. // Then bind it in color-to-depth mode. // diff --git a/GPU/Common/GPUStateUtils.cpp b/GPU/Common/GPUStateUtils.cpp index 03b957f803..ddfecff444 100644 --- a/GPU/Common/GPUStateUtils.cpp +++ b/GPU/Common/GPUStateUtils.cpp @@ -1018,7 +1018,7 @@ void ConvertMaskState(GenericMaskState &maskState, bool allowFramebufferRead) { return; } - if (gstate_c.renderMode == FB_MODE_COLOR_TO_DEPTH) { + if (gstate_c.renderMode == RASTER_MODE_COLOR_TO_DEPTH) { // Suppress color writes entirely in this mode. maskState.applyFramebufferRead = false; maskState.rgba[0] = false; diff --git a/GPU/Common/ShaderId.cpp b/GPU/Common/ShaderId.cpp index 5a4b2ac30b..1176200799 100644 --- a/GPU/Common/ShaderId.cpp +++ b/GPU/Common/ShaderId.cpp @@ -264,7 +264,7 @@ void ComputeFragmentShaderID(FShaderID *id_out, const Draw::Bugs &bugs) { bool doFlatShading = gstate.getShadeMode() == GE_SHADE_FLAT; bool useShaderDepal = gstate_c.useShaderDepal; bool colorWriteMask = IsColorWriteMaskComplex(gstate_c.allowFramebufferRead); - bool colorToDepth = gstate_c.renderMode == FramebufferRenderMode::FB_MODE_COLOR_TO_DEPTH; + bool colorToDepth = gstate_c.renderMode == RasterMode::RASTER_MODE_COLOR_TO_DEPTH; // Note how we here recompute some of the work already done in state mapping. // Not ideal! At least we share the code. diff --git a/GPU/Common/TextureCacheCommon.cpp b/GPU/Common/TextureCacheCommon.cpp index fa1abdcf49..6049b4e787 100644 --- a/GPU/Common/TextureCacheCommon.cpp +++ b/GPU/Common/TextureCacheCommon.cpp @@ -265,7 +265,7 @@ SamplerCacheKey TextureCacheCommon::GetSamplingParams(int maxLevel, const TexCac } } - if (gstate_c.renderMode == FB_MODE_COLOR_TO_DEPTH) { + if (gstate_c.renderMode == RASTER_MODE_COLOR_TO_DEPTH) { forceFiltering = TEX_FILTER_FORCE_NEAREST; } @@ -625,8 +625,8 @@ std::vector TextureCacheCommon::GetFramebufferCandidates(const std::vector candidates; - FramebufferNotificationChannel channel = Memory::IsDepthTexVRAMAddress(entry.addr) ? FramebufferNotificationChannel::NOTIFY_FB_DEPTH : FramebufferNotificationChannel::NOTIFY_FB_COLOR; - if (channel == FramebufferNotificationChannel::NOTIFY_FB_DEPTH && !gstate_c.Supports(GPU_SUPPORTS_DEPTH_TEXTURE)) { + RasterChannel channel = Memory::IsDepthTexVRAMAddress(entry.addr) ? RasterChannel::RASTER_DEPTH : RasterChannel::RASTER_COLOR; + if (channel == RasterChannel::RASTER_DEPTH && !gstate_c.Supports(GPU_SUPPORTS_DEPTH_TEXTURE)) { // Depth texture not supported. Don't try to match it, fall back to the memory behind.. return std::vector(); } @@ -645,7 +645,7 @@ std::vector TextureCacheCommon::GetFramebufferCandidates(const } if (candidates.size() > 1) { - bool depth = channel == FramebufferNotificationChannel::NOTIFY_FB_DEPTH; + bool depth = channel == RasterChannel::RASTER_DEPTH; std::string cands; for (auto &candidate : candidates) { @@ -687,7 +687,7 @@ int TextureCacheCommon::GetBestCandidateIndex(const std::vector } // Bonus point for matching stride. - if (candidate.channel == NOTIFY_FB_COLOR && candidate.fb->fb_stride == candidate.entry.bufw) { + if (candidate.channel == RASTER_COLOR && candidate.fb->fb_stride == candidate.entry.bufw) { relevancy += 100; } @@ -696,9 +696,9 @@ int TextureCacheCommon::GetBestCandidateIndex(const std::vector relevancy += 10; } - if (candidate.channel == NOTIFY_FB_COLOR && candidate.fb->last_frame_render == gpuStats.numFlips) { + if (candidate.channel == RASTER_COLOR && candidate.fb->last_frame_render == gpuStats.numFlips) { relevancy += 5; - } else if (candidate.channel == NOTIFY_FB_DEPTH && candidate.fb->last_frame_depth_render == gpuStats.numFlips) { + } else if (candidate.channel == RASTER_DEPTH && candidate.fb->last_frame_depth_render == gpuStats.numFlips) { relevancy += 5; } @@ -878,10 +878,10 @@ void TextureCacheCommon::NotifyFramebuffer(VirtualFramebuffer *framebuffer, Fram FramebufferMatchInfo TextureCacheCommon::MatchFramebuffer( const TextureDefinition &entry, - VirtualFramebuffer *framebuffer, u32 texaddrOffset, FramebufferNotificationChannel channel) const { + VirtualFramebuffer *framebuffer, u32 texaddrOffset, RasterChannel channel) const { static const u32 MAX_SUBAREA_Y_OFFSET_SAFE = 32; - uint32_t fb_address = channel == NOTIFY_FB_DEPTH ? framebuffer->z_address : framebuffer->fb_address; + uint32_t fb_address = channel == RASTER_DEPTH ? framebuffer->z_address : framebuffer->fb_address; u32 addr = fb_address & 0x3FFFFFFF; u32 texaddr = entry.addr + texaddrOffset; @@ -906,14 +906,14 @@ FramebufferMatchInfo TextureCacheCommon::MatchFramebuffer( case 0x00000000: case 0x00400000: // Don't match the depth channel with these addresses when texturing. - if (channel == FramebufferNotificationChannel::NOTIFY_FB_DEPTH) { + if (channel == RasterChannel::RASTER_DEPTH) { return FramebufferMatchInfo{ FramebufferMatch::NO_MATCH }; } break; case 0x00200000: case 0x00600000: // Don't match the color channel with these addresses when texturing. - if (channel == FramebufferNotificationChannel::NOTIFY_FB_COLOR) { + if (channel == RasterChannel::RASTER_COLOR) { return FramebufferMatchInfo{ FramebufferMatch::NO_MATCH }; } break; @@ -924,7 +924,7 @@ FramebufferMatchInfo TextureCacheCommon::MatchFramebuffer( } const bool noOffset = texaddr == addr; - const bool exactMatch = noOffset && entry.format < 4 && channel == NOTIFY_FB_COLOR; + const bool exactMatch = noOffset && entry.format < 4 && channel == RASTER_COLOR; const u32 w = 1 << ((entry.dim >> 0) & 0xf); const u32 h = 1 << ((entry.dim >> 8) & 0xf); // 512 on a 272 framebuffer is sane, so let's be lenient. @@ -958,9 +958,9 @@ FramebufferMatchInfo TextureCacheCommon::MatchFramebuffer( // Check works for D16 too (???) const bool matchingClutFormat = - (channel != NOTIFY_FB_COLOR && entry.format == GE_TFMT_CLUT16) || - (channel == NOTIFY_FB_COLOR && framebuffer->format == GE_FORMAT_8888 && entry.format == GE_TFMT_CLUT32) || - (channel == NOTIFY_FB_COLOR && framebuffer->format != GE_FORMAT_8888 && entry.format == GE_TFMT_CLUT16); + (channel != RASTER_COLOR && entry.format == GE_TFMT_CLUT16) || + (channel == RASTER_COLOR && framebuffer->format == GE_FORMAT_8888 && entry.format == GE_TFMT_CLUT32) || + (channel == RASTER_COLOR && framebuffer->format != GE_FORMAT_8888 && entry.format == GE_TFMT_CLUT16); // To avoid ruining git blame, kept the same name as the old struct. FramebufferMatchInfo fbInfo{ FramebufferMatch::VALID }; @@ -1782,7 +1782,7 @@ void TextureCacheCommon::ApplyTexture() { if (nextFramebufferTexture_) { bool depth = Memory::IsDepthTexVRAMAddress(gstate.getTextureAddress(0)); // ApplyTextureFrameBuffer is responsible for setting SetTextureFullAlpha. - ApplyTextureFramebuffer(nextFramebufferTexture_, gstate.getTextureFormat(), depth ? NOTIFY_FB_DEPTH : NOTIFY_FB_COLOR); + ApplyTextureFramebuffer(nextFramebufferTexture_, gstate.getTextureFormat(), depth ? RASTER_DEPTH : RASTER_COLOR); nextFramebufferTexture_ = nullptr; } @@ -1845,12 +1845,12 @@ void TextureCacheCommon::ApplyTexture() { gstate_c.SetTextureIs3D((entry->status & TexCacheEntry::STATUS_3D) != 0); } -void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer, GETextureFormat texFormat, FramebufferNotificationChannel channel) { +void TextureCacheCommon::ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer, GETextureFormat texFormat, RasterChannel channel) { DepalShader *depalShader = nullptr; uint32_t clutMode = gstate.clutformat & 0xFFFFFF; bool need_depalettize = IsClutFormat(texFormat); - bool depth = channel == NOTIFY_FB_DEPTH; + bool depth = channel == RASTER_DEPTH; bool useShaderDepal = framebufferManager_->GetCurrentRenderVFB() != framebuffer && !depth && !gstate_c.curTextureIs3D; // TODO: Implement shader depal in the fragment shader generator for D3D11 at least. @@ -2262,7 +2262,7 @@ bool TextureCacheCommon::PrepareBuildTexture(BuildTexturePlan &plan, TexCacheEnt } // Don't upscale textures in color-to-depth mode. - if (gstate_c.renderMode == FB_MODE_COLOR_TO_DEPTH) { + if (gstate_c.renderMode == RASTER_MODE_COLOR_TO_DEPTH) { plan.scaleFactor = 1; } diff --git a/GPU/Common/TextureCacheCommon.h b/GPU/Common/TextureCacheCommon.h index 4280848a02..3095efc466 100644 --- a/GPU/Common/TextureCacheCommon.h +++ b/GPU/Common/TextureCacheCommon.h @@ -25,6 +25,7 @@ #include "Common/MemoryUtil.h" #include "Core/TextureReplacer.h" #include "Core/System.h" +#include "GPU/GPU.h" #include "GPU/Common/GPUDebugInterface.h" #include "GPU/Common/TextureDecoder.h" #include "GPU/Common/TextureScalerCommon.h" @@ -36,11 +37,6 @@ enum FramebufferNotification { NOTIFY_FB_DESTROYED, }; -enum FramebufferNotificationChannel { - NOTIFY_FB_COLOR = 0, - NOTIFY_FB_DEPTH = 1, -}; - // Changes more frequent than this will be considered "frequent" and prevent texture scaling. #define TEXCACHE_FRAME_CHANGE_FREQUENT 6 // Note: only used when hash backoff is disabled. @@ -229,7 +225,7 @@ struct AttachCandidate { FramebufferMatchInfo match; TextureDefinition entry; VirtualFramebuffer *fb; - FramebufferNotificationChannel channel; + RasterChannel channel; std::string ToString(); }; @@ -336,7 +332,7 @@ protected: void DeleteTexture(TexCache::iterator it); void Decimate(bool forcePressure = false); - void ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer, GETextureFormat texFormat, FramebufferNotificationChannel channel); + void ApplyTextureFramebuffer(VirtualFramebuffer *framebuffer, GETextureFormat texFormat, RasterChannel channel); void HandleTextureChange(TexCacheEntry *const entry, const char *reason, bool initialMatch, bool doDelete); virtual void BuildTexture(TexCacheEntry *const entry) = 0; @@ -369,7 +365,7 @@ protected: SamplerCacheKey GetFramebufferSamplingParams(u16 bufferWidth, u16 bufferHeight); void UpdateMaxSeenV(TexCacheEntry *entry, bool throughMode); - FramebufferMatchInfo MatchFramebuffer(const TextureDefinition &entry, VirtualFramebuffer *framebuffer, u32 texaddrOffset, FramebufferNotificationChannel channel) const; + FramebufferMatchInfo MatchFramebuffer(const TextureDefinition &entry, VirtualFramebuffer *framebuffer, u32 texaddrOffset, RasterChannel channel) const; std::vector GetFramebufferCandidates(const TextureDefinition &entry, u32 texAddrOffset); int GetBestCandidateIndex(const std::vector &candidates); diff --git a/GPU/D3D11/StateMappingD3D11.cpp b/GPU/D3D11/StateMappingD3D11.cpp index 843da3d4e7..79a169a8ab 100644 --- a/GPU/D3D11/StateMappingD3D11.cpp +++ b/GPU/D3D11/StateMappingD3D11.cpp @@ -293,7 +293,7 @@ void DrawEngineD3D11::ApplyDrawState(int prim) { GenericStencilFuncState stencilState; ConvertStencilFuncState(stencilState); - if (gstate_c.renderMode == FB_MODE_COLOR_TO_DEPTH) { + if (gstate_c.renderMode == RASTER_MODE_COLOR_TO_DEPTH) { // Enforce plain depth writing. keys_.depthStencil.value = 0; keys_.depthStencil.depthTestEnable = true; diff --git a/GPU/Directx9/StateMappingDX9.cpp b/GPU/Directx9/StateMappingDX9.cpp index 47dfe6e86f..018d3253ed 100644 --- a/GPU/Directx9/StateMappingDX9.cpp +++ b/GPU/Directx9/StateMappingDX9.cpp @@ -214,7 +214,7 @@ void DrawEngineDX9::ApplyDrawState(int prim) { // Set Stencil/Depth - if (gstate_c.renderMode == FB_MODE_COLOR_TO_DEPTH) { + if (gstate_c.renderMode == RASTER_MODE_COLOR_TO_DEPTH) { // Enforce plain depth writing. dxstate.depthTest.enable(); dxstate.depthFunc.set(D3DCMP_ALWAYS); diff --git a/GPU/GLES/StateMappingGLES.cpp b/GPU/GLES/StateMappingGLES.cpp index 55af56b039..54c94ccbd3 100644 --- a/GPU/GLES/StateMappingGLES.cpp +++ b/GPU/GLES/StateMappingGLES.cpp @@ -251,7 +251,7 @@ void DrawEngineGLES::ApplyDrawState(int prim) { GenericStencilFuncState stencilState; ConvertStencilFuncState(stencilState); - if (gstate_c.renderMode == FB_MODE_COLOR_TO_DEPTH) { + if (gstate_c.renderMode == RASTER_MODE_COLOR_TO_DEPTH) { // Enforce plain depth writing. renderManager->SetStencilDisabled(); renderManager->SetDepth(true, true, GL_ALWAYS); diff --git a/GPU/GPU.h b/GPU/GPU.h index 55ae857ab3..ecb9ae33c4 100644 --- a/GPU/GPU.h +++ b/GPU/GPU.h @@ -24,9 +24,17 @@ class GPUInterface; class GPUDebugInterface; class GraphicsContext; -enum FramebufferRenderMode { - FB_MODE_NORMAL = 0, - FB_MODE_COLOR_TO_DEPTH = 1, +enum RasterMode { + RASTER_MODE_NORMAL = 0, + RASTER_MODE_COLOR_TO_DEPTH = 1, +}; + +// PSP rasterization has two outputs, color and depth. Stencil is packed +// into the alpha channel of color (if exists), so possibly RASTER_COLOR +// should be named RASTER_COLOR_STENCIL but it gets kinda hard to read. +enum RasterChannel { + RASTER_COLOR = 0, + RASTER_DEPTH = 1, }; enum SkipDrawReasonFlags { diff --git a/GPU/GPUState.h b/GPU/GPUState.h index d81ae86235..8d6d04039b 100644 --- a/GPU/GPUState.h +++ b/GPU/GPUState.h @@ -555,7 +555,7 @@ struct GPUStateCache { Dirty(DIRTY_FRAGMENTSHADER_STATE | (is3D ? DIRTY_MIPBIAS : 0)); } } - void SetFramebufferRenderMode(FramebufferRenderMode mode) { + void SetFramebufferRenderMode(RasterMode mode) { if (mode != renderMode) { // This mode modifies the fragment shader to write depth, the depth state to write without testing, and the blend state to write nothing to color. // So we need to re-evaluate those states. @@ -614,7 +614,7 @@ struct GPUStateCache { bool blueToAlpha; // Some games try to write to the Z buffer using color. Catch that and actually do the writes to the Z buffer instead. - FramebufferRenderMode renderMode; + RasterMode renderMode; // TODO: These should be accessed from the current VFB object directly. u32 curRTWidth; diff --git a/GPU/Vulkan/StateMappingVulkan.cpp b/GPU/Vulkan/StateMappingVulkan.cpp index b9560c9f47..6aa176c864 100644 --- a/GPU/Vulkan/StateMappingVulkan.cpp +++ b/GPU/Vulkan/StateMappingVulkan.cpp @@ -250,7 +250,7 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag GenericStencilFuncState stencilState; ConvertStencilFuncState(stencilState); - if (gstate_c.renderMode == FB_MODE_COLOR_TO_DEPTH) { + if (gstate_c.renderMode == RASTER_MODE_COLOR_TO_DEPTH) { // Enforce plain depth writing. key.depthTestEnable = true; key.depthWriteEnable = true; From 252550fbd2d4c425bcab058cdc876ff0fd60056b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 7 Aug 2022 13:19:27 +0200 Subject: [PATCH 2/3] Enable framebuffer depth blits through raster. Fixes games like Jeanne D'Arc on D3D9. --- Common/GPU/ShaderWriter.cpp | 45 ++++++++++++++++--- Common/GPU/ShaderWriter.h | 9 +++- GPU/Common/DepalettizeShaderCommon.cpp | 4 +- GPU/Common/Draw2D.cpp | 55 +++++++++++++++++------ GPU/Common/FramebufferManagerCommon.cpp | 58 +++++++++++++++++-------- GPU/Common/FramebufferManagerCommon.h | 10 +++-- GPU/Common/ReinterpretFramebuffer.cpp | 4 +- GPU/Common/StencilCommon.cpp | 4 +- 8 files changed, 140 insertions(+), 49 deletions(-) diff --git a/Common/GPU/ShaderWriter.cpp b/Common/GPU/ShaderWriter.cpp index 1671d5d6a5..d57a855ac7 100644 --- a/Common/GPU/ShaderWriter.cpp +++ b/Common/GPU/ShaderWriter.cpp @@ -212,7 +212,7 @@ void ShaderWriter::BeginVSMain(Slice inputs, Slice uniform } } -void ShaderWriter::BeginFSMain(Slice uniforms, Slice varyings) { +void ShaderWriter::BeginFSMain(Slice uniforms, Slice varyings, FSFlags flags) { _assert_(this->stage_ == ShaderStage::Fragment); switch (lang_.shaderLanguage) { case HLSL_D3D11: @@ -226,29 +226,56 @@ void ShaderWriter::BeginFSMain(Slice uniforms, Slice var C("};\n"); } + if (flags & FSFLAG_WRITEDEPTH) { + C("float gl_FragDepth;\n"); + } + + C("struct PS_OUT {\n"); + C(" vec4 target : SV_Target0;\n"); + if (flags & FSFLAG_WRITEDEPTH) { + C(" float depth : SV_Depth;\n"); + } + C("};\n"); + // Let's do the varyings as parameters to main, no struct. - C("vec4 main("); + C("PS_OUT main("); for (auto &varying : varyings) { F(" %s %s : %s, ", varying.type, varying.name, semanticNames[varying.semantic]); } // Erase the last comma Rewind(2); - F(") : SV_Target0 {\n"); + F(") {\n"); + C(" PS_OUT ps_out;\n"); + if (flags & FSFLAG_WRITEDEPTH) { + C(" float gl_FragDepth;\n"); + } break; case HLSL_D3D9: + C("struct PS_OUT {\n"); + C(" vec4 target : SV_Target0;\n"); + if (flags & FSFLAG_WRITEDEPTH) { + C(" float depth : DEPTH;\n"); + } + C("};\n"); + for (auto &uniform : uniforms) { F(" %s %s : register(c%d);\n", uniform.type, uniform.name, uniform.index); } // Let's do the varyings as parameters to main, no struct. - C("vec4 main("); + C("PS_OUT main("); for (auto &varying : varyings) { F(" %s %s : %s, ", varying.type, varying.name, semanticNames[varying.semantic]); } // Erase the last comma Rewind(2); - F(") : COLOR {\n"); + F(") {\n"); + C(" PS_OUT ps_out;\n"); + if (flags & FSFLAG_WRITEDEPTH) { + C(" float gl_FragDepth;\n"); + } + break; case GLSL_VULKAN: for (auto &varying : varyings) { @@ -299,12 +326,16 @@ void ShaderWriter::EndVSMain(Slice varyings) { C("}\n"); } -void ShaderWriter::EndFSMain(const char *vec4_color_variable) { +void ShaderWriter::EndFSMain(const char *vec4_color_variable, FSFlags flags) { _assert_(this->stage_ == ShaderStage::Fragment); switch (lang_.shaderLanguage) { case HLSL_D3D11: case HLSL_D3D9: - F(" return %s;\n", vec4_color_variable); + F(" ps_out.target = %s;\n", vec4_color_variable); + if (flags & FSFLAG_WRITEDEPTH) { + C(" ps_out.depth = gl_FragDepth;\n"); + } + C(" return ps_out;\n"); break; case GLSL_VULKAN: default: // OpenGL diff --git a/Common/GPU/ShaderWriter.h b/Common/GPU/ShaderWriter.h index 0624a8aca9..9d16f2bf9a 100644 --- a/Common/GPU/ShaderWriter.h +++ b/Common/GPU/ShaderWriter.h @@ -36,6 +36,11 @@ struct VaryingDef { const char *precision; }; +enum FSFlags { + FSFLAG_NONE = 0, + FSFLAG_WRITEDEPTH = 1, +}; + class ShaderWriter { public: ShaderWriter(char *buffer, const ShaderLanguageDesc &lang, ShaderStage stage, const char **gl_extensions, size_t num_gl_extensions) : p_(buffer), lang_(lang), stage_(stage) { @@ -82,11 +87,11 @@ public: // Simple shaders with no special tricks. void BeginVSMain(Slice inputs, Slice uniforms, Slice varyings); - void BeginFSMain(Slice uniforms, Slice varyings); + void BeginFSMain(Slice uniforms, Slice varyings, FSFlags flags); // For simple shaders that output a single color, we can deal with this generically. void EndVSMain(Slice varyings); - void EndFSMain(const char *vec4_color_variable); + void EndFSMain(const char *vec4_color_variable, FSFlags flags); void Rewind(size_t offset) { diff --git a/GPU/Common/DepalettizeShaderCommon.cpp b/GPU/Common/DepalettizeShaderCommon.cpp index 45e6dba76e..c35cc0e41f 100644 --- a/GPU/Common/DepalettizeShaderCommon.cpp +++ b/GPU/Common/DepalettizeShaderCommon.cpp @@ -267,7 +267,7 @@ void GenerateDepalFs(char *buffer, const DepalConfig &config, const ShaderLangua ShaderWriter writer(buffer, lang, ShaderStage::Fragment, nullptr, 0); writer.DeclareSamplers(samplers); writer.HighPrecisionFloat(); - writer.BeginFSMain(Slice::empty(), varyings); + writer.BeginFSMain(Slice::empty(), varyings, FSFLAG_NONE); switch (lang.shaderLanguage) { case HLSL_D3D9: case GLSL_1xx: @@ -281,7 +281,7 @@ void GenerateDepalFs(char *buffer, const DepalConfig &config, const ShaderLangua default: _assert_msg_(false, "Depal shader language not supported: %d", (int)lang.shaderLanguage); } - writer.EndFSMain("outColor"); + writer.EndFSMain("outColor", FSFLAG_NONE); } void GenerateDepalVs(char *buffer, const ShaderLanguageDesc &lang) { diff --git a/GPU/Common/Draw2D.cpp b/GPU/Common/Draw2D.cpp index 9dedfd2782..1ea143bd8a 100644 --- a/GPU/Common/Draw2D.cpp +++ b/GPU/Common/Draw2D.cpp @@ -39,12 +39,21 @@ static const SamplerDef samplers[1] = { { "tex" }, }; -void GenerateDraw2DFs(char *buffer, const ShaderLanguageDesc &lang, const Draw::Bugs &bugs) { +void GenerateDraw2DFs(char *buffer, const ShaderLanguageDesc &lang) { ShaderWriter writer(buffer, lang, ShaderStage::Fragment, nullptr, 0); writer.DeclareSamplers(samplers); - writer.BeginFSMain(Slice::empty(), varyings); + writer.BeginFSMain(Slice::empty(), varyings, FSFLAG_NONE); writer.C(" vec4 outColor = ").SampleTexture2D("tex", "v_texcoord.xy").C(";\n"); - writer.EndFSMain("outColor"); + writer.EndFSMain("outColor", FSFLAG_NONE); +} + +void GenerateDraw2DDepthFs(char *buffer, const ShaderLanguageDesc &lang) { + ShaderWriter writer(buffer, lang, ShaderStage::Fragment, nullptr, 0); + writer.DeclareSamplers(samplers); + writer.BeginFSMain(Slice::empty(), varyings, FSFLAG_WRITEDEPTH); + writer.C(" vec4 outColor = vec4(0.0, 0.0, 0.0, 0.0);\n"); + writer.C(" gl_FragDepth = ").SampleTexture2D("tex", "v_texcoord.xy").C(".x;\n"); + writer.EndFSMain("outColor", FSFLAG_WRITEDEPTH); } void GenerateDraw2DVS(char *buffer, const ShaderLanguageDesc &lang) { @@ -60,21 +69,24 @@ void GenerateDraw2DVS(char *buffer, const ShaderLanguageDesc &lang) { } // verts have positions in clip coordinates. -void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter) { +void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter, RasterChannel channel) { using namespace Draw; - if (!draw2DPipelineLinear_) { + if (!draw2DPipelineColor_) { const ShaderLanguageDesc &shaderLanguageDesc = draw_->GetShaderLanguageDesc(); char *fsCode = new char[4000]; + char *fsDepthCode = new char[4000]; char *vsCode = new char[4000]; - GenerateDraw2DFs(fsCode, shaderLanguageDesc, draw_->GetBugs()); + GenerateDraw2DFs(fsCode, shaderLanguageDesc); + GenerateDraw2DDepthFs(fsDepthCode, shaderLanguageDesc); GenerateDraw2DVS(vsCode, shaderLanguageDesc); draw2DFs_ = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsCode, strlen(fsCode), "draw2d_fs"); + draw2DFsDepth_ = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsDepthCode, strlen(fsDepthCode), "draw2d_depth_fs"); draw2DVs_ = draw_->CreateShaderModule(ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage, (const uint8_t *)vsCode, strlen(vsCode), "draw2d_vs"); - _assert_(draw2DFs_ && draw2DVs_); + _assert_(draw2DFs_ && draw2DVs_ && draw2DFsDepth_); InputLayoutDesc desc = { { @@ -88,24 +100,41 @@ void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *ver InputLayout *inputLayout = draw_->CreateInputLayout(desc); BlendState *blendOff = draw_->CreateBlendState({ false, 0xF }); - DepthStencilStateDesc dsDesc{}; - DepthStencilState *noDepthStencil = draw_->CreateDepthStencilState(dsDesc); + BlendState *blendDiscard = draw_->CreateBlendState({ false, 0x0 }); + + DepthStencilState *noDepthStencil = draw_->CreateDepthStencilState(DepthStencilStateDesc{}); RasterState *rasterNoCull = draw_->CreateRasterState({}); - PipelineDesc stencilWriteDesc{ + DepthStencilStateDesc dsWriteDesc{}; + dsWriteDesc.depthTestEnabled = true; + dsWriteDesc.depthWriteEnabled = true; + dsWriteDesc.depthCompare = Draw::Comparison::ALWAYS; + DepthStencilState *depthWriteAlways = draw_->CreateDepthStencilState(dsWriteDesc); + + PipelineDesc draw2DColorPipelineDesc{ Primitive::TRIANGLE_STRIP, { draw2DVs_, draw2DFs_ }, inputLayout, noDepthStencil, blendOff, rasterNoCull, nullptr, }; - draw2DPipelineLinear_ = draw_->CreateGraphicsPipeline(stencilWriteDesc); - _assert_(draw2DPipelineLinear_); + + draw2DPipelineColor_ = draw_->CreateGraphicsPipeline(draw2DColorPipelineDesc); + + PipelineDesc draw2DDepthPipelineDesc{ + Primitive::TRIANGLE_STRIP, + { draw2DVs_, draw2DFsDepth_ }, + inputLayout, depthWriteAlways, blendDiscard, rasterNoCull, nullptr, + }; + draw2DPipelineDepth_ = draw_->CreateGraphicsPipeline(draw2DDepthPipelineDesc); + _assert_(draw2DPipelineDepth_); delete[] fsCode; delete[] vsCode; rasterNoCull->Release(); blendOff->Release(); + blendDiscard->Release(); noDepthStencil->Release(); + depthWriteAlways->Release(); inputLayout->Release(); SamplerStateDesc descLinear{}; @@ -125,7 +154,7 @@ void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *ver draw2DSamplerNearest_ = draw_->CreateSamplerState(descNearest); } - draw_->BindPipeline(draw2DPipelineLinear_); + draw_->BindPipeline(channel == RASTER_COLOR ? draw2DPipelineColor_ : draw2DPipelineDepth_); if (tex) { draw_->BindTextures(TEX_SLOT_PSP_TEXTURE, 1, &tex); } diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 7d5077b298..42603951c7 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -564,6 +564,8 @@ void FramebufferManagerCommon::DestroyFramebuf(VirtualFramebuffer *v) { void FramebufferManagerCommon::BlitFramebufferDepth(VirtualFramebuffer *src, VirtualFramebuffer *dst) { _dbg_assert_(src && dst); + _dbg_assert_(src != dst); + // Check that the depth address is even the same before actually blitting. bool matchingDepthBuffer = src->z_address == dst->z_address && src->z_stride != 0 && dst->z_stride != 0; bool matchingSize = (src->width == dst->width || (src->width == 512 && dst->width == 480) || (src->width == 480 && dst->width == 512)) && src->height == dst->height; @@ -579,7 +581,14 @@ void FramebufferManagerCommon::BlitFramebufferDepth(VirtualFramebuffer *src, Vir return; } - gpuStats.numDepthCopies++; + bool useCopy = draw_->GetDeviceCaps().framebufferSeparateDepthCopySupported || (!draw_->GetDeviceCaps().framebufferDepthBlitSupported && draw_->GetDeviceCaps().framebufferCopySupported); + bool useBlit = draw_->GetDeviceCaps().framebufferDepthBlitSupported; + + // Attempt at optimization - if destination already bound, draw depth using raster + if (true || currentRenderVfb_ == dst) { + useCopy = false; + useBlit = false; + } int w = std::min(src->renderWidth, dst->renderWidth); int h = std::min(src->renderHeight, dst->renderHeight); @@ -587,14 +596,20 @@ void FramebufferManagerCommon::BlitFramebufferDepth(VirtualFramebuffer *src, Vir // TODO: It might even be advantageous on some GPUs to do this copy using a fragment shader that writes to Z, that way upcoming commands can just continue that render pass. // Some GPUs can copy depth but only if stencil gets to come along for the ride. We only want to use this if there is no blit functionality. - if (draw_->GetDeviceCaps().framebufferSeparateDepthCopySupported || (!draw_->GetDeviceCaps().framebufferDepthBlitSupported && draw_->GetDeviceCaps().framebufferCopySupported)) { + if (useCopy) { draw_->CopyFramebufferImage(src->fbo, 0, 0, 0, 0, dst->fbo, 0, 0, 0, 0, w, h, 1, Draw::FB_DEPTH_BIT, "BlitFramebufferDepth"); RebindFramebuffer("After BlitFramebufferDepth"); - } else if (draw_->GetDeviceCaps().framebufferDepthBlitSupported) { + } else if (useBlit) { // We'll accept whether we get a separate depth blit or not... draw_->BlitFramebuffer(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, Draw::FB_DEPTH_BIT, Draw::FB_BLIT_NEAREST, "BlitFramebufferDepth"); RebindFramebuffer("After BlitFramebufferDepth"); + } else { + BlitUsingRaster(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, false, RasterChannel::RASTER_DEPTH); } + + draw_->InvalidateCachedState(); + + gpuStats.numDepthCopies++; dst->last_frame_depth_updated = gpuStats.numFlips; } @@ -2495,11 +2510,13 @@ void FramebufferManagerCommon::DeviceLost() { DoRelease(stencilUploadVs_); DoRelease(stencilUploadSampler_); DoRelease(stencilUploadPipeline_); - DoRelease(draw2DPipelineLinear_); + DoRelease(draw2DPipelineColor_); + DoRelease(draw2DPipelineDepth_); DoRelease(draw2DSamplerNearest_); DoRelease(draw2DSamplerLinear_); DoRelease(draw2DVs_); DoRelease(draw2DFs_); + DoRelease(draw2DFsDepth_); presentation_->DeviceLost(); draw_ = nullptr; } @@ -2557,15 +2574,18 @@ void FramebufferManagerCommon::DrawActiveTexture(float x, float y, float w, floa // Rearrange to strip form. std::swap(coord[2], coord[3]); - DrawStrip2D(nullptr, coord, 4, (flags & DRAWTEX_LINEAR) != 0); + DrawStrip2D(nullptr, coord, 4, (flags & DRAWTEX_LINEAR) != 0, RASTER_COLOR); 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); } void FramebufferManagerCommon::BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag) { + RasterChannel channel = RASTER_COLOR; + if (!dst->fbo || !src->fbo || !useBufferedRendering_) { // This can happen if they recently switched from non-buffered. if (useBufferedRendering_) { + // Just bind the back buffer for rendering, forget about doing anything else as we're in a weird state. draw_->BindFramebufferAsRenderTarget(nullptr, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitFramebuffer"); } return; @@ -2638,30 +2658,35 @@ void FramebufferManagerCommon::BlitFramebuffer(VirtualFramebuffer *dst, int dstX const bool xOverlap = src == dst && srcX2 > dstX1 && srcX1 < dstX2; const bool yOverlap = src == dst && srcY2 > dstY1 && srcY1 < dstY2; if (sameSize && srcInsideBounds && dstInsideBounds && !(xOverlap && yOverlap)) { - draw_->CopyFramebufferImage(src->fbo, 0, srcX1, srcY1, 0, dst->fbo, 0, dstX1, dstY1, 0, dstX2 - dstX1, dstY2 - dstY1, 1, Draw::FB_COLOR_BIT, tag); + draw_->CopyFramebufferImage(src->fbo, 0, srcX1, srcY1, 0, dst->fbo, 0, dstX1, dstY1, 0, dstX2 - dstX1, dstY2 - dstY1, 1, + channel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, tag); return; } } if (useBlit) { - draw_->BlitFramebuffer(src->fbo, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, Draw::FB_COLOR_BIT, Draw::FB_BLIT_NEAREST, tag); + draw_->BlitFramebuffer(src->fbo, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, + channel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, Draw::FB_BLIT_NEAREST, tag); } else { Draw::Framebuffer *srcFBO = src->fbo; if (src == dst) { Draw::Framebuffer *tempFBO = GetTempFBO(TempFBO::BLIT, src->renderWidth, src->renderHeight); - BlitUsingRaster(src->fbo, srcX1, srcY1, srcX2, srcY2, tempFBO, dstX1, dstY1, dstX2, dstY2, false); + BlitUsingRaster(src->fbo, srcX1, srcY1, srcX2, srcY2, tempFBO, dstX1, dstY1, dstX2, dstY2, false, channel); srcFBO = tempFBO; } - BlitUsingRaster(srcFBO, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, false); + BlitUsingRaster(srcFBO, srcX1, srcY1, srcX2, srcY2, dst->fbo, dstX1, dstY1, dstX2, dstY2, false, channel); } + draw_->InvalidateCachedState(); + gstate_c.Dirty(DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_BLEND_STATE | DIRTY_RASTER_STATE); } void FramebufferManagerCommon::BlitUsingRaster( Draw::Framebuffer *src, float srcX1, float srcY1, float srcX2, float srcY2, Draw::Framebuffer *dest, float destX1, float destY1, float destX2, float destY2, - bool linearFilter) { + bool linearFilter, + RasterChannel channel) { int destW, destH, srcW, srcH; draw_->GetFramebufferDimensions(src, &srcW, &srcH); @@ -2678,17 +2703,16 @@ void FramebufferManagerCommon::BlitUsingRaster( { -1.0f + 2.0f * dX * destX2, -(1.0f - 2.0f * dY * destY2), sX * srcX2, sY * srcY2 }, }; - if (dest != currentRenderVfb_->fbo) { - // Unbind the texture first to avoid the D3D11 hazard check (can't set render target to things bound as textures and vice versa, not even temporarily). - draw_->BindTexture(0, nullptr); - draw_->BindFramebufferAsRenderTarget(dest, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitUsingRaster"); - } - draw_->BindFramebufferAsTexture(src, 0, Draw::FB_COLOR_BIT, 0); + // Unbind the texture first to avoid the D3D11 hazard check (can't set render target to things bound as textures and vice versa, not even temporarily). + draw_->BindTexture(0, nullptr); + // This will get optimized away in case it's already bound (in VK and GL at least..) + draw_->BindFramebufferAsRenderTarget(dest, { Draw::RPAction::KEEP, Draw::RPAction::KEEP, Draw::RPAction::KEEP }, "BlitUsingRaster"); + draw_->BindFramebufferAsTexture(src, 0, channel == RASTER_COLOR ? Draw::FB_COLOR_BIT : Draw::FB_DEPTH_BIT, 0); Draw::Viewport vp{ 0.0f, 0.0f, (float)dest->Width(), (float)dest->Height(), 0.0f, 1.0f }; draw_->SetViewports(1, &vp); draw_->SetScissorRect(0, 0, (int)dest->Width(), (int)dest->Height()); - DrawStrip2D(nullptr, vtx, 4, linearFilter); + DrawStrip2D(nullptr, vtx, 4, linearFilter, channel); gstate_c.Dirty(DIRTY_BLEND_STATE | DIRTY_DEPTHSTENCIL_STATE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VERTEXSHADER_STATE | DIRTY_FRAGMENTSHADER_STATE); } diff --git a/GPU/Common/FramebufferManagerCommon.h b/GPU/Common/FramebufferManagerCommon.h index a1557cfed8..5277d6a03e 100644 --- a/GPU/Common/FramebufferManagerCommon.h +++ b/GPU/Common/FramebufferManagerCommon.h @@ -359,7 +359,7 @@ protected: Draw::Texture *MakePixelTexture(const u8 *srcPixels, GEBufferFormat srcPixelFormat, int srcStride, int width, int height); void DrawActiveTexture(float x, float y, float w, float h, float destW, float destH, float u0, float v0, float u1, float v1, int uvRotation, int flags); - void DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter); + void DrawStrip2D(Draw::Texture *tex, Draw2DVertex *verts, int vertexCount, bool linearFilter, RasterChannel channel); bool UpdateSize(); @@ -367,11 +367,11 @@ protected: virtual void DecimateFBOs(); // keeping it virtual to let D3D do a little extra // Used by ReadFramebufferToMemory and later framebuffer block copies - virtual void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag); + void BlitFramebuffer(VirtualFramebuffer *dst, int dstX, int dstY, VirtualFramebuffer *src, int srcX, int srcY, int w, int h, int bpp, const char *tag); void BlitUsingRaster( Draw::Framebuffer *src, float srcX1, float srcY1, float srcX2, float srcY2, - Draw::Framebuffer *dest, float destX1, float destY1, float destX2, float destY2, bool linearFilter); + Draw::Framebuffer *dest, float destX1, float destY1, float destX2, float destY2, bool linearFilter, RasterChannel channel); void CopyFramebufferForColorTexture(VirtualFramebuffer *dst, VirtualFramebuffer *src, int flags); @@ -485,9 +485,11 @@ protected: Draw::SamplerState *stencilUploadSampler_ = nullptr; // Draw2D pipelines - Draw::Pipeline *draw2DPipelineLinear_ = nullptr; + Draw::Pipeline *draw2DPipelineColor_ = nullptr; + Draw::Pipeline *draw2DPipelineDepth_ = nullptr; Draw::SamplerState *draw2DSamplerLinear_ = nullptr; Draw::SamplerState *draw2DSamplerNearest_ = nullptr; Draw::ShaderModule *draw2DVs_ = nullptr; Draw::ShaderModule *draw2DFs_ = nullptr; + Draw::ShaderModule *draw2DFsDepth_ = nullptr; }; diff --git a/GPU/Common/ReinterpretFramebuffer.cpp b/GPU/Common/ReinterpretFramebuffer.cpp index f0066e0313..71b0b24910 100644 --- a/GPU/Common/ReinterpretFramebuffer.cpp +++ b/GPU/Common/ReinterpretFramebuffer.cpp @@ -28,7 +28,7 @@ bool GenerateReinterpretFragmentShader(char *buffer, GEBufferFormat from, GEBuff writer.DeclareSamplers(samplers); - writer.BeginFSMain(Slice::empty(), varyings); + writer.BeginFSMain(Slice::empty(), varyings, FSFLAG_NONE); writer.C(" vec4 val = ").SampleTexture2D("tex", "v_texcoord.xy").C(";\n"); @@ -68,7 +68,7 @@ bool GenerateReinterpretFragmentShader(char *buffer, GEBufferFormat from, GEBuff break; } - writer.EndFSMain("outColor"); + writer.EndFSMain("outColor", FSFLAG_NONE); return true; } diff --git a/GPU/Common/StencilCommon.cpp b/GPU/Common/StencilCommon.cpp index 0881771ce3..950c84dd35 100644 --- a/GPU/Common/StencilCommon.cpp +++ b/GPU/Common/StencilCommon.cpp @@ -94,7 +94,7 @@ void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw: writer.C("float roundAndScaleTo255f(in float x) { return floor(x * 255.99); }\n"); - writer.BeginFSMain(uniforms, varyings); + writer.BeginFSMain(uniforms, varyings, FSFLAG_NONE); writer.C(" vec4 index = ").SampleTexture2D("tex", "v_texcoord.xy").C(";\n"); writer.C(" vec4 outColor = index.aaaa;\n"); // Only care about a. @@ -106,7 +106,7 @@ void GenerateStencilFs(char *buffer, const ShaderLanguageDesc &lang, const Draw: writer.C(" gl_FragDepth = gl_FragCoord.z;\n"); } - writer.EndFSMain("outColor"); + writer.EndFSMain("outColor", FSFLAG_NONE); } // This can probably be shared with some other shaders, like reinterpret or the future depth upload. From 79ee532609596cad49889d844abdd140d7c16b6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 8 Aug 2022 12:07:50 +0200 Subject: [PATCH 3/3] Fix feature checks --- Common/GPU/D3D11/thin3d_d3d11.cpp | 1 + Common/GPU/D3D9/thin3d_d3d9.cpp | 1 + Common/GPU/OpenGL/thin3d_gl.cpp | 7 +++++++ Common/GPU/Vulkan/thin3d_vulkan.cpp | 1 + Common/GPU/thin3d.h | 1 + GPU/Common/Draw2D.cpp | 23 +++++++++++++++++++---- GPU/Common/FramebufferManagerCommon.cpp | 16 +++++++++++++--- 7 files changed, 43 insertions(+), 7 deletions(-) diff --git a/Common/GPU/D3D11/thin3d_d3d11.cpp b/Common/GPU/D3D11/thin3d_d3d11.cpp index 2448d8996e..90bec0ecfe 100644 --- a/Common/GPU/D3D11/thin3d_d3d11.cpp +++ b/Common/GPU/D3D11/thin3d_d3d11.cpp @@ -269,6 +269,7 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de caps_.fragmentShaderInt32Supported = true; caps_.anisoSupported = true; caps_.textureNPOTFullySupported = true; + caps_.fragmentShaderDepthWriteSupported = true; D3D11_FEATURE_DATA_D3D11_OPTIONS options{}; HRESULT result = device_->CheckFeatureSupport(D3D11_FEATURE_D3D11_OPTIONS, &options, sizeof(options)); diff --git a/Common/GPU/D3D9/thin3d_d3d9.cpp b/Common/GPU/D3D9/thin3d_d3d9.cpp index 10fa3beb44..7b2fa934b0 100644 --- a/Common/GPU/D3D9/thin3d_d3d9.cpp +++ b/Common/GPU/D3D9/thin3d_d3d9.cpp @@ -669,6 +669,7 @@ D3D9Context::D3D9Context(IDirect3D9 *d3d, IDirect3D9Ex *d3dEx, int adapterId, ID caps_.framebufferSeparateDepthCopySupported = false; caps_.texture3DSupported = true; caps_.textureNPOTFullySupported = true; + caps_.fragmentShaderDepthWriteSupported = true; if (d3d) { D3DDISPLAYMODE displayMode; diff --git a/Common/GPU/OpenGL/thin3d_gl.cpp b/Common/GPU/OpenGL/thin3d_gl.cpp index 7a17b3a036..3088abc22f 100644 --- a/Common/GPU/OpenGL/thin3d_gl.cpp +++ b/Common/GPU/OpenGL/thin3d_gl.cpp @@ -560,6 +560,13 @@ OpenGLContext::OpenGLContext() { gl_extensions.IsCoreContext || gl_extensions.GLES3 || gl_extensions.ARB_texture_non_power_of_two || gl_extensions.OES_texture_npot; + if (gl_extensions.IsGLES) { + caps_.fragmentShaderDepthWriteSupported = gl_extensions.GLES3; + // There's also GL_EXT_frag_depth but it's rare along with 2.0. Most chips that support it are simply 3.0 chips. + } else { + caps_.fragmentShaderDepthWriteSupported = true; + } + // Interesting potential hack for emulating GL_DEPTH_CLAMP (use a separate varying, force depth in fragment shader): // This will induce a performance penalty on many architectures though so a blanket enable of this // is probably not a good idea. diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index aa55b4e707..3b0f0d10e6 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -793,6 +793,7 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit) caps_.texture3DSupported = true; caps_.fragmentShaderInt32Supported = true; caps_.textureNPOTFullySupported = true; + caps_.fragmentShaderDepthWriteSupported = true; auto deviceProps = vulkan->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDeviceIndex()).properties; switch (deviceProps.vendorID) { diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index 6099c198a3..cbd5cafef1 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -541,6 +541,7 @@ struct DeviceCaps { bool texture3DSupported; bool fragmentShaderInt32Supported; bool textureNPOTFullySupported; + bool fragmentShaderDepthWriteSupported; std::string deviceName; // The device name to use when creating the thin3d context, to get the same one. }; diff --git a/GPU/Common/Draw2D.cpp b/GPU/Common/Draw2D.cpp index 1ea143bd8a..882da8590f 100644 --- a/GPU/Common/Draw2D.cpp +++ b/GPU/Common/Draw2D.cpp @@ -83,10 +83,16 @@ void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *ver GenerateDraw2DVS(vsCode, shaderLanguageDesc); draw2DFs_ = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsCode, strlen(fsCode), "draw2d_fs"); - draw2DFsDepth_ = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsDepthCode, strlen(fsDepthCode), "draw2d_depth_fs"); draw2DVs_ = draw_->CreateShaderModule(ShaderStage::Vertex, shaderLanguageDesc.shaderLanguage, (const uint8_t *)vsCode, strlen(vsCode), "draw2d_vs"); - _assert_(draw2DFs_ && draw2DVs_ && draw2DFsDepth_); + _assert_(draw2DFs_ && draw2DVs_); + + if (draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported) { + draw2DFsDepth_ = draw_->CreateShaderModule(ShaderStage::Fragment, shaderLanguageDesc.shaderLanguage, (const uint8_t *)fsDepthCode, strlen(fsDepthCode), "draw2d_depth_fs"); + _assert_(draw2DFsDepth_); + } else { + draw2DFsDepth_ = nullptr; + } InputLayoutDesc desc = { { @@ -124,8 +130,13 @@ void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *ver { draw2DVs_, draw2DFsDepth_ }, inputLayout, depthWriteAlways, blendDiscard, rasterNoCull, nullptr, }; - draw2DPipelineDepth_ = draw_->CreateGraphicsPipeline(draw2DDepthPipelineDesc); - _assert_(draw2DPipelineDepth_); + + if (draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported) { + draw2DPipelineDepth_ = draw_->CreateGraphicsPipeline(draw2DDepthPipelineDesc); + _assert_(draw2DPipelineDepth_); + } else { + draw2DPipelineDepth_ = nullptr; + } delete[] fsCode; delete[] vsCode; @@ -154,6 +165,10 @@ void FramebufferManagerCommon::DrawStrip2D(Draw::Texture *tex, Draw2DVertex *ver draw2DSamplerNearest_ = draw_->CreateSamplerState(descNearest); } + if (channel == RASTER_DEPTH && !draw2DPipelineDepth_) { + return; + } + draw_->BindPipeline(channel == RASTER_COLOR ? draw2DPipelineColor_ : draw2DPipelineDepth_); if (tex) { draw_->BindTextures(TEX_SLOT_PSP_TEXTURE, 1, &tex); diff --git a/GPU/Common/FramebufferManagerCommon.cpp b/GPU/Common/FramebufferManagerCommon.cpp index 42603951c7..68920e2a12 100644 --- a/GPU/Common/FramebufferManagerCommon.cpp +++ b/GPU/Common/FramebufferManagerCommon.cpp @@ -584,11 +584,17 @@ void FramebufferManagerCommon::BlitFramebufferDepth(VirtualFramebuffer *src, Vir bool useCopy = draw_->GetDeviceCaps().framebufferSeparateDepthCopySupported || (!draw_->GetDeviceCaps().framebufferDepthBlitSupported && draw_->GetDeviceCaps().framebufferCopySupported); bool useBlit = draw_->GetDeviceCaps().framebufferDepthBlitSupported; - // Attempt at optimization - if destination already bound, draw depth using raster - if (true || currentRenderVfb_ == dst) { + bool useRaster = draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported; + + // Could do an attempt at optimization - if destination already bound, draw depth using raster. + // Let's experiment later, commented out for now. Currently we fall back to raster as a last resort here. + + /* + if (currentRenderVfb_ == dst) { useCopy = false; useBlit = false; } + */ int w = std::min(src->renderWidth, dst->renderWidth); int h = std::min(src->renderHeight, dst->renderHeight); @@ -603,7 +609,7 @@ void FramebufferManagerCommon::BlitFramebufferDepth(VirtualFramebuffer *src, Vir // We'll accept whether we get a separate depth blit or not... draw_->BlitFramebuffer(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, Draw::FB_DEPTH_BIT, Draw::FB_BLIT_NEAREST, "BlitFramebufferDepth"); RebindFramebuffer("After BlitFramebufferDepth"); - } else { + } else if (useRaster) { BlitUsingRaster(src->fbo, 0, 0, w, h, dst->fbo, 0, 0, w, h, false, RasterChannel::RASTER_DEPTH); } @@ -2688,6 +2694,10 @@ void FramebufferManagerCommon::BlitUsingRaster( bool linearFilter, RasterChannel channel) { + if (channel == RASTER_DEPTH) { + _dbg_assert_(draw_->GetDeviceCaps().fragmentShaderDepthWriteSupported); + } + int destW, destH, srcW, srcH; draw_->GetFramebufferDimensions(src, &srcW, &srcH); draw_->GetFramebufferDimensions(dest, &destW, &destH);