nv2a: Depth buffer precision improvements and polygon offset slope factor

1. Use barycentric coordinates to interpolate depth values. Linux, Mesa
and AMD Radeon RX 6600 with Vulkan driver currently has quite poor
interpolation precision, which results in artifacts in at least Chronicles
of Riddick. Intel integrated UHD 770 has much better precision, for
example. This commit handles depth interpolation manually. Also note that
the previous w-buffer interpolation used gl_FragCoord.w which can't produce
all w-values, e.g. 1.0f/16777046.0f equals 1.0f/16777047.0f with 32-bit
floats. This also uses depth value differences in interpolation which has
the desired property that a triangle with the same z-value on all vertices
will result in exactly that same z-value when interpolated. At least the
game Shenmue II sky rendering relies on this.

2. Computes polygon depth bias slope for both z-buffering and w-buffering.
These are computed by taking the max and abs of partial derivatives of
either of the functions z=z(x,y) or w=w(x,y), where x,y,z,w are
screen-space coordinates. This matches Xbox hardware for z-buffering where
the partial derivatives are constants over any fixed triangle. However,
for w-buffering the partial derivatives vary over any fixed triangle, but
Xbox appears to compute just a single depth slope at the first visible
pixel (where "first" means something like first in top-left order) and uses
that over the whole triangle. This commit computes the slope per-pixel.
The way to compute the partial derivatives is by using the chain-rule, e.g.
dw/dx = -w^2 * d(1/w)/dx. This is useful since 1/w is linear in
screen-space and therefore d(1/w)/dx is constant over any fixed triangle.
But, as mentioned, finding out the w-value for the first visible pixel
of a triangle is difficult in OpenGL/Vulkan and is not done here. Instead
we calculate depth slope per-pixel.
This commit is contained in:
coldhex
2025-10-24 15:31:28 -04:00
committed by mborgerson
parent 594f787343
commit d6cb7536a2
14 changed files with 526 additions and 284 deletions
+4 -38
View File
@@ -208,38 +208,10 @@ void pgraph_gl_draw_begin(NV2AState *d)
& NV_PGRAPH_SETUPRASTER_FRONTFACE
? GL_CW : GL_CCW);
/* Polygon offset */
/* FIXME: GL implementation-specific, maybe do this in VS? */
if (pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER) &
NV_PGRAPH_SETUPRASTER_POFFSETFILLENABLE) {
glEnable(GL_POLYGON_OFFSET_FILL);
} else {
glDisable(GL_POLYGON_OFFSET_FILL);
}
if (pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER) &
NV_PGRAPH_SETUPRASTER_POFFSETLINEENABLE) {
glEnable(GL_POLYGON_OFFSET_LINE);
} else {
glDisable(GL_POLYGON_OFFSET_LINE);
}
if (pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER) &
NV_PGRAPH_SETUPRASTER_POFFSETPOINTENABLE) {
glEnable(GL_POLYGON_OFFSET_POINT);
} else {
glDisable(GL_POLYGON_OFFSET_POINT);
}
if (pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER) &
(NV_PGRAPH_SETUPRASTER_POFFSETFILLENABLE |
NV_PGRAPH_SETUPRASTER_POFFSETLINEENABLE |
NV_PGRAPH_SETUPRASTER_POFFSETPOINTENABLE)) {
uint32_t zfactor_u32 = pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETFACTOR);
GLfloat zfactor = *(float*)&zfactor_u32;
uint32_t zbias_u32 = pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETBIAS);
GLfloat zbias = *(float*)&zbias_u32;
// FIXME: with Linux and Mesa, zbias must be multiplied by 0.5 in
// order to have the same depth value offset as Xbox.
glPolygonOffset(zfactor, zbias);
}
/* Polygon offset is handled in geometry and fragment shaders explicitly */
glDisable(GL_POLYGON_OFFSET_FILL);
glDisable(GL_POLYGON_OFFSET_LINE);
glDisable(GL_POLYGON_OFFSET_POINT);
/* Depth testing */
if (depth_test) {
@@ -255,12 +227,6 @@ void pgraph_gl_draw_begin(NV2AState *d)
glEnable(GL_DEPTH_CLAMP);
if (GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_3),
NV_PGRAPH_CONTROL_3_SHADEMODE) ==
NV_PGRAPH_CONTROL_3_SHADEMODE_FLAT) {
glProvokingVertex(GL_FIRST_VERTEX_CONVENTION);
}
if (stencil_test) {
glEnable(GL_STENCIL_TEST);
+3 -4
View File
@@ -31,10 +31,6 @@
static GLenum get_gl_primitive_mode(enum ShaderPolygonMode polygon_mode, enum ShaderPrimitiveMode primitive_mode)
{
if (polygon_mode == POLY_MODE_POINT) {
return GL_POINTS;
}
switch (primitive_mode) {
case PRIM_TYPE_POINTS: return GL_POINTS;
case PRIM_TYPE_LINES: return GL_LINES;
@@ -705,6 +701,9 @@ static void apply_uniform_updates(const UniformInfo *info, int *locs,
case UniformElementType_int:
glUniform1iv(locs[i], info[i].count, value);
break;
case UniformElementType_ivec2:
glUniform2iv(locs[i], info[i].count, value);
break;
case UniformElementType_ivec4:
glUniform4iv(locs[i], info[i].count, value);
break;
+4
View File
@@ -48,6 +48,10 @@ MString *pgraph_glsl_get_vtx_header(MString *out, bool location, bool smooth,
{ smooth_s, vec4_s, "vtxT1" },
{ smooth_s, vec4_s, "vtxT2" },
{ smooth_s, vec4_s, "vtxT3" },
{ flat_s, vec4_s, "vtxPos0" },
{ flat_s, vec4_s, "vtxPos1" },
{ flat_s, vec4_s, "vtxPos2" },
{ flat_s, float_s, "triMZ" },
};
for (int i = 0; i < ARRAY_SIZE(attr); i++) {
+2
View File
@@ -25,6 +25,7 @@
#include "qemu/osdep.h"
#include "qemu/mstring.h"
typedef int ivec2[2];
typedef int ivec4[4];
typedef float mat2[2 * 2];
typedef unsigned int uint;
@@ -35,6 +36,7 @@ typedef float vec4[4];
#define UNIFORM_ELEMENT_TYPE_X(DECL) \
DECL(float) \
DECL(int) \
DECL(ivec2) \
DECL(ivec4) \
DECL(mat2) \
DECL(uint) \
File diff suppressed because it is too large Load Diff
+1
View File
@@ -30,6 +30,7 @@ typedef struct {
enum ShaderPolygonMode polygon_front_mode;
enum ShaderPolygonMode polygon_back_mode;
bool smooth_shading;
bool z_perspective;
} GeomState;
typedef struct GenGeomGlslOptions {
+172 -68
View File
@@ -209,6 +209,26 @@ void pgraph_glsl_set_psh_state(PGRAPHState *pg, PshState *state)
state->conv_tex[i] = kernel;
}
state->surface_zeta_format = pg->surface_shape.zeta_format;
unsigned int z_format = GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER),
NV_PGRAPH_SETUPRASTER_Z_FORMAT);
switch (pg->surface_shape.zeta_format) {
case NV097_SET_SURFACE_FORMAT_ZETA_Z16:
state->depth_format =
z_format ? DEPTH_FORMAT_F16 : DEPTH_FORMAT_D16;
break;
case NV097_SET_SURFACE_FORMAT_ZETA_Z24S8:
state->depth_format =
z_format ? DEPTH_FORMAT_F24 : DEPTH_FORMAT_D24;
break;
default:
fprintf(stderr, "Unknown zeta surface format: 0x%x\n",
pg->surface_shape.zeta_format);
assert(false);
break;
}
}
struct InputInfo {
@@ -875,6 +895,23 @@ static MString* psh_convert(struct PixelShader *ps)
"vec3 dotmap_hilo_hemisphere(vec4 col) {\n"
" return col.rgb;\n" // FIXME
"}\n"
// Kahan's algorithm for computing determinant using FMA for higher
// precision. See e.g.:
// Muller et al, "Handbook of Floating-Point Arithmetic", 2nd ed.
// or
// Claude-Pierre Jeannerod, Nicolas Louvet, and Jean-Michel Muller,
// Further analysis of Kahan's algorithm for the accurate
// computation of 2x2 determinants,
// Mathematics of Computation 82(284), October 2013.
"float kahan_det(vec2 a, vec2 b) {\n"
" precise float cd = a.y*b.x;\n"
" precise float err = fma(-a.y, b.x, cd);\n"
" precise float res = fma(a.x, b.y, -cd) + err;\n"
" return res;\n"
"}\n"
"float area(vec2 a, vec2 b, vec2 c) {\n"
" return kahan_det(b - a, c - a);\n"
"}\n"
"const float[9] gaussian3x3 = float[9](\n"
" 1.0/16.0, 2.0/16.0, 1.0/16.0,\n"
" 2.0/16.0, 4.0/16.0, 2.0/16.0,\n"
@@ -911,45 +948,69 @@ static MString* psh_convert(struct PixelShader *ps)
"}\n");
}
if (ps->state->z_perspective) {
mstring_append(
clip,
"vec2 unscaled_xy = gl_FragCoord.xy / surfaceScale;\n"
"precise float bc0 = area(unscaled_xy, vtxPos1.xy, vtxPos2.xy);\n"
"precise float bc1 = area(unscaled_xy, vtxPos2.xy, vtxPos0.xy);\n"
"precise float bc2 = area(unscaled_xy, vtxPos0.xy, vtxPos1.xy);\n"
"bc0 /= vtxPos0.w;\n"
"bc1 /= vtxPos1.w;\n"
"bc2 /= vtxPos2.w;\n"
"float inv_bcsum = 1.0 / (bc0 + bc1 + bc2);\n"
// Denominator can be zero in case the rasterized primitive is a
// point or a degenerate line or triangle.
"if (isinf(inv_bcsum)) {\n"
" inv_bcsum = 0.0;\n"
"}\n"
"bc1 *= inv_bcsum;\n"
"bc2 *= inv_bcsum;\n"
"precise float zvalue = vtxPos0.w + (bc1*(vtxPos1.w - vtxPos0.w) + bc2*(vtxPos2.w - vtxPos0.w));\n"
// If GPU clipping is inaccurate, the point gl_FragCoord.xy might
// be above the horizon of the plane of a rasterized triangle
// making the interpolated w-coordinate above zero or negative. We
// should prevent such wrapping through infinity by clamping to
// infinity.
"if (zvalue > 0.0) {\n"
" float zslopeofs = depthFactor*triMZ*zvalue*zvalue;\n"
" zvalue += depthOffset;\n"
" zvalue += zslopeofs;\n"
"} else {\n"
" zvalue = uintBitsToFloat(0x7F7FFFFFu);\n"
"}\n"
"if (isnan(zvalue)) {\n"
" zvalue = uintBitsToFloat(0x7F7FFFFFu);\n"
"}\n");
} else {
mstring_append(
clip,
"vec2 unscaled_xy = gl_FragCoord.xy / surfaceScale;\n"
"precise float bc0 = area(unscaled_xy, vtxPos1.xy, vtxPos2.xy);\n"
"precise float bc1 = area(unscaled_xy, vtxPos2.xy, vtxPos0.xy);\n"
"precise float bc2 = area(unscaled_xy, vtxPos0.xy, vtxPos1.xy);\n"
"float inv_bcsum = 1.0 / (bc0 + bc1 + bc2);\n"
// Denominator can be zero in case the rasterized primitive is a
// point or a degenerate line or triangle.
"if (isinf(inv_bcsum)) {\n"
" inv_bcsum = 0.0;\n"
"}\n"
"bc1 *= inv_bcsum;\n"
"bc2 *= inv_bcsum;\n"
"precise float zvalue = vtxPos0.z + (bc1*(vtxPos1.z - vtxPos0.z) + bc2*(vtxPos2.z - vtxPos0.z));\n"
"zvalue += depthOffset;\n"
"zvalue += depthFactor*triMZ;\n");
}
/* Depth clipping */
if (ps->state->depth_clipping) {
if (ps->state->z_perspective) {
mstring_append(
clip, "float zvalue = 1.0/gl_FragCoord.w + depthOffset;\n"
"if (zvalue < clipRange.z || clipRange.w < zvalue) {\n"
" discard;\n"
"}\n");
} else {
/* Take care of floating point precision problems. MS dashboard
* outputs exactly 0.0 z-coordinates and then our fixed function
* vertex shader outputs -w as the z-coordinate when OpenGL is
* used. Since -w/w = -1, this should give us exactly 0.0 as
* gl_FragCoord.z here. Unfortunately, with AMD Radeon RX 6600 the
* result is slightly greater than 0. MS dashboard sets the clip
* range to [0.0, 0.0] and so the imprecision causes unwanted
* clipping. Note that since Vulkan uses NDC range [0,1] it
* doesn't suffer from this problem with Radeon. Also, despite the
* imprecision OpenGL Radeon writes the correct value 0 to the depth
* buffer (if writing is enabled.) Radeon appears to write floored
* values. To compare, Intel integrated UHD 770 has gl_FragCoord.z
* exactly 0 (and writes rounded to closest integer values to the
* depth buffer.) Radeon OpenGL problem could also be fixed by using
* glClipControl(), but it requires OpenGL 4.5.
* Above is based on experiments with Linux and Mesa.
*/
if (ps->opts.vulkan) {
mstring_append(
clip, "if (gl_FragCoord.z*clipRange.y < clipRange.z ||\n"
" gl_FragCoord.z*clipRange.y > clipRange.w) {\n"
" discard;\n"
"}\n");
} else {
mstring_append(
clip, "if ((gl_FragCoord.z + 1.0f/16777216.0f)*clipRange.y < clipRange.z ||\n"
" (gl_FragCoord.z - 1.0f/16777216.0f)*clipRange.y > clipRange.w) {\n"
" discard;\n"
"}\n");
}
}
mstring_append(
clip, "if (zvalue < clipRange.z || clipRange.w < zvalue) {\n"
" discard;\n"
"}\n");
} else {
mstring_append(
clip, "zvalue = clamp(zvalue, clipRange.z, clipRange.w);\n");
}
MString *vars = mstring_new();
@@ -1334,21 +1395,33 @@ static MString* psh_convert(struct PixelShader *ps)
}
}
if (ps->state->z_perspective) {
if (!ps->state->depth_clipping) {
mstring_append(ps->code,
"float zvalue = 1.0/gl_FragCoord.w + depthOffset;\n");
}
/* TODO: With integer depth buffers Xbox hardware floors values and so
* does Radeon, but Intel UHD 770 rounds to nearest. Should probably
* floor here explicitly (in some way that doesn't also cause
* imprecision issues due to division by clipRange.y)
*/
mstring_append(ps->code,
"gl_FragDepth = clamp(zvalue, clipRange.z, clipRange.w)/clipRange.y;\n");
} else if (!ps->state->depth_clipping) {
mstring_append(ps->code,
"gl_FragDepth = clamp(gl_FragCoord.z, clipRange.z/clipRange.y, clipRange.w/clipRange.y);\n");
/* With integer depth buffers Xbox hardware floors values. For gl_FragDepth
* range [0,1] Radeon floors values to integer depth buffer, but Intel UHD
* 770 rounds to nearest. For 24-bit OpenGL/Vulkan integer depth buffer,
* we divide the desired depth integer value by 16777216.0, then add 1 in
* integer bit representation to get the same result as dividing the
* desired depth integer by 16777215.0 would give. (GPUs can't divide by
* 16777215.0, only multiply by 1.0/16777215.0 which gives different results
* due to rounding.)
*/
switch (ps->state->depth_format) {
case DEPTH_FORMAT_D16:
// 16-bit unsigned int
mstring_append(
ps->code,
"gl_FragDepth = floor(zvalue) / 65535.0;\n");
break;
case DEPTH_FORMAT_D24:
// 24-bit unsigned int
mstring_append(
ps->code,
"gl_FragDepth = uintBitsToFloat(floatBitsToUint(floor(zvalue) / 16777216.0) + 1u);\n");
break;
default:
// TODO: handle floating-point depth buffers properly
mstring_append(ps->code, "gl_FragDepth = zvalue / clipRange.y;\n");
break;
}
MString *final = mstring_new();
@@ -1542,31 +1615,62 @@ void pgraph_glsl_set_psh_uniform_values(PGRAPHState *pg,
pgraph_glsl_set_clip_range_uniform_value(pg, values->clipRange[0]);
}
bool polygon_offset_enabled = false;
if (pg->primitive_mode >= PRIM_TYPE_TRIANGLES) {
uint32_t raster = pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER);
uint32_t polygon_mode =
GET_MASK(raster, NV_PGRAPH_SETUPRASTER_FRONTFACEMODE);
if ((polygon_mode == NV_PGRAPH_SETUPRASTER_FRONTFACEMODE_FILL &&
(raster & NV_PGRAPH_SETUPRASTER_POFFSETFILLENABLE)) ||
(polygon_mode == NV_PGRAPH_SETUPRASTER_FRONTFACEMODE_LINE &&
(raster & NV_PGRAPH_SETUPRASTER_POFFSETLINEENABLE)) ||
(polygon_mode == NV_PGRAPH_SETUPRASTER_FRONTFACEMODE_POINT &&
(raster & NV_PGRAPH_SETUPRASTER_POFFSETPOINTENABLE))) {
polygon_offset_enabled = true;
}
}
if (locs[PshUniform_depthOffset] != -1) {
float zbias = 0.0f;
if (pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER) &
(NV_PGRAPH_SETUPRASTER_POFFSETFILLENABLE |
NV_PGRAPH_SETUPRASTER_POFFSETLINEENABLE |
NV_PGRAPH_SETUPRASTER_POFFSETPOINTENABLE)) {
if (polygon_offset_enabled) {
uint32_t zbias_u32 = pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETBIAS);
zbias = *(float *)&zbias_u32;
if (pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETFACTOR) != 0 &&
(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0) &
NV_PGRAPH_CONTROL_0_Z_PERSPECTIVE_ENABLE)) {
/* TODO: emulate zfactor when z_perspective true, i.e.
* w-buffering. Perhaps calculate an additional offset based on
* triangle orientation in geometry shader and pass the result
* to fragment shader and add it to gl_FragDepth as well.
*/
NV2A_UNIMPLEMENTED("NV_PGRAPH_ZOFFSETFACTOR for w-buffering");
}
}
values->depthOffset[0] = zbias;
}
if (locs[PshUniform_depthFactor] != -1) {
float zfactor = 0.0f;
if (polygon_offset_enabled) {
uint32_t zfactor_u32 = pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETFACTOR);
zfactor = *(float *)&zfactor_u32;
if (zfactor != 0.0f &&
(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0) &
NV_PGRAPH_CONTROL_0_Z_PERSPECTIVE_ENABLE)) {
/* FIXME: for w-buffering, polygon slope in screen-space is
* computed per-pixel, but Xbox appears to use constant that
* is the polygon slope at the first visible pixel in top-left
* order.
*/
NV2A_UNIMPLEMENTED("NV_PGRAPH_ZOFFSETFACTOR only partially implemented for w-buffering");
}
}
values->depthFactor[0] = zfactor;
}
if (locs[PshUniform_surfaceScale] != -1) {
unsigned int wscale = 1, hscale = 1;
pgraph_apply_anti_aliasing_factor(pg, &wscale, &hscale);
pgraph_apply_scaling_factor(pg, &wscale, &hscale);
values->surfaceScale[0][0] = wscale;
values->surfaceScale[0][1] = hscale;
}
unsigned int max_gl_width = pg->surface_binding_dim.width;
unsigned int max_gl_height = pg->surface_binding_dim.height;
pgraph_apply_scaling_factor(pg, &max_gl_width, &max_gl_height);
+12
View File
@@ -27,6 +27,13 @@
typedef struct PGRAPHState PGRAPHState;
enum PshDepthFormat {
DEPTH_FORMAT_D24,
DEPTH_FORMAT_D16,
DEPTH_FORMAT_F24,
DEPTH_FORMAT_F16,
};
typedef struct PshState {
uint32_t combiner_control;
uint32_t shader_stage_program;
@@ -61,6 +68,9 @@ typedef struct PshState {
bool smooth_shading;
bool depth_clipping;
bool z_perspective;
unsigned int surface_zeta_format;
enum PshDepthFormat depth_format;
} PshState;
void pgraph_glsl_set_psh_state(PGRAPHState *pg, PshState *state);
@@ -75,8 +85,10 @@ void pgraph_glsl_set_psh_state(PGRAPHState *pg, PshState *state);
DECL(S, colorKey, uint, 4) \
DECL(S, colorKeyMask, uint, 4) \
DECL(S, consts, vec4, 18) \
DECL(S, depthFactor, float, 1) \
DECL(S, depthOffset, float, 1) \
DECL(S, fogColor, vec4, 1) \
DECL(S, surfaceScale, ivec2, 1) \
DECL(S, texScale, float, 4)
DECL_UNIFORM_TYPES(PshUniform, PSH_UNIFORM_DECL_X)
+2 -1
View File
@@ -73,7 +73,8 @@ bool pgraph_glsl_check_shader_state_dirty(PGRAPHState *pg,
pg->swizzle_attrs != state->vsh.swizzle_attrs ||
pg->compressed_attrs != state->vsh.compressed_attrs ||
pg->primitive_mode != state->geom.primitive_mode ||
pg->surface_scale_factor != state->vsh.surface_scale_factor) {
pg->surface_scale_factor != state->vsh.surface_scale_factor ||
pg->surface_shape.zeta_format != state->psh.surface_zeta_format) {
return true;
}
+2 -1
View File
@@ -479,11 +479,12 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
mstring_append(body,
" oPos = tPosition * compositeMat;\n"
" oPos.z = oPos.z / clipRange.y;\n"
" oPos.w = clampAwayZeroInf(oPos.w);\n"
" oPos.xy /= oPos.w;\n"
" oPos.xy += c[" stringify(NV_IGRAPH_XF_XFCTX_VPOFF) "].xy;\n"
" oPos.xy = roundScreenCoords(oPos.xy);\n"
" vec4 vtxPos = vec4(oPos.xy, oPos.z / oPos.w, oPos.w);\n"
" oPos.z = oPos.z / clipRange.y;\n"
" oPos.xy = (2.0f * oPos.xy - surfaceSize) / surfaceSize;\n"
" oPos.xy *= oPos.w;\n"
);
+3 -3
View File
@@ -755,10 +755,10 @@ void pgraph_glsl_gen_vsh_prog(uint16_t version, const uint32_t *tokens,
* in clip space.
*/
" oPos.xy = roundScreenCoords(oPos.xy);\n"
" oPos.xy = (2.0f * oPos.xy - surfaceSize) / surfaceSize;\n"
" oPos.z = oPos.z / clipRange.y;\n"
" oPos.w = clampAwayZeroInf(oPos.w);\n"
" vec4 vtxPos = oPos;\n"
" oPos.xy = (2.0f * oPos.xy - surfaceSize) / surfaceSize;\n"
" oPos.z = oPos.z / clipRange.y;\n"
/* Undo perspective divide by w.
* Note that games may also have vertex shaders that do
+8
View File
@@ -245,6 +245,10 @@ MString *pgraph_glsl_gen_vsh(const VshState *state, GenVshGlslOptions opts)
"#define vtxT1 v_vtxT1\n"
"#define vtxT2 v_vtxT2\n"
"#define vtxT3 v_vtxT3\n"
"#define vtxPos0 v_vtxPos0\n"
"#define vtxPos1 v_vtxPos1\n"
"#define vtxPos2 v_vtxPos2\n"
"#define triMZ v_triMZ\n"
);
}
mstring_append(header, "\n");
@@ -393,6 +397,10 @@ MString *pgraph_glsl_gen_vsh(const VshState *state, GenVshGlslOptions opts)
" vtxT1 = oT1;\n"
" vtxT2 = oT2;\n"
" vtxT3 = oT3;\n"
" vtxPos0 = vtxPos;\n"
" vtxPos1 = vtxPos;\n"
" vtxPos2 = vtxPos;\n"
" triMZ = 0.0;\n"
" gl_PointSize = oPts.x;\n"
);
+3 -32
View File
@@ -54,10 +54,6 @@ static VkPrimitiveTopology get_primitive_topology(PGRAPHState *pg)
int polygon_mode = r->shader_binding->state.geom.polygon_front_mode;
int primitive_mode = r->shader_binding->state.geom.primitive_mode;
if (polygon_mode == POLY_MODE_POINT) {
return VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
}
// FIXME: Replace with LUT
switch (primitive_mode) {
case PRIM_TYPE_POINTS:
@@ -795,12 +791,10 @@ static void create_pipeline(PGRAPHState *pg)
VkPipelineRasterizationProvokingVertexStateCreateInfoEXT provoking_state;
if (r->provoking_vertex_extension_enabled) {
// TODO: remove use of provoking vertex extension since we just want
// the default last vertex convention always.
VkProvokingVertexModeEXT provoking_mode =
GET_MASK(pgraph_reg_r(pg, NV_PGRAPH_CONTROL_3),
NV_PGRAPH_CONTROL_3_SHADEMODE) ==
NV_PGRAPH_CONTROL_3_SHADEMODE_FLAT ?
VK_PROVOKING_VERTEX_MODE_FIRST_VERTEX_EXT :
VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT;
VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT;
provoking_state =
(VkPipelineRasterizationProvokingVertexStateCreateInfoEXT){
@@ -809,8 +803,6 @@ static void create_pipeline(PGRAPHState *pg)
.provokingVertexMode = provoking_mode,
};
rasterizer_next_struct = &provoking_state;
} else {
// FIXME: Handle in shader?
}
VkPipelineRasterizationStateCreateInfo rasterizer = {
@@ -968,27 +960,6 @@ static void create_pipeline(PGRAPHState *pg)
.pDynamicStates = dynamic_states,
};
// /* Polygon offset */
// /* FIXME: GL implementation-specific, maybe do this in VS? */
// if (pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER) &
// NV_PGRAPH_SETUPRASTER_POFFSETFILLENABLE)
// if (pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER) &
// NV_PGRAPH_SETUPRASTER_POFFSETLINEENABLE)
// if (pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER) &
// NV_PGRAPH_SETUPRASTER_POFFSETPOINTENABLE)
if (pgraph_reg_r(pg, NV_PGRAPH_SETUPRASTER) &
(NV_PGRAPH_SETUPRASTER_POFFSETFILLENABLE |
NV_PGRAPH_SETUPRASTER_POFFSETLINEENABLE |
NV_PGRAPH_SETUPRASTER_POFFSETPOINTENABLE)) {
uint32_t zfactor_u32 = pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETFACTOR);
float zfactor = *(float *)&zfactor_u32;
uint32_t zbias_u32 = pgraph_reg_r(pg, NV_PGRAPH_ZOFFSETBIAS);
float zbias = *(float *)&zbias_u32;
rasterizer.depthBiasEnable = VK_TRUE;
rasterizer.depthBiasSlopeFactor = zfactor;
rasterizer.depthBiasConstantFactor = zbias;
}
// FIXME: Dither
// if (pgraph_reg_r(pg, NV_PGRAPH_CONTROL_0) &
// NV_PGRAPH_CONTROL_0_DITHERENABLE))
+2 -1
View File
@@ -106,7 +106,8 @@ const char *unpack_z24s8_to_d32_sfloat_s8_uint_glsl =
"void main() {\n"
" uint idx_out = gl_GlobalInvocationID.x;\n"
" uint idx_in = get_input_idx(idx_out);\n"
" depth_out[idx_out] = float(depth_stencil_in[idx_in] >> 8) / float(0xffffff);\n"
// Conversion to float depth must be the same as in fragment shader
" depth_out[idx_out] = uintBitsToFloat(floatBitsToUint(float(depth_stencil_in[idx_in] >> 8) / 16777216.0) + 1u);\n"
" if (idx_out % 4 == 0) {\n"
" uint stencil_value = 0;\n"
" for (int i = 0; i < 4; i++) {\n" // Include next 3 pixels