From 2366b9bc9c3548601d3603fbd00473de400e8970 Mon Sep 17 00:00:00 2001
From: Jannik Vogel <email@jannikvogel.de>
Date: Fri, 4 Sep 2015 14:02:50 +0200
Subject: [PATCH 1/2] Support for QUAD_STRIP and POLYGON (Fill and point
 rendering only)

---
 hw/xbox/nv2a.c         | 15 ++++++++++++---
 hw/xbox/nv2a_shaders.c | 13 ++++++++++++-
 2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c
index 34109acb21..470ad86546 100644
--- a/hw/xbox/nv2a.c
+++ b/hw/xbox/nv2a.c
@@ -1101,9 +1101,9 @@ static const GLenum kelvin_primitive_map[] = {
     GL_TRIANGLES,
     GL_TRIANGLE_STRIP,
     GL_TRIANGLE_FAN,
-    GL_LINES_ADJACENCY, // GL_QUADS,
-    // GL_QUAD_STRIP,
-    // GL_POLYGON,
+    GL_LINES_ADJACENCY, /* QUADS */
+    GL_LINE_STRIP_ADJACENCY, /* QUAD_STRIP */
+    GL_TRIANGLE_FAN /* POLYGON */
 };
 
 static const GLenum pgraph_texture_min_filter_map[] = {
@@ -5329,6 +5329,15 @@ static void pgraph_method(NV2AState *d,
             assert(front_mode < ARRAYSIZE(pgraph_polygon_mode_map));
             glPolygonMode(GL_FRONT_AND_BACK,
                           pgraph_polygon_mode_map[front_mode]);
+            /* FIXME: Line rendering for POLYGON can be done using line loop,
+             *        QUADS and QUAD_STRIP need a geometry shader. Also what
+             *        about the interpolation / provoking vertex for flat
+             *        shaded points / lines?
+             */
+            assert(!((pg->primitive_mode == PRIM_TYPE_QUADS ||
+                      pg->primitive_mode == PRIM_TYPE_QUAD_STRIP ||
+                      pg->primitive_mode == PRIM_TYPE_POLYGON) &&
+                     front_mode == NV_PGRAPH_SETUPRASTER_FRONTFACEMODE_LINE));
 
             /* Polygon offset */
             /* FIXME: GL implementation-specific, maybe do this in VS? */
diff --git a/hw/xbox/nv2a_shaders.c b/hw/xbox/nv2a_shaders.c
index 082d883c9d..59f9a1cd95 100644
--- a/hw/xbox/nv2a_shaders.c
+++ b/hw/xbox/nv2a_shaders.c
@@ -39,6 +39,7 @@ static QString* generate_geometry_shader(enum ShaderPrimitiveMode primitive_mode
     qstring_append(s, "\n");
     switch (primitive_mode) {
     case PRIM_TYPE_QUADS:
+    case PRIM_TYPE_QUAD_STRIP:
         qstring_append(s, "layout(lines_adjacency) in;\n");
         qstring_append(s, "layout(triangle_strip, max_vertices = 4) out;\n");
         break;
@@ -63,6 +64,15 @@ static QString* generate_geometry_shader(enum ShaderPrimitiveMode primitive_mode
         generate_geometry_shader_pass_vertex(s, "2");
         qstring_append(s, "EndPrimitive();\n");
         break;
+    case PRIM_TYPE_QUAD_STRIP:
+        qstring_append(s, "if ((gl_PrimitiveIDIn & 1) == 0) {\n");
+        generate_geometry_shader_pass_vertex(s, "0");
+        generate_geometry_shader_pass_vertex(s, "1");
+        generate_geometry_shader_pass_vertex(s, "2");
+        generate_geometry_shader_pass_vertex(s, "3");
+        qstring_append(s, "  EndPrimitive();\n"
+                          "}");
+        break;
     default:
         assert(false);
         break;
@@ -593,7 +603,8 @@ ShaderBinding* generate_shaders(const ShaderState state)
 {
     int i, j;
 
-    bool with_geom = state.primitive_mode == PRIM_TYPE_QUADS;
+    bool with_geom = state.primitive_mode == PRIM_TYPE_QUADS ||
+                     state.primitive_mode == PRIM_TYPE_QUAD_STRIP;
     char vtx_prefix = with_geom ? 'v' : 'g';
 
     GLuint program = glCreateProgram();

From cd6259287fee1ce52cf79aa77af57ac4847b8464 Mon Sep 17 00:00:00 2001
From: Jannik Vogel <email@jannikvogel.de>
Date: Fri, 4 Sep 2015 14:18:45 +0200
Subject: [PATCH 2/2] Implement polygon modes in geometry shader

---
 hw/xbox/nv2a.c         |  59 ++--------
 hw/xbox/nv2a_shaders.c | 257 +++++++++++++++++++++++++++++------------
 hw/xbox/nv2a_shaders.h |   9 ++
 3 files changed, 204 insertions(+), 121 deletions(-)

diff --git a/hw/xbox/nv2a.c b/hw/xbox/nv2a.c
index 470ad86546..e80aa64794 100644
--- a/hw/xbox/nv2a.c
+++ b/hw/xbox/nv2a.c
@@ -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, /* QUADS */
-    GL_LINE_STRIP_ADJACENCY, /* QUAD_STRIP */
-    GL_TRIANGLE_FAN /* 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,26 +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]);
-            /* FIXME: Line rendering for POLYGON can be done using line loop,
-             *        QUADS and QUAD_STRIP need a geometry shader. Also what
-             *        about the interpolation / provoking vertex for flat
-             *        shaded points / lines?
-             */
-            assert(!((pg->primitive_mode == PRIM_TYPE_QUADS ||
-                      pg->primitive_mode == PRIM_TYPE_QUAD_STRIP ||
-                      pg->primitive_mode == PRIM_TYPE_POLYGON) &&
-                     front_mode == NV_PGRAPH_SETUPRASTER_FRONTFACEMODE_LINE));
-
             /* Polygon offset */
             /* FIXME: GL implementation-specific, maybe do this in VS? */
             if (pg->regs[NV_PGRAPH_SETUPRASTER] &
diff --git a/hw/xbox/nv2a_shaders.c b/hw/xbox/nv2a_shaders.c
index 59f9a1cd95..87647794fb 100644
--- a/hw/xbox/nv2a_shaders.c
+++ b/hw/xbox/nv2a_shaders.c
@@ -23,60 +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:
-    case PRIM_TYPE_QUAD_STRIP:
-        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;
-    case PRIM_TYPE_QUAD_STRIP:
-        qstring_append(s, "if ((gl_PrimitiveIDIn & 1) == 0) {\n");
-        generate_geometry_shader_pass_vertex(s, "0");
-        generate_geometry_shader_pass_vertex(s, "1");
-        generate_geometry_shader_pass_vertex(s, "2");
-        generate_geometry_shader_pass_vertex(s, "3");
-        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;
@@ -602,13 +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 ||
-                     state.primitive_mode == PRIM_TYPE_QUAD_STRIP;
-    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;
@@ -616,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 {
@@ -669,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;
@@ -720,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++) {
diff --git a/hw/xbox/nv2a_shaders.h b/hw/xbox/nv2a_shaders.h
index b3c7c72a9e..57a99426d1 100644
--- a/hw/xbox/nv2a_shaders.h
+++ b/hw/xbox/nv2a_shaders.h
@@ -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;