D3D and OpenGL shader buildfixes

This commit is contained in:
Henrik Rydgård committed 2026-05-30 19:07:59 +02:00
1 parent 058b1af285
commit eaacbbc226
4 files changed
+48 -34

No files matched your search

+40 -34
View File
@@ -131,20 +131,29 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
bool highpFog = false;
bool highpTexcoord = false;
const bool isModeThrough = id.Bit(VS_BIT_IS_THROUGH);
const bool useHWTransform = id.Bit(VS_BIT_USE_HW_TRANSFORM);
const bool clipEnable = id.Bit(VS_BIT_CLIP_ENABLE) && !isModeThrough; // this is the PSP clip flag, which has some various consequences.
const bool clipNearPlane = gstate_c.Use(GPU_USE_CLIP_DISTANCE) && useHWTransform;
const bool clipMinMax = gstate_c.Use(GPU_USE_CLIP_DISTANCE); // If clip planes are available, we want to use them for min/max. We skip the min/max culling in software transform (not yet implemented).
const bool rangeCulling = id.Bit(VS_BIT_VERTEX_RANGE_CULLING);
const bool depthCullEnable = gstate_c.Use(GPU_USE_CULL_DISTANCE) && !isModeThrough && rangeCulling && useHWTransform; // Range culling is gated on draw type, we don't want to do this culling for splines apparently.
std::vector<const char*> extensions;
extensions.reserve(6);
if (ShaderLanguageIsOpenGL(compat.shaderLanguage)) {
if (gl_extensions.EXT_gpu_shader4) {
extensions.push_back("#extension GL_EXT_gpu_shader4 : enable");
}
bool useClamp = gstate_c.Use(GPU_USE_DEPTH_CLAMP) && !id.Bit(VS_BIT_IS_THROUGH);
if (gl_extensions.EXT_clip_cull_distance && (id.Bit(VS_BIT_VERTEX_RANGE_CULLING) || useClamp)) {
if (gl_extensions.EXT_clip_cull_distance && (depthCullEnable || clipMinMax || clipNearPlane)) {
extensions.push_back("#extension GL_EXT_clip_cull_distance : enable");
}
if (gl_extensions.APPLE_clip_distance && (id.Bit(VS_BIT_VERTEX_RANGE_CULLING) || useClamp)) {
if (gl_extensions.APPLE_clip_distance && (clipMinMax || clipNearPlane)) {
extensions.push_back("#extension GL_APPLE_clip_distance : enable");
}
if (gl_extensions.ARB_cull_distance && id.Bit(VS_BIT_VERTEX_RANGE_CULLING)) {
if (gl_extensions.ARB_cull_distance && depthCullEnable) {
extensions.push_back("#extension GL_ARB_cull_distance : enable");
}
}
@@ -163,7 +172,6 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
p.F("// %s\n", VertexShaderDesc(id).c_str());
bool isModeThrough = id.Bit(VS_BIT_IS_THROUGH);
bool lmode = id.Bit(VS_BIT_LMODE);
GETexMapMode uvGenMode = static_cast<GETexMapMode>(id.Bits(VS_BIT_UVGEN_MODE, 2));
@@ -179,7 +187,6 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
bool doFlatShading = id.Bit(VS_BIT_FLATSHADE) && !flatBug;
bool useHWTransform = id.Bit(VS_BIT_USE_HW_TRANSFORM);
bool hasColor = id.Bit(VS_BIT_HAS_COLOR) || !useHWTransform;
bool hasNormal = id.Bit(VS_BIT_HAS_NORMAL) && useHWTransform;
bool hasTexcoord = id.Bit(VS_BIT_HAS_TEXCOORD) || !useHWTransform;
@@ -238,13 +245,12 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
}
bool texCoordInVec3 = false;
const bool clipEnable = id.Bit(VS_BIT_CLIP_ENABLE) && !isModeThrough;
const bool rangeCulling = id.Bit(VS_BIT_VERTEX_RANGE_CULLING);
const bool depthCullEnable = gstate_c.Use(GPU_USE_CULL_DISTANCE) && !isModeThrough && rangeCulling; // Range culling is gated on draw type, we don't want to do this culling for splines apparently.
const char *minZClipPlaneSuffix = "[0]";
const char *maxZClipPlaneSuffix = "[1]";
const char *zClipPlaneSuffix = "[2]";
const char *zClipPlaneSuffix = "[0]";
const char *minZClipPlaneSuffix = "[1]";
const char *maxZClipPlaneSuffix = "[2]";
const char *cullDistanceNearSuffix = "[0]";
const char *cullDistanceFarSuffix = "[1]";
if (compat.shaderLanguage == GLSL_VULKAN) {
WRITE(p, "\n");
@@ -351,11 +357,15 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
WRITE(p, " float v_fogdepth : TEXCOORD1;\n");
WRITE(p, " vec4 gl_Position : SV_Position;\n");
zClipPlaneSuffix = ".x";
minZClipPlaneSuffix = ".y";
maxZClipPlaneSuffix = ".z";
if (!isModeThrough && gstate_c.Use(GPU_USE_CLIP_DISTANCE)) {
minZClipPlaneSuffix = ".x";
maxZClipPlaneSuffix = ".y";
zClipPlaneSuffix = ".z";
if (clipMinMax && clipNearPlane) {
WRITE(p, " float3 gl_ClipDistance : SV_ClipDistance;\n");
} else if (clipMinMax) {
WRITE(p, " float2 gl_ClipDistance : SV_ClipDistance;\n");
} else if (clipNearPlane) {
_dbg_assert_(false); // not an allowed combination
}
if (depthCullEnable) {
WRITE(p, " float2 gl_CullDistance : SV_CullDistance0;\n");
@@ -409,6 +419,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
}
WRITE(p, "uniform vec4 u_xywh;\n");
WRITE(p, "uniform float u_NaN;\n");
*uniformMask |= DIRTY_PROJTHROUGHMATRIX;
WRITE(p, "uniform vec2 u_minZmaxZ;\n");
@@ -829,15 +840,15 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
WRITE(p, " zClipped = true;\n");
WRITE(p, " }\n");
// Then we actually add the clip plane.
if (gstate_c.Use(GPU_USE_CLIP_DISTANCE)) {
if (clipNearPlane) {
WRITE(p, " %sgl_ClipDistance%s = outPos.z + outPos.w;\n", compat.vsOutPrefix, zClipPlaneSuffix);
}
if (depthCullEnable) {
// Before the viewport, discard any primitives that are fully outside the clipping volume in Z.
// NOTE: This volume is very slightly too small. It's unclear to me how to allow hex 0x3F8000XX (1.0000.. + epsilon) where XX are arbitrary.
WRITE(p, " %sgl_CullDistance[0] = outPos.z + outPos.w;\n", compat.vsOutPrefix);
WRITE(p, " %sgl_CullDistance[1] = outPos.w - outPos.z;\n", compat.vsOutPrefix);
WRITE(p, " %sgl_CullDistance%s = outPos.z + outPos.w;\n", compat.vsOutPrefix, cullDistanceNearSuffix);
WRITE(p, " %sgl_CullDistance%s = outPos.w - outPos.z;\n", compat.vsOutPrefix, cullDistanceFarSuffix);
}
// Perform the perspective projection and viewport transform. (We'll have to undo the division before passing the coordinate along).
@@ -1212,22 +1223,17 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
// Apply raster offset after the range culling.
WRITE(p, " outPos.xy -= u_rasterOffset.xy;\n");
}
if (gstate_c.Use(GPU_USE_CLIP_DISTANCE)) {
// We use clipping, where available, to implement min/max Z.
// 1.0 is used to disable the clip plane (should we generate more shaders instead? how costly are they?)
// Note: outPos.z need to be multiplied by outPos.w to undo the division, which shouldn't be in effect here.
// We should probably store the undivided outPos in a variable.
// We apply a small offset here, it's needed to break some ties, like in the map in Test Drive Unlimited.
WRITE(p, " %sgl_ClipDistance%s = u_minZmaxZ.x > 0.0 ? (outPos.z + 0.5 - u_minZmaxZ.x) * outPos.w : 1.0;\n", compat.vsOutPrefix, minZClipPlaneSuffix);
WRITE(p, " %sgl_ClipDistance%s = u_minZmaxZ.y < 65535.0 ? (u_minZmaxZ.y - (outPos.z + 0.5)) * outPos.w : 1.0;\n", compat.vsOutPrefix, maxZClipPlaneSuffix);
}
} else {
if (gstate_c.Use(GPU_USE_CLIP_DISTANCE)) {
// In through mode we output a dummy clip distance.
WRITE(p, " %sgl_ClipDistance%s = 1.0f;\n", compat.vsOutPrefix, minZClipPlaneSuffix);
WRITE(p, " %sgl_ClipDistance%s = 1.0f;\n", compat.vsOutPrefix, maxZClipPlaneSuffix);
}
// I think we should use min/max clipping for through-mode as well, right?
if (clipMinMax) {
// We use clipping, where available, to implement min/max Z.
// 1.0 is used to disable the clip plane (should we generate more shaders instead? how costly are they?)
// Note: outPos.z need to be multiplied by outPos.w to undo the division, which shouldn't be in effect here.
// We should probably store the undivided outPos in a variable.
// We apply a small offset here, it's needed to break some ties, like in the map in Test Drive Unlimited.
WRITE(p, " %sgl_ClipDistance%s = u_minZmaxZ.x > 0.0 ? (outPos.z + 0.5 - u_minZmaxZ.x) * outPos.w : 1.0;\n", compat.vsOutPrefix, minZClipPlaneSuffix);
WRITE(p, " %sgl_ClipDistance%s = u_minZmaxZ.y < 65535.0 ? (u_minZmaxZ.y - (outPos.z + 0.5)) * outPos.w : 1.0;\n", compat.vsOutPrefix, maxZClipPlaneSuffix);
}
// Convert to NDC space, using the framebuffer offset and size stored in u_xywh.
+6
View File
@@ -120,6 +120,7 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs,
queries.push_back({ &u_blendFixA, "u_blendFixA" });
queries.push_back({ &u_blendFixB, "u_blendFixB" });
queries.push_back({ &u_fbotexSize, "u_fbotexSize" });
queries.push_back({ &u_NaN, "u_NaN" });
// Transform
queries.push_back({ &u_view, "u_view" });
@@ -436,6 +437,8 @@ void LinkedShader::UpdateUniforms(const ShaderID &vsid, bool useBufferedRenderin
xywh[2] = (float)gstate_c.curRTWidth;
xywh[3] = (float)gstate_c.curRTHeight;
SetFloatUniform4(render_, &u_xywh, xywh);
float nan = std::numeric_limits<float>::quiet_NaN();
render_->SetUniformF1(&u_NaN, nan);
}
if (dirty & DIRTY_TEXENV) {
SetColorUniform3(render_, &u_texenv, gstate.texenvcolor);
@@ -1138,6 +1141,9 @@ void ShaderManagerGLES::SaveCache(const Path &filename, DrawEngineGLES *drawEngi
if (linkedShaderCache_.empty()) {
return;
}
// TODO: We shouldn't save the cache if we're just running a frame dump.
INFO_LOG(Log::G3D, "Saving the shader cache to '%s'", filename.c_str());
FILE *f = File::OpenCFile(filename, "wb");
if (!f) {
+1
View File
@@ -70,6 +70,7 @@ public:
int u_mipBias;
int u_scaleX;
int u_scaleY;
int u_NaN;
int u_rasterOffset;
int u_minZmaxZ;
+1
View File
@@ -142,6 +142,7 @@ struct GPUStatsPerFrame {
};
struct GPUStatsTotals {
// Flip count. Doesn't really belong here.
int numFlips;
};