mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-26 19:58:36 +01:00
First reasonable output appears.
This commit is contained in:
1 parent
4d8b8dd743
commit
e027407900
9 files changed
+136
-255
No files matched your search
+19
-157
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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" });
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user