diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c index 62601b4b31..b3739519a1 100644 --- a/hw/xbox/nv2a.c +++ b/hw/xbox/nv2a.c @@ -1143,7 +1143,7 @@ typedef struct ShaderState { int program_length; /* primitive format for geomotry shader */ - unsigned int primitive_mode; + unsigned int primitive_mode; } ShaderState; typedef struct ShaderBinding { @@ -2122,25 +2122,17 @@ static void generate_geometry_shader_pass_vertex(QString* s, const char* v) static QString* generate_geometry_shader(unsigned int primitive_mode) { + /* generate a geometry shader to support deprecated primitive types */ QString* s = qstring_new(); qstring_append(s, "#version 330\n"); qstring_append(s, "\n"); switch (primitive_mode) { - // case NV097_SET_BEGIN_END_OP_POINTS: - // qstring_append(s, "layout(points) in;\n"); - // qstring_append(s, "layout(points, max_vertices = 1) out;\n"); - // break; - // case NV097_SET_BEGIN_END_OP_LINES: - // case NV097_SET_BEGIN_END_OP_LINE_STRIP: - // qstring_append(s, "layout(lines) in;") - // qstring_append(s, "layout(line_strip, max_vertices = 6) out;\n"); case NV097_SET_BEGIN_END_OP_QUADS: qstring_append(s, "layout(lines_adjacency) in;\n"); qstring_append(s, "layout(triangle_strip, max_vertices = 6) out;\n"); break; default: - qstring_append(s, "layout(triangles) in;\n"); - qstring_append(s, "layout(triangle_strip, max_vertices = 3) out;\n"); + assert(false); break; } qstring_append(s, "\n"); @@ -2179,10 +2171,7 @@ static QString* generate_geometry_shader(unsigned int primitive_mode) qstring_append(s, "EndPrimitive();\n"); break; default: - generate_geometry_shader_pass_vertex(s, "0"); - generate_geometry_shader_pass_vertex(s, "1"); - generate_geometry_shader_pass_vertex(s, "2"); - qstring_append(s, "EndPrimitive();\n"); + assert(false); break; } qstring_append(s, "}\n"); @@ -2206,7 +2195,7 @@ static ShaderBinding* generate_shaders(const ShaderState state) if (state.fixed_function) { /* generate vertex shader mimicking fixed function */ vertex_shader_code = qstring_new(); - qstring_append(vertex_shader_code, + qstring_append(vertex_shader_code, "#version 330\n" "\n" "in vec4 position;\n" @@ -2214,10 +2203,12 @@ static ShaderBinding* generate_shaders(const ShaderState state) "in vec4 diffuse;\n" "in vec4 specular;\n" "in float fogCoord;\n" -"in vec4 multiTexCoord0;\n" -"in vec4 multiTexCoord1;\n" -"in vec4 multiTexCoord2;\n" -"in vec4 multiTexCoord3;\n" +"in vec4 backDiffuse;\n" +"in vec4 backSpecular;\n" +"in vec4 texture0;\n" +"in vec4 texture1;\n" +"in vec4 texture2;\n" +"in vec4 texture3;\n" "\n"); qstring_append_fmt(vertex_shader_code, @@ -2256,15 +2247,21 @@ static ShaderBinding* generate_shaders(const ShaderState state) qstring_append_fmt(vertex_shader_code, "%cPos_w = 1.0/gl_Position.w;\n", v_prefix); qstring_append_fmt(vertex_shader_code, - "%cD0 = diffuse;\n", v_prefix); + "%cD0 = diffuse * %cPos_w;\n", v_prefix, v_prefix); qstring_append_fmt(vertex_shader_code, - "%cT0 = multiTexCoord0;\n", v_prefix); + "%cD1 = specular * %cPos_w;\n", v_prefix, v_prefix); qstring_append_fmt(vertex_shader_code, - "%cT1 = multiTexCoord1;\n", v_prefix); + "%cB0 = backDiffuse * %cPos_w;\n", v_prefix, v_prefix); qstring_append_fmt(vertex_shader_code, - "%cT2 = multiTexCoord2;\n", v_prefix); + "%cB1 = backSpecular * %cPos_w;\n", v_prefix, v_prefix); qstring_append_fmt(vertex_shader_code, - "%cT3 = multiTexCoord3;\n", v_prefix); + "%cT0 = texture0 * %cPos_w;\n", v_prefix, v_prefix); + qstring_append_fmt(vertex_shader_code, + "%cT1 = texture1 * %cPos_w;\n", v_prefix, v_prefix); + qstring_append_fmt(vertex_shader_code, + "%cT2 = texture2 * %cPos_w;\n", v_prefix, v_prefix); + qstring_append_fmt(vertex_shader_code, + "%cT3 = texture3 * %cPos_w;\n", v_prefix, v_prefix); qstring_append(vertex_shader_code, "}\n"); @@ -2273,7 +2270,6 @@ static ShaderBinding* generate_shaders(const ShaderState state) (uint32_t*)state.program_data, state.program_length, v_prefix); - } else { assert(false); } @@ -2309,10 +2305,12 @@ static ShaderBinding* generate_shaders(const ShaderState state) glBindAttribLocation(program, NV2A_VERTEX_ATTR_DIFFUSE, "diffuse"); glBindAttribLocation(program, NV2A_VERTEX_ATTR_SPECULAR, "specular"); glBindAttribLocation(program, NV2A_VERTEX_ATTR_FOG, "fog"); - glBindAttribLocation(program, NV2A_VERTEX_ATTR_TEXTURE0, "multiTexCoord0"); - glBindAttribLocation(program, NV2A_VERTEX_ATTR_TEXTURE1, "multiTexCoord1"); - glBindAttribLocation(program, NV2A_VERTEX_ATTR_TEXTURE2, "multiTexCoord2"); - glBindAttribLocation(program, NV2A_VERTEX_ATTR_TEXTURE3, "multiTexCoord3"); + glBindAttribLocation(program, NV2A_VERTEX_ATTR_BACK_DIFFUSE, "backDiffuse"); + glBindAttribLocation(program, NV2A_VERTEX_ATTR_BACK_SPECULAR, "backSpecular"); + glBindAttribLocation(program, NV2A_VERTEX_ATTR_TEXTURE0, "texture0"); + glBindAttribLocation(program, NV2A_VERTEX_ATTR_TEXTURE1, "texture1"); + glBindAttribLocation(program, NV2A_VERTEX_ATTR_TEXTURE2, "texture2"); + glBindAttribLocation(program, NV2A_VERTEX_ATTR_TEXTURE3, "texture3"); } else if (state.vertex_program) { /* Bind attributes for transform program*/ char tmp[8]; @@ -2320,6 +2318,8 @@ static ShaderBinding* generate_shaders(const ShaderState state) snprintf(tmp, sizeof(tmp), "v%d", i); glBindAttribLocation(program, i, tmp); } + } else { + assert(false); } diff --git a/hw/xbox/nv2a_psh.c b/hw/xbox/nv2a_psh.c index f8b2a627ee..f8145c525f 100644 --- a/hw/xbox/nv2a_psh.c +++ b/hw/xbox/nv2a_psh.c @@ -544,6 +544,7 @@ static QString* psh_convert(struct PixelShader *ps) qstring_append(preflight, "out vec4 fragColor;\n"); qstring_append(preflight, "\n"); + /* calculate perspective-correct inputs */ QString *vars = qstring_new(); qstring_append(vars, "float pFactor = gPos_w;\n"); qstring_append(vars, "vec4 pD0 = gD0 / pFactor;\n"); diff --git a/hw/xbox/nv2a_vsh.c b/hw/xbox/nv2a_vsh.c index f6101df7a8..9605acaf0c 100644 --- a/hw/xbox/nv2a_vsh.c +++ b/hw/xbox/nv2a_vsh.c @@ -782,6 +782,9 @@ QString* vsh_translate(uint16_t version, } assert(has_final); + /* pre-divide and output the generated W so we can do persepctive correct + * interpolation manually. OpenGL can't, since we give it a W of 1 to work + * around the perspective divide */ qstring_append_fmt(body, "if (oPos.w == 0.0 || isinf(oPos.w)) {\n" " %cPos_w = 1.0;" @@ -801,27 +804,30 @@ QString* vsh_translate(uint16_t version, qstring_append(body, /* the shaders leave the result in screen space, while - * opengl expects it in clip coordinates. - * Use the magic viewport constants for now, - * but they're not necessarily present... - */ + * opengl expects it in clip space. + */ - " /* Un-screenspace transform */\n" - "oPos.x = (oPos.x - viewportOffset.x) / viewportScale.x;\n" - "oPos.y = (oPos.y - viewportOffset.y) / viewportScale.y;\n" - "if (clipRange.y != clipRange.x) {\n" - " oPos.z = (oPos.z - 0.5 * (clipRange.x + clipRange.y)) / (0.5 * (clipRange.y - clipRange.x));\n" - "}\n" - - "if (oPos.w <= 0.0) {\n" - /* undo the perspective divide in the case where the point would be - * clipped so opengl can clip it correctly */ - " oPos.xyz *= oPos.w;\n" - "} else {\n" - " oPos.w = 1.0;\n" + /* Use magic viewport constants to translate xyz back into clip space + * TODO: Are they always present? + */ + "oPos.x = (oPos.x - viewportOffset.x) / viewportScale.x;\n" + "oPos.y = (oPos.y - viewportOffset.y) / viewportScale.y;\n" + "if (clipRange.y != clipRange.x) {\n" + " oPos.z = (oPos.z - 0.5 * (clipRange.x + clipRange.y)) / (0.5 * (clipRange.y - clipRange.x));\n" "}\n" - " /* Set outputs */\n" + /* Correct for the perspective divide */ + "if (oPos.w <= 0.0) {\n" + /* undo the perspective divide in the case where the point would be + * clipped so opengl can clip it correctly */ + " oPos.xyz *= oPos.w;\n" + "} else {\n" + /* we don't want the OpenGL perspective divide to happen, but we + * can't multiply by W because it could be meaningless here */ + " oPos.w = 1.0;\n" + "}\n" + + /* Set outputs */ " gl_Position = oPos;\n" " gl_PointSize = oPts.x;\n" "\n"