diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c
index 5f3195e3fd..40166856c1 100644
--- a/hw/xbox/nv2a.c
+++ b/hw/xbox/nv2a.c
@@ -2,6 +2,7 @@
* QEMU Geforce NV2A implementation
*
* Copyright (c) 2012 espes
+ * Copyright (c) 2015 JayFoxRox
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -32,8 +33,7 @@
#include "hw/xbox/g-lru-cache.h"
#include "hw/xbox/swizzle.h"
#include "hw/xbox/u_format_r11g11b10f.h"
-#include "hw/xbox/nv2a_vsh.h"
-#include "hw/xbox/nv2a_psh.h"
+#include "hw/xbox/nv2a_shaders.h"
#include "hw/xbox/nv2a.h"
@@ -1269,31 +1269,11 @@ static const SurfaceColorFormatInfo kelvin_surface_color_format_map[] = {
{4, GL_RGBA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV},
};
-#define NV2A_VERTEX_ATTR_POSITION 0
-#define NV2A_VERTEX_ATTR_WEIGHT 1
-#define NV2A_VERTEX_ATTR_NORMAL 2
-#define NV2A_VERTEX_ATTR_DIFFUSE 3
-#define NV2A_VERTEX_ATTR_SPECULAR 4
-#define NV2A_VERTEX_ATTR_FOG 5
-#define NV2A_VERTEX_ATTR_POINT_SIZE 6
-#define NV2A_VERTEX_ATTR_BACK_DIFFUSE 7
-#define NV2A_VERTEX_ATTR_BACK_SPECULAR 8
-#define NV2A_VERTEX_ATTR_TEXTURE0 9
-#define NV2A_VERTEX_ATTR_TEXTURE1 10
-#define NV2A_VERTEX_ATTR_TEXTURE2 11
-#define NV2A_VERTEX_ATTR_TEXTURE3 12
-#define NV2A_VERTEX_ATTR_RESERVED1 13
-#define NV2A_VERTEX_ATTR_RESERVED2 14
-#define NV2A_VERTEX_ATTR_RESERVED3 15
-
-
#define NV2A_CRYSTAL_FREQ 13500000
#define NV2A_NUM_CHANNELS 32
#define NV2A_NUM_SUBCHANNELS 8
#define NV2A_MAX_BATCH_LENGTH 0xFFFF
-#define NV2A_MAX_TRANSFORM_PROGRAM_LENGTH 136
-#define NV2A_VERTEXSHADER_CONSTANTS 192
#define NV2A_VERTEXSHADER_ATTRIBUTES 16
#define NV2A_MAX_TEXTURES 4
@@ -1379,48 +1359,6 @@ typedef struct VertexShaderConstant {
uint32_t data[4];
} VertexShaderConstant;
-typedef struct ShaderState {
- /* fragment shader - register combiner stuff */
- uint32_t combiner_control;
- uint32_t shader_stage_program;
- uint32_t other_stage_input;
- uint32_t final_inputs_0;
- uint32_t final_inputs_1;
-
- uint32_t rgb_inputs[8], rgb_outputs[8];
- uint32_t alpha_inputs[8], alpha_outputs[8];
-
- bool rect_tex[4];
- bool compare_mode[4][4];
- bool alphakill[4];
-
- bool alpha_test;
- enum PshAlphaFunc alpha_func;
-
- bool texture_matrix_enable[4];
- enum VshTexgen texgen[4][4];
-
- enum VshSkinning skinning;
-
- bool normalization;
-
- bool fixed_function;
-
- /* vertex program */
- bool vertex_program;
- uint32_t program_data[NV2A_MAX_TRANSFORM_PROGRAM_LENGTH][VSH_TOKEN_SIZE];
- int program_length;
-
- /* primitive format for geomotry shader */
- unsigned int primitive_mode;
-} ShaderState;
-
-typedef struct ShaderBinding {
- GLuint gl_program;
- GLint psh_constant_loc[9][2];
- GLint vsh_constant_loc[NV2A_VERTEXSHADER_CONSTANTS];
-} ShaderBinding;
-
typedef struct Surface {
bool draw_dirty;
bool buffer_dirty;
@@ -2708,492 +2646,6 @@ static void pgraph_bind_textures(NV2AState *d)
NV2A_GL_DGROUP_END();
}
-/* hash and equality for shader cache hash table */
-static guint shader_hash(gconstpointer key)
-{
- return fnv_hash(key, sizeof(ShaderState));
-}
-static gboolean shader_equal(gconstpointer a, gconstpointer b)
-{
- const ShaderState *as = a, *bs = b;
- return memcmp(as, bs, sizeof(ShaderState)) == 0;
-}
-
-static void generate_geometry_shader_pass_vertex(QString* s, const char* v)
-{
- qstring_append_fmt(s, " gD0 = vD0[%s];\n", v);
- qstring_append_fmt(s, " gD1 = vD1[%s];\n", v);
- qstring_append_fmt(s, " gB0 = vB0[%s];\n", v);
- qstring_append_fmt(s, " gB1 = vB1[%s];\n", v);
- qstring_append_fmt(s, " gFog = vFog[%s];\n", v);
- qstring_append_fmt(s, " gT0 = vT0[%s];\n", v);
- qstring_append_fmt(s, " gT1 = vT1[%s];\n", v);
- qstring_append_fmt(s, " gT2 = vT2[%s];\n", v);
- qstring_append_fmt(s, " gT3 = vT3[%s];\n", v);
- qstring_append_fmt(s, " gPos_w = vPos_w[%s];\n", v);
- qstring_append_fmt(s, " gl_Position = gl_in[%s].gl_Position;\n", v);
- qstring_append(s, " EmitVertex();\n");
-}
-
-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_QUADS:
- qstring_append(s, "layout(lines_adjacency) in;\n");
- qstring_append(s, "layout(triangle_strip, max_vertices = 4) out;\n");
- break;
- default:
- assert(false);
- break;
- }
- qstring_append(s, "\n");
- qstring_append(s, "noperspective in float vPos_w[];\n");
- qstring_append(s, "noperspective in vec4 vD0[];\n");
- qstring_append(s, "noperspective in vec4 vD1[];\n");
- qstring_append(s, "noperspective in vec4 vB0[];\n");
- qstring_append(s, "noperspective in vec4 vB1[];\n");
- qstring_append(s, "noperspective in vec4 vFog[];\n");
- qstring_append(s, "noperspective in vec4 vT0[];\n");
- qstring_append(s, "noperspective in vec4 vT1[];\n");
- qstring_append(s, "noperspective in vec4 vT2[];\n");
- qstring_append(s, "noperspective in vec4 vT3[];\n");
- qstring_append(s, "\n");
- qstring_append(s, "noperspective out float gPos_w;\n");
- qstring_append(s, "noperspective out vec4 gD0;\n");
- qstring_append(s, "noperspective out vec4 gD1;\n");
- qstring_append(s, "noperspective out vec4 gB0;\n");
- qstring_append(s, "noperspective out vec4 gB1;\n");
- qstring_append(s, "noperspective out vec4 gFog;\n");
- qstring_append(s, "noperspective out vec4 gT0;\n");
- qstring_append(s, "noperspective out vec4 gT1;\n");
- qstring_append(s, "noperspective out vec4 gT2;\n");
- qstring_append(s, "noperspective out vec4 gT3;\n");
- qstring_append(s, "\n");
- qstring_append(s, "void main() {\n");
- switch (primitive_mode) {
- case NV097_SET_BEGIN_END_OP_QUADS:
- generate_geometry_shader_pass_vertex(s, "0");
- generate_geometry_shader_pass_vertex(s, "1");
- generate_geometry_shader_pass_vertex(s, "3");
- generate_geometry_shader_pass_vertex(s, "2");
- qstring_append(s, "EndPrimitive();\n");
- break;
- default:
- assert(false);
- break;
- }
- qstring_append(s, "}\n");
-
- return s;
-}
-
-static ShaderBinding* generate_shaders(const ShaderState state)
-{
- int i, j;
- GLint compiled = 0;
-
- bool with_geom = state.primitive_mode == NV097_SET_BEGIN_END_OP_QUADS;
- char v_prefix = with_geom ? 'v' : 'g';
-
- GLuint program = glCreateProgram();
-
- /* create the vertex shader */
-
- QString *vertex_shader_code = NULL;
- if (state.fixed_function) {
- /* generate vertex shader mimicking fixed function */
- vertex_shader_code = qstring_new();
- qstring_append(vertex_shader_code,
-"#version 330\n"
-"\n"
-"in vec4 position;\n"
-"in vec4 weight;\n"
-"in vec3 normal;\n"
-"in vec4 diffuse;\n"
-"in vec4 specular;\n"
-"in float fogCoord;\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,
- "noperspective out float %cPos_w;\n", v_prefix);
- qstring_append_fmt(vertex_shader_code,
- "noperspective out vec4 %cD0 = vec4(0.0,0.0,0.0,1.0);\n", v_prefix);
- qstring_append_fmt(vertex_shader_code,
- "noperspective out vec4 %cD1 = vec4(0.0,0.0,0.0,1.0);\n", v_prefix);
- qstring_append_fmt(vertex_shader_code,
- "noperspective out vec4 %cB0 = vec4(0.0,0.0,0.0,1.0);\n", v_prefix);
- qstring_append_fmt(vertex_shader_code,
- "noperspective out vec4 %cB1 = vec4(0.0,0.0,0.0,1.0);\n", v_prefix);
- qstring_append_fmt(vertex_shader_code,
- "noperspective out vec4 %cFog = vec4(0.0,0.0,0.0,1.0);\n", v_prefix);
- qstring_append_fmt(vertex_shader_code,
- "noperspective out vec4 %cT0 = vec4(0.0,0.0,0.0,1.0);\n", v_prefix);
- qstring_append_fmt(vertex_shader_code,
- "noperspective out vec4 %cT1 = vec4(0.0,0.0,0.0,1.0);\n", v_prefix);
- qstring_append_fmt(vertex_shader_code,
- "noperspective out vec4 %cT2 = vec4(0.0,0.0,0.0,1.0);\n", v_prefix);
- qstring_append_fmt(vertex_shader_code,
- "noperspective out vec4 %cT3 = vec4(0.0,0.0,0.0,1.0);\n", v_prefix);
-
- qstring_append(vertex_shader_code,
-"\n"
-/* FIXME: Add these uniforms using code when they are used */
-"uniform mat4 texMat0;\n"
-"uniform mat4 texMat1;\n"
-"uniform mat4 texMat2;\n"
-"uniform mat4 texMat3;\n"
-"uniform mat4 modelViewMat0;\n"
-"uniform mat4 modelViewMat1;\n"
-"uniform mat4 modelViewMat2;\n"
-"uniform mat4 modelViewMat3;\n"
-"uniform mat4 invModelViewMat0;\n"
-"uniform mat4 invModelViewMat1;\n"
-"uniform mat4 invModelViewMat2;\n"
-"uniform mat4 invModelViewMat3;\n"
-"uniform mat4 projectionMat; /* FIXME: when is this used? */\n"
-"uniform mat4 compositeMat;\n"
-"uniform mat4 invViewport;\n"
-"\n"
-"void main() {\n");
-
- /* Skinning */
- unsigned int count;
- bool mix;
- switch (state.skinning) {
- case SKINNING_OFF:
- count = 0; break;
- case SKINNING_1WEIGHTS:
- mix = true; count = 2; break;
- case SKINNING_2WEIGHTS:
- mix = true; count = 3; break;
- case SKINNING_3WEIGHTS:
- mix = true; count = 4; break;
- case SKINNING_2WEIGHTS2MATRICES:
- mix = false; count = 2; break;
- case SKINNING_3WEIGHTS3MATRICES:
- mix = false; count = 3; break;
- case SKINNING_4WEIGHTS4MATRICES:
- mix = false; count = 4; break;
- default:
- assert(false);
- break;
- }
- qstring_append_fmt(vertex_shader_code, "/* Skinning mode %d */\n",
- state.skinning);
- if (count == 0) {
- qstring_append(vertex_shader_code, "vec4 tPosition = position * modelViewMat0;\n");
- /* FIXME: Is the normal still transformed? */
- qstring_append(vertex_shader_code, "vec3 tNormal = (vec4(normal, 0.0) * invModelViewMat0).xyz;\n");
- } else {
- qstring_append(vertex_shader_code, "vec4 tPosition = vec4(0.0);\n");
- qstring_append(vertex_shader_code, "vec3 tNormal = vec3(0.0);\n");
- if (mix) {
- /* Tweening */
- if (count == 2) {
- qstring_append(vertex_shader_code,
- "tPosition += mix(position * modelViewMat1,\n"
- " position * modelViewMat0, weight.x);\n"
- "tNormal += mix((vec4(normal, 0.0) * invModelViewMat1).xyz,\n"
- " (vec4(normal, 0.0) * invModelViewMat0).xyz, weight.x);\n");
- } else {
- /* FIXME: Not sure how blend weights are calculated */
- assert(false);
- }
- } else {
- /* Individual matrices */
- for (i = 0; i < count; i++) {
- char c = "xyzw"[i];
- qstring_append_fmt(vertex_shader_code, "tPosition += position * modelViewMat%d * weight.%c;\n",
- i, c);
- qstring_append_fmt(vertex_shader_code, "tNormal += (vec4(normal, 0.0) * invModelViewMat%d * weight.%c).xyz;\n",
- i, c);
- }
- assert(false); /* FIXME: Untested */
- }
- }
-
- /* Normalization */
- if (state.normalization) {
- qstring_append(vertex_shader_code, "tNormal = normalize(tNormal);\n");
- }
-
- /* Texgen */
- for (i = 0; i < 4; i++) {
- qstring_append_fmt(vertex_shader_code, "/* Texgen for stage %d */\n",
- i);
- qstring_append_fmt(vertex_shader_code, "vec4 tTexture%d;\n",
- i);
- /* Set each component individually */
- /* FIXME: could be nicer if some channels share the same texgen */
- for (j = 0; j < 4; j++) {
- char c = "xyzw"[j];
- switch (state.texgen[i][j]) {
- case TEXGEN_DISABLE:
- qstring_append_fmt(vertex_shader_code, "tTexture%d.%c = texture%d.%c;\n",
- i, c, i, c);
- break;
- case TEXGEN_EYE_LINEAR:
- qstring_append_fmt(vertex_shader_code, "tTexture%d.%c = tPosition.%c;\n",
- i, c, c);
- break;
- case TEXGEN_OBJECT_LINEAR:
- qstring_append_fmt(vertex_shader_code, "tTexture%d.%c = position.%c;\n",
- i, c, c);
- break;
- case TEXGEN_SPHERE_MAP:
- assert(i < 2); /* Channels S,T only! */
- assert(false);
- break;
- case TEXGEN_REFLECTION_MAP:
- assert(i < 3); /* Channels S,T,R only! */
- qstring_append_fmt(vertex_shader_code, "tTexture%d.%c = reflect(???, tNormal).%c;\n",
- i, c, c);
- assert(false); /* FIXME: Code not complete yet! */
- break;
- case TEXGEN_NORMAL_MAP:
- assert(i < 3); /* Channels S,T,R only! */
- qstring_append_fmt(vertex_shader_code, "tTexture%d.%c = tNormal.%c;\n",
- i, c, c);
- break;
- default:
- assert(false);
- break;
- }
- }
- }
-
- /* Apply texture matrices */
- for (i = 0; i < 4; i++) {
- if (state.texture_matrix_enable[i]) {
- qstring_append_fmt(vertex_shader_code, "tTexture%d = tTexture%d * texMat%d;\n",
- i, i, i);
- }
- }
-
- /* If skinning is off the composite matrix already includes the MV matrix */
- if (state.skinning == SKINNING_OFF) {
- qstring_append(vertex_shader_code, "tPosition = position;\n");
- }
-
- qstring_append(vertex_shader_code,
-" gl_Position = invViewport * (tPosition * compositeMat);\n"
-/* temp hack: the composite matrix includes the view transform... */
-//" gl_Position = position * compositeMat;\n"
-//" gl_Position.x = (gl_Position.x - 320.0) / 320.0;\n"
-//" gl_Position.y = -(gl_Position.y - 240.0) / 240.0;\n"
-" gl_Position.z = gl_Position.z * 2.0 - gl_Position.w;\n");
-
- qstring_append_fmt(vertex_shader_code,
- "%cPos_w = 1.0/gl_Position.w;\n", v_prefix);
- qstring_append_fmt(vertex_shader_code,
- "%cD0 = diffuse * %cPos_w;\n", v_prefix, v_prefix);
- qstring_append_fmt(vertex_shader_code,
- "%cD1 = specular * %cPos_w;\n", v_prefix, v_prefix);
- qstring_append_fmt(vertex_shader_code,
- "%cB0 = backDiffuse * %cPos_w;\n", v_prefix, v_prefix);
- qstring_append_fmt(vertex_shader_code,
- "%cB1 = backSpecular * %cPos_w;\n", v_prefix, v_prefix);
- qstring_append_fmt(vertex_shader_code,
- "%cT0 = tTexture0 * %cPos_w;\n", v_prefix, v_prefix);
- qstring_append_fmt(vertex_shader_code,
- "%cT1 = tTexture1 * %cPos_w;\n", v_prefix, v_prefix);
- qstring_append_fmt(vertex_shader_code,
- "%cT2 = tTexture2 * %cPos_w;\n", v_prefix, v_prefix);
- qstring_append_fmt(vertex_shader_code,
- "%cT3 = tTexture3 * %cPos_w;\n", v_prefix, v_prefix);
-
- qstring_append(vertex_shader_code, "}\n");
-
- } else if (state.vertex_program) {
- vertex_shader_code = vsh_translate(VSH_VERSION_XVS,
- (uint32_t*)state.program_data,
- state.program_length,
- v_prefix);
- } else {
- assert(false);
- }
-
- if (vertex_shader_code) {
- const char* vertex_shader_code_str = qstring_get_str(vertex_shader_code);
-
- GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
- glAttachShader(program, vertex_shader);
-
- glShaderSource(vertex_shader, 1, &vertex_shader_code_str, 0);
- glCompileShader(vertex_shader);
-
- NV2A_DPRINTF("bind new vertex shader, code:\n%s\n", vertex_shader_code_str);
-
- /* Check it compiled */
- compiled = 0;
- glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &compiled);
- if (!compiled) {
- GLchar log[1024];
- glGetShaderInfoLog(vertex_shader, 1024, NULL, log);
- fprintf(stderr, "nv2a: vertex shader compilation failed: %s\n", log);
- abort();
- }
-
- QDECREF(vertex_shader_code);
- }
-
-
- if (state.fixed_function) {
- /* bind fixed function vertex attributes */
- glBindAttribLocation(program, NV2A_VERTEX_ATTR_POSITION, "position");
- glBindAttribLocation(program, NV2A_VERTEX_ATTR_WEIGHT, "weight");
- 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_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];
- for(i = 0; i < 16; i++) {
- snprintf(tmp, sizeof(tmp), "v%d", i);
- glBindAttribLocation(program, i, tmp);
- }
- } else {
- assert(false);
- }
-
-
- /* generate a fragment shader from register combiners */
- GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
- glAttachShader(program, fragment_shader);
-
- QString *fragment_shader_code = psh_translate(state.combiner_control,
- state.shader_stage_program,
- state.other_stage_input,
- state.rgb_inputs, state.rgb_outputs,
- state.alpha_inputs, state.alpha_outputs,
- /* constant_0, constant_1, */
- state.final_inputs_0, state.final_inputs_1,
- /* final_constant_0, final_constant_1, */
- state.rect_tex,
- state.compare_mode,
- state.alphakill,
- state.alpha_test, state.alpha_func);
-
- const char *fragment_shader_code_str = qstring_get_str(fragment_shader_code);
-
- NV2A_DPRINTF("bind new fragment shader, code:\n%s\n", fragment_shader_code_str);
-
- glShaderSource(fragment_shader, 1, &fragment_shader_code_str, 0);
- glCompileShader(fragment_shader);
-
- /* Check it compiled */
- glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &compiled);
- if (!compiled) {
- GLchar log[1024];
- glGetShaderInfoLog(fragment_shader, 1024, NULL, log);
- fprintf(stderr, "nv2a: fragment shader compilation failed: %s\n", log);
- abort();
- }
-
- QDECREF(fragment_shader_code);
-
-
- if (with_geom) {
- GLuint geometry_shader = glCreateShader(GL_GEOMETRY_SHADER);
- glAttachShader(program, geometry_shader);
-
- QString* geometry_shader_code =
- generate_geometry_shader(state.primitive_mode);
- const char* geometry_shader_code_str =
- qstring_get_str(geometry_shader_code);
-
- NV2A_DPRINTF("bind geometry shader, code:\n%s\n", geometry_shader_code_str);
-
- glShaderSource(geometry_shader, 1, &geometry_shader_code_str, 0);
- glCompileShader(geometry_shader);
-
- /* Check it compiled */
- compiled = 0;
- glGetShaderiv(geometry_shader, GL_COMPILE_STATUS, &compiled);
- if (!compiled) {
- GLchar log[2048];
- glGetShaderInfoLog(geometry_shader, 2048, NULL, log);
- fprintf(stderr, "nv2a: geometry shader compilation failed: %s\n", log);
- abort();
- }
-
- QDECREF(geometry_shader_code);
- }
-
-
- /* link the program */
- glLinkProgram(program);
- GLint linked = 0;
- glGetProgramiv(program, GL_LINK_STATUS, &linked);
- if(!linked) {
- GLchar log[2048];
- glGetProgramInfoLog(program, 2048, NULL, log);
- fprintf(stderr, "nv2a: shader linking failed: %s\n", log);
- abort();
- }
-
- glUseProgram(program);
-
- /* set texture samplers */
- for (i = 0; i < NV2A_MAX_TEXTURES; i++) {
- char samplerName[16];
- snprintf(samplerName, sizeof(samplerName), "texSamp%d", i);
- GLint texSampLoc = glGetUniformLocation(program, samplerName);
- if (texSampLoc >= 0) {
- glUniform1i(texSampLoc, i);
- }
- }
-
- /* validate the program */
- glValidateProgram(program);
- GLint valid = 0;
- glGetProgramiv(program, GL_VALIDATE_STATUS, &valid);
- if (!valid) {
- GLchar log[1024];
- glGetProgramInfoLog(program, 1024, NULL, log);
- fprintf(stderr, "nv2a: shader validation failed: %s\n", log);
- abort();
- }
-
- ShaderBinding* ret = g_malloc0(sizeof(ShaderBinding));
- ret->gl_program = program;
-
- /* lookup fragment shader locations */
- for (i=0; i<=8; i++) {
- for (j=0; j<2; j++) {
- char tmp[8];
- snprintf(tmp, sizeof(tmp), "c_%d_%d", i, j);
- ret->psh_constant_loc[i][j] = glGetUniformLocation(program, tmp);
- }
- }
- if (state.vertex_program) {
- /* lookup vertex shader bindings */
- for(i = 0; i < NV2A_VERTEXSHADER_CONSTANTS; i++) {
- char tmp[8];
- snprintf(tmp, sizeof(tmp), "c[%d]", i);
- ret->vsh_constant_loc[i] = glGetUniformLocation(program, tmp);
- }
- }
-
- return ret;
-}
-
static void pgraph_apply_anti_aliasing_factor(PGRAPHState *pg,
unsigned int *width,
unsigned int *height)
@@ -3228,6 +2680,17 @@ static void pgraph_get_surface_dimensions(PGRAPHState *pg,
}
}
+/* hash and equality for shader cache hash table */
+static guint shader_hash(gconstpointer key)
+{
+ return fnv_hash(key, sizeof(ShaderState));
+}
+static gboolean shader_equal(gconstpointer a, gconstpointer b)
+{
+ const ShaderState *as = a, *bs = b;
+ return memcmp(as, bs, sizeof(ShaderState)) == 0;
+}
+
static void pgraph_bind_shaders(PGRAPHState *pg)
{
int i, j;
@@ -5502,7 +4965,7 @@ static void pgraph_method(NV2AState *d,
if (pg->draw_arrays_length > 0) {
unsigned int last_start =
pg->gl_draw_arrays_start[pg->draw_arrays_length - 1];
- unsigned int* last_count =
+ GLsizei* last_count =
&pg->gl_draw_arrays_count[pg->draw_arrays_length - 1];
if (start == (last_start + *last_count)) {
*last_count += count;
diff --git a/hw/xbox/nv2a_shaders.c b/hw/xbox/nv2a_shaders.c
new file mode 100644
index 0000000000..9cf305cf03
--- /dev/null
+++ b/hw/xbox/nv2a_shaders.c
@@ -0,0 +1,523 @@
+/*
+ * QEMU Geforce NV2A shader generator
+ *
+ * Copyright (c) 2015 espes
+ * Copyright (c) 2015 JayFoxRox
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+#include "qemu-common.h"
+#include "hw/xbox/nv2a_shaders.h"
+
+// #define DEBUG
+#ifdef DEBUG
+# define NV2A_DPRINTF(format, ...) printf("nv2a: " format, ## __VA_ARGS__)
+#else
+# define NV2A_DPRINTF(format, ...) do { } while (0)
+#endif
+
+static void generate_geometry_shader_pass_vertex(QString* s, const char* v)
+{
+ qstring_append_fmt(s, " gD0 = vD0[%s];\n", v);
+ qstring_append_fmt(s, " gD1 = vD1[%s];\n", v);
+ qstring_append_fmt(s, " gB0 = vB0[%s];\n", v);
+ qstring_append_fmt(s, " gB1 = vB1[%s];\n", v);
+ qstring_append_fmt(s, " gFog = vFog[%s];\n", v);
+ qstring_append_fmt(s, " gT0 = vT0[%s];\n", v);
+ qstring_append_fmt(s, " gT1 = vT1[%s];\n", v);
+ qstring_append_fmt(s, " gT2 = vT2[%s];\n", v);
+ qstring_append_fmt(s, " gT3 = vT3[%s];\n", v);
+ qstring_append_fmt(s, " gPos_w = vPos_w[%s];\n", v);
+ qstring_append_fmt(s, " gl_Position = gl_in[%s].gl_Position;\n", v);
+ qstring_append(s, " EmitVertex();\n");
+}
+
+static QString* generate_geometry_shader(enum ShaderPrimitiveMode 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 PRIM_TYPE_QUADS:
+ qstring_append(s, "layout(lines_adjacency) in;\n");
+ qstring_append(s, "layout(triangle_strip, max_vertices = 4) out;\n");
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ qstring_append(s, "\n");
+ qstring_append(s, "noperspective in float vPos_w[];\n");
+ qstring_append(s, "noperspective in vec4 vD0[];\n");
+ qstring_append(s, "noperspective in vec4 vD1[];\n");
+ qstring_append(s, "noperspective in vec4 vB0[];\n");
+ qstring_append(s, "noperspective in vec4 vB1[];\n");
+ qstring_append(s, "noperspective in vec4 vFog[];\n");
+ qstring_append(s, "noperspective in vec4 vT0[];\n");
+ qstring_append(s, "noperspective in vec4 vT1[];\n");
+ qstring_append(s, "noperspective in vec4 vT2[];\n");
+ qstring_append(s, "noperspective in vec4 vT3[];\n");
+ qstring_append(s, "\n");
+ qstring_append(s, "noperspective out float gPos_w;\n");
+ qstring_append(s, "noperspective out vec4 gD0;\n");
+ qstring_append(s, "noperspective out vec4 gD1;\n");
+ qstring_append(s, "noperspective out vec4 gB0;\n");
+ qstring_append(s, "noperspective out vec4 gB1;\n");
+ qstring_append(s, "noperspective out vec4 gFog;\n");
+ qstring_append(s, "noperspective out vec4 gT0;\n");
+ qstring_append(s, "noperspective out vec4 gT1;\n");
+ qstring_append(s, "noperspective out vec4 gT2;\n");
+ qstring_append(s, "noperspective out vec4 gT3;\n");
+ qstring_append(s, "\n");
+ qstring_append(s, "void main() {\n");
+ switch (primitive_mode) {
+ case PRIM_TYPE_QUADS:
+ generate_geometry_shader_pass_vertex(s, "0");
+ generate_geometry_shader_pass_vertex(s, "1");
+ generate_geometry_shader_pass_vertex(s, "3");
+ generate_geometry_shader_pass_vertex(s, "2");
+ qstring_append(s, "EndPrimitive();\n");
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ qstring_append(s, "}\n");
+
+ return s;
+}
+
+
+
+static QString* generate_fixed_function(const ShaderState state, char v_prefix)
+{
+ int i, j;
+
+ /* generate vertex shader mimicking fixed function */
+ QString* vertex_shader_code = qstring_new();
+ qstring_append(vertex_shader_code,
+"#version 330\n"
+"\n"
+"in vec4 position;\n"
+"in vec4 weight;\n"
+"in vec3 normal;\n"
+"in vec4 diffuse;\n"
+"in vec4 specular;\n"
+"in float fogCoord;\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,
+ "noperspective out float %cPos_w;\n", v_prefix);
+ qstring_append_fmt(vertex_shader_code,
+ "noperspective out vec4 %cD0 = vec4(0.0,0.0,0.0,1.0);\n", v_prefix);
+ qstring_append_fmt(vertex_shader_code,
+ "noperspective out vec4 %cD1 = vec4(0.0,0.0,0.0,1.0);\n", v_prefix);
+ qstring_append_fmt(vertex_shader_code,
+ "noperspective out vec4 %cB0 = vec4(0.0,0.0,0.0,1.0);\n", v_prefix);
+ qstring_append_fmt(vertex_shader_code,
+ "noperspective out vec4 %cB1 = vec4(0.0,0.0,0.0,1.0);\n", v_prefix);
+ qstring_append_fmt(vertex_shader_code,
+ "noperspective out vec4 %cFog = vec4(0.0,0.0,0.0,1.0);\n", v_prefix);
+ qstring_append_fmt(vertex_shader_code,
+ "noperspective out vec4 %cT0 = vec4(0.0,0.0,0.0,1.0);\n", v_prefix);
+ qstring_append_fmt(vertex_shader_code,
+ "noperspective out vec4 %cT1 = vec4(0.0,0.0,0.0,1.0);\n", v_prefix);
+ qstring_append_fmt(vertex_shader_code,
+ "noperspective out vec4 %cT2 = vec4(0.0,0.0,0.0,1.0);\n", v_prefix);
+ qstring_append_fmt(vertex_shader_code,
+ "noperspective out vec4 %cT3 = vec4(0.0,0.0,0.0,1.0);\n", v_prefix);
+
+ qstring_append(vertex_shader_code,
+"\n"
+/* FIXME: Add these uniforms using code when they are used */
+"uniform mat4 texMat0;\n"
+"uniform mat4 texMat1;\n"
+"uniform mat4 texMat2;\n"
+"uniform mat4 texMat3;\n"
+"uniform mat4 modelViewMat0;\n"
+"uniform mat4 modelViewMat1;\n"
+"uniform mat4 modelViewMat2;\n"
+"uniform mat4 modelViewMat3;\n"
+"uniform mat4 invModelViewMat0;\n"
+"uniform mat4 invModelViewMat1;\n"
+"uniform mat4 invModelViewMat2;\n"
+"uniform mat4 invModelViewMat3;\n"
+"uniform mat4 projectionMat; /* FIXME: when is this used? */\n"
+"uniform mat4 compositeMat;\n"
+"uniform mat4 invViewport;\n"
+"\n"
+"void main() {\n");
+
+ /* Skinning */
+ unsigned int count;
+ bool mix;
+ switch (state.skinning) {
+ case SKINNING_OFF:
+ count = 0; break;
+ case SKINNING_1WEIGHTS:
+ mix = true; count = 2; break;
+ case SKINNING_2WEIGHTS:
+ mix = true; count = 3; break;
+ case SKINNING_3WEIGHTS:
+ mix = true; count = 4; break;
+ case SKINNING_2WEIGHTS2MATRICES:
+ mix = false; count = 2; break;
+ case SKINNING_3WEIGHTS3MATRICES:
+ mix = false; count = 3; break;
+ case SKINNING_4WEIGHTS4MATRICES:
+ mix = false; count = 4; break;
+ default:
+ assert(false);
+ break;
+ }
+ qstring_append_fmt(vertex_shader_code, "/* Skinning mode %d */\n",
+ state.skinning);
+ if (count == 0) {
+ qstring_append(vertex_shader_code, "vec4 tPosition = position * modelViewMat0;\n");
+ /* FIXME: Is the normal still transformed? */
+ qstring_append(vertex_shader_code, "vec3 tNormal = (vec4(normal, 0.0) * invModelViewMat0).xyz;\n");
+ } else {
+ qstring_append(vertex_shader_code, "vec4 tPosition = vec4(0.0);\n");
+ qstring_append(vertex_shader_code, "vec3 tNormal = vec3(0.0);\n");
+ if (mix) {
+ /* Tweening */
+ if (count == 2) {
+ qstring_append(vertex_shader_code,
+ "tPosition += mix(position * modelViewMat1,\n"
+ " position * modelViewMat0, weight.x);\n"
+ "tNormal += mix((vec4(normal, 0.0) * invModelViewMat1).xyz,\n"
+ " (vec4(normal, 0.0) * invModelViewMat0).xyz, weight.x);\n");
+ } else {
+ /* FIXME: Not sure how blend weights are calculated */
+ assert(false);
+ }
+ } else {
+ /* Individual matrices */
+ for (i = 0; i < count; i++) {
+ char c = "xyzw"[i];
+ qstring_append_fmt(vertex_shader_code,
+ "tPosition += position * modelViewMat%d * weight.%c;\n",
+ i, c);
+ qstring_append_fmt(vertex_shader_code,
+ "tNormal += (vec4(normal, 0.0) * invModelViewMat%d * weight.%c).xyz;\n",
+ i, c);
+ }
+ assert(false); /* FIXME: Untested */
+ }
+ }
+
+ /* Normalization */
+ if (state.normalization) {
+ qstring_append(vertex_shader_code, "tNormal = normalize(tNormal);\n");
+ }
+
+ /* Texgen */
+ for (i = 0; i < 4; i++) {
+ qstring_append_fmt(vertex_shader_code, "/* Texgen for stage %d */\n",
+ i);
+ qstring_append_fmt(vertex_shader_code, "vec4 tTexture%d;\n",
+ i);
+ /* Set each component individually */
+ /* FIXME: could be nicer if some channels share the same texgen */
+ for (j = 0; j < 4; j++) {
+ char c = "xyzw"[j];
+ switch (state.texgen[i][j]) {
+ case TEXGEN_DISABLE:
+ qstring_append_fmt(vertex_shader_code,
+ "tTexture%d.%c = texture%d.%c;\n",
+ i, c, i, c);
+ break;
+ case TEXGEN_EYE_LINEAR:
+ qstring_append_fmt(vertex_shader_code,
+ "tTexture%d.%c = tPosition.%c;\n",
+ i, c, c);
+ break;
+ case TEXGEN_OBJECT_LINEAR:
+ qstring_append_fmt(vertex_shader_code,
+ "tTexture%d.%c = position.%c;\n",
+ i, c, c);
+ break;
+ case TEXGEN_SPHERE_MAP:
+ assert(i < 2); /* Channels S,T only! */
+ assert(false);
+ break;
+ case TEXGEN_REFLECTION_MAP:
+ assert(i < 3); /* Channels S,T,R only! */
+ qstring_append_fmt(vertex_shader_code,
+ "tTexture%d.%c = reflect(???, tNormal).%c;\n",
+ i, c, c);
+ assert(false); /* FIXME: Code not complete yet! */
+ break;
+ case TEXGEN_NORMAL_MAP:
+ assert(i < 3); /* Channels S,T,R only! */
+ qstring_append_fmt(vertex_shader_code,
+ "tTexture%d.%c = tNormal.%c;\n",
+ i, c, c);
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ }
+ }
+
+ /* Apply texture matrices */
+ for (i = 0; i < 4; i++) {
+ if (state.texture_matrix_enable[i]) {
+ qstring_append_fmt(vertex_shader_code,
+ "tTexture%d = tTexture%d * texMat%d;\n",
+ i, i, i);
+ }
+ }
+
+ /* If skinning is off the composite matrix already includes the MV matrix */
+ if (state.skinning == SKINNING_OFF) {
+ qstring_append(vertex_shader_code, "tPosition = position;\n");
+ }
+
+ qstring_append(vertex_shader_code,
+ " gl_Position = invViewport * (tPosition * compositeMat);\n"
+/* temp hack: the composite matrix includes the view transform... */
+//" gl_Position = position * compositeMat;\n"
+//" gl_Position.x = (gl_Position.x - 320.0) / 320.0;\n"
+//" gl_Position.y = -(gl_Position.y - 240.0) / 240.0;\n"
+ " gl_Position.z = gl_Position.z * 2.0 - gl_Position.w;\n");
+
+ qstring_append_fmt(vertex_shader_code,
+ "%cPos_w = 1.0/gl_Position.w;\n", v_prefix);
+ qstring_append_fmt(vertex_shader_code,
+ "%cD0 = diffuse * %cPos_w;\n", v_prefix, v_prefix);
+ qstring_append_fmt(vertex_shader_code,
+ "%cD1 = specular * %cPos_w;\n", v_prefix, v_prefix);
+ qstring_append_fmt(vertex_shader_code,
+ "%cB0 = backDiffuse * %cPos_w;\n", v_prefix, v_prefix);
+ qstring_append_fmt(vertex_shader_code,
+ "%cB1 = backSpecular * %cPos_w;\n", v_prefix, v_prefix);
+ qstring_append_fmt(vertex_shader_code,
+ "%cT0 = tTexture0 * %cPos_w;\n", v_prefix, v_prefix);
+ qstring_append_fmt(vertex_shader_code,
+ "%cT1 = tTexture1 * %cPos_w;\n", v_prefix, v_prefix);
+ qstring_append_fmt(vertex_shader_code,
+ "%cT2 = tTexture2 * %cPos_w;\n", v_prefix, v_prefix);
+ qstring_append_fmt(vertex_shader_code,
+ "%cT3 = tTexture3 * %cPos_w;\n", v_prefix, v_prefix);
+
+ qstring_append(vertex_shader_code, "}\n");
+
+ return vertex_shader_code;
+}
+
+ShaderBinding* generate_shaders(const ShaderState state)
+{
+ int i, j;
+ GLint compiled = 0;
+
+ bool with_geom = state.primitive_mode == PRIM_TYPE_QUADS;
+ char v_prefix = with_geom ? 'v' : 'g';
+
+ GLuint program = glCreateProgram();
+
+ /* create the vertex shader */
+
+ QString *vertex_shader_code = NULL;
+ if (state.fixed_function) {
+ vertex_shader_code = generate_fixed_function(state, v_prefix);
+
+ } else if (state.vertex_program) {
+ vertex_shader_code = vsh_translate(VSH_VERSION_XVS,
+ (uint32_t*)state.program_data,
+ state.program_length,
+ v_prefix);
+ } else {
+ assert(false);
+ }
+
+ if (vertex_shader_code) {
+ const char* vertex_shader_code_str = qstring_get_str(vertex_shader_code);
+
+ GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
+ glAttachShader(program, vertex_shader);
+
+ glShaderSource(vertex_shader, 1, &vertex_shader_code_str, 0);
+ glCompileShader(vertex_shader);
+
+ NV2A_DPRINTF("bind new vertex shader, code:\n%s\n", vertex_shader_code_str);
+
+ /* Check it compiled */
+ compiled = 0;
+ glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &compiled);
+ if (!compiled) {
+ GLchar log[1024];
+ glGetShaderInfoLog(vertex_shader, 1024, NULL, log);
+ fprintf(stderr, "nv2a: vertex shader compilation failed: %s\n", log);
+ abort();
+ }
+
+ QDECREF(vertex_shader_code);
+ }
+
+
+ if (state.fixed_function) {
+ /* bind fixed function vertex attributes */
+ glBindAttribLocation(program, NV2A_VERTEX_ATTR_POSITION, "position");
+ glBindAttribLocation(program, NV2A_VERTEX_ATTR_WEIGHT, "weight");
+ 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_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];
+ for(i = 0; i < 16; i++) {
+ snprintf(tmp, sizeof(tmp), "v%d", i);
+ glBindAttribLocation(program, i, tmp);
+ }
+ } else {
+ assert(false);
+ }
+
+
+ /* generate a fragment shader from register combiners */
+ GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
+ glAttachShader(program, fragment_shader);
+
+ QString *fragment_shader_code = psh_translate(state.combiner_control,
+ state.shader_stage_program,
+ state.other_stage_input,
+ state.rgb_inputs, state.rgb_outputs,
+ state.alpha_inputs, state.alpha_outputs,
+ /* constant_0, constant_1, */
+ state.final_inputs_0, state.final_inputs_1,
+ /* final_constant_0, final_constant_1, */
+ state.rect_tex,
+ state.compare_mode,
+ state.alphakill,
+ state.alpha_test, state.alpha_func);
+
+ const char *fragment_shader_code_str = qstring_get_str(fragment_shader_code);
+
+ NV2A_DPRINTF("bind new fragment shader, code:\n%s\n", fragment_shader_code_str);
+
+ glShaderSource(fragment_shader, 1, &fragment_shader_code_str, 0);
+ glCompileShader(fragment_shader);
+
+ /* Check it compiled */
+ glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &compiled);
+ if (!compiled) {
+ GLchar log[1024];
+ glGetShaderInfoLog(fragment_shader, 1024, NULL, log);
+ fprintf(stderr, "nv2a: fragment shader compilation failed: %s\n", log);
+ abort();
+ }
+
+ QDECREF(fragment_shader_code);
+
+
+ if (with_geom) {
+ GLuint geometry_shader = glCreateShader(GL_GEOMETRY_SHADER);
+ glAttachShader(program, geometry_shader);
+
+ QString* geometry_shader_code =
+ generate_geometry_shader(state.primitive_mode);
+ const char* geometry_shader_code_str =
+ qstring_get_str(geometry_shader_code);
+
+ NV2A_DPRINTF("bind geometry shader, code:\n%s\n", geometry_shader_code_str);
+
+ glShaderSource(geometry_shader, 1, &geometry_shader_code_str, 0);
+ glCompileShader(geometry_shader);
+
+ /* Check it compiled */
+ compiled = 0;
+ glGetShaderiv(geometry_shader, GL_COMPILE_STATUS, &compiled);
+ if (!compiled) {
+ GLchar log[2048];
+ glGetShaderInfoLog(geometry_shader, 2048, NULL, log);
+ fprintf(stderr, "nv2a: geometry shader compilation failed: %s\n", log);
+ abort();
+ }
+
+ QDECREF(geometry_shader_code);
+ }
+
+
+ /* link the program */
+ glLinkProgram(program);
+ GLint linked = 0;
+ glGetProgramiv(program, GL_LINK_STATUS, &linked);
+ if(!linked) {
+ GLchar log[2048];
+ glGetProgramInfoLog(program, 2048, NULL, log);
+ fprintf(stderr, "nv2a: shader linking failed: %s\n", log);
+ abort();
+ }
+
+ glUseProgram(program);
+
+ /* set texture samplers */
+ for (i = 0; i < 4; i++) {
+ char samplerName[16];
+ snprintf(samplerName, sizeof(samplerName), "texSamp%d", i);
+ GLint texSampLoc = glGetUniformLocation(program, samplerName);
+ if (texSampLoc >= 0) {
+ glUniform1i(texSampLoc, i);
+ }
+ }
+
+ /* validate the program */
+ glValidateProgram(program);
+ GLint valid = 0;
+ glGetProgramiv(program, GL_VALIDATE_STATUS, &valid);
+ if (!valid) {
+ GLchar log[1024];
+ glGetProgramInfoLog(program, 1024, NULL, log);
+ fprintf(stderr, "nv2a: shader validation failed: %s\n", log);
+ abort();
+ }
+
+ ShaderBinding* ret = g_malloc0(sizeof(ShaderBinding));
+ ret->gl_program = program;
+
+ /* lookup fragment shader locations */
+ for (i=0; i<=8; i++) {
+ for (j=0; j<2; j++) {
+ char tmp[8];
+ snprintf(tmp, sizeof(tmp), "c_%d_%d", i, j);
+ ret->psh_constant_loc[i][j] = glGetUniformLocation(program, tmp);
+ }
+ }
+ if (state.vertex_program) {
+ /* lookup vertex shader bindings */
+ for(i = 0; i < NV2A_VERTEXSHADER_CONSTANTS; i++) {
+ char tmp[8];
+ snprintf(tmp, sizeof(tmp), "c[%d]", i);
+ ret->vsh_constant_loc[i] = glGetUniformLocation(program, tmp);
+ }
+ }
+
+ return ret;
+}
\ No newline at end of file
diff --git a/hw/xbox/nv2a_shaders.h b/hw/xbox/nv2a_shaders.h
new file mode 100644
index 0000000000..bd644d6e60
--- /dev/null
+++ b/hw/xbox/nv2a_shaders.h
@@ -0,0 +1,104 @@
+/*
+ * QEMU Geforce NV2A shader generator
+ *
+ * Copyright (c) 2015 espes
+ * Copyright (c) 2015 JayFoxRox
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+#include "qapi/qmp/qstring.h"
+#include "gl/gloffscreen.h"
+
+#include "nv2a_vsh.h"
+#include "nv2a_psh.h"
+
+#define NV2A_VERTEX_ATTR_POSITION 0
+#define NV2A_VERTEX_ATTR_WEIGHT 1
+#define NV2A_VERTEX_ATTR_NORMAL 2
+#define NV2A_VERTEX_ATTR_DIFFUSE 3
+#define NV2A_VERTEX_ATTR_SPECULAR 4
+#define NV2A_VERTEX_ATTR_FOG 5
+#define NV2A_VERTEX_ATTR_POINT_SIZE 6
+#define NV2A_VERTEX_ATTR_BACK_DIFFUSE 7
+#define NV2A_VERTEX_ATTR_BACK_SPECULAR 8
+#define NV2A_VERTEX_ATTR_TEXTURE0 9
+#define NV2A_VERTEX_ATTR_TEXTURE1 10
+#define NV2A_VERTEX_ATTR_TEXTURE2 11
+#define NV2A_VERTEX_ATTR_TEXTURE3 12
+#define NV2A_VERTEX_ATTR_RESERVED1 13
+#define NV2A_VERTEX_ATTR_RESERVED2 14
+#define NV2A_VERTEX_ATTR_RESERVED3 15
+
+#define NV2A_MAX_TRANSFORM_PROGRAM_LENGTH 136
+#define NV2A_VERTEXSHADER_CONSTANTS 192
+
+enum ShaderPrimitiveMode {
+ PRIM_TYPE_NONE,
+ PRIM_TYPE_POINTS,
+ PRIM_TYPE_LINES,
+ PRIM_TYPE_LINE_LOOP,
+ PRIM_TYPE_LINE_STRIP,
+ PRIM_TYPE_TRIANGLES,
+ PRIM_TYPE_TRIANGLE_STRIP,
+ PRIM_TYPE_TRIANGLE_FAN,
+ PRIM_TYPE_QUADS,
+ PRIM_TYPE_QUAD_STRIP,
+ PRIM_TYPE_POLYGON,
+};
+
+typedef struct ShaderState {
+ /* fragment shader - register combiner stuff */
+ uint32_t combiner_control;
+ uint32_t shader_stage_program;
+ uint32_t other_stage_input;
+ uint32_t final_inputs_0;
+ uint32_t final_inputs_1;
+
+ uint32_t rgb_inputs[8], rgb_outputs[8];
+ uint32_t alpha_inputs[8], alpha_outputs[8];
+
+ bool rect_tex[4];
+ bool compare_mode[4][4];
+ bool alphakill[4];
+
+ bool alpha_test;
+ enum PshAlphaFunc alpha_func;
+
+ bool texture_matrix_enable[4];
+ enum VshTexgen texgen[4][4];
+
+ enum VshSkinning skinning;
+
+ bool normalization;
+
+ bool fixed_function;
+
+ /* vertex program */
+ bool vertex_program;
+ uint32_t program_data[NV2A_MAX_TRANSFORM_PROGRAM_LENGTH][VSH_TOKEN_SIZE];
+ int program_length;
+
+ /* primitive format for geometry shader */
+ enum ShaderPrimitiveMode primitive_mode;
+} ShaderState;
+
+typedef struct ShaderBinding {
+ GLuint gl_program;
+ GLint psh_constant_loc[9][2];
+ GLint vsh_constant_loc[NV2A_VERTEXSHADER_CONSTANTS];
+} ShaderBinding;
+
+ShaderBinding* generate_shaders(const ShaderState state);
+