Skip to content
Permalink
Browse files

Merge pull request #11287 from unknownbrackets/gpu-clipping

Improve clipping/culling handling in software renderer
  • Loading branch information...
hrydgard committed Aug 6, 2018
2 parents 96ff23a + 31d5c39 commit 945eab6fe59a22bc3b4e3c9ac7197ec1909158b4
@@ -676,7 +676,7 @@ void ConvertViewportAndScissor(bool useBufferedRendering, float renderWidth, flo
float minz = gstate.getDepthRangeMin();
float maxz = gstate.getDepthRangeMax();

if (gstate.isClippingEnabled() && (minz == 0 || maxz == 65535)) {
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.
@@ -58,7 +58,7 @@ struct GPUgstate {
region2,
lightingEnable,
lightEnable[4],
clipEnable,
depthClampEnable,
cullfaceEnable,
textureMapEnable, // 0x1E GE_CMD_TEXTUREMAPENABLE
fogEnable,
@@ -392,8 +392,9 @@ struct GPUgstate {
int getRegionX2() const { return (region2 & 0x3FF); }
int getRegionY2() const { return (region2 >> 10) & 0x3FF; }

bool isDepthClampEnabled() const { return depthClampEnable & 1; }

// Note that the X1/Y1/Z1 here does not mean the upper-left corner, but half the dimensions. X2/Y2/Z2 are the center.
bool isClippingEnabled() const { return clipEnable & 1; }
float getViewportXScale() const { return getFloat24(viewportxscale); }
float getViewportYScale() const { return getFloat24(viewportyscale); }
float getViewportZScale() const { return getFloat24(viewportzscale); }
@@ -39,6 +39,7 @@ enum {
static inline int CalcClipMask(const ClipCoords& v)
{
int mask = 0;
// This checks `x / w` compared to 1 or -1, skipping the division.
if (v.x > v.w) mask |= CLIP_POS_X_BIT;
if (v.x < -v.w) mask |= CLIP_NEG_X_BIT;
if (v.y > v.w) mask |= CLIP_POS_Y_BIT;
@@ -255,11 +256,7 @@ void ProcessLine(VertexData& v0, VertexData& v1)
return;
}

if (mask && gstate.isClippingEnabled()) {
// discard if any vertex is outside the near clipping plane
if (mask & CLIP_NEG_Z_BIT)
return;

if (mask) {
CLIP_LINE(CLIP_POS_X_BIT, -1, 0, 0, 1);
CLIP_LINE(CLIP_NEG_X_BIT, 1, 0, 0, 1);
CLIP_LINE(CLIP_POS_Y_BIT, 0, -1, 0, 1);
@@ -303,11 +300,7 @@ void ProcessTriangle(VertexData& v0, VertexData& v1, VertexData& v2)
mask |= CalcClipMask(v1.clippos);
mask |= CalcClipMask(v2.clippos);

if (mask && gstate.isClippingEnabled()) {
// discard if any vertex is outside the near clipping plane
if (mask & CLIP_NEG_Z_BIT)
return;

if (mask) {
for (int i = 0; i < 3; i += 3) {
int vlist[2][2*6+1];
int *inlist = vlist[0], *outlist = vlist[1];
@@ -104,16 +104,23 @@ static inline ScreenCoords ClipToScreenInternal(const ClipCoords& coords, bool *
float y = coords.y * yScale / coords.w + yCenter;
float z = coords.z * zScale / coords.w + zCenter;

// Account for rounding for X and Y.
const float SCREEN_BOUND = 4095.0f + (15.0f / 16.0f) + 0.375f;
// TODO: Validate actual rounding range.
const float DEPTH_BOUND = 65535.5f;

// This matches hardware tests - depth is clamped when this flag is on.
if (gstate.isClippingEnabled()) {
if (gstate.isDepthClampEnabled()) {
// Note: if the depth is clamped, the outside_range_flag should NOT be set, even for x and y.
if (z < 0.f)
z = 0.f;
if (z > 65535.f)
z = 65535.f;
}

if (outside_range_flag && (x > 4095.9375f || y > 4095.9375f || x < 0 || y < 0 || z < 0 || z > 65535.f))
else if (z > 65535.0f)
z = 65535.0f;
else if (outside_range_flag && (x >= SCREEN_BOUND || y >= SCREEN_BOUND || x < 0 || y < 0))
*outside_range_flag = true;
} else if (outside_range_flag && (x > 4095.9675f || y >= SCREEN_BOUND || x < 0 || y < 0 || z < 0 || z >= DEPTH_BOUND)) {
*outside_range_flag = true;
}

// 16 = 0xFFFF / 4095.9375
// Round up at 0.625 to the nearest subpixel.
@@ -247,7 +247,7 @@ void DrawEngineVulkan::ConvertStateToVulkanKey(FramebufferManagerVulkan &fbManag
// Set cull
bool wantCull = !gstate.isModeThrough() && prim != GE_PRIM_RECTANGLES && gstate.isCullEnabled();
key.cullMode = wantCull ? (gstate.getCullMode() ? VK_CULL_MODE_FRONT_BIT : VK_CULL_MODE_BACK_BIT) : VK_CULL_MODE_NONE;
key.depthClampEnable = gstate.isClippingEnabled() && gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP);
key.depthClampEnable = gstate.isDepthClampEnabled() && gstate_c.Supports(GPU_SUPPORTS_DEPTH_CLAMP);
}
}

@@ -369,7 +369,7 @@ void CtrlMatrixList::GetColumnText(wchar_t *dest, int row, int col) {
if (row >= MATRIXLIST_ROW_BONE_0_0) {
int b = (row - MATRIXLIST_ROW_BONE_0_0) / 3;
int r = (row - MATRIXLIST_ROW_BONE_0_0) % 3;
int offset = (row - MATRIXLIST_ROW_BONE_0_0) * 4 + col - 1;
int offset = b * 12 + r + (col - 1) * 3;

switch (col) {
case MATRIXLIST_COL_NAME:
@@ -382,7 +382,7 @@ void CtrlMatrixList::GetColumnText(wchar_t *dest, int row, int col) {
}
} else if (row >= MATRIXLIST_ROW_TGEN_0) {
int r = row - MATRIXLIST_ROW_TGEN_0;
int offset = r * 4 + col - 1;
int offset = r + (col - 1) * 4;

switch (col) {
case MATRIXLIST_COL_NAME:
@@ -395,7 +395,7 @@ void CtrlMatrixList::GetColumnText(wchar_t *dest, int row, int col) {
}
} else if (row >= MATRIXLIST_ROW_PROJ_0) {
int r = row - MATRIXLIST_ROW_PROJ_0;
int offset = r * 4 + col - 1;
int offset = r + (col - 1) * 4;

switch (col) {
case MATRIXLIST_COL_NAME:
@@ -408,7 +408,7 @@ void CtrlMatrixList::GetColumnText(wchar_t *dest, int row, int col) {
}
} else if (row >= MATRIXLIST_ROW_VIEW_0) {
int r = row - MATRIXLIST_ROW_VIEW_0;
int offset = r * 4 + col - 1;
int offset = r + (col - 1) * 3;

switch (col) {
case MATRIXLIST_COL_NAME:
@@ -421,7 +421,7 @@ void CtrlMatrixList::GetColumnText(wchar_t *dest, int row, int col) {
}
} else {
int r = row - MATRIXLIST_ROW_WORLD_0;
int offset = r * 4 + col - 1;
int offset = r + (col - 1) * 3;

switch (col) {
case MATRIXLIST_COL_NAME:
@@ -494,7 +494,7 @@ void CGEDebugger::UpdatePrimPreview(u32 op, int which) {
}

if (texPreviewVao == 0) {
glDisableVertexAttribArray(previewProgram->a_position);
glDisableVertexAttribArray(texPreviewProgram->a_position);
}

secondWindow->End();

0 comments on commit 945eab6

Please sign in to comment.
You can’t perform that action at this time.