Skip to content

Commit 5016691

Browse files
author
coldhex
committed
nv2a: Fix polygon line mode and implement flat shading provoking vertex
Xbox draws lines in polygon mode without trying to avoid overlaps, e.g. internal edge lines are drawn twice for triangle strips and fans. This is evidenced by using additive blending and also stencil adds. This commit removes the gl_PrimitiveIDIn==0 checks which were there to avoid drawing lines twice. This commit also implements flat shading first/last provoking vertex handling. This fixes triangle strip and fan flat shading in nxdk_pgraph_tests shade model tests.
1 parent 4f81e33 commit 5016691

File tree

6 files changed

+133
-150
lines changed

6 files changed

+133
-150
lines changed

hw/xbox/nv2a/nv2a_regs.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,9 @@
467467
# define NV_PGRAPH_CONTROL_2_STENCIL_OP_V_INCR 7
468468
# define NV_PGRAPH_CONTROL_2_STENCIL_OP_V_DECR 8
469469
#define NV_PGRAPH_CONTROL_3 0x00001958
470+
# define NV_PGRAPH_CONTROL_3_PROVOKING_VERTEX (1 << 0)
471+
# define NV_PGRAPH_CONTROL_3_PROVOKING_VERTEX_LAST 0
472+
# define NV_PGRAPH_CONTROL_3_PROVOKING_VERTEX_FIRST 1
470473
# define NV_PGRAPH_CONTROL_3_SHADEMODE (1 << 7)
471474
# define NV_PGRAPH_CONTROL_3_SHADEMODE_FLAT 0
472475
# define NV_PGRAPH_CONTROL_3_SHADEMODE_SMOOTH 1
@@ -1057,6 +1060,9 @@
10571060
# define NV097_SET_TEXGEN_VIEW_MODEL_INFINITE_VIEWER 1
10581061
# define NV097_SET_FOG_PLANE 0x000009D0
10591062
# define NV097_SET_SPECULAR_PARAMS 0x000009E0
1063+
# define NV097_SET_PROVOKING_VERTEX 0x000009FC
1064+
# define NV097_SET_PROVOKING_VERTEX_LAST 0
1065+
# define NV097_SET_PROVOKING_VERTEX_FIRST 1
10601066
# define NV097_SET_SCENE_AMBIENT_COLOR 0x00000A10
10611067
# define NV097_SET_VIEWPORT_OFFSET 0x00000A20
10621068
# define NV097_SET_POINT_PARAMS 0x00000A30

hw/xbox/nv2a/pgraph/glsl/geom.c

Lines changed: 113 additions & 150 deletions
Original file line numberDiff line numberDiff line change
@@ -35,67 +35,47 @@ MString *pgraph_gen_geom_glsl(const ShaderState *state)
3535
const char *layout_in = NULL;
3636
const char *layout_out = NULL;
3737
const char *body = NULL;
38+
const char *provoking_index = "0";
3839

40+
/* TODO: frontface/backface culling for polygon modes POLY_MODE_LINE and
41+
* POLY_MODE_POINT.
42+
*/
3943
switch (state->primitive_mode) {
4044
case PRIM_TYPE_POINTS: return NULL;
4145
case PRIM_TYPE_LINES:
4246
case PRIM_TYPE_LINE_LOOP:
4347
case PRIM_TYPE_LINE_STRIP:
48+
provoking_index = state->first_vertex_is_provoking ? "0" : "1";
4449
need_linez = true;
4550
layout_in = "layout(lines) in;\n";
4651
layout_out = "layout(line_strip, max_vertices = 2) out;\n";
4752
body = " mat4 pz = calc_linez(0, 1);\n"
48-
" emit_vertex(0, 0, pz);\n"
49-
" emit_vertex(1, 1, pz);\n"
53+
" emit_vertex(0, pz);\n"
54+
" emit_vertex(1, pz);\n"
5055
" EndPrimitive();\n";
5156
break;
5257
case PRIM_TYPE_TRIANGLES:
53-
need_triz = true;
54-
layout_in = "layout(triangles) in;\n";
55-
if (polygon_mode == POLY_MODE_FILL) {
56-
layout_out = "layout(triangle_strip, max_vertices = 3) out;\n";
57-
body = " mat4 pz = calc_triz(0, 1, 2);\n"
58-
" emit_vertex(0, 0, pz);\n"
59-
" emit_vertex(1, 1, pz);\n"
60-
" emit_vertex(2, 2, pz);\n"
61-
" EndPrimitive();\n";
62-
} else if (polygon_mode == POLY_MODE_LINE) {
63-
need_linez = true;
64-
layout_out = "layout(line_strip, max_vertices = 4) out;\n";
65-
body = " float triMZ = calc_triz(0, 1, 2)[3].x;\n"
66-
" mat4 pz1 = calc_linez(0, 1);\n"
67-
" pz1[3].x = triMZ;\n"
68-
" mat4 pz2 = calc_linez(1, 2);\n"
69-
" pz2[3].x = triMZ;\n"
70-
" mat4 pz3 = calc_linez(2, 0);\n"
71-
" pz3[3].x = triMZ;\n"
72-
" emit_vertex(0, 0, pz1);\n"
73-
" emit_vertex(1, 0, pz1);\n"
74-
" emit_vertex(2, 0, pz2);\n"
75-
" emit_vertex(0, 0, pz3);\n"
76-
" EndPrimitive();\n";
77-
} else {
78-
assert(polygon_mode == POLY_MODE_POINT);
79-
layout_out = "layout(points, max_vertices = 3) out;\n";
80-
body = " mat4 pz = calc_triz(0, 1, 2);\n"
81-
" emit_vertex(0, 0, mat4(pz[0], pz[0], pz[0], pz[3]));\n"
82-
" EndPrimitive();\n"
83-
" emit_vertex(1, 0, mat4(pz[1], pz[1], pz[1], pz[3]));\n"
84-
" EndPrimitive();\n"
85-
" emit_vertex(2, 0, mat4(pz[2], pz[2], pz[2], pz[3]));\n"
86-
" EndPrimitive();\n";
87-
}
88-
break;
8958
case PRIM_TYPE_TRIANGLE_STRIP:
9059
case PRIM_TYPE_TRIANGLE_FAN:
60+
if (state->first_vertex_is_provoking) {
61+
if (state->primitive_mode == PRIM_TYPE_TRIANGLE_STRIP) {
62+
provoking_index = "gl_PrimitiveIDIn & 1";
63+
} else if (state->primitive_mode == PRIM_TYPE_TRIANGLE_FAN) {
64+
provoking_index = "1";
65+
} else {
66+
provoking_index = "0";
67+
}
68+
} else {
69+
provoking_index = "2";
70+
}
9171
need_triz = true;
9272
layout_in = "layout(triangles) in;\n";
9373
if (polygon_mode == POLY_MODE_FILL) {
9474
layout_out = "layout(triangle_strip, max_vertices = 3) out;\n";
9575
body = " mat4 pz = calc_triz(0, 1, 2);\n"
96-
" emit_vertex(0, 0, pz);\n"
97-
" emit_vertex(1, 1, pz);\n"
98-
" emit_vertex(2, 2, pz);\n"
76+
" emit_vertex(0, pz);\n"
77+
" emit_vertex(1, pz);\n"
78+
" emit_vertex(2, pz);\n"
9979
" EndPrimitive();\n";
10080
} else if (polygon_mode == POLY_MODE_LINE) {
10181
need_linez = true;
@@ -107,31 +87,37 @@ MString *pgraph_gen_geom_glsl(const ShaderState *state)
10787
" pz2[3].x = triMZ;\n"
10888
" mat4 pz3 = calc_linez(2, 0);\n"
10989
" pz3[3].x = triMZ;\n"
110-
" if (gl_PrimitiveIDIn == 0) {\n"
111-
" emit_vertex(0, 0, pz1);\n"
112-
" }\n"
113-
" emit_vertex(1, 0, pz1);\n"
114-
" emit_vertex(2, 0, pz2);\n"
115-
" emit_vertex(0, 0, pz3);\n"
90+
" emit_vertex(0, pz1);\n"
91+
" emit_vertex(1, pz1);\n"
92+
" emit_vertex(2, pz2);\n"
93+
" emit_vertex(0, pz3);\n"
11694
" EndPrimitive();\n";
11795
} else {
11896
assert(polygon_mode == POLY_MODE_POINT);
11997
layout_out = "layout(points, max_vertices = 3) out;\n";
12098
body = " mat4 pz = calc_triz(0, 1, 2);\n"
121-
" if (gl_PrimitiveIDIn == 0) {\n"
122-
" emit_vertex(0, 0, mat4(pz[0], pz[0], pz[0], pz[3]));\n"
123-
" EndPrimitive();\n"
124-
" emit_vertex(1, 0, mat4(pz[1], pz[1], pz[1], pz[3]));\n"
125-
" EndPrimitive();\n"
126-
" }\n"
127-
" emit_vertex(2, 0, mat4(pz[2], pz[2], pz[2], pz[3]));\n"
99+
" emit_vertex(0, mat4(pz[0], pz[0], pz[0], pz[3]));\n"
100+
" EndPrimitive();\n"
101+
" emit_vertex(1, mat4(pz[1], pz[1], pz[1], pz[3]));\n"
102+
" EndPrimitive();\n"
103+
" emit_vertex(2, mat4(pz[2], pz[2], pz[2], pz[3]));\n"
128104
" EndPrimitive();\n";
129105
}
130106
break;
131107
case PRIM_TYPE_QUADS:
108+
provoking_index = "3";
132109
need_quadz = true;
133110
layout_in = "layout(lines_adjacency) in;\n";
134-
if (polygon_mode == POLY_MODE_LINE) {
111+
if (polygon_mode == POLY_MODE_FILL) {
112+
layout_out = "layout(triangle_strip, max_vertices = 4) out;\n";
113+
body = " mat4 pz, pz2;\n"
114+
" calc_quadz(0, 1, 2, 3, pz, pz2);\n"
115+
" emit_vertex(1, pz);\n"
116+
" emit_vertex(2, pz2);\n"
117+
" emit_vertex(0, pz);\n"
118+
" emit_vertex(3, pz2);\n"
119+
" EndPrimitive();\n";
120+
} else if (polygon_mode == POLY_MODE_LINE) {
135121
need_linez = true;
136122
layout_out = "layout(line_strip, max_vertices = 5) out;\n";
137123
body = " mat4 pz, pzs;\n"
@@ -144,40 +130,42 @@ MString *pgraph_gen_geom_glsl(const ShaderState *state)
144130
" pz3[3].x = pzs[3].x;\n"
145131
" mat4 pz4 = calc_linez(3, 0);\n"
146132
" pz4[3].x = pzs[3].x;\n"
147-
" emit_vertex(0, 3, pz1);\n"
148-
" emit_vertex(1, 3, pz1);\n"
149-
" emit_vertex(2, 3, pz2);\n"
150-
" emit_vertex(3, 3, pz3);\n"
151-
" emit_vertex(0, 3, pz4);\n"
152-
" EndPrimitive();\n";
153-
} else if (polygon_mode == POLY_MODE_FILL) {
154-
layout_out = "layout(triangle_strip, max_vertices = 4) out;\n";
155-
body = " mat4 pz, pz2;\n"
156-
" calc_quadz(0, 1, 2, 3, pz, pz2);\n"
157-
" emit_vertex(1, 3, pz);\n"
158-
" emit_vertex(2, 3, pz2);\n"
159-
" emit_vertex(0, 3, pz);\n"
160-
" emit_vertex(3, 3, pz2);\n"
133+
" emit_vertex(0, pz1);\n"
134+
" emit_vertex(1, pz1);\n"
135+
" emit_vertex(2, pz2);\n"
136+
" emit_vertex(3, pz3);\n"
137+
" emit_vertex(0, pz4);\n"
161138
" EndPrimitive();\n";
162139
} else {
163140
assert(polygon_mode == POLY_MODE_POINT);
164141
layout_out = "layout(points, max_vertices = 4) out;\n";
165142
body = " mat4 pz, pz2;\n"
166143
" calc_quadz(0, 1, 2, 3, pz, pz2);\n"
167-
" emit_vertex(0, 3, mat4(pz[0], pz[0], pz[0], pz[3]));\n"
144+
" emit_vertex(0, mat4(pz[0], pz[0], pz[0], pz[3]));\n"
168145
" EndPrimitive();\n"
169-
" emit_vertex(1, 3, mat4(pz[1], pz[1], pz[1], pz[3]));\n"
146+
" emit_vertex(1, mat4(pz[1], pz[1], pz[1], pz[3]));\n"
170147
" EndPrimitive();\n"
171-
" emit_vertex(2, 3, mat4(pz[2], pz[2], pz[2], pz[3]));\n"
148+
" emit_vertex(2, mat4(pz[2], pz[2], pz[2], pz[3]));\n"
172149
" EndPrimitive();\n"
173-
" emit_vertex(3, 3, mat4(pz2[2], pz2[2], pz2[2], pz2[3]));\n"
150+
" emit_vertex(3, mat4(pz2[2], pz2[2], pz2[2], pz2[3]));\n"
174151
" EndPrimitive();\n";
175152
}
176153
break;
177154
case PRIM_TYPE_QUAD_STRIP:
155+
provoking_index = "3";
178156
need_quadz = true;
179157
layout_in = "layout(lines_adjacency) in;\n";
180-
if (polygon_mode == POLY_MODE_LINE) {
158+
if (polygon_mode == POLY_MODE_FILL) {
159+
layout_out = "layout(triangle_strip, max_vertices = 4) out;\n";
160+
body = " if ((gl_PrimitiveIDIn & 1) != 0) { return; }\n"
161+
" mat4 pz, pz2;\n"
162+
" calc_quadz(2, 0, 1, 3, pz, pz2);\n"
163+
" emit_vertex(0, pz);\n"
164+
" emit_vertex(1, pz2);\n"
165+
" emit_vertex(2, pz);\n"
166+
" emit_vertex(3, pz2);\n"
167+
" EndPrimitive();\n";
168+
} else if (polygon_mode == POLY_MODE_LINE) {
181169
need_linez = true;
182170
layout_out = "layout(line_strip, max_vertices = 5) out;\n";
183171
body = " if ((gl_PrimitiveIDIn & 1) != 0) { return; }\n"
@@ -191,63 +179,51 @@ MString *pgraph_gen_geom_glsl(const ShaderState *state)
191179
" pz3[3].x = pzs[3].x;\n"
192180
" mat4 pz4 = calc_linez(2, 0);\n"
193181
" pz4[3].x = pz[3].x;\n"
194-
" if (gl_PrimitiveIDIn == 0) {\n"
195-
" emit_vertex(0, 3, pz1);\n"
196-
" }\n"
197-
" emit_vertex(1, 3, pz1);\n"
198-
" emit_vertex(3, 3, pz2);\n"
199-
" emit_vertex(2, 3, pz3);\n"
200-
" emit_vertex(0, 3, pz4);\n"
201-
" EndPrimitive();\n";
202-
} else if (polygon_mode == POLY_MODE_FILL) {
203-
layout_out = "layout(triangle_strip, max_vertices = 4) out;\n";
204-
body = " if ((gl_PrimitiveIDIn & 1) != 0) { return; }\n"
205-
" mat4 pz, pz2;\n"
206-
" calc_quadz(2, 0, 1, 3, pz, pz2);\n"
207-
" emit_vertex(0, 3, pz);\n"
208-
" emit_vertex(1, 3, pz2);\n"
209-
" emit_vertex(2, 3, pz);\n"
210-
" emit_vertex(3, 3, pz2);\n"
182+
" emit_vertex(0, pz1);\n"
183+
" emit_vertex(1, pz1);\n"
184+
" emit_vertex(3, pz2);\n"
185+
" emit_vertex(2, pz3);\n"
186+
" emit_vertex(0, pz4);\n"
211187
" EndPrimitive();\n";
212188
} else {
213189
assert(polygon_mode == POLY_MODE_POINT);
214190
layout_out = "layout(points, max_vertices = 4) out;\n";
215191
body = " if ((gl_PrimitiveIDIn & 1) != 0) { return; }\n"
216192
" mat4 pz, pz2;\n"
217193
" calc_quadz(2, 0, 1, 3, pz, pz2);\n"
218-
" if (gl_PrimitiveIDIn == 0) {\n"
219-
" emit_vertex(0, 3, mat4(pz[1], pz[1], pz[1], pz[3]));\n"
220-
" EndPrimitive();\n"
221-
" emit_vertex(1, 3, mat4(pz[2], pz[2], pz[2], pz[3]));\n"
222-
" EndPrimitive();\n"
223-
" }\n"
224-
" emit_vertex(2, 3, mat4(pz[0], pz[0], pz[0], pz[3]));\n"
194+
" emit_vertex(0, mat4(pz[1], pz[1], pz[1], pz[3]));\n"
195+
" EndPrimitive();\n"
196+
" emit_vertex(1, mat4(pz[2], pz[2], pz[2], pz[3]));\n"
225197
" EndPrimitive();\n"
226-
" emit_vertex(3, 3, mat4(pz2[2], pz2[2], pz2[2], pz2[3]));\n"
198+
" emit_vertex(2, mat4(pz[0], pz[0], pz[0], pz[3]));\n"
199+
" EndPrimitive();\n"
200+
" emit_vertex(3, mat4(pz2[2], pz2[2], pz2[2], pz2[3]));\n"
227201
" EndPrimitive();\n";
228202
}
229203
break;
230204
case PRIM_TYPE_POLYGON:
205+
provoking_index = "0";
231206
if (polygon_mode == POLY_MODE_FILL) {
232207
need_triz = true;
233208
layout_in = "layout(triangles) in;\n";
234209
layout_out = "layout(triangle_strip, max_vertices = 3) out;\n";
235210
body = " mat4 pz = calc_triz(0, 1, 2);\n"
236-
" emit_vertex(0, 0, pz);\n"
237-
" emit_vertex(1, 0, pz);\n"
238-
" emit_vertex(2, 0, pz);\n"
211+
" emit_vertex(0, pz);\n"
212+
" emit_vertex(1, pz);\n"
213+
" emit_vertex(2, pz);\n"
239214
" EndPrimitive();\n";
240215
} else if (polygon_mode == POLY_MODE_LINE) {
241216
need_linez = true;
242-
// FIXME: input here is lines and not triangles so we cannot
243-
// calculate triangle plane slope. Also, the first vertex of the
244-
// polygon is unavailable so flat shading provoking vertex is
245-
// wrong.
217+
/* FIXME: input here is lines and not triangles so we cannot
218+
* calculate triangle plane slope. Also, the first vertex of the
219+
* polygon is unavailable so flat shading provoking vertex is
220+
* wrong.
221+
*/
246222
layout_in = "layout(lines) in;\n";
247223
layout_out = "layout(line_strip, max_vertices = 2) out;\n";
248224
body = " mat4 pz = calc_linez(0, 1);\n"
249-
" emit_vertex(0, 0, pz);\n"
250-
" emit_vertex(1, 1, pz);\n"
225+
" emit_vertex(0, pz);\n"
226+
" emit_vertex(1, pz);\n"
251227
" EndPrimitive();\n";
252228
} else {
253229
assert(false);
@@ -276,49 +252,34 @@ MString *pgraph_gen_geom_glsl(const ShaderState *state)
276252
false, false, false);
277253

278254
if (state->smooth_shading) {
279-
mstring_append(
280-
s,
281-
"void emit_vertex(int index, int _unused, mat4 pz) {\n"
282-
" gl_Position = gl_in[index].gl_Position;\n"
283-
" gl_PointSize = gl_in[index].gl_PointSize;\n"
284-
" vtxD0 = v_vtxD0[index];\n"
285-
" vtxD1 = v_vtxD1[index];\n"
286-
" vtxB0 = v_vtxB0[index];\n"
287-
" vtxB1 = v_vtxB1[index];\n"
288-
" vtxFog = v_vtxFog[index];\n"
289-
" vtxT0 = v_vtxT0[index];\n"
290-
" vtxT1 = v_vtxT1[index];\n"
291-
" vtxT2 = v_vtxT2[index];\n"
292-
" vtxT3 = v_vtxT3[index];\n"
293-
" vtxPos0 = pz[0];\n"
294-
" vtxPos1 = pz[1];\n"
295-
" vtxPos2 = pz[2];\n"
296-
" triMZ = (isnan(pz[3].x) || isinf(pz[3].x)) ? 0.0 : pz[3].x;\n"
297-
" EmitVertex();\n"
298-
"}\n");
299-
} else {
300-
mstring_append(
301-
s,
302-
"void emit_vertex(int index, int provoking_index, mat4 pz) {\n"
303-
" gl_Position = gl_in[index].gl_Position;\n"
304-
" gl_PointSize = gl_in[index].gl_PointSize;\n"
305-
" vtxD0 = v_vtxD0[provoking_index];\n"
306-
" vtxD1 = v_vtxD1[provoking_index];\n"
307-
" vtxB0 = v_vtxB0[provoking_index];\n"
308-
" vtxB1 = v_vtxB1[provoking_index];\n"
309-
" vtxFog = v_vtxFog[index];\n"
310-
" vtxT0 = v_vtxT0[index];\n"
311-
" vtxT1 = v_vtxT1[index];\n"
312-
" vtxT2 = v_vtxT2[index];\n"
313-
" vtxT3 = v_vtxT3[index];\n"
314-
" vtxPos0 = pz[0];\n"
315-
" vtxPos1 = pz[1];\n"
316-
" vtxPos2 = pz[2];\n"
317-
" triMZ = (isnan(pz[3].x) || isinf(pz[3].x)) ? 0.0 : pz[3].x;\n"
318-
" EmitVertex();\n"
319-
"}\n");
255+
provoking_index = "index";
320256
}
321257

258+
mstring_append_fmt(
259+
s,
260+
"void emit_vertex(int index, mat4 pz) {\n"
261+
" gl_Position = gl_in[index].gl_Position;\n"
262+
" gl_PointSize = gl_in[index].gl_PointSize;\n"
263+
" vtxD0 = v_vtxD0[%s];\n"
264+
" vtxD1 = v_vtxD1[%s];\n"
265+
" vtxB0 = v_vtxB0[%s];\n"
266+
" vtxB1 = v_vtxB1[%s];\n"
267+
" vtxFog = v_vtxFog[index];\n"
268+
" vtxT0 = v_vtxT0[index];\n"
269+
" vtxT1 = v_vtxT1[index];\n"
270+
" vtxT2 = v_vtxT2[index];\n"
271+
" vtxT3 = v_vtxT3[index];\n"
272+
" vtxPos0 = pz[0];\n"
273+
" vtxPos1 = pz[1];\n"
274+
" vtxPos2 = pz[2];\n"
275+
" triMZ = (isnan(pz[3].x) || isinf(pz[3].x)) ? 0.0 : pz[3].x;\n"
276+
" EmitVertex();\n"
277+
"}\n",
278+
provoking_index,
279+
provoking_index,
280+
provoking_index,
281+
provoking_index);
282+
322283
if (need_triz || need_quadz) {
323284
mstring_append(
324285
s,
@@ -380,10 +341,12 @@ MString *pgraph_gen_geom_glsl(const ShaderState *state)
380341
if (need_linez) {
381342
mstring_append(
382343
s,
344+
// Calculate a third vertex by rotating 90 degrees so that triangle
345+
// interpolation in fragment shader can be used as is for lines.
383346
"mat4 calc_linez(int i0, int i1) {\n"
384347
" vec2 delta = v_vtxPos[i1].xy - v_vtxPos[i0].xy;\n"
385348
" vec2 v2 = vec2(-delta.y, delta.x) + v_vtxPos[i0].xy;\n"
386-
" return mat4(v_vtxPos[i0], v_vtxPos[i1], vec4(v2, v_vtxPos[i0].zw), vec4(0.0));\n"
349+
" return mat4(v_vtxPos[i0], v_vtxPos[i1], v2, v_vtxPos[i0].zw, vec4(0.0));\n"
387350
"}\n");
388351
}
389352

0 commit comments

Comments
 (0)