First reasonable output appears.

This commit is contained in:
Henrik Rydgård committed 2026-01-11 20:26:49 +01:00
1 parent 4d8b8dd743
commit e027407900
9 files changed
+136 -255

No files matched your search

+19 -157
View File
@@ -637,165 +637,27 @@ void ConvertViewportAndScissor(const DisplayLayoutConfig &config, bool useBuffer
DepthScaleFactors depthScale = GetDepthScaleFactors(gstate_c.UseFlags());
if (out.throughMode) {
// If renderX/renderY are offset to compensate for a split framebuffer,
// applying the offset to the viewport isn't enough, since the viewport clips.
// We need to apply either directly to the vertices, or to the "through" projection matrix.
out.viewportX = displayOffsetX;
out.viewportY = displayOffsetY;
out.viewportW = curRTWidth * renderWidthFactor;
out.viewportH = curRTHeight * renderHeightFactor;
out.depthRangeMin = depthScale.EncodeFromU16(0.0f);
out.depthRangeMax = depthScale.EncodeFromU16(65536.0f);
} else {
// These we can turn into a glViewport call, offset by offsetX and offsetY. Math after.
float vpXScale = gstate.getViewportXScale();
float vpXCenter = gstate.getViewportXCenter();
float vpYScale = gstate.getViewportYScale();
float vpYCenter = gstate.getViewportYCenter();
// If renderX/renderY are offset to compensate for a split framebuffer,
// applying the offset to the viewport isn't enough, since the viewport clips.
// We need to apply either directly to the vertices, or to the "through" projection matrix.
out.viewportX = displayOffsetX;
out.viewportY = displayOffsetY;
out.viewportW = curRTWidth * renderWidthFactor;
out.viewportH = curRTHeight * renderHeightFactor;
// TODO: This clip the entire draw if minz > maxz.
float minz = gstate.getDepthRangeMin();
float maxz = gstate.getDepthRangeMax();
// The viewport transform appears to go like this:
// Xscreen = -offsetX + vpXCenter + vpXScale * Xview
// Yscreen = -offsetY + vpYCenter + vpYScale * Yview
// Zscreen = vpZCenter + vpZScale * Zview
out.depthRangeMin = depthScale.EncodeFromU16(minz);
out.depthRangeMax = depthScale.EncodeFromU16(maxz);
// The viewport is normally centered at 2048,2048 but can also be centered at other locations.
// Offset is subtracted from the viewport center and is also set to values in those ranges, and is set so that the viewport will cover
// the desired screen area ([0-480)x[0-272)), so 1808,1912.
// This means that to get the analogue glViewport we must:
float vpX0 = vpXCenter - offsetX - fabsf(vpXScale);
float vpY0 = vpYCenter - offsetY - fabsf(vpYScale);
gstate_c.vpWidth = vpXScale * 2.0f;
gstate_c.vpHeight = vpYScale * 2.0f;
float vpWidth = fabsf(gstate_c.vpWidth);
float vpHeight = fabsf(gstate_c.vpHeight);
float left = renderX + vpX0;
float top = renderY + vpY0;
float right = left + vpWidth;
float bottom = top + vpHeight;
out.widthScale = 1.0f;
out.xOffset = 0.0f;
out.heightScale = 1.0f;
out.yOffset = 0.0f;
// If we're within the bounds, we want clipping the viewport way. So leave it be.
{
float overageLeft = std::max(-left, 0.0f);
float overageRight = std::max(right - bufferWidth, 0.0f);
// Expand viewport to cover scissor region. The viewport doesn't clip on the PSP.
if (right < scissorX2) {
overageRight -= scissorX2 - right;
}
if (left > scissorX1) {
overageLeft += scissorX1 - left;
}
// Our center drifted by the difference in overages.
float drift = overageRight - overageLeft;
if (overageLeft != 0.0f || overageRight != 0.0f) {
left += overageLeft;
right -= overageRight;
// Protect against the viewport being entirely outside the scissor.
// Emit a tiny but valid viewport. Really, we should probably emit a flag to ignore draws.
if (right <= left) {
right = left + 1.0f;
}
out.widthScale = vpWidth / (right - left);
out.xOffset = drift / (right - left);
}
}
{
float overageTop = std::max(-top, 0.0f);
float overageBottom = std::max(bottom - bufferHeight, 0.0f);
// Expand viewport to cover scissor region. The viewport doesn't clip on the PSP.
if (bottom < scissorY2) {
overageBottom -= scissorY2 - bottom;
}
if (top > scissorY1) {
overageTop += scissorY1 - top;
}
// Our center drifted by the difference in overages.
float drift = overageBottom - overageTop;
if (overageTop != 0.0f || overageBottom != 0.0f) {
top += overageTop;
bottom -= overageBottom;
// Protect against the viewport being entirely outside the scissor.
// Emit a tiny but valid viewport. Really, we should probably emit a flag to ignore draws.
if (bottom <= top) {
bottom = top + 1.0f;
}
out.heightScale = vpHeight / (bottom - top);
out.yOffset = drift / (bottom - top);
}
}
out.viewportX = left * renderWidthFactor + displayOffsetX;
out.viewportY = top * renderHeightFactor + displayOffsetY;
out.viewportW = (right - left) * renderWidthFactor;
out.viewportH = (bottom - top) * renderHeightFactor;
// The depth viewport parameters are the same, but we handle it a bit differently.
// When clipping is enabled, depth is clamped to [0, 65535]. And minz/maxz discard.
// So, we apply the depth range as minz/maxz, and transform for the viewport.
float vpZScale = gstate.getViewportZScale();
float vpZCenter = gstate.getViewportZCenter();
// TODO: This clip the entire draw if minz > maxz.
float minz = gstate.getDepthRangeMin();
float maxz = gstate.getDepthRangeMax();
if (gstate.isDepthClampEnabled() && (minz == 0 || maxz == 65535)) {
// Here, we should "clamp." But clamping per fragment would be slow.
// So, instead, we just increase the available range and hope.
// If depthSliceFactor is 4, it means (75% / 2) of the depth lies in each direction.
float fullDepthRange = 65535.0f * (depthScale.Scale() - 1.0f) * (1.0f / 2.0f);
if (minz == 0) {
minz -= fullDepthRange;
}
if (maxz == 65535) {
maxz += fullDepthRange;
}
} else if (maxz == 65535) {
// This means clamp isn't enabled, but we still want to allow values up to 65535.99.
// If DepthSliceFactor() is 1.0, though, this would make out.depthRangeMax exceed 1.
// Since that would clamp, it would make Z=1234 not match between draws when maxz changes.
if (depthScale.Scale() > 1.0f)
maxz = 65535.99f;
}
// Okay. So, in our shader, -1 will map to minz, and +1 will map to maxz.
float halfActualZRange = (maxz - minz) * (1.0f / 2.0f);
out.depthScale = halfActualZRange < std::numeric_limits<float>::epsilon() ? 1.0f : vpZScale / halfActualZRange;
// This adjusts the center from halfActualZRange to vpZCenter.
out.zOffset = halfActualZRange < std::numeric_limits<float>::epsilon() ? 0.0f : (vpZCenter - (minz + halfActualZRange)) / halfActualZRange;
if (!gstate_c.Use(GPU_USE_ACCURATE_DEPTH)) {
out.depthScale = 1.0f;
out.zOffset = 0.0f;
out.depthRangeMin = depthScale.EncodeFromU16(vpZCenter - vpZScale);
out.depthRangeMax = depthScale.EncodeFromU16(vpZCenter + vpZScale);
} else {
out.depthRangeMin = depthScale.EncodeFromU16(minz);
out.depthRangeMax = depthScale.EncodeFromU16(maxz);
}
// OpenGL will clamp these for us anyway, and Direct3D will error if not clamped.
// Of course, if this happens we've skewed out.depthScale/out.zOffset and may get z-fighting.
out.depthRangeMin = std::max(out.depthRangeMin, 0.0f);
out.depthRangeMax = std::min(out.depthRangeMax, 1.0f);
}
// Not really using these now.
out.widthScale = 1.0f;
out.heightScale = 1.0f;
out.depthScale = 1.0f;
out.zOffset = 0.0f;
out.xOffset = 0.0f;
out.yOffset = 0.0f;
}
void UpdateCachedViewportState(const ViewportAndScissor &vpAndScissor) {
+7 -2
View File
@@ -70,6 +70,9 @@ enum : uint64_t {
DIRTY_UVSCALEOFFSET = 1ULL << 18,
DIRTY_DEPTHRANGE = 1ULL << 19,
DIRTY_VIEWPORT_UNIFORMS = 1ULL << 20,
// Free bit 20!
DIRTY_WORLDMATRIX = 1ULL << 21,
DIRTY_VIEWMATRIX = 1ULL << 22,
DIRTY_TEXMATRIX = 1ULL << 23,
@@ -93,12 +96,14 @@ enum : uint64_t {
DIRTY_LIGHT_CONTROL = 1ULL << 38,
DIRTY_TEX_ALPHA_MUL = 1ULL << 39,
// Bits 40-42 are free for new uniforms. Then we're really out and need to start merging.
DIRTY_RASTER_OFFSET = 1ULL << 40,
// Bits 41-42 are free for new uniforms (although the mask below needs updating). Then we're really out and need to start merging.
// Don't forget to update DIRTY_ALL_UNIFORMS when you start using them.
DIRTY_BONE_UNIFORMS = 0xFF000000ULL,
DIRTY_ALL_UNIFORMS = 0x0FFFFFFFFFFULL,
DIRTY_ALL_UNIFORMS = 0x1FFFFFFFFFFULL,
// Other dirty elements that aren't uniforms
DIRTY_CULL_PLANES = 1ULL << 43,
+19 -32
View File
@@ -14,18 +14,6 @@
using namespace Lin;
static void ConvertProjMatrixToVulkan(Matrix4x4 &in) {
const Vec3 trans(gstate_c.vpXOffset, gstate_c.vpYOffset, gstate_c.vpZOffset * 0.5f + 0.5f);
const Vec3 scale(gstate_c.vpWidthScale, gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f);
in.translateAndScale(trans, scale);
}
static void ConvertProjMatrixToD3D11(Matrix4x4 &in) {
const Vec3 trans(gstate_c.vpXOffset, -gstate_c.vpYOffset, gstate_c.vpZOffset * 0.5f + 0.5f);
const Vec3 scale(gstate_c.vpWidthScale, -gstate_c.vpHeightScale, gstate_c.vpDepthScale * 0.5f);
in.translateAndScale(trans, scale);
}
void CalcCullRange(float minValues[4], float maxValues[4], bool flipViewport, bool hasNegZ) {
// Account for the projection viewport adjustment when viewport is too large.
auto reverseViewportX = [](float x) {
@@ -115,28 +103,12 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView
Matrix4x4 flippedMatrix;
memcpy(&flippedMatrix, gstate.projMatrix, 16 * sizeof(float));
const bool invertedY = gstate_c.vpHeight < 0;
if (invertedY) {
flippedMatrix[1] = -flippedMatrix[1];
flippedMatrix[5] = -flippedMatrix[5];
flippedMatrix[9] = -flippedMatrix[9];
flippedMatrix[13] = -flippedMatrix[13];
}
const bool invertedX = gstate_c.vpWidth < 0;
if (invertedX) {
flippedMatrix[0] = -flippedMatrix[0];
flippedMatrix[4] = -flippedMatrix[4];
flippedMatrix[8] = -flippedMatrix[8];
flippedMatrix[12] = -flippedMatrix[12];
}
if (flipViewport) {
ConvertProjMatrixToD3D11(flippedMatrix);
} else {
ConvertProjMatrixToVulkan(flippedMatrix);
}
// TODO: Flip something for D3D11.
if (!useBufferedRendering && g_display.rotation != DisplayRotation::ROTATE_0) {
flippedMatrix = flippedMatrix * g_display.rot_matrix;
// TODO: We have to apply the rotation some other way now that we've moved the viewport
// into the vertex shader.
// flippedMatrix = flippedMatrix * g_display.rot_matrix;
}
CopyMatrix4x4(ub->proj, flippedMatrix.getReadPtr());
@@ -153,6 +125,21 @@ void BaseUpdateUniforms(UB_VS_FS_Base *ub, uint64_t dirtyUniforms, bool flipView
CopyFloat4(ub->xywh, xywh);
}
if (dirtyUniforms & DIRTY_RASTER_OFFSET) {
ub->rasterOffset[0] = gstate.getOffsetX();
ub->rasterOffset[1] = gstate.getOffsetY();
}
if (dirtyUniforms & DIRTY_VIEWPORT_UNIFORMS) {
// TODO: This should be a couple of SIMD instructions.
ub->vpScale[0] = gstate.getViewportXScale();
ub->vpScale[1] = gstate.getViewportYScale();
ub->vpScale[2] = gstate.getViewportZScale();
ub->vpOffset[0] = gstate.getViewportXCenter();
ub->vpOffset[1] = gstate.getViewportYCenter();
ub->vpOffset[2] = gstate.getViewportZCenter();
}
// Transform
if (dirtyUniforms & DIRTY_WORLDMATRIX) {
ConvertMatrix4x3To3x4Transposed(ub->world, gstate.worldMatrix);
+13 -5
View File
@@ -11,20 +11,23 @@ enum : uint64_t {
DIRTY_WORLDMATRIX | DIRTY_PROJTHROUGHMATRIX | DIRTY_VIEWMATRIX | DIRTY_TEXMATRIX | DIRTY_ALPHACOLORREF |
DIRTY_PROJMATRIX | DIRTY_FOGCOLOR | DIRTY_FOGCOEF | DIRTY_TEXENV | DIRTY_TEX_ALPHA_MUL | DIRTY_STENCILREPLACEVALUE |
DIRTY_ALPHACOLORMASK | DIRTY_SHADERBLEND | DIRTY_COLORWRITEMASK | DIRTY_UVSCALEOFFSET | DIRTY_TEXCLAMP | DIRTY_DEPTHRANGE | DIRTY_MATAMBIENTALPHA |
DIRTY_BEZIERSPLINE | DIRTY_DEPAL,
DIRTY_BEZIERSPLINE | DIRTY_DEPAL | DIRTY_VIEWPORT_UNIFORMS | DIRTY_RASTER_OFFSET,
DIRTY_LIGHT_UNIFORMS =
DIRTY_LIGHT_CONTROL | DIRTY_LIGHT0 | DIRTY_LIGHT1 | DIRTY_LIGHT2 | DIRTY_LIGHT3 |
DIRTY_MATDIFFUSE | DIRTY_MATSPECULAR | DIRTY_MATEMISSIVE | DIRTY_AMBIENT,
};
// Currently 496 bytes.
// Currently 480 bytes.
// Every line here is a 4-float.
struct alignas(16) UB_VS_FS_Base {
float proj[16];
float xywh[4]; // replacement for the old proj_through
float view[12];
float world[12];
float tex[12];
float xywh[4]; // replacement for the old proj_through
float vpScale[3]; float padding1;
float vpOffset[3]; float padding2;
float rasterOffset[2]; float padding3[2];
float uvScaleOffset[4];
float depthRange[4];
float matAmbient[4];
@@ -33,7 +36,7 @@ struct alignas(16) UB_VS_FS_Base {
uint32_t spline_counts; uint32_t depal_mask_shift_off_fmt; // 4 params packed into one.
uint32_t colorWriteMask; float mipBias;
// Fragment data
float texNoAlpha; float texMul; float padding[2]; // this vec4 will hold ubershader stuff. We won't use integer flags in the fragment shader.
float texNoAlpha; float texMul; float padding4[2]; // this vec4 will hold ubershader stuff. We won't use integer flags in the fragment shader.
float fogColor[3]; uint32_t alphaColorRef;
float texEnvColor[3]; uint32_t colorTestMask;
float texClamp[4];
@@ -44,12 +47,17 @@ struct alignas(16) UB_VS_FS_Base {
// with just uploading the first 448 bytes of the struct (up to and including fogCoef).
};
static_assert(sizeof(UB_VS_FS_Base) == 480);
static const char * const ub_baseStr =
R"( mat4 u_proj;
vec4 u_xywh;
mat3x4 u_view;
mat3x4 u_world;
mat3x4 u_texmtx;
vec4 u_xywh;
vec4 u_vpScale; // w = offsetX
vec4 u_vpOffset; // w = offsetY
vec2 u_rasterOffset; vec2 pad0;
vec4 u_uvscaleoffset;
vec4 u_depthRange;
vec4 u_matambientalpha;
+5 -5
View File
@@ -567,15 +567,15 @@ void SoftwareTransform::BuildDrawingParams(int prim, int vertexCount, u32 vertTy
void SoftwareTransform::CalcCullParams(float &minZValue, float &maxZValue) const {
// The projected Z can be up to 0x3F8000FF, which is where this constant is from.
// It seems like it may only maintain 15 mantissa bits (excluding implied.)
maxZValue = 1.000030517578125f * gstate_c.vpDepthScale;
maxZValue = 1.000030517578125f * gstate.getViewportZScale();
minZValue = -maxZValue;
// Scale and offset the Z appropriately, since we baked that into a projection transform.
if (params_.usesHalfZ) {
maxZValue = maxZValue * 0.5f + 0.5f + gstate_c.vpZOffset * 0.5f;
minZValue = minZValue * 0.5f + 0.5f + gstate_c.vpZOffset * 0.5f;
maxZValue = maxZValue * 0.5f + 0.5f + gstate.getViewportZCenter() * 0.5f;
minZValue = minZValue * 0.5f + 0.5f + gstate.getViewportZCenter() * 0.5f;
} else {
maxZValue += gstate_c.vpZOffset;
minZValue += gstate_c.vpZOffset;
maxZValue += gstate.getViewportZCenter();
minZValue += gstate.getViewportZCenter();
}
// In case scale was negative, flip.
if (minZValue > maxZValue)
+57 -44
View File
@@ -747,11 +747,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
WRITE(p, " %sv_fogdepth = fog;\n", compat.vsOutPrefix);
if (isModeThrough) {
// The proj_through matrix already has the rotation, if needed.
WRITE(p, " vec4 outPos;\n");
WRITE(p, " outPos.x = ((position.x - u_xywh.x) / u_xywh.z) * 2.0 - 1.0;");
WRITE(p, " outPos.y = ((position.y - u_xywh.y) / u_xywh.w) * 2.0 - 1.0;");
WRITE(p, " outPos.z = position.z;\n");
WRITE(p, " outPos.w = 1.0;\n");
WRITE(p, " vec4 outPos = vec4(position.x, position.y, position.z, 1.0);\n");
} else {
if (compat.shaderLanguage == GLSL_VULKAN) {
// Apply rotation from the uniform.
@@ -772,6 +768,10 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
} else {
WRITE(p, " vec4 outPos = pos;\n");
}
// Here we need to apply the viewport and also range culling, just like with the hardware transform below.
}
} else {
// Step 1: World Transform / Skinning
@@ -866,6 +866,54 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
}
}
// Perform the perspective projection and viewport transform.
WRITE(p, " outPos.xyz = (outPos.xyz / outPos.w) * u_vpScale.xyz + u_vpOffset.xyz;\n");
// We leave W as is to preserve the perspective correct interpolation.
if (vertexRangeCulling) {
// Position is now already projected here.
WRITE(p, " vec3 projPos = outPos.xyz;\n");
WRITE(p, " float projZ = (projPos.z - u_depthRange.z) * u_depthRange.w;\n");
if (!bugs.Has(Draw::Bugs::BROKEN_NAN_IN_CONDITIONAL)) {
// 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 < 0.0 || projPos.y < 0.0";
const char *outMax = "projPos.x > 4096.0 || projPos.y > 4096.0";
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 *cull0 = compat.shaderLanguage == HLSL_D3D11 ? ".x" : "[0]";
const char *cull1 = compat.shaderLanguage == HLSL_D3D11 ? ".y" : "[1]";
if (gstate_c.Use(GPU_USE_CLIP_DISTANCE)) {
// TODO: Ignore triangles from GE_PRIM_RECTANGLES in transform mode, which should not clip to neg z.
// We add a small amount to prevent errors as in #15816 (PSP Z is only 16-bit fixed point, anyway.)
WRITE(p, " %sgl_ClipDistance%s = projZ * outPos.w + outPos.w + %f;\n", compat.vsOutPrefix, vertexRangeClipSuffix, 0.0625 / 65536.0);
}
if (gstate_c.Use(GPU_USE_CULL_DISTANCE)) {
// Cull any triangle fully outside in the same direction when depth clamp enabled.
// We check u_depthRange in case depthScale was zero - in that case we can't work out the cull distance.
WRITE(p, " if (u_cullRangeMin.w > 0.0 && u_depthRange.w != 0.0f) {\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, " } else {\n");
WRITE(p, " %sgl_CullDistance%s = 0.0;\n", compat.vsOutPrefix, cull0);
WRITE(p, " %sgl_CullDistance%s = 0.0;\n", compat.vsOutPrefix, cull1);
WRITE(p, " }\n");
}
}
// Apply raster offset after the range culling.
WRITE(p, " outPos.xy -= u_rasterOffset.xy;\n");
// TODO: Declare variables for dots for shade mapping if needed.
const char *srcCol = "color0";
@@ -1230,45 +1278,10 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag
WRITE(p, " }\n");
}
if (vertexRangeCulling) {
WRITE(p, " vec3 projPos = outPos.xyz / outPos.w;\n");
WRITE(p, " float projZ = (projPos.z - u_depthRange.z) * u_depthRange.w;\n");
if (!bugs.Has(Draw::Bugs::BROKEN_NAN_IN_CONDITIONAL)) {
// 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 *cull0 = compat.shaderLanguage == HLSL_D3D11 ? ".x" : "[0]";
const char *cull1 = compat.shaderLanguage == HLSL_D3D11 ? ".y" : "[1]";
if (gstate_c.Use(GPU_USE_CLIP_DISTANCE)) {
// TODO: Ignore triangles from GE_PRIM_RECTANGLES in transform mode, which should not clip to neg z.
// We add a small amount to prevent error as in #15816 (PSP Z is only 16-bit fixed point, anyway.)
WRITE(p, " %sgl_ClipDistance%s = projZ * outPos.w + outPos.w + %f;\n", compat.vsOutPrefix, vertexRangeClipSuffix, 0.0625 / 65536.0);
}
if (gstate_c.Use(GPU_USE_CULL_DISTANCE)) {
// Cull any triangle fully outside in the same direction when depth clamp enabled.
// We check u_depthRange in case depthScale was zero - in that case we can't work out the cull distance.
WRITE(p, " if (u_cullRangeMin.w > 0.0 && u_depthRange.w != 0.0f) {\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, " } else {\n");
WRITE(p, " %sgl_CullDistance%s = 0.0;\n", compat.vsOutPrefix, cull0);
WRITE(p, " %sgl_CullDistance%s = 0.0;\n", compat.vsOutPrefix, cull1);
WRITE(p, " }\n");
}
}
// Convert to NDC space.
WRITE(p, " outPos.x = ((outPos.x - u_xywh.x) / u_xywh.z) * 2.0 - 1.0;\n");
WRITE(p, " outPos.y = ((outPos.y - u_xywh.y) / u_xywh.w) * 2.0 - 1.0;\n");
WRITE(p, " outPos.z = outPos.z / 65535.0;\n");
// We've named the output gl_Position in HLSL as well.
WRITE(p, " %sgl_Position = outPos;\n", compat.vsOutPrefix);
+2
View File
@@ -106,6 +106,8 @@ LinkedShader::LinkedShader(GLRenderManager *render, VShaderID VSID, Shader *vs,
queries.push_back({ &u_proj, "u_proj" });
queries.push_back({ &u_proj_lens, "u_proj_lens" });
queries.push_back({ &u_xywh, "u_xywh" });
queries.push_back({ &u_vpScale, "u_vpScale" });
queries.push_back({ &u_vpOffset, "u_vpOffset" });
queries.push_back({ &u_texenv, "u_texenv" });
queries.push_back({ &u_fogcolor, "u_fogcolor" });
queries.push_back({ &u_fogcoef, "u_fogcoef" });
+2
View File
@@ -61,6 +61,8 @@ public:
int u_proj;
int u_proj_lens;
int u_xywh;
int u_vpScale;
int u_vpOffset;
int u_texenv;
int u_view;
int u_texmtx;
+12 -10
View File
@@ -191,19 +191,19 @@ const CommonCommandTableEntry commonCommandTable[] = {
{ GE_CMD_ANTIALIASENABLE, FLAG_FLUSHBEFOREONCHANGE },
// Viewport.
{ GE_CMD_OFFSETX, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE | DIRTY_CULL_PLANES },
{ GE_CMD_OFFSETY, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE | DIRTY_CULL_PLANES },
{ GE_CMD_VIEWPORTXSCALE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULL_PLANES },
{ GE_CMD_VIEWPORTYSCALE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULL_PLANES },
{ GE_CMD_VIEWPORTXCENTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULL_PLANES },
{ GE_CMD_VIEWPORTYCENTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULL_PLANES },
{ GE_CMD_VIEWPORTZSCALE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_DEPTHRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE },
{ GE_CMD_VIEWPORTZCENTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_DEPTHRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE },
{ GE_CMD_OFFSETX, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE | DIRTY_CULL_PLANES | DIRTY_RASTER_OFFSET },
{ GE_CMD_OFFSETY, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE | DIRTY_CULL_PLANES | DIRTY_RASTER_OFFSET },
{ GE_CMD_VIEWPORTXSCALE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULL_PLANES | DIRTY_VIEWPORT_UNIFORMS },
{ GE_CMD_VIEWPORTYSCALE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULL_PLANES | DIRTY_VIEWPORT_UNIFORMS },
{ GE_CMD_VIEWPORTXCENTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULL_PLANES | DIRTY_VIEWPORT_UNIFORMS },
{ GE_CMD_VIEWPORTYCENTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULL_PLANES | DIRTY_VIEWPORT_UNIFORMS },
{ GE_CMD_VIEWPORTZSCALE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VIEWPORT_UNIFORMS },
{ GE_CMD_VIEWPORTZCENTER, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_CULLRANGE | DIRTY_PROJMATRIX | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_VIEWPORT_UNIFORMS },
{ GE_CMD_DEPTHCLAMPENABLE, FLAG_FLUSHBEFOREONCHANGE, DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE | DIRTY_RASTER_STATE },
// Z clip
{ GE_CMD_MINZ, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHRANGE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE },
{ GE_CMD_MAXZ, FLAG_FLUSHBEFOREONCHANGE, DIRTY_DEPTHRANGE | DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE },
{ GE_CMD_MINZ, FLAG_FLUSHBEFOREONCHANGE, DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE | DIRTY_DEPTHRANGE },
{ GE_CMD_MAXZ, FLAG_FLUSHBEFOREONCHANGE, DIRTY_RASTER_STATE | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE | DIRTY_DEPTHRANGE },
// Region
{ GE_CMD_REGION1, FLAG_FLUSHBEFOREONCHANGE, DIRTY_FRAMEBUF | DIRTY_TEXTURE_PARAMS | DIRTY_VIEWPORTSCISSOR_STATE | DIRTY_CULLRANGE | DIRTY_CULL_PLANES },
@@ -592,6 +592,7 @@ u32 GPUCommonHW::CheckGPUFeatures() const {
features |= GPU_USE_BLEND_MINMAX;
}
/*
if (draw_->GetDeviceCaps().clipDistanceSupported) {
features |= GPU_USE_CLIP_DISTANCE;
}
@@ -599,6 +600,7 @@ u32 GPUCommonHW::CheckGPUFeatures() const {
if (draw_->GetDeviceCaps().cullDistanceSupported) {
features |= GPU_USE_CULL_DISTANCE;
}
*/
if (draw_->GetDeviceCaps().textureDepthSupported) {
features |= GPU_USE_DEPTH_TEXTURE;