Merge pull request #14833 from unknownbrackets/guardband

Handle guardband clip/cull better for hardware backends
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2021-10-19 12:00:01 +02:00
commit 16bf5197e4
25 files changed
+184 -107

No files matched your search

+4 -1
View File
@@ -245,6 +245,9 @@ D3D11DrawContext::D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *de
// Seems like a fair approximation...
caps_.dualSourceBlend = featureLevel_ >= D3D_FEATURE_LEVEL_10_0;
caps_.depthClampSupported = featureLevel_ >= D3D_FEATURE_LEVEL_10_0;
// SV_ClipDistance# seems to be 10+.
caps_.clipDistanceSupported = featureLevel_ >= D3D_FEATURE_LEVEL_10_0;
caps_.cullDistanceSupported = featureLevel_ >= D3D_FEATURE_LEVEL_10_0;
caps_.depthRangeMinusOneToOne = false;
caps_.framebufferBlitSupported = false;
@@ -1345,7 +1348,7 @@ void D3D11DrawContext::BindSamplerStates(int start, int count, SamplerState **st
_assert_(start + count <= ARRAY_SIZE(samplers));
for (int i = 0; i < count; i++) {
D3D11SamplerState *samp = (D3D11SamplerState *)states[i];
samplers[i] = samp->ss;
samplers[i] = samp ? samp->ss : nullptr;
}
context_->PSSetSamplers(start, count, samplers);
}
+2 -1
View File
@@ -530,7 +530,8 @@ public:
_assert_(start + count <= MAX_BOUND_TEXTURES);
for (int i = 0; i < count; ++i) {
D3D9SamplerState *s = static_cast<D3D9SamplerState *>(states[i]);
s->Apply(device_, start + i);
if (s)
s->Apply(device_, start + i);
}
}
void BindVertexBuffers(int start, int count, Buffer **buffers, const int *offsets) override {
+1
View File
@@ -385,6 +385,7 @@ void CheckGLExtensions() {
gl_extensions.OES_texture_float = g_set_gl_extensions.count("GL_OES_texture_float") != 0;
gl_extensions.EXT_buffer_storage = g_set_gl_extensions.count("GL_EXT_buffer_storage") != 0;
gl_extensions.EXT_clip_cull_distance = g_set_gl_extensions.count("GL_EXT_clip_cull_distance") != 0;
gl_extensions.APPLE_clip_distance = g_set_gl_extensions.count("GL_APPLE_clip_distance") != 0;
#if defined(__ANDROID__)
// On Android, incredibly, this is not consistently non-zero! It does seem to have the same value though.
+3
View File
@@ -94,6 +94,9 @@ struct GLExtensions {
// ARM
bool ARM_shader_framebuffer_fetch;
// APPLE
bool APPLE_clip_distance;
// EGL
bool EGL_NV_system_time;
bool EGL_NV_coverage_sample;
+17
View File
@@ -17,6 +17,13 @@
#include "GLRenderManager.h"
#include "DataFormatGL.h"
// These are the same value, alias for simplicity.
#if defined(GL_CLIP_DISTANCE0_EXT) && !defined(GL_CLIP_DISTANCE0)
#define GL_CLIP_DISTANCE0 GL_CLIP_DISTANCE0_EXT
#elif !defined(GL_CLIP_DISTANCE0)
#define GL_CLIP_DISTANCE0 0x3000
#endif
static constexpr int TEXCACHE_NAME_CACHE_SIZE = 16;
#if PPSSPP_PLATFORM(IOS)
@@ -798,6 +805,7 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step, bool first, bool last
int logicOp = -1;
bool logicEnabled = false;
#endif
bool clipDistance0Enabled = false;
GLuint blendEqColor = (GLuint)-1;
GLuint blendEqAlpha = (GLuint)-1;
@@ -1106,6 +1114,13 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step, bool first, bool last
{
if (curProgram != c.program.program) {
glUseProgram(c.program.program->program);
if (c.program.program->use_clip_distance0 != clipDistance0Enabled) {
if (c.program.program->use_clip_distance0)
glEnable(GL_CLIP_DISTANCE0);
else
glDisable(GL_CLIP_DISTANCE0);
clipDistance0Enabled = c.program.program->use_clip_distance0;
}
curProgram = c.program.program;
}
CHECK_GL_ERROR_IF_DEBUG();
@@ -1340,6 +1355,8 @@ void GLQueueRunner::PerformRenderPass(const GLRStep &step, bool first, bool last
glDisable(GL_COLOR_LOGIC_OP);
}
#endif
if (clipDistance0Enabled)
glDisable(GL_CLIP_DISTANCE0);
if ((colorMask & 15) != 15)
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
CHECK_GL_ERROR_IF_DEBUG();
+3 -1
View File
@@ -119,6 +119,7 @@ public:
std::vector<Semantic> semantics_;
std::vector<UniformLocQuery> queries_;
std::vector<Initializer> initialize_;
bool use_clip_distance0 = false;
struct UniformInfo {
int loc_;
@@ -422,13 +423,14 @@ public:
// not be an active render pass.
GLRProgram *CreateProgram(
std::vector<GLRShader *> shaders, std::vector<GLRProgram::Semantic> semantics, std::vector<GLRProgram::UniformLocQuery> queries,
std::vector<GLRProgram::Initializer> initalizers, bool supportDualSource) {
std::vector<GLRProgram::Initializer> initalizers, bool supportDualSource, bool useClipDistance0) {
GLRInitStep step{ GLRInitStepType::CREATE_PROGRAM };
_assert_(shaders.size() <= ARRAY_SIZE(step.create_program.shaders));
step.create_program.program = new GLRProgram();
step.create_program.program->semantics_ = semantics;
step.create_program.program->queries_ = queries;
step.create_program.program->initialize_ = initalizers;
step.create_program.program->use_clip_distance0 = useClipDistance0;
step.create_program.support_dual_source = supportDualSource;
_assert_msg_(shaders.size() > 0, "Can't create a program with zero shaders");
for (size_t i = 0; i < shaders.size(); i++) {
+8 -1
View File
@@ -534,6 +534,13 @@ OpenGLContext::OpenGLContext() {
caps_.framebufferBlitSupported = gl_extensions.NV_framebuffer_blit || gl_extensions.ARB_framebuffer_object;
caps_.framebufferDepthBlitSupported = 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;
caps_.cullDistanceSupported = gl_extensions.EXT_clip_cull_distance;
} else {
caps_.clipDistanceSupported = gl_extensions.VersionGEThan(3, 0);
caps_.cullDistanceSupported = gl_extensions.ARB_cull_distance;
}
// 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
@@ -1162,7 +1169,7 @@ bool OpenGLPipeline::LinkShaders() {
std::vector<GLRProgram::Initializer> initialize;
for (int i = 0; i < MAX_TEXTURE_SLOTS; ++i)
initialize.push_back({ &samplerLocs_[i], 0, i });
program_ = render_->CreateProgram(linkShaders, semantics, queries, initialize, false);
program_ = render_->CreateProgram(linkShaders, semantics, queries, initialize, false, false);
return true;
}
+2
View File
@@ -580,6 +580,8 @@ void VulkanContext::ChooseDevice(int physical_device) {
deviceFeatures_.enabled.depthClamp = deviceFeatures_.available.depthClamp;
deviceFeatures_.enabled.depthBounds = deviceFeatures_.available.depthBounds;
deviceFeatures_.enabled.samplerAnisotropy = deviceFeatures_.available.samplerAnisotropy;
deviceFeatures_.enabled.shaderClipDistance = deviceFeatures_.available.shaderClipDistance;
deviceFeatures_.enabled.shaderCullDistance = deviceFeatures_.available.shaderCullDistance;
// For easy wireframe mode, someday.
deviceFeatures_.enabled.fillModeNonSolid = deviceFeatures_.available.fillModeNonSolid;
+7
View File
@@ -780,6 +780,8 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit)
caps_.multiViewport = vulkan->GetDeviceFeatures().enabled.multiViewport != 0;
caps_.dualSourceBlend = vulkan->GetDeviceFeatures().enabled.dualSrcBlend != 0;
caps_.depthClampSupported = vulkan->GetDeviceFeatures().enabled.depthClamp != 0;
caps_.clipDistanceSupported = vulkan->GetDeviceFeatures().enabled.shaderClipDistance != 0;
caps_.cullDistanceSupported = vulkan->GetDeviceFeatures().enabled.shaderCullDistance != 0;
caps_.framebufferBlitSupported = true;
caps_.framebufferCopySupported = true;
caps_.framebufferDepthBlitSupported = false; // Can be checked for.
@@ -816,6 +818,11 @@ VKContext::VKContext(VulkanContext *vulkan, bool splitSubmit)
} else if (caps_.vendor == GPUVendor::VENDOR_INTEL) {
// Workaround for Intel driver bug. TODO: Re-enable after some driver version
bugs_.Infest(Bugs::DUAL_SOURCE_BLENDING_BROKEN);
} else if (caps_.vendor == GPUVendor::VENDOR_ARM) {
// These GPUs (up to some certain hardware version?) have a bug where draws where gl_Position.w == .z
// corrupt the depth buffer. This is easily worked around by simply scaling Z down a tiny bit when this case
// is detected. See: https://github.com/hrydgard/ppsspp/issues/11937
bugs_.Infest(Bugs::EQUAL_WZ_CORRUPTS_DEPTH);
}
caps_.deviceID = deviceProps.deviceID;
+3
View File
@@ -317,6 +317,7 @@ public:
BROKEN_NAN_IN_CONDITIONAL = 4,
COLORWRITEMASK_BROKEN_WITH_DEPTHTEST = 5,
BROKEN_FLAT_IN_SHADER = 6,
EQUAL_WZ_CORRUPTS_DEPTH = 7,
};
protected:
@@ -520,6 +521,8 @@ struct DeviceCaps {
bool dualSourceBlend;
bool logicOpSupported;
bool depthClampSupported;
bool clipDistanceSupported;
bool cullDistanceSupported;
bool framebufferCopySupported;
bool framebufferBlitSupported;
bool framebufferDepthCopySupported;
+5 -1
View File
@@ -56,7 +56,11 @@ void UIContext::BeginNoTex() {
void UIContext::BeginPipeline(Draw::Pipeline *pipeline, Draw::SamplerState *samplerState) {
_assert_(pipeline != nullptr);
draw_->BindSamplerStates(0, 1, &samplerState);
// Also clear out any other textures bound.
Draw::SamplerState *samplers[3]{ samplerState };
draw_->BindSamplerStates(0, 3, samplers);
Draw::Texture *textures[2]{};
draw_->BindTextures(1, 2, textures);
RebindTexture();
UIBegin(pipeline);
}
+8 -32
View File
@@ -43,29 +43,12 @@ void CalcCullRange(float minValues[4], float maxValues[4], bool flipViewport, bo
float pspViewport = (y - gstate.getViewportYCenter()) * (1.0f / gstate.getViewportYScale());
return (pspViewport * heightScale) - yOffset;
};
auto reverseViewportZ = [hasNegZ](float z) {
float vpZScale = gstate.getViewportZScale();
float vpZCenter = gstate.getViewportZCenter();
float scale, center;
if (gstate_c.Supports(GPU_SUPPORTS_ACCURATE_DEPTH)) {
// These are just the reverse of the formulas in GPUStateUtils.
float halfActualZRange = vpZScale * (1.0f / gstate_c.vpDepthScale);
float minz = -((gstate_c.vpZOffset * halfActualZRange) - vpZCenter) - halfActualZRange;
// In accurate depth mode, we're comparing against a value scaled to (minz, maxz).
// And minz might be very negative, (e.g. if we're clamping in that direction.)
scale = halfActualZRange;
center = minz + halfActualZRange;
} else {
// In old-style depth mode, we're comparing against a value scaled to viewport.
// (and possibly incorrectly clipped against it.)
scale = vpZScale;
center = vpZCenter;
auto transformZ = [hasNegZ](float z) {
// Z culling ignores the viewport, so we just redo the projection matrix adjustments.
if (hasNegZ) {
return (z * gstate_c.vpDepthScale) + gstate_c.vpZOffset;
}
float realViewport = (z - center) * (1.0f / scale);
return hasNegZ ? realViewport : (realViewport * 0.5f + 0.5f);
return (z * gstate_c.vpDepthScale * 0.5f) + gstate_c.vpZOffset * 0.5f + 0.5f;
};
auto sortPair = [](float a, float b) {
return a > b ? std::make_pair(b, a) : std::make_pair(a, b);
@@ -75,7 +58,7 @@ void CalcCullRange(float minValues[4], float maxValues[4], bool flipViewport, bo
// Any vertex outside this range (unless depth clamp enabled) is discarded.
auto x = sortPair(reverseViewportX(0.0f), reverseViewportX(4096.0f));
auto y = sortPair(reverseViewportY(0.0f), reverseViewportY(4096.0f));
auto z = sortPair(reverseViewportZ(0.0f), reverseViewportZ(65535.5f));
auto z = sortPair(transformZ(-1.000030517578125f), transformZ(1.000030517578125f));
// Since we have space in w, use it to pass the depth clamp flag. We also pass NAN for w "discard".
float clampEnable = gstate.isDepthClampEnabled() ? 1.0f : 0.0f;
@@ -243,18 +226,11 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView
float viewZScale = halfActualZRange * 2.0f;
// Account for the half pixel offset.
float viewZCenter = minz + (DepthSliceFactor() / 256.0f) * 0.5f;
float viewZInvScale;
if (viewZScale != 0.0) {
viewZInvScale = 1.0f / viewZScale;
} else {
viewZInvScale = 0.0;
}
ub->depthRange[0] = viewZScale;
ub->depthRange[1] = viewZCenter;
ub->depthRange[2] = viewZCenter;
ub->depthRange[3] = viewZInvScale;
ub->depthRange[2] = gstate_c.vpZOffset * 0.5f + 0.5f;
ub->depthRange[3] = 2.0f * (1.0f / gstate_c.vpDepthScale);
}
if (dirtyUniforms & DIRTY_CULLRANGE) {
+22 -13
View File
@@ -64,14 +64,8 @@ static void SwapUVs(TransformedVertex &a, TransformedVertex &b) {
// Note: 0 is BR and 2 is TL.
static void RotateUV(TransformedVertex v[4], float flippedMatrix[16], bool flippedY) {
// Transform these two coordinates to figure out whether they're flipped or not.
Vec4f tl;
Vec3ByMatrix44(tl.AsArray(), v[2].pos, flippedMatrix);
Vec4f br;
Vec3ByMatrix44(br.AsArray(), v[0].pos, flippedMatrix);
static void RotateUV(TransformedVertex v[4], Vec4f tl, Vec4f br, bool flippedY) {
// We use the transformed tl/br coordinates to figure out whether they're flipped or not.
float ySign = flippedY ? -1.0 : 1.0;
const float invtlw = 1.0f / tl.w;
@@ -438,7 +432,7 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt
// TODO: This bleeds outside the play area in non-buffered mode. Big deal? Probably not.
// TODO: Allow creating a depth clear and a color draw.
bool reallyAClear = false;
if (maxIndex > 1 && prim == GE_PRIM_RECTANGLES && gstate.isModeClear()) {
if (maxIndex > 1 && prim == GE_PRIM_RECTANGLES && gstate.isModeClear() && throughmode) {
int scissorX2 = gstate.getScissorX2() + 1;
int scissorY2 = gstate.getScissorY2() + 1;
reallyAClear = IsReallyAClear(transformed, maxIndex, scissorX2, scissorY2);
@@ -465,7 +459,7 @@ void SoftwareTransform::Decode(int prim, u32 vertType, const DecVtxFormat &decVt
}
// Detect full screen "clears" that might not be so obvious, to set the safe size if possible.
if (!result->setSafeSize && prim == GE_PRIM_RECTANGLES && maxIndex == 2) {
if (!result->setSafeSize && prim == GE_PRIM_RECTANGLES && maxIndex == 2 && throughmode) {
bool clearingColor = gstate.isModeClear() && (gstate.isClearModeColorMask() || gstate.isClearModeAlphaMask());
bool writingColor = gstate.getColorMask() != 0xFFFFFFFF;
bool startsZeroX = transformed[0].x <= 0.0f && transformed[1].x > 0.0f && transformed[1].x > transformed[0].x;
@@ -629,10 +623,25 @@ void SoftwareTransform::BuildDrawingParams(int prim, int vertexCount, u32 vertTy
trans[3].u = transVtxTL.u;
// That's the four corners. Now process UV rotation.
if (throughmode)
if (throughmode) {
RotateUVThrough(trans);
else
RotateUV(trans, flippedMatrix, flippedY);
} else {
Vec4f tl;
Vec3ByMatrix44(tl.AsArray(), transVtxTL.pos, flippedMatrix);
Vec4f br;
Vec3ByMatrix44(br.AsArray(), transVtxBR.pos, flippedMatrix);
// If both transformed verts are outside Z, cull this rectangle entirely.
constexpr float outsideValue = 1.000030517578125f;
bool tlOutside = fabsf(tl.z / tl.w) >= outsideValue;
bool brOutside = fabsf(br.z / br.w) >= outsideValue;
if (tlOutside && brOutside)
continue;
if (!gstate.isDepthClampEnabled() && (tlOutside || brOutside))
continue;
RotateUV(trans, tl, br, flippedY);
}
// Triangle: BR-TR-TL
indsOut[0] = i * 2 + 0;
+46 -16
View File
@@ -105,6 +105,8 @@ const char *boneWeightAttrInitHLSL[9] = {
// to 0 and 65535 if a depth clamping/clipping flag is set (x/y clipping is performed only if depth
// needs to be clamped.)
//
// Additionally, depth is clipped to negative z based on vec.z (before viewport), at -1.
//
// All this above is for full transform mode.
// In through mode, the Z coordinate just goes straight through and there is no perspective division.
// We simulate this of course with pretty much an identity matrix. Rounding Z becomes very easy.
@@ -139,6 +141,12 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
if (gl_extensions.EXT_gpu_shader4) {
gl_exts.push_back("#extension GL_EXT_gpu_shader4 : enable");
}
if (gl_extensions.EXT_clip_cull_distance && id.Bit(VS_BIT_VERTEX_RANGE_CULLING)) {
gl_exts.push_back("#extension GL_EXT_clip_cull_distance : enable");
}
if (gl_extensions.APPLE_clip_distance && id.Bit(VS_BIT_VERTEX_RANGE_CULLING)) {
gl_exts.push_back("#extension GL_APPLE_clip_distance : enable");
}
}
ShaderWriter p(buffer, compat, ShaderStage::Vertex, gl_exts.data(), gl_exts.size());
@@ -154,6 +162,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
bool doShadeMapping = uvGenMode == GE_TEXMAP_ENVIRONMENT_MAP;
bool flatBug = bugs.Has(Draw::Bugs::BROKEN_FLAT_IN_SHADER) && g_Config.bVendorBugChecksEnabled;
bool needsZWHack = bugs.Has(Draw::Bugs::EQUAL_WZ_CORRUPTS_DEPTH) && g_Config.bVendorBugChecksEnabled;
bool doFlatShading = id.Bit(VS_BIT_FLATSHADE) && !flatBug;
bool useHWTransform = id.Bit(VS_BIT_USE_HW_TRANSFORM);
@@ -332,10 +341,8 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
}
}
if (!isModeThrough && gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
WRITE(p, "vec4 u_depthRange : register(c%i);\n", CONST_VS_DEPTHRANGE);
}
if (!isModeThrough) {
WRITE(p, "vec4 u_depthRange : register(c%i);\n", CONST_VS_DEPTHRANGE);
WRITE(p, "vec4 u_cullRangeMin : register(c%i);\n", CONST_VS_CULLRANGEMIN);
WRITE(p, "vec4 u_cullRangeMax : register(c%i);\n", CONST_VS_CULLRANGEMAX);
}
@@ -397,6 +404,12 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
WRITE(p, " vec4 gl_Position : POSITION;\n");
} else {
WRITE(p, " vec4 gl_Position : SV_Position;\n");
if (vertexRangeCulling && gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) {
WRITE(p, " float gl_ClipDistance : SV_ClipDistance0;\n");
}
if (vertexRangeCulling && gstate_c.Supports(GPU_SUPPORTS_CULL_DISTANCE)) {
WRITE(p, " float2 gl_CullDistance : SV_CullDistance0;\n");
}
}
WRITE(p, "};\n");
} else {
@@ -517,15 +530,11 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
*uniformMask |= DIRTY_FOGCOEF;
}
if (!isModeThrough && gstate_c.Supports(GPU_ROUND_DEPTH_TO_16BIT)) {
WRITE(p, "uniform highp vec4 u_depthRange;\n");
*uniformMask |= DIRTY_DEPTHRANGE;
}
if (!isModeThrough) {
WRITE(p, "uniform highp vec4 u_depthRange;\n");
WRITE(p, "uniform highp vec4 u_cullRangeMin;\n");
WRITE(p, "uniform highp vec4 u_cullRangeMax;\n");
*uniformMask |= DIRTY_CULLRANGE;
*uniformMask |= DIRTY_DEPTHRANGE | DIRTY_CULLRANGE;
}
WRITE(p, "%s%s lowp vec4 v_color0;\n", shading, compat.varying_vs);
@@ -554,7 +563,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
WRITE(p, " float z = v.z / v.w;\n");
WRITE(p, " z = z * u_depthRange.x + u_depthRange.y;\n");
WRITE(p, " z = floor(z);\n");
WRITE(p, " z = (z - u_depthRange.z) * u_depthRange.w;\n");
WRITE(p, " z = (z - u_depthRange.y) / u_depthRange.x;\n");
WRITE(p, " return vec4(v.x, v.y, z * v.w, v.w);\n");
WRITE(p, "}\n\n");
}
@@ -1099,21 +1108,42 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
if (vertexRangeCulling) {
WRITE(p, " vec3 projPos = outPos.xyz / outPos.w;\n");
// Vertex range culling doesn't happen when depth is clamped, so only do this if in range.
WRITE(p, " if (u_cullRangeMin.w <= 0.0 || (projPos.z >= u_cullRangeMin.z && projPos.z <= u_cullRangeMax.z)) {\n");
const char *outMin = "projPos.x < u_cullRangeMin.x || projPos.y < u_cullRangeMin.y || projPos.z < u_cullRangeMin.z";
const char *outMax = "projPos.x > u_cullRangeMax.x || projPos.y > u_cullRangeMax.y || projPos.z > u_cullRangeMax.z";
WRITE(p, " float projZ = (projPos.z - u_depthRange.z) * u_depthRange.w;\n");
// Vertex range culling doesn't happen when Z clips, note sign of w is important.
WRITE(p, " if (u_cullRangeMin.w <= 0.0 || projZ * outPos.w > -outPos.w) {\n");
const char *outMin = "projPos.x < u_cullRangeMin.x || projPos.y < u_cullRangeMin.y";
const char *outMax = "projPos.x > u_cullRangeMax.x || projPos.y > u_cullRangeMax.y";
WRITE(p, " if (%s || %s) {\n", outMin, outMax);
WRITE(p, " outPos.xyzw = u_cullRangeMax.wwww;\n");
WRITE(p, " }\n");
WRITE(p, " }\n");
WRITE(p, " if (u_cullRangeMin.w <= 0.0) {\n");
WRITE(p, " if (projPos.z < u_cullRangeMin.z || projPos.z > u_cullRangeMax.z) {\n");
WRITE(p, " outPos.xyzw = u_cullRangeMax.wwww;\n");
WRITE(p, " }\n");
WRITE(p, " }\n");
const char *clip0 = compat.shaderLanguage == HLSL_D3D11 ? "" : "[0]";
const char *cull0 = compat.shaderLanguage == HLSL_D3D11 ? ".x" : "[0]";
const char *cull1 = compat.shaderLanguage == HLSL_D3D11 ? ".y" : "[1]";
if (gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE)) {
// TODO: Not rectangles...
WRITE(p, " %sgl_ClipDistance%s = projZ * outPos.w + outPos.w;\n", compat.vsOutPrefix, clip0);
}
if (gstate_c.Supports(GPU_SUPPORTS_CULL_DISTANCE)) {
// Cull any triangle fully outside in the same direction when depth clamp enabled.
WRITE(p, " if (u_cullRangeMin.w > 0.0) {\n");
WRITE(p, " %sgl_CullDistance%s = projPos.z - u_cullRangeMin.z;\n", compat.vsOutPrefix, cull0);
WRITE(p, " %sgl_CullDistance%s = u_cullRangeMax.z - projPos.z;\n", compat.vsOutPrefix, cull1);
WRITE(p, " }\n");
}
}
// We've named the output gl_Position in HLSL as well.
WRITE(p, " %sgl_Position = outPos;\n", compat.vsOutPrefix);
if (gstate_c.Supports(GPU_NEEDS_Z_EQUAL_W_HACK)) {
// See comment in GPU_Vulkan.cpp.
if (needsZWHack) {
// See comment in thin3d_vulkan.cpp.
WRITE(p, " if (%sgl_Position.z == %sgl_Position.w) %sgl_Position.z *= 0.999999;\n",
compat.vsOutPrefix, compat.vsOutPrefix, compat.vsOutPrefix);
}
+4
View File
@@ -128,6 +128,10 @@ void GPU_D3D11::CheckGPUFeatures() {
features |= GPU_SUPPORTS_DUALSOURCE_BLEND;
if (draw_->GetDeviceCaps().depthClampSupported)
features |= GPU_SUPPORTS_DEPTH_CLAMP;
if (draw_->GetDeviceCaps().clipDistanceSupported)
features |= GPU_SUPPORTS_CLIP_DISTANCE;
if (draw_->GetDeviceCaps().cullDistanceSupported)
features |= GPU_SUPPORTS_CULL_DISTANCE;
features |= GPU_SUPPORTS_COPY_IMAGE;
features |= GPU_SUPPORTS_TEXTURE_FLOAT;
features |= GPU_SUPPORTS_INSTANCE_RENDERING;
+3 -8
View File
@@ -439,15 +439,10 @@ void ShaderManagerDX9::VSUpdateUniforms(u64 dirtyUniforms) {
float viewZScale = halfActualZRange * 2.0f;
// Account for the half pixel offset.
float viewZCenter = minz + (DepthSliceFactor() / 256.0f) * 0.5f;
float viewZInvScale;
float reverseScale = 2.0f * (1.0f / gstate_c.vpDepthScale);
float reverseTranslate = gstate_c.vpZOffset * 0.5f + 0.5f;
if (viewZScale != 0.0) {
viewZInvScale = 1.0f / viewZScale;
} else {
viewZInvScale = 0.0;
}
float data[4] = { viewZScale, viewZCenter, viewZCenter, viewZInvScale };
float data[4] = { viewZScale, viewZCenter, reverseTranslate, reverseScale };
VSSetFloatUniform4(CONST_VS_DEPTHRANGE, data);
}
if (dirtyUniforms & DIRTY_CULLRANGE) {
+1 -1
View File
@@ -183,7 +183,7 @@ DepalShader *DepalShaderCacheGLES::GetDepalettizeShader(uint32_t clutMode, GEBuf
std::vector<GLRShader *> shaders{ vertexShader_, fragShader };
GLRProgram *program = render_->CreateProgram(shaders, semantics, queries, initializer, false);
GLRProgram *program = render_->CreateProgram(shaders, semantics, queries, initializer, false, false);
depal->program = program;
depal->fragShader = fragShader;
+1 -1
View File
@@ -116,7 +116,7 @@ void FramebufferManagerGLES::PackDepthbuffer(VirtualFramebuffer *vfb, int x, int
queries.push_back({ &u_depthDownloadTo8, "u_depthTo8" });
std::vector<GLRProgram::Initializer> inits;
inits.push_back({ &u_depthDownloadTex, 0, TEX_SLOT_PSP_TEXTURE });
depthDownloadProgram_ = render_->CreateProgram(shaders, semantics, queries, inits, false);
depthDownloadProgram_ = render_->CreateProgram(shaders, semantics, queries, inits, false, false);
for (auto iter : shaders) {
render_->DeleteShader(iter);
}
+1 -1
View File
@@ -87,7 +87,7 @@ void FramebufferManagerGLES::CompileDraw2DProgram() {
std::vector<GLRProgram::Semantic> semantics;
semantics.push_back({ 0, "a_position" });
semantics.push_back({ 1, "a_texcoord0" });
draw2dprogram_ = render_->CreateProgram(shaders, semantics, queries, initializers, false);
draw2dprogram_ = render_->CreateProgram(shaders, semantics, queries, initializers, false, false);
for (auto shader : shaders)
render_->DeleteShader(shader);
}
+4
View File
@@ -228,6 +228,10 @@ void GPU_GLES::CheckGPUFeatures() {
if (gl_extensions.GLES3)
features |= GPU_SUPPORTS_DEPTH_TEXTURE;
}
if (draw_->GetDeviceCaps().clipDistanceSupported)
features |= GPU_SUPPORTS_CLIP_DISTANCE;
if (draw_->GetDeviceCaps().cullDistanceSupported)
features |= GPU_SUPPORTS_CULL_DISTANCE;
// If we already have a 16-bit depth buffer, we don't need to round.
bool prefer24 = draw_->GetDeviceCaps().preferredDepthBufferFormat == Draw::DataFormat::D24_S8;
+13 -15
View File
@@ -51,10 +51,10 @@
using namespace Lin;
Shader::Shader(GLRenderManager *render, const char *code, const std::string &desc, uint32_t glShaderType, bool useHWTransform, uint32_t attrMask, uint64_t uniformMask)
: render_(render), failed_(false), useHWTransform_(useHWTransform), attrMask_(attrMask), uniformMask_(uniformMask) {
Shader::Shader(GLRenderManager *render, const char *code, const std::string &desc, const ShaderDescGLES &params)
: render_(render), useHWTransform_(params.useHWTransform), attrMask_(params.attrMask), uniformMask_(params.uniformMask) {
PROFILE_THIS_SCOPE("shadercomp");
isFragment_ = glShaderType == GL_FRAGMENT_SHADER;
isFragment_ = params.glShaderType == GL_FRAGMENT_SHADER;
source_ = code;
#ifdef SHADERLOG
#ifdef _WIN32
@@ -63,7 +63,7 @@ Shader::Shader(GLRenderManager *render, const char *code, const std::string &des
printf("%s\n", code);
#endif
#endif
shader = render->CreateShader(glShaderType, source_, desc);
shader = render->CreateShader(params.glShaderType, source_, desc);
}
Shader::~Shader() {
@@ -182,7 +182,9 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs,
initialize.push_back({ &u_tess_weights_u, 0, 5 });
initialize.push_back({ &u_tess_weights_v, 0, 6 });
program = render->CreateProgram(shaders, semantics, queries, initialize, gstate_c.featureFlags & GPU_SUPPORTS_DUALSOURCE_BLEND);
bool useDualSource = (gstate_c.featureFlags & GPU_SUPPORTS_DUALSOURCE_BLEND) != 0;
bool useClip0 = VSID.Bit(VS_BIT_VERTEX_RANGE_CULLING) && gstate_c.Supports(GPU_SUPPORTS_CLIP_DISTANCE);
program = render->CreateProgram(shaders, semantics, queries, initialize, useDualSource, useClip0);
// The rest, use the "dirty" mechanism.
dirtyUniforms = DIRTY_ALL_UNIFORMS;
@@ -476,14 +478,7 @@ void LinkedShader::UpdateUniforms(u32 vertType, const ShaderID &vsid, bool useBu
viewZCenter = vpZCenter;
}
float viewZInvScale;
if (viewZScale != 0.0) {
viewZInvScale = 1.0f / viewZScale;
} else {
viewZInvScale = 0.0;
}
float data[4] = { viewZScale, viewZCenter, viewZCenter, viewZInvScale };
float data[4] = { viewZScale, viewZCenter, gstate_c.vpZOffset, 1.0f / gstate_c.vpDepthScale };
SetFloatUniform4(render_, &u_depthRange, data);
}
if (dirty & DIRTY_CULLRANGE) {
@@ -640,7 +635,8 @@ Shader *ShaderManagerGLES::CompileFragmentShader(FShaderID FSID) {
return nullptr;
}
std::string desc = FragmentShaderDesc(FSID);
return new Shader(render_, codeBuffer_, desc, GL_FRAGMENT_SHADER, false, 0, uniformMask);
ShaderDescGLES params{ GL_FRAGMENT_SHADER, 0, uniformMask };
return new Shader(render_, codeBuffer_, desc, params);
}
Shader *ShaderManagerGLES::CompileVertexShader(VShaderID VSID) {
@@ -653,7 +649,9 @@ Shader *ShaderManagerGLES::CompileVertexShader(VShaderID VSID) {
return nullptr;
}
std::string desc = VertexShaderDesc(VSID);
return new Shader(render_, codeBuffer_, desc, GL_VERTEX_SHADER, useHWTransform, attrMask, uniformMask);
ShaderDescGLES params{ GL_VERTEX_SHADER, attrMask, uniformMask };
params.useHWTransform = useHWTransform;
return new Shader(render_, codeBuffer_, desc, params);
}
Shader *ShaderManagerGLES::ApplyVertexShader(bool useHWTransform, bool useHWTessellation, u32 vertType, bool weightsAsFloat, VShaderID *VSID) {
+9 -2
View File
@@ -114,9 +114,16 @@ public:
// Real public interface
struct ShaderDescGLES {
uint32_t glShaderType;
uint32_t attrMask;
uint64_t uniformMask;
bool useHWTransform;
};
class Shader {
public:
Shader(GLRenderManager *render, const char *code, const std::string &desc, uint32_t glShaderType, bool useHWTransform, uint32_t attrMask, uint64_t uniformMask);
Shader(GLRenderManager *render, const char *code, const std::string &desc, const ShaderDescGLES &params);
~Shader();
GLRShader *shader;
@@ -131,7 +138,7 @@ public:
private:
GLRenderManager *render_;
std::string source_;
bool failed_;
bool failed_ = false;
bool useHWTransform_;
bool isFragment_;
uint32_t attrMask_; // only used in vertex shaders
+1 -1
View File
@@ -147,7 +147,7 @@ bool FramebufferManagerGLES::NotifyStencilUpload(u32 addr, int size, StencilUplo
queries.push_back({ &u_stencilValue, "u_stencilValue" });
std::vector<GLRProgram::Initializer> inits;
inits.push_back({ &u_stencilUploadTex, 0, TEX_SLOT_PSP_TEXTURE });
stencilUploadProgram_ = render_->CreateProgram(shaders, semantics, queries, inits, false);
stencilUploadProgram_ = render_->CreateProgram(shaders, semantics, queries, inits, false, false);
for (auto iter : shaders) {
render_->DeleteShader(iter);
}
+3 -3
View File
@@ -482,7 +482,7 @@ enum {
GPU_SUPPORTS_32BIT_INT_FSHADER = FLAG_BIT(15),
GPU_SUPPORTS_DEPTH_TEXTURE = FLAG_BIT(16),
GPU_SUPPORTS_ACCURATE_DEPTH = FLAG_BIT(17),
// Free bit: 18,
// Free bit: 18
GPU_SUPPORTS_COPY_IMAGE = FLAG_BIT(19),
GPU_SUPPORTS_ANY_FRAMEBUFFER_FETCH = FLAG_BIT(20),
GPU_SCALE_DEPTH_FROM_24BIT_TO_16BIT = FLAG_BIT(21),
@@ -492,8 +492,8 @@ enum {
GPU_SUPPORTS_FRAMEBUFFER_BLIT = FLAG_BIT(26),
GPU_SUPPORTS_FRAMEBUFFER_BLIT_TO_DEPTH = FLAG_BIT(27),
GPU_SUPPORTS_TEXTURE_NPOT = FLAG_BIT(28),
GPU_NEEDS_Z_EQUAL_W_HACK = FLAG_BIT(29),
// Free bit: 30
GPU_SUPPORTS_CLIP_DISTANCE = FLAG_BIT(29),
GPU_SUPPORTS_CULL_DISTANCE = FLAG_BIT(30),
GPU_PREFER_REVERSE_COLOR_ORDER = FLAG_BIT(31),
};
+13 -9
View File
@@ -206,10 +206,6 @@ void GPU_Vulkan::CheckGPUFeatures() {
if (!PSP_CoreParameter().compat.flags().DisableAccurateDepth || driverTooOld) {
features |= GPU_SUPPORTS_ACCURATE_DEPTH;
}
// These GPUs (up to some certain hardware version?) has a bug where draws where gl_Position.w == .z
// corrupt the depth buffer. This is easily worked around by simply scaling Z down a tiny bit when this case
// is detected. See: https://github.com/hrydgard/ppsspp/issues/11937
features |= GPU_NEEDS_Z_EQUAL_W_HACK;
break;
}
default:
@@ -238,21 +234,29 @@ void GPU_Vulkan::CheckGPUFeatures() {
features |= GPU_SUPPORTS_FRAMEBUFFER_BLIT_TO_DEPTH;
}
if (vulkan_->GetDeviceFeatures().enabled.wideLines) {
auto &enabledFeatures = vulkan_->GetDeviceFeatures().enabled;
if (enabledFeatures.wideLines) {
features |= GPU_SUPPORTS_WIDE_LINES;
}
if (vulkan_->GetDeviceFeatures().enabled.depthClamp) {
if (enabledFeatures.depthClamp) {
features |= GPU_SUPPORTS_DEPTH_CLAMP;
}
if (vulkan_->GetDeviceFeatures().enabled.dualSrcBlend) {
if (enabledFeatures.shaderClipDistance) {
features |= GPU_SUPPORTS_CLIP_DISTANCE;
}
if (enabledFeatures.shaderCullDistance) {
// Must support at least 8 if feature supported, so we're fine.
features |= GPU_SUPPORTS_CULL_DISTANCE;
}
if (enabledFeatures.dualSrcBlend) {
if (!g_Config.bVendorBugChecksEnabled || !draw_->GetBugs().Has(Draw::Bugs::DUAL_SOURCE_BLENDING_BROKEN)) {
features |= GPU_SUPPORTS_DUALSOURCE_BLEND;
}
}
if (vulkan_->GetDeviceFeatures().enabled.logicOp) {
if (enabledFeatures.logicOp) {
features |= GPU_SUPPORTS_LOGIC_OP;
}
if (vulkan_->GetDeviceFeatures().enabled.samplerAnisotropy) {
if (enabledFeatures.samplerAnisotropy) {
features |= GPU_SUPPORTS_ANISOTROPY;
}