mirror of https://github.com/xemu-project/xemu.git
Merge pull request #60 from JayFoxRox/prim-modes-line
Implement polygon modes in geometry shader
This commit is contained in:
commit
f68e558e4a
|
@ -1091,21 +1091,6 @@
|
|||
# define NV097_SET_TRANSFORM_PROGRAM_START 0x00971EA0
|
||||
# define NV097_SET_TRANSFORM_CONSTANT_LOAD 0x00971EA4
|
||||
|
||||
|
||||
static const GLenum kelvin_primitive_map[] = {
|
||||
0,
|
||||
GL_POINTS,
|
||||
GL_LINES,
|
||||
GL_LINE_LOOP,
|
||||
GL_LINE_STRIP,
|
||||
GL_TRIANGLES,
|
||||
GL_TRIANGLE_STRIP,
|
||||
GL_TRIANGLE_FAN,
|
||||
GL_LINES_ADJACENCY, // GL_QUADS,
|
||||
// GL_QUAD_STRIP,
|
||||
// GL_POLYGON,
|
||||
};
|
||||
|
||||
static const GLenum pgraph_texture_min_filter_map[] = {
|
||||
0,
|
||||
GL_NEAREST,
|
||||
|
@ -1189,12 +1174,6 @@ static const GLenum pgraph_cull_face_map[] = {
|
|||
GL_FRONT_AND_BACK
|
||||
};
|
||||
|
||||
static const GLenum pgraph_polygon_mode_map[] = {
|
||||
GL_FILL,
|
||||
GL_POINT,
|
||||
GL_LINE
|
||||
};
|
||||
|
||||
static const GLenum pgraph_depth_func_map[] = {
|
||||
GL_NEVER,
|
||||
GL_LESS,
|
||||
|
@ -1636,7 +1615,6 @@ typedef struct PGRAPHState {
|
|||
hwaddr dma_vertex_a, dma_vertex_b;
|
||||
|
||||
unsigned int primitive_mode;
|
||||
GLenum gl_primitive_mode;
|
||||
|
||||
bool enable_vertex_program_write;
|
||||
|
||||
|
@ -2969,6 +2947,10 @@ static void pgraph_bind_shaders(PGRAPHState *pg)
|
|||
|
||||
/* geometry shader stuff */
|
||||
.primitive_mode = pg->primitive_mode,
|
||||
.polygon_front_mode = GET_MASK(pg->regs[NV_PGRAPH_SETUPRASTER],
|
||||
NV_PGRAPH_SETUPRASTER_FRONTFACEMODE),
|
||||
.polygon_back_mode = GET_MASK(pg->regs[NV_PGRAPH_SETUPRASTER],
|
||||
NV_PGRAPH_SETUPRASTER_BACKFACEMODE),
|
||||
};
|
||||
|
||||
state.program_length = 0;
|
||||
|
@ -5155,6 +5137,8 @@ static void pgraph_method(NV2AState *d,
|
|||
|
||||
if (parameter == NV097_SET_BEGIN_END_OP_END) {
|
||||
|
||||
assert(pg->shader_binding);
|
||||
|
||||
if (pg->draw_arrays_length) {
|
||||
|
||||
NV2A_GL_DPRINTF(false, "Draw Arrays");
|
||||
|
@ -5165,7 +5149,7 @@ static void pgraph_method(NV2AState *d,
|
|||
|
||||
pgraph_bind_vertex_attributes(d, pg->draw_arrays_max_count,
|
||||
false, 0);
|
||||
glMultiDrawArrays(pg->gl_primitive_mode,
|
||||
glMultiDrawArrays(pg->shader_binding->gl_primitive_mode,
|
||||
pg->gl_draw_arrays_start,
|
||||
pg->gl_draw_arrays_count,
|
||||
pg->draw_arrays_length);
|
||||
|
@ -5204,7 +5188,7 @@ static void pgraph_method(NV2AState *d,
|
|||
|
||||
}
|
||||
|
||||
glDrawArrays(pg->gl_primitive_mode,
|
||||
glDrawArrays(pg->shader_binding->gl_primitive_mode,
|
||||
0, pg->inline_buffer_length);
|
||||
} else if (pg->inline_array_length) {
|
||||
|
||||
|
@ -5215,7 +5199,8 @@ static void pgraph_method(NV2AState *d,
|
|||
assert(pg->inline_elements_length == 0);
|
||||
|
||||
unsigned int index_count = pgraph_bind_inline_array(d);
|
||||
glDrawArrays(pg->gl_primitive_mode, 0, index_count);
|
||||
glDrawArrays(pg->shader_binding->gl_primitive_mode,
|
||||
0, index_count);
|
||||
} else if (pg->inline_elements_length) {
|
||||
|
||||
NV2A_GL_DPRINTF(false, "Inline Elements");
|
||||
|
@ -5239,7 +5224,7 @@ static void pgraph_method(NV2AState *d,
|
|||
pg->inline_elements,
|
||||
GL_DYNAMIC_DRAW);
|
||||
|
||||
glDrawRangeElements(pg->gl_primitive_mode,
|
||||
glDrawRangeElements(pg->shader_binding->gl_primitive_mode,
|
||||
min_element, max_element,
|
||||
pg->inline_elements_length,
|
||||
GL_UNSIGNED_INT,
|
||||
|
@ -5262,9 +5247,7 @@ static void pgraph_method(NV2AState *d,
|
|||
|
||||
pgraph_update_surface(d, true, true, depth_test || stencil_test);
|
||||
|
||||
assert(parameter < ARRAYSIZE(kelvin_primitive_map));
|
||||
pg->primitive_mode = parameter;
|
||||
pg->gl_primitive_mode = kelvin_primitive_map[parameter];
|
||||
|
||||
uint32_t control_0 = pg->regs[NV_PGRAPH_CONTROL_0];
|
||||
|
||||
|
@ -5319,17 +5302,6 @@ static void pgraph_method(NV2AState *d,
|
|||
& NV_PGRAPH_SETUPRASTER_FRONTFACE
|
||||
? GL_CCW : GL_CW);
|
||||
|
||||
/* Polygon mode */
|
||||
uint32_t front_mode = GET_MASK(pg->regs[NV_PGRAPH_SETUPRASTER],
|
||||
NV_PGRAPH_SETUPRASTER_FRONTFACEMODE);
|
||||
uint32_t back_mode = GET_MASK(pg->regs[NV_PGRAPH_SETUPRASTER],
|
||||
NV_PGRAPH_SETUPRASTER_BACKFACEMODE);
|
||||
/* FIXME: GL3+ only supports GL_FRONT_AND_BACK, how to handle? */
|
||||
assert(front_mode == back_mode);
|
||||
assert(front_mode < ARRAYSIZE(pgraph_polygon_mode_map));
|
||||
glPolygonMode(GL_FRONT_AND_BACK,
|
||||
pgraph_polygon_mode_map[front_mode]);
|
||||
|
||||
/* Polygon offset */
|
||||
/* FIXME: GL implementation-specific, maybe do this in VS? */
|
||||
if (pg->regs[NV_PGRAPH_SETUPRASTER] &
|
||||
|
|
|
@ -23,50 +23,166 @@
|
|||
#include "hw/xbox/nv2a_shaders_common.h"
|
||||
#include "hw/xbox/nv2a_shaders.h"
|
||||
|
||||
static void generate_geometry_shader_pass_vertex(QString* s, const char* v)
|
||||
static QString* generate_geometry_shader(
|
||||
enum ShaderPolygonMode polygon_front_mode,
|
||||
enum ShaderPolygonMode polygon_back_mode,
|
||||
enum ShaderPrimitiveMode primitive_mode,
|
||||
GLenum *gl_primitive_mode)
|
||||
{
|
||||
qstring_append_fmt(s, " gl_Position = gl_in[%s].gl_Position;\n", v);
|
||||
qstring_append_fmt(s, " gl_PointSize = gl_in[%s].gl_PointSize;\n", v);
|
||||
qstring_append_fmt(s, " g_vtx = v_vtx[%s];\n", v);
|
||||
qstring_append(s, " EmitVertex();\n");
|
||||
}
|
||||
|
||||
static QString* generate_geometry_shader(enum ShaderPrimitiveMode primitive_mode)
|
||||
{
|
||||
/* FIXME: Missing support for 2-sided-poly mode */
|
||||
assert(polygon_front_mode == polygon_back_mode);
|
||||
enum ShaderPolygonMode polygon_mode = polygon_front_mode;
|
||||
|
||||
/* POINT mode shouldn't require any special work */
|
||||
if (polygon_mode == POLY_MODE_POINT) {
|
||||
*gl_primitive_mode = GL_POINTS;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Handle LINE and FILL mode */
|
||||
const char *layout_in = NULL;
|
||||
const char *layout_out = NULL;
|
||||
const char *body = NULL;
|
||||
switch (primitive_mode) {
|
||||
case PRIM_TYPE_POINTS: *gl_primitive_mode = GL_POINTS; return NULL;
|
||||
case PRIM_TYPE_LINES: *gl_primitive_mode = GL_LINES; return NULL;
|
||||
case PRIM_TYPE_LINE_LOOP: *gl_primitive_mode = GL_LINE_LOOP; return NULL;
|
||||
case PRIM_TYPE_LINE_STRIP: *gl_primitive_mode = GL_LINE_STRIP; return NULL;
|
||||
case PRIM_TYPE_TRIANGLES:
|
||||
*gl_primitive_mode = GL_TRIANGLES;
|
||||
if (polygon_mode == POLY_MODE_FILL) { return NULL; }
|
||||
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"
|
||||
" EndPrimitive();\n";
|
||||
break;
|
||||
case PRIM_TYPE_TRIANGLE_STRIP:
|
||||
*gl_primitive_mode = GL_TRIANGLE_STRIP;
|
||||
if (polygon_mode == POLY_MODE_FILL) { return NULL; }
|
||||
assert(polygon_mode == POLY_MODE_LINE);
|
||||
layout_in = "layout(triangles) in;\n";
|
||||
layout_out = "layout(line_strip, max_vertices = 4) out;\n";
|
||||
/* Imagine a quad made of a tristrip, the comments tell you which
|
||||
* vertex we are using */
|
||||
body = " if ((gl_PrimitiveIDIn & 1) == 0) {\n"
|
||||
" if (gl_PrimitiveIDIn == 0) {\n"
|
||||
" emit_vertex(0);\n" /* bottom right */
|
||||
" }\n"
|
||||
" emit_vertex(1);\n" /* top right */
|
||||
" emit_vertex(2);\n" /* bottom left */
|
||||
" emit_vertex(0);\n" /* bottom right */
|
||||
" } else {\n"
|
||||
" emit_vertex(2);\n" /* bottom left */
|
||||
" emit_vertex(1);\n" /* top left */
|
||||
" emit_vertex(0);\n" /* top right */
|
||||
" }\n"
|
||||
" EndPrimitive();\n";
|
||||
break;
|
||||
case PRIM_TYPE_TRIANGLE_FAN:
|
||||
*gl_primitive_mode = GL_TRIANGLE_FAN;
|
||||
if (polygon_mode == POLY_MODE_FILL) { return NULL; }
|
||||
assert(polygon_mode == POLY_MODE_LINE);
|
||||
layout_in = "layout(triangles) in;\n";
|
||||
layout_out = "layout(line_strip, max_vertices = 4) out;\n";
|
||||
body = " if (gl_PrimitiveIDIn == 0) {\n"
|
||||
" emit_vertex(0);\n"
|
||||
" }\n"
|
||||
" emit_vertex(1);\n"
|
||||
" emit_vertex(2);\n"
|
||||
" emit_vertex(0);\n"
|
||||
" EndPrimitive();\n";
|
||||
break;
|
||||
case PRIM_TYPE_QUADS:
|
||||
*gl_primitive_mode = GL_LINES_ADJACENCY;
|
||||
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"
|
||||
" 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"
|
||||
" EndPrimitive();\n";
|
||||
} else {
|
||||
assert(false);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case PRIM_TYPE_QUAD_STRIP:
|
||||
*gl_primitive_mode = GL_LINE_STRIP_ADJACENCY;
|
||||
layout_in = "layout(lines_adjacency) in;\n";
|
||||
if (polygon_mode == POLY_MODE_LINE) {
|
||||
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"
|
||||
" }\n"
|
||||
" emit_vertex(1);\n"
|
||||
" emit_vertex(3);\n"
|
||||
" emit_vertex(2);\n"
|
||||
" emit_vertex(0);\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"
|
||||
" EndPrimitive();\n";
|
||||
} else {
|
||||
assert(false);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
case PRIM_TYPE_POLYGON:
|
||||
if (polygon_mode == POLY_MODE_LINE) {
|
||||
*gl_primitive_mode = GL_LINE_LOOP;
|
||||
} else if (polygon_mode == POLY_MODE_FILL) {
|
||||
*gl_primitive_mode = GL_TRIANGLE_FAN;
|
||||
} else {
|
||||
assert(false);
|
||||
}
|
||||
return NULL;
|
||||
default:
|
||||
assert(false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* 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, STRUCT_VERTEX_DATA);
|
||||
qstring_append(s,
|
||||
"noperspective in VertexData v_vtx[];\n");
|
||||
qstring_append(s,
|
||||
"noperspective out VertexData g_vtx;\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;
|
||||
}
|
||||
assert(layout_in);
|
||||
assert(layout_out);
|
||||
assert(body);
|
||||
QString* s = qstring_from_str("#version 330\n"
|
||||
"\n");
|
||||
qstring_append(s, layout_in);
|
||||
qstring_append(s, layout_out);
|
||||
qstring_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");
|
||||
qstring_append(s, body);
|
||||
qstring_append(s, "}\n");
|
||||
|
||||
return s;
|
||||
|
@ -592,12 +708,33 @@ static GLuint create_gl_shader(GLenum gl_shader_type,
|
|||
ShaderBinding* generate_shaders(const ShaderState state)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
bool with_geom = state.primitive_mode == PRIM_TYPE_QUADS;
|
||||
char vtx_prefix = with_geom ? 'v' : 'g';
|
||||
|
||||
char vtx_prefix;
|
||||
GLuint program = glCreateProgram();
|
||||
|
||||
/* Create an option geometry shader and find primitive type */
|
||||
|
||||
GLenum gl_primitive_mode;
|
||||
QString* geometry_shader_code =
|
||||
generate_geometry_shader(state.polygon_front_mode,
|
||||
state.polygon_back_mode,
|
||||
state.primitive_mode,
|
||||
&gl_primitive_mode);
|
||||
if (geometry_shader_code) {
|
||||
const char* geometry_shader_code_str =
|
||||
qstring_get_str(geometry_shader_code);
|
||||
|
||||
GLuint geometry_shader = create_gl_shader(GL_GEOMETRY_SHADER,
|
||||
geometry_shader_code_str,
|
||||
"geometry shader");
|
||||
glAttachShader(program, geometry_shader);
|
||||
|
||||
QDECREF(geometry_shader_code);
|
||||
|
||||
vtx_prefix = 'v';
|
||||
} else {
|
||||
vtx_prefix = 'g';
|
||||
}
|
||||
|
||||
/* create the vertex shader */
|
||||
|
||||
QString *s = NULL;
|
||||
|
@ -605,8 +742,7 @@ ShaderBinding* generate_shaders(const ShaderState state)
|
|||
s = generate_fixed_function(state, vtx_prefix);
|
||||
|
||||
} else if (state.vertex_program) {
|
||||
s = vsh_translate(VSH_VERSION_XVS,
|
||||
(uint32_t*)state.program_data,
|
||||
s = vsh_translate(VSH_VERSION_XVS, (uint32_t*)state.program_data,
|
||||
state.program_length,
|
||||
vtx_prefix);
|
||||
} else {
|
||||
|
@ -658,21 +794,6 @@ ShaderBinding* generate_shaders(const ShaderState state)
|
|||
QDECREF(fragment_shader_code);
|
||||
|
||||
|
||||
if (with_geom) {
|
||||
QString* geometry_shader_code =
|
||||
generate_geometry_shader(state.primitive_mode);
|
||||
const char* geometry_shader_code_str =
|
||||
qstring_get_str(geometry_shader_code);
|
||||
|
||||
GLuint geometry_shader = create_gl_shader(GL_GEOMETRY_SHADER,
|
||||
geometry_shader_code_str,
|
||||
"geometry shader");
|
||||
glAttachShader(program, geometry_shader);
|
||||
|
||||
QDECREF(geometry_shader_code);
|
||||
}
|
||||
|
||||
|
||||
/* link the program */
|
||||
glLinkProgram(program);
|
||||
GLint linked = 0;
|
||||
|
@ -709,6 +830,7 @@ ShaderBinding* generate_shaders(const ShaderState state)
|
|||
|
||||
ShaderBinding* ret = g_malloc0(sizeof(ShaderBinding));
|
||||
ret->gl_program = program;
|
||||
ret->gl_primitive_mode = gl_primitive_mode;
|
||||
|
||||
/* lookup fragment shader locations */
|
||||
for (i=0; i<=8; i++) {
|
||||
|
|
|
@ -45,6 +45,12 @@ enum ShaderPrimitiveMode {
|
|||
PRIM_TYPE_POLYGON,
|
||||
};
|
||||
|
||||
enum ShaderPolygonMode {
|
||||
POLY_MODE_FILL,
|
||||
POLY_MODE_POINT,
|
||||
POLY_MODE_LINE,
|
||||
};
|
||||
|
||||
typedef struct ShaderState {
|
||||
/* fragment shader - register combiner stuff */
|
||||
uint32_t combiner_control;
|
||||
|
@ -85,11 +91,14 @@ typedef struct ShaderState {
|
|||
int program_length;
|
||||
|
||||
/* primitive format for geometry shader */
|
||||
enum ShaderPolygonMode polygon_front_mode;
|
||||
enum ShaderPolygonMode polygon_back_mode;
|
||||
enum ShaderPrimitiveMode primitive_mode;
|
||||
} ShaderState;
|
||||
|
||||
typedef struct ShaderBinding {
|
||||
GLuint gl_program;
|
||||
GLenum gl_primitive_mode;
|
||||
GLint psh_constant_loc[9][2];
|
||||
GLint gl_constants_loc;
|
||||
} ShaderBinding;
|
||||
|
|
Loading…
Reference in New Issue