nv2a: Implement SET_SHADE_MODEL

This commit is contained in:
Erik Abair 2022-06-20 17:03:25 -07:00 committed by mborgerson
parent 0d84befb82
commit 4132845336
10 changed files with 193 additions and 98 deletions

View File

@ -348,6 +348,8 @@ typedef struct PGRAPHState {
bool ltc1_dirty[NV2A_LTC1_COUNT];
float material_alpha;
// FIXME: Find the correct register for this.
uint32_t shade_model;
// should figure out where these are in lighting context
float light_infinite_half_vector[NV2A_MAX_LIGHTS][3];

View File

@ -974,6 +974,9 @@
# define NV097_SET_STENCIL_OP_V_INVERT 0x150A
# define NV097_SET_STENCIL_OP_V_INCR 0x8507
# define NV097_SET_STENCIL_OP_V_DECR 0x8508
# define NV097_SET_SHADE_MODEL 0x0000037C
# define NV097_SET_SHADE_MODEL_FLAT 0x1D00
# define NV097_SET_SHADE_MODEL_SMOOTH 0x1D01
# define NV097_SET_POLYGON_OFFSET_SCALE_FACTOR 0x00000384
# define NV097_SET_POLYGON_OFFSET_BIAS 0x00000388
# define NV097_SET_FRONT_POLYGON_MODE 0x0000038C

View File

@ -1840,6 +1840,12 @@ DEF_METHOD(NV097, SET_STENCIL_OP_ZPASS)
kelvin_map_stencil_op(parameter));
}
DEF_METHOD(NV097, SET_SHADE_MODEL)
{
// FIXME: Find the correct register for this.
pg->shade_model = parameter;
}
DEF_METHOD(NV097, SET_POLYGON_OFFSET_SCALE_FACTOR)
{
pg->regs[NV_PGRAPH_ZOFFSETFACTOR] = parameter;
@ -2973,6 +2979,10 @@ DEF_METHOD(NV097, SET_BEGIN_END)
glDisable(GL_DEPTH_CLAMP);
}
if (pg->shade_model == NV097_SET_SHADE_MODEL_FLAT) {
glProvokingVertex(GL_FIRST_VERTEX_CONVENTION);
}
if (stencil_test) {
glEnable(GL_STENCIL_TEST);
@ -3996,6 +4006,7 @@ void pgraph_init(NV2AState *d)
pg->shader_cache = g_hash_table_new(shader_hash, shader_equal);
pg->material_alpha = 0.0f;
pg->shade_model = NV097_SET_SHADE_MODEL_SMOOTH;
pg->primitive_mode = PRIM_TYPE_INVALID;
for (i=0; i<NV2A_VERTEXSHADER_ATTRIBUTES; i++) {
@ -4320,6 +4331,7 @@ static bool pgraph_bind_shaders_test_dirty(PGRAPHState *pg)
CR_8(NV_PGRAPH_WINDOWCLIPX0) \
CR_8(NV_PGRAPH_WINDOWCLIPY0) \
CF(pg->primitive_mode, primitive_mode) \
CF(pg->shade_model, shade_model) \
CF(pg->surface_scale_factor, surface_scale_factor) \
CF(pg->compressed_attrs, compressed_attrs) \
CFA(pg->texture_matrix_enable, texture_matrix_enable)
@ -4441,6 +4453,9 @@ static void pgraph_bind_shaders(PGRAPHState *pg)
state.polygon_back_mode = (enum ShaderPolygonMode)GET_MASK(pg->regs[NV_PGRAPH_SETUPRASTER],
NV_PGRAPH_SETUPRASTER_BACKFACEMODE);
state.shade_model_flat = pg->shade_model == NV097_SET_SHADE_MODEL_FLAT;
state.psh.shade_model_flat = pg->shade_model == NV097_SET_SHADE_MODEL_FLAT;
state.program_length = 0;
if (vertex_program) {

View File

@ -66,6 +66,7 @@ DEF_METHOD(NV097, SET_STENCIL_FUNC_MASK)
DEF_METHOD(NV097, SET_STENCIL_OP_FAIL)
DEF_METHOD(NV097, SET_STENCIL_OP_ZFAIL)
DEF_METHOD(NV097, SET_STENCIL_OP_ZPASS)
DEF_METHOD(NV097, SET_SHADE_MODEL)
DEF_METHOD(NV097, SET_POLYGON_OFFSET_SCALE_FACTOR)
DEF_METHOD(NV097, SET_POLYGON_OFFSET_BIAS)
DEF_METHOD(NV097, SET_FRONT_POLYGON_MODE)

View File

@ -690,9 +690,8 @@ static MString* psh_convert(struct PixelShader *ps)
int i;
MString *preflight = mstring_new();
mstring_append(preflight, STRUCT_VERTEX_DATA);
mstring_append(preflight, "noperspective in VertexData g_vtx;\n");
mstring_append(preflight, "#define vtx g_vtx\n");
mstring_append(preflight,
ps->state.shade_model_flat ? STRUCT_VERTEX_DATA_IN_FLAT : STRUCT_VERTEX_DATA_IN_SMOOTH);
mstring_append(preflight, "\n");
mstring_append(preflight, "out vec4 fragColor;\n");
mstring_append(preflight, "\n");
@ -801,19 +800,19 @@ static MString* psh_convert(struct PixelShader *ps)
/* calculate perspective-correct inputs */
MString *vars = mstring_new();
mstring_append(vars, "vec4 pD0 = vtx.D0 / vtx.inv_w;\n");
mstring_append(vars, "vec4 pD1 = vtx.D1 / vtx.inv_w;\n");
mstring_append(vars, "vec4 pB0 = vtx.B0 / vtx.inv_w;\n");
mstring_append(vars, "vec4 pB1 = vtx.B1 / vtx.inv_w;\n");
mstring_append(vars, "vec4 pFog = vec4(fogColor.rgb, clamp(vtx.Fog / vtx.inv_w, 0.0, 1.0));\n");
mstring_append(vars, "vec4 pT0 = vtx.T0 / vtx.inv_w;\n");
mstring_append(vars, "vec4 pT1 = vtx.T1 / vtx.inv_w;\n");
mstring_append(vars, "vec4 pT2 = vtx.T2 / vtx.inv_w;\n");
mstring_append(vars, "vec4 pD0 = vtxD0 / vtx_inv_w;\n");
mstring_append(vars, "vec4 pD1 = vtxD1 / vtx_inv_w;\n");
mstring_append(vars, "vec4 pB0 = vtxB0 / vtx_inv_w;\n");
mstring_append(vars, "vec4 pB1 = vtxB1 / vtx_inv_w;\n");
mstring_append(vars, "vec4 pFog = vec4(fogColor.rgb, clamp(vtxFog / vtx_inv_w, 0.0, 1.0));\n");
mstring_append(vars, "vec4 pT0 = vtxT0 / vtx_inv_w;\n");
mstring_append(vars, "vec4 pT1 = vtxT1 / vtx_inv_w;\n");
mstring_append(vars, "vec4 pT2 = vtxT2 / vtx_inv_w;\n");
if (ps->state.point_sprite) {
assert(!ps->state.rect_tex[3]);
mstring_append(vars, "vec4 pT3 = vec4(gl_PointCoord, 1.0, 1.0);\n");
} else {
mstring_append(vars, "vec4 pT3 = vtx.T3 / vtx.inv_w;\n");
mstring_append(vars, "vec4 pT3 = vtxT3 / vtx_inv_w;\n");
}
mstring_append(vars, "\n");
mstring_append(vars, "vec4 v0 = pD0;\n");

View File

@ -78,6 +78,8 @@ typedef struct PshState {
enum PshAlphaFunc alpha_func;
bool window_clip_exclusive;
bool shade_model_flat;
} PshState;
MString *psh_translate(const PshState state);

View File

@ -75,7 +75,8 @@ static MString* generate_geometry_shader(
enum ShaderPolygonMode polygon_front_mode,
enum ShaderPolygonMode polygon_back_mode,
enum ShaderPrimitiveMode primitive_mode,
GLenum *gl_primitive_mode)
GLenum *gl_primitive_mode,
bool shade_model_flat)
{
/* FIXME: Missing support for 2-sided-poly mode */
@ -103,10 +104,10 @@ static MString* generate_geometry_shader(
assert(polygon_mode == POLY_MODE_LINE);
layout_in = "layout(triangles) in;\n";
layout_out = "layout(line_strip, max_vertices = 4) out;\n";
body = " emit_vertex(0);\n"
" emit_vertex(1);\n"
" emit_vertex(2);\n"
" emit_vertex(0);\n"
body = " emit_vertex(0, 0);\n"
" emit_vertex(1, 0);\n"
" emit_vertex(2, 0);\n"
" emit_vertex(0, 0);\n"
" EndPrimitive();\n";
break;
case PRIM_TYPE_TRIANGLE_STRIP:
@ -119,15 +120,15 @@ static MString* generate_geometry_shader(
* vertex we are using */
body = " if ((gl_PrimitiveIDIn & 1) == 0) {\n"
" if (gl_PrimitiveIDIn == 0) {\n"
" emit_vertex(0);\n" /* bottom right */
" emit_vertex(0, 0);\n" /* bottom right */
" }\n"
" emit_vertex(1);\n" /* top right */
" emit_vertex(2);\n" /* bottom left */
" emit_vertex(0);\n" /* bottom right */
" emit_vertex(1, 0);\n" /* top right */
" emit_vertex(2, 0);\n" /* bottom left */
" emit_vertex(0, 0);\n" /* bottom right */
" } else {\n"
" emit_vertex(2);\n" /* bottom left */
" emit_vertex(1);\n" /* top left */
" emit_vertex(0);\n" /* top right */
" emit_vertex(2, 0);\n" /* bottom left */
" emit_vertex(1, 0);\n" /* top left */
" emit_vertex(0, 0);\n" /* top right */
" }\n"
" EndPrimitive();\n";
break;
@ -140,9 +141,9 @@ static MString* generate_geometry_shader(
body = " if (gl_PrimitiveIDIn == 0) {\n"
" emit_vertex(0);\n"
" }\n"
" emit_vertex(1);\n"
" emit_vertex(2);\n"
" emit_vertex(0);\n"
" emit_vertex(1, 0);\n"
" emit_vertex(2, 0);\n"
" emit_vertex(0, 0);\n"
" EndPrimitive();\n";
break;
case PRIM_TYPE_QUADS:
@ -150,18 +151,18 @@ static MString* generate_geometry_shader(
layout_in = "layout(lines_adjacency) in;\n";
if (polygon_mode == POLY_MODE_LINE) {
layout_out = "layout(line_strip, max_vertices = 5) out;\n";
body = " emit_vertex(0);\n"
" emit_vertex(1);\n"
" emit_vertex(2);\n"
" emit_vertex(3);\n"
" emit_vertex(0);\n"
body = " emit_vertex(0, 3);\n"
" emit_vertex(1, 3);\n"
" emit_vertex(2, 3);\n"
" emit_vertex(3, 3);\n"
" emit_vertex(0, 3);\n"
" EndPrimitive();\n";
} else if (polygon_mode == POLY_MODE_FILL) {
layout_out = "layout(triangle_strip, max_vertices = 4) out;\n";
body = " emit_vertex(0);\n"
" emit_vertex(1);\n"
" emit_vertex(3);\n"
" emit_vertex(2);\n"
body = " emit_vertex(3, 3);\n"
" emit_vertex(0, 3);\n"
" emit_vertex(2, 3);\n"
" emit_vertex(1, 3);\n"
" EndPrimitive();\n";
} else {
assert(false);
@ -175,20 +176,20 @@ static MString* generate_geometry_shader(
layout_out = "layout(line_strip, max_vertices = 5) out;\n";
body = " if ((gl_PrimitiveIDIn & 1) != 0) { return; }\n"
" if (gl_PrimitiveIDIn == 0) {\n"
" emit_vertex(0);\n"
" emit_vertex(0, 3);\n"
" }\n"
" emit_vertex(1);\n"
" emit_vertex(3);\n"
" emit_vertex(2);\n"
" emit_vertex(0);\n"
" emit_vertex(1, 3);\n"
" emit_vertex(3, 3);\n"
" emit_vertex(2, 3);\n"
" emit_vertex(0, 3);\n"
" EndPrimitive();\n";
} else if (polygon_mode == POLY_MODE_FILL) {
layout_out = "layout(triangle_strip, max_vertices = 4) out;\n";
body = " if ((gl_PrimitiveIDIn & 1) != 0) { return; }\n"
" emit_vertex(0);\n"
" emit_vertex(1);\n"
" emit_vertex(2);\n"
" emit_vertex(3);\n"
" emit_vertex(0, 3);\n"
" emit_vertex(1, 3);\n"
" emit_vertex(2, 3);\n"
" emit_vertex(3, 3);\n"
" EndPrimitive();\n";
} else {
assert(false);
@ -198,12 +199,25 @@ static MString* generate_geometry_shader(
case PRIM_TYPE_POLYGON:
if (polygon_mode == POLY_MODE_LINE) {
*gl_primitive_mode = GL_LINE_LOOP;
} else if (polygon_mode == POLY_MODE_FILL) {
return NULL;
}
if (polygon_mode == POLY_MODE_FILL) {
*gl_primitive_mode = GL_TRIANGLE_FAN;
if (!shade_model_flat) {
return NULL;
}
layout_in = "layout(triangles) in;\n";
layout_out = "layout(triangle_strip, max_vertices = 3) out;\n";
body = " emit_vertex(0, 2);\n"
" emit_vertex(1, 2);\n"
" emit_vertex(2, 2);\n"
" EndPrimitive();\n";
} else {
assert(false);
return NULL;
}
return NULL;
break;
default:
assert(false);
return NULL;
@ -217,18 +231,52 @@ static MString* generate_geometry_shader(
"\n");
mstring_append(s, layout_in);
mstring_append(s, layout_out);
mstring_append(s, "\n");
if (shade_model_flat) {
mstring_append(s,
STRUCT_V_VERTEX_DATA_IN_ARRAY_FLAT
"\n"
STRUCT_VERTEX_DATA_OUT_FLAT
"\n"
"void emit_vertex(int index, int provoking_index) {\n"
" gl_Position = gl_in[index].gl_Position;\n"
" gl_PointSize = gl_in[index].gl_PointSize;\n"
" vtx_inv_w = v_vtx_inv_w[index];\n"
" vtxD0 = v_vtxD0[provoking_index];\n"
" vtxD1 = v_vtxD1[provoking_index];\n"
" vtxB0 = v_vtxB0[provoking_index];\n"
" vtxB1 = v_vtxB1[provoking_index];\n"
" vtxFog = v_vtxFog[index];\n"
" vtxT0 = v_vtxT0[index];\n"
" vtxT1 = v_vtxT1[index];\n"
" vtxT2 = v_vtxT2[index];\n"
" vtxT3 = v_vtxT3[index];\n"
" EmitVertex();\n"
"}\n");
} else {
mstring_append(s,
STRUCT_V_VERTEX_DATA_IN_ARRAY_SMOOTH
"\n"
STRUCT_VERTEX_DATA_OUT_SMOOTH
"\n"
"void emit_vertex(int index, int _unused) {\n"
" gl_Position = gl_in[index].gl_Position;\n"
" gl_PointSize = gl_in[index].gl_PointSize;\n"
" vtx_inv_w = v_vtx_inv_w[index];\n"
" vtxD0 = v_vtxD0[index];\n"
" vtxD1 = v_vtxD1[index];\n"
" vtxB0 = v_vtxB0[index];\n"
" vtxB1 = v_vtxB1[index];\n"
" vtxFog = v_vtxFog[index];\n"
" vtxT0 = v_vtxT0[index];\n"
" vtxT1 = v_vtxT1[index];\n"
" vtxT2 = v_vtxT2[index];\n"
" vtxT3 = v_vtxT3[index];\n"
" EmitVertex();\n"
"}\n");
}
mstring_append(s, "\n"
STRUCT_VERTEX_DATA
"noperspective in VertexData v_vtx[];\n"
"noperspective out VertexData g_vtx;\n"
"\n"
"void emit_vertex(int index) {\n"
" gl_Position = gl_in[index].gl_Position;\n"
" gl_PointSize = gl_in[index].gl_PointSize;\n"
" g_vtx = v_vtx[index];\n"
" EmitVertex();\n"
"}\n"
"\n"
"void main() {\n");
mstring_append(s, body);
mstring_append(s, "}\n");
@ -694,17 +742,16 @@ GLSL_DEFINE(materialEmissionColor, GLSL_LTCTXA(NV_IGRAPH_XF_LTCTXA_CM_COL) ".xyz
state->surface_scale_factor);
}
mstring_append(body,
" if (oPos.w == 0.0 || isinf(oPos.w)) {\n"
" vtx.inv_w = 1.0;\n"
" vtx_inv_w = 1.0;\n"
" } else {\n"
" vtx.inv_w = 1.0 / oPos.w;\n"
" vtx_inv_w = 1.0 / oPos.w;\n"
" }\n");
}
static MString *generate_vertex_shader(const ShaderState *state,
char vtx_prefix)
bool prefix_outputs)
{
int i;
MString *header = mstring_from_str(
@ -758,13 +805,32 @@ GLSL_DEFINE(texMat3, GLSL_C_MAT4(NV_IGRAPH_XF_XFCTX_T3MAT))
" float y = float(bitfieldExtract(cmp, 11, 11)) / 1023.0;\n"
" float z = float(bitfieldExtract(cmp, 22, 10)) / 511.0;\n"
" return vec4(x, y, z, 1);\n"
"}\n"
STRUCT_VERTEX_DATA);
mstring_append_fmt(header, "noperspective out VertexData %c_vtx;\n",
vtx_prefix);
mstring_append_fmt(header, "#define vtx %c_vtx\n",
vtx_prefix);
"}\n");
if (prefix_outputs) {
if (state->shade_model_flat) {
mstring_append(header, STRUCT_V_VERTEX_DATA_OUT_FLAT);
} else {
mstring_append(header, STRUCT_V_VERTEX_DATA_OUT_SMOOTH);
}
mstring_append(header,
"#define vtx_inv_w v_vtx_inv_w\n"
"#define vtxD0 v_vtxD0\n"
"#define vtxD1 v_vtxD1\n"
"#define vtxB0 v_vtxB0\n"
"#define vtxB1 v_vtxB1\n"
"#define vtxFog v_vtxFog\n"
"#define vtxT0 v_vtxT0\n"
"#define vtxT1 v_vtxT1\n"
"#define vtxT2 v_vtxT2\n"
"#define vtxT3 v_vtxT3\n"
);
} else {
if (state->shade_model_flat) {
mstring_append(header, STRUCT_VERTEX_DATA_OUT_FLAT);
} else {
mstring_append(header, STRUCT_VERTEX_DATA_OUT_SMOOTH);
}
}
mstring_append(header, "\n");
for (i = 0; i < NV2A_VERTEXSHADER_ATTRIBUTES; i++) {
if (state->compressed_attrs & (1 << i)) {
@ -885,15 +951,15 @@ STRUCT_VERTEX_DATA);
/* Set outputs */
mstring_append(body, "\n"
" vtx.D0 = clamp(oD0, 0.0, 1.0) * vtx.inv_w;\n"
" vtx.D1 = clamp(oD1, 0.0, 1.0) * vtx.inv_w;\n"
" vtx.B0 = clamp(oB0, 0.0, 1.0) * vtx.inv_w;\n"
" vtx.B1 = clamp(oB1, 0.0, 1.0) * vtx.inv_w;\n"
" vtx.Fog = oFog.x * vtx.inv_w;\n"
" vtx.T0 = oT0 * vtx.inv_w;\n"
" vtx.T1 = oT1 * vtx.inv_w;\n"
" vtx.T2 = oT2 * vtx.inv_w;\n"
" vtx.T3 = oT3 * vtx.inv_w;\n"
" vtxD0 = clamp(oD0, 0.0, 1.0) * vtx_inv_w;\n"
" vtxD1 = clamp(oD1, 0.0, 1.0) * vtx_inv_w;\n"
" vtxB0 = clamp(oB0, 0.0, 1.0) * vtx_inv_w;\n"
" vtxB1 = clamp(oB1, 0.0, 1.0) * vtx_inv_w;\n"
" vtxFog = oFog.x * vtx_inv_w;\n"
" vtxT0 = oT0 * vtx_inv_w;\n"
" vtxT1 = oT1 * vtx_inv_w;\n"
" vtxT2 = oT2 * vtx_inv_w;\n"
" vtxT3 = oT3 * vtx_inv_w;\n"
" gl_Position = oPos;\n"
" gl_PointSize = oPts.x;\n"
"\n"
@ -955,7 +1021,6 @@ ShaderBinding *generate_shaders(const ShaderState *state)
/* Ensure numeric values are printed with '.' radix, no grouping */
setlocale(LC_NUMERIC, "C");
char vtx_prefix;
GLuint program = glCreateProgram();
/* Create an option geometry shader and find primitive type */
@ -964,7 +1029,8 @@ ShaderBinding *generate_shaders(const ShaderState *state)
generate_geometry_shader(state->polygon_front_mode,
state->polygon_back_mode,
state->primitive_mode,
&gl_primitive_mode);
&gl_primitive_mode,
state->shade_model_flat);
if (geometry_shader_code) {
const char* geometry_shader_code_str =
mstring_get_str(geometry_shader_code);
@ -973,13 +1039,10 @@ ShaderBinding *generate_shaders(const ShaderState *state)
"geometry shader");
glAttachShader(program, geometry_shader);
mstring_unref(geometry_shader_code);
vtx_prefix = 'v';
} else {
vtx_prefix = 'g';
}
/* create the vertex shader */
MString *vertex_shader_code = generate_vertex_shader(state, vtx_prefix);
MString *vertex_shader_code = generate_vertex_shader(state, geometry_shader_code);
GLuint vertex_shader = create_gl_shader(GL_VERTEX_SHADER,
mstring_get_str(vertex_shader_code),
"vertex shader");

View File

@ -97,6 +97,8 @@ typedef struct ShaderState {
bool point_params_enable;
float point_size;
float point_params[8];
bool shade_model_flat;
} ShaderState;
typedef struct ShaderBinding {

View File

@ -23,19 +23,27 @@
#include "debug.h"
#define STRUCT_VERTEX_DATA "struct VertexData {\n" \
" float inv_w;\n" \
" vec4 D0;\n" \
" vec4 D1;\n" \
" vec4 B0;\n" \
" vec4 B1;\n" \
" float Fog;\n" \
" vec4 T0;\n" \
" vec4 T1;\n" \
" vec4 T2;\n" \
" vec4 T3;\n" \
"};\n"
#define DEF_VERTEX_DATA(qualifier, in_out, prefix, suffix) \
"noperspective " in_out " float " prefix "vtx_inv_w" suffix ";\n" \
qualifier " " in_out " vec4 " prefix "vtxD0" suffix ";\n" \
qualifier " " in_out " vec4 " prefix "vtxD1" suffix ";\n" \
qualifier " " in_out " vec4 " prefix "vtxB0" suffix ";\n" \
qualifier " " in_out " vec4 " prefix "vtxB1" suffix ";\n" \
"noperspective " in_out " float " prefix "vtxFog" suffix ";\n" \
"noperspective " in_out " vec4 " prefix "vtxT0" suffix ";\n" \
"noperspective " in_out " vec4 " prefix "vtxT1" suffix ";\n" \
"noperspective " in_out " vec4 " prefix "vtxT2" suffix ";\n" \
"noperspective " in_out " vec4 " prefix "vtxT3" suffix ";\n"
#define STRUCT_VERTEX_DATA_OUT_SMOOTH DEF_VERTEX_DATA("noperspective", "out", "", "")
#define STRUCT_VERTEX_DATA_IN_SMOOTH DEF_VERTEX_DATA("noperspective", "in", "", "")
#define STRUCT_V_VERTEX_DATA_OUT_SMOOTH DEF_VERTEX_DATA("noperspective", "out", "v_", "")
#define STRUCT_V_VERTEX_DATA_IN_ARRAY_SMOOTH DEF_VERTEX_DATA("noperspective", "in", "v_", "[]")
#define STRUCT_VERTEX_DATA_OUT_FLAT DEF_VERTEX_DATA("flat", "out", "", "")
#define STRUCT_VERTEX_DATA_IN_FLAT DEF_VERTEX_DATA("flat", "in", "", "")
#define STRUCT_V_VERTEX_DATA_OUT_FLAT DEF_VERTEX_DATA("flat", "out", "v_", "")
#define STRUCT_V_VERTEX_DATA_IN_ARRAY_FLAT DEF_VERTEX_DATA("flat", "in", "v_", "[]")
typedef struct {
int ref;

View File

@ -821,9 +821,9 @@ void vsh_translate(uint16_t version,
* around the perspective divide */
mstring_append(body,
" if (oPos.w == 0.0 || isinf(oPos.w)) {\n"
" vtx.inv_w = 1.0;\n"
" vtx_inv_w = 1.0;\n"
" } else {\n"
" vtx.inv_w = 1.0 / oPos.w;\n"
" vtx_inv_w = 1.0 / oPos.w;\n"
" }\n"
);