mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Vulkan: Limit stencil workaround to Adreno 5xx.
This commit is contained in:
parent
1f594f3fb5
commit
f8ce9b08ba
9 changed files with 53 additions and 18 deletions
|
@ -1,6 +1,7 @@
|
|||
#include <string>
|
||||
#include <sstream>
|
||||
|
||||
#include "thin3d/thin3d.h"
|
||||
#include "Common/StringUtils.h"
|
||||
#include "Core/Config.h"
|
||||
|
||||
|
@ -225,7 +226,7 @@ std::string FragmentShaderDesc(const ShaderID &id) {
|
|||
|
||||
// Here we must take all the bits of the gstate that determine what the fragment shader will
|
||||
// look like, and concatenate them together into an ID.
|
||||
void ComputeFragmentShaderID(ShaderID *id_out) {
|
||||
void ComputeFragmentShaderID(ShaderID *id_out, const Draw::Bugs &bugs) {
|
||||
ShaderID id;
|
||||
if (gstate.isModeClear()) {
|
||||
// We only need one clear shader, so let's ignore the rest of the bits.
|
||||
|
@ -292,9 +293,6 @@ void ComputeFragmentShaderID(ShaderID *id_out) {
|
|||
if (stencilToAlpha != REPLACE_ALPHA_NO) {
|
||||
// 4 bits
|
||||
id.SetBits(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE, 4, ReplaceAlphaWithStencilType());
|
||||
} else {
|
||||
// Use those bits instead for whether stencil output is disabled.
|
||||
id.SetBit(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE, IsStencilTestOutputDisabled());
|
||||
}
|
||||
|
||||
// 2 bits.
|
||||
|
@ -312,6 +310,12 @@ void ComputeFragmentShaderID(ShaderID *id_out) {
|
|||
id.SetBit(FS_BIT_FLATSHADE, doFlatShading);
|
||||
|
||||
id.SetBit(FS_BIT_SHADER_DEPAL, useShaderDepal);
|
||||
|
||||
if (g_Config.bVendorBugChecksEnabled) {
|
||||
if (bugs.Has(Draw::Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL)) {
|
||||
id.SetBit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL, !IsStencilTestOutputDisabled() && !gstate.isDepthWriteEnabled());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*id_out = id;
|
||||
|
|
|
@ -87,7 +87,8 @@ enum {
|
|||
FS_BIT_FLATSHADE = 46,
|
||||
FS_BIT_BGRA_TEXTURE = 47,
|
||||
FS_BIT_TEST_DISCARD_TO_ZERO = 48,
|
||||
// 49+ are free.
|
||||
FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL = 49,
|
||||
// 50+ are free.
|
||||
};
|
||||
|
||||
struct ShaderID {
|
||||
|
@ -175,11 +176,15 @@ struct FShaderID : ShaderID {
|
|||
}
|
||||
};
|
||||
|
||||
namespace Draw {
|
||||
class Bugs;
|
||||
}
|
||||
|
||||
|
||||
void ComputeVertexShaderID(ShaderID *id, uint32_t vertexType, bool useHWTransform);
|
||||
// Generates a compact string that describes the shader. Useful in a list to get an overview
|
||||
// of the current flora of shaders.
|
||||
std::string VertexShaderDesc(const ShaderID &id);
|
||||
|
||||
void ComputeFragmentShaderID(ShaderID *id);
|
||||
void ComputeFragmentShaderID(ShaderID *id, const Draw::Bugs &bugs);
|
||||
std::string FragmentShaderDesc(const ShaderID &id);
|
||||
|
|
|
@ -191,7 +191,7 @@ void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader **
|
|||
|
||||
if (gstate_c.IsDirty(DIRTY_FRAGMENTSHADER_STATE)) {
|
||||
gstate_c.Clean(DIRTY_FRAGMENTSHADER_STATE);
|
||||
ComputeFragmentShaderID(&FSID);
|
||||
ComputeFragmentShaderID(&FSID, draw_->GetBugs());
|
||||
} else {
|
||||
FSID = lastFSID_;
|
||||
}
|
||||
|
|
|
@ -556,7 +556,7 @@ VSShader *ShaderManagerDX9::ApplyShader(int prim, u32 vertType) {
|
|||
FShaderID FSID;
|
||||
if (gstate_c.IsDirty(DIRTY_FRAGMENTSHADER_STATE)) {
|
||||
gstate_c.Clean(DIRTY_FRAGMENTSHADER_STATE);
|
||||
ComputeFragmentShaderID(&FSID);
|
||||
ComputeFragmentShaderID(&FSID, draw_->GetBugs());
|
||||
} else {
|
||||
FSID = lastFSID_;
|
||||
}
|
||||
|
|
|
@ -703,7 +703,7 @@ LinkedShader *ShaderManagerGLES::ApplyFragmentShader(VShaderID VSID, Shader *vs,
|
|||
FShaderID FSID;
|
||||
if (gstate_c.IsDirty(DIRTY_FRAGMENTSHADER_STATE)) {
|
||||
gstate_c.Clean(DIRTY_FRAGMENTSHADER_STATE);
|
||||
ComputeFragmentShaderID(&FSID);
|
||||
ComputeFragmentShaderID(&FSID, draw_->GetBugs());
|
||||
} else {
|
||||
FSID = lastFSID_;
|
||||
}
|
||||
|
|
|
@ -84,15 +84,11 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_
|
|||
|
||||
const char *shading = doFlatShading ? "flat" : "";
|
||||
bool earlyFragmentTests = ((!enableAlphaTest && !enableColorTest) || testForceToZero) && !gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT);
|
||||
bool hasStencilOutput = stencilToAlpha != REPLACE_ALPHA_NO || id.Bit(FS_BIT_REPLACE_ALPHA_WITH_STENCIL_TYPE) == 0;
|
||||
|
||||
// TODO: This is a bug affecting shader cache generality - we CANNOT check anything but the shader ID and (indirectly) the game ID in here really.
|
||||
// Need to move this check somehow to the shader ID generator. That's tricky though because it's generic...
|
||||
bool isAdreno = vulkanVendorId == VULKAN_VENDOR_QUALCOMM && g_Config.bVendorBugChecksEnabled;
|
||||
bool useAdrenoBugWorkaround = id.Bit(FS_BIT_NO_DEPTH_CANNOT_DISCARD_STENCIL);
|
||||
|
||||
if (earlyFragmentTests) {
|
||||
WRITE(p, "layout (early_fragment_tests) in;\n");
|
||||
} else if (isAdreno && hasStencilOutput && !gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) {
|
||||
} else if (useAdrenoBugWorkaround && !gstate_c.Supports(GPU_ROUND_FRAGMENT_DEPTH_TO_16BIT)) {
|
||||
WRITE(p, "layout (depth_unchanged) out float gl_FragDepth;\n");
|
||||
}
|
||||
|
||||
|
@ -588,7 +584,7 @@ bool GenerateVulkanGLSLFragmentShader(const FShaderID &id, char *buffer, uint32_
|
|||
WRITE(p, " z = (1.0/65535.0) * floor(z * 65535.0);\n");
|
||||
}
|
||||
WRITE(p, " gl_FragDepth = z;\n");
|
||||
} else if (!earlyFragmentTests && isAdreno && hasStencilOutput) {
|
||||
} else if (!earlyFragmentTests && useAdrenoBugWorkaround) {
|
||||
// Adreno (and possibly MESA/others) apply early frag tests even with discard in the shader.
|
||||
// Writing depth prevents the bug, even with depth_unchanged specified.
|
||||
WRITE(p, " gl_FragDepth = gl_FragCoord.z;\n");
|
||||
|
|
|
@ -240,7 +240,7 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader
|
|||
FShaderID FSID;
|
||||
if (gstate_c.IsDirty(DIRTY_FRAGMENTSHADER_STATE)) {
|
||||
gstate_c.Clean(DIRTY_FRAGMENTSHADER_STATE);
|
||||
ComputeFragmentShaderID(&FSID);
|
||||
ComputeFragmentShaderID(&FSID, draw_->GetBugs());
|
||||
} else {
|
||||
FSID = lastFSID_;
|
||||
}
|
||||
|
|
|
@ -315,6 +315,23 @@ struct Viewport {
|
|||
float MaxDepth;
|
||||
};
|
||||
|
||||
class Bugs {
|
||||
public:
|
||||
bool Has(uint32_t bug) const {
|
||||
return (flags_ & (1 << bug)) != 0;
|
||||
}
|
||||
void Infest(uint32_t bug) {
|
||||
flags_ |= (1 << bug);
|
||||
}
|
||||
|
||||
enum : uint32_t {
|
||||
NO_DEPTH_CANNOT_DISCARD_STENCIL = 0,
|
||||
};
|
||||
|
||||
protected:
|
||||
uint32_t flags_ = 0;
|
||||
};
|
||||
|
||||
class RefCountedObject {
|
||||
public:
|
||||
RefCountedObject() : refcount_(1) {}
|
||||
|
@ -524,6 +541,8 @@ public:
|
|||
bool CreatePresets();
|
||||
void DestroyPresets();
|
||||
|
||||
Bugs GetBugs() const { return bugs_; }
|
||||
|
||||
virtual const DeviceCaps &GetDeviceCaps() const = 0;
|
||||
virtual uint32_t GetDataFormatSupport(DataFormat fmt) const = 0;
|
||||
virtual std::vector<std::string> GetFeatureList() const { return std::vector<std::string>(); }
|
||||
|
@ -647,6 +666,8 @@ protected:
|
|||
|
||||
int targetWidth_;
|
||||
int targetHeight_;
|
||||
|
||||
Bugs bugs_;
|
||||
};
|
||||
|
||||
extern const UniformBufferDesc UBPresetDesc;
|
||||
|
|
|
@ -762,7 +762,8 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit)
|
|||
caps_.framebufferDepthCopySupported = true; // Will pretty much always be the case.
|
||||
caps_.preferredDepthBufferFormat = DataFormat::D24_S8; // TODO: Ask vulkan.
|
||||
|
||||
switch (vulkan->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice()).vendorID) {
|
||||
auto deviceProps = vulkan->GetPhysicalDeviceProperties(vulkan_->GetCurrentPhysicalDevice());
|
||||
switch (deviceProps.vendorID) {
|
||||
case VULKAN_VENDOR_AMD: caps_.vendor = GPUVendor::VENDOR_AMD; break;
|
||||
case VULKAN_VENDOR_ARM: caps_.vendor = GPUVendor::VENDOR_ARM; break;
|
||||
case VULKAN_VENDOR_IMGTEC: caps_.vendor = GPUVendor::VENDOR_IMGTEC; break;
|
||||
|
@ -773,6 +774,14 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit)
|
|||
caps_.vendor = GPUVendor::VENDOR_UNKNOWN;
|
||||
}
|
||||
|
||||
if (caps_.vendor == GPUVendor::VENDOR_QUALCOMM) {
|
||||
// Adreno 5xx devices, all known driver versions, fail to discard stencil when depth write is off.
|
||||
// See: https://github.com/hrydgard/ppsspp/pull/11684
|
||||
if (deviceProps.deviceID >= 0x05000000 && deviceProps.deviceID < 0x06000000) {
|
||||
bugs_.Infest(Bugs::NO_DEPTH_CANNOT_DISCARD_STENCIL);
|
||||
}
|
||||
}
|
||||
|
||||
device_ = vulkan->GetDevice();
|
||||
|
||||
queue_ = vulkan->GetGraphicsQueue();
|
||||
|
|
Loading…
Add table
Reference in a new issue