mesa: implement core Mesa support for GL_ARB_draw_instanced
authorBrian Paul <brianp@vmware.com>
Mon, 5 Apr 2010 00:21:16 +0000 (18:21 -0600)
committerBrian Paul <brianp@vmware.com>
Mon, 5 Apr 2010 01:05:38 +0000 (19:05 -0600)
src/mesa/main/dd.h
src/mesa/main/vtxfmt.c
src/mesa/main/vtxfmt_tmp.h
src/mesa/vbo/vbo.h
src/mesa/vbo/vbo_exec_api.c
src/mesa/vbo/vbo_exec_array.c
src/mesa/vbo/vbo_save_api.c

index 7c02faaa535a46b88b21ca23b1939fb78f8635a1..4679be72f7659d0737a9bbe0cb4d1c2228dfb039 100644 (file)
@@ -1186,6 +1186,11 @@ typedef struct {
                                                   const GLvoid **indices,
                                                   GLsizei primcount,
                                                   const GLint *basevertex);
+   void (GLAPIENTRYP DrawArraysInstanced)(GLenum mode, GLint first,
+                                          GLsizei count, GLsizei primcount);
+   void (GLAPIENTRYP DrawElementsInstanced)(GLenum mode, GLsizei count,
+                                            GLenum type, const GLvoid *indices,
+                                            GLsizei primcount);
    /*@}*/
 
    /**
index 0dd3e5e52ee55969741adf4dc1ba9ce7d33efe51..ca352e88e6b89956d1016e4d1f51a2cee8a7e494 100644 (file)
@@ -140,6 +140,8 @@ install_vtxfmt( struct _glapi_table *tab, const GLvertexformat *vfmt )
    SET_DrawElementsBaseVertex(tab, vfmt->DrawElementsBaseVertex);
    SET_DrawRangeElementsBaseVertex(tab, vfmt->DrawRangeElementsBaseVertex);
    SET_MultiDrawElementsBaseVertex(tab, vfmt->MultiDrawElementsBaseVertex);
+   SET_DrawArraysInstanced(tab, vfmt->DrawArraysInstanced);
+   SET_DrawElementsInstanced(tab, vfmt->DrawElementsInstanced);
 
    /* GL_NV_vertex_program */
    SET_VertexAttrib1fNV(tab, vfmt->VertexAttrib1fNV);
index 037c4b1888b1452805e79ad24de20290e3230ead..9ec6ea49aa20d642400a3e503c81e7eb62e2acda 100644 (file)
@@ -391,6 +391,25 @@ static void GLAPIENTRY TAG(MultiDrawElementsBaseVertex)( GLenum mode,
                                                      primcount, basevertex ));
 }
 
+static void GLAPIENTRY
+TAG(DrawArraysInstanced)(GLenum mode, GLint first,
+                         GLsizei count, GLsizei primcount)
+{
+   PRE_LOOPBACK( DrawArraysInstanced );
+   CALL_DrawArraysInstanced(GET_DISPATCH(), (mode, first, count, primcount));
+}
+
+static void GLAPIENTRY
+TAG(DrawElementsInstanced)(GLenum mode, GLsizei count,
+                           GLenum type, const GLvoid *indices,
+                           GLsizei primcount)
+{
+   PRE_LOOPBACK( DrawElementsInstanced );
+   CALL_DrawElementsInstanced(GET_DISPATCH(),
+                              (mode, count, type, indices, primcount));
+}
+
+
 static void GLAPIENTRY TAG(EvalMesh1)( GLenum mode, GLint i1, GLint i2 )
 {
    PRE_LOOPBACK( EvalMesh1 );
@@ -574,6 +593,8 @@ static GLvertexformat TAG(vtxfmt) = {
    TAG(DrawElementsBaseVertex),
    TAG(DrawRangeElementsBaseVertex),
    TAG(MultiDrawElementsBaseVertex),
+   TAG(DrawArraysInstanced),
+   TAG(DrawElementsInstanced),
    TAG(EvalMesh1),
    TAG(EvalMesh2)
 };
index b24ecfd7cde4a238607ae9fd5c43ca0e39497c8c..7a085f63c7398d08959874d3a8047ef240fb7865 100644 (file)
@@ -45,6 +45,7 @@ struct _mesa_prim {
    GLuint start;
    GLuint count;
    GLint basevertex;
+   GLsizei num_instances;
 };
 
 /* Would like to call this a "vbo_index_buffer", but this would be
index e40f5f9dc440d46b28e612699abce9b915e89d40..e83bd9e4045aa052fa39401062e775c23e3b8633 100644 (file)
@@ -531,6 +531,7 @@ static void GLAPIENTRY vbo_exec_Begin( GLenum mode )
       exec->vtx.prim[i].pad = 0;
       exec->vtx.prim[i].start = exec->vtx.vert_count;
       exec->vtx.prim[i].count = 0;
+      exec->vtx.prim[i].num_instances = 1;
 
       ctx->Driver.CurrentExecPrimitive = mode;
    }
index 90474da7c02e1b055baf67f9195d18249325a6f1..d4dbc8d2562d94b9a6bc2f69a3500fd38fe21a8e 100644 (file)
@@ -520,6 +520,7 @@ vbo_exec_DrawArrays(GLenum mode, GLint start, GLsizei count)
    prim[0].count = count;
    prim[0].indexed = 0;
    prim[0].basevertex = 0;
+   prim[0].num_instances = 1;
 
    vbo->draw_prims( ctx, exec->array.inputs, prim, 1, NULL,
                     GL_TRUE, start, start + count - 1 );
@@ -532,6 +533,62 @@ vbo_exec_DrawArrays(GLenum mode, GLint start, GLsizei count)
 }
 
 
+static void GLAPIENTRY
+vbo_exec_DrawArraysInstanced(GLenum mode, GLint start, GLsizei count,
+                             GLsizei primcount)
+{
+   GET_CURRENT_CONTEXT(ctx);
+   struct vbo_context *vbo = vbo_context(ctx);
+   struct vbo_exec_context *exec = &vbo->exec;
+   struct _mesa_prim prim[1];
+
+   if (MESA_VERBOSE & VERBOSE_DRAW)
+      _mesa_debug(ctx, "glDrawArraysInstanced(%s, %d, %d, %d)\n",
+                  _mesa_lookup_enum_by_nr(mode), start, count, primcount);
+
+   if (!_mesa_validate_DrawArraysInstanced(ctx, mode, start, count, primcount))
+      return;
+
+   FLUSH_CURRENT( ctx, 0 );
+
+   if (!_mesa_valid_to_render(ctx, "glDrawArraysInstanced")) {
+      return;
+   }
+
+#if 0 /* debug */
+   check_draw_arrays_data(ctx, start, count);
+#endif
+
+   bind_arrays( ctx );
+
+   /* Again... because we may have changed the bitmask of per-vertex varying
+    * attributes.  If we regenerate the fixed-function vertex program now
+    * we may be able to prune down the number of vertex attributes which we
+    * need in the shader.
+    */
+   if (ctx->NewState)
+      _mesa_update_state( ctx );
+
+   prim[0].begin = 1;
+   prim[0].end = 1;
+   prim[0].weak = 0;
+   prim[0].pad = 0;
+   prim[0].mode = mode;
+   prim[0].start = start;
+   prim[0].count = count;
+   prim[0].indexed = 0;
+   prim[0].basevertex = 0;
+   prim[0].num_instances = primcount;
+
+   vbo->draw_prims( ctx, exec->array.inputs, prim, 1, NULL,
+                    GL_TRUE, start, start + count - 1 );
+
+#if 0 /* debug */
+   print_draw_arrays(ctx, exec, mode, start, count);
+#endif
+}
+
+
 /**
  * Map GL_ELEMENT_ARRAY_BUFFER and print contents.
  */
@@ -595,7 +652,7 @@ vbo_validated_drawrangeelements(GLcontext *ctx, GLenum mode,
                                GLuint start, GLuint end,
                                GLsizei count, GLenum type,
                                const GLvoid *indices,
-                               GLint basevertex)
+                               GLint basevertex, GLint primcount)
 {
    struct vbo_context *vbo = vbo_context(ctx);
    struct vbo_exec_context *exec = &vbo->exec;
@@ -628,6 +685,7 @@ vbo_validated_drawrangeelements(GLcontext *ctx, GLenum mode,
    prim[0].count = count;
    prim[0].indexed = 1;
    prim[0].basevertex = basevertex;
+   prim[0].num_instances = primcount;
 
    /* Need to give special consideration to rendering a range of
     * indices starting somewhere above zero.  Typically the
@@ -769,7 +827,7 @@ vbo_exec_DrawRangeElementsBaseVertex(GLenum mode,
 #endif
 
    vbo_validated_drawrangeelements(ctx, mode, GL_TRUE, start, end,
-                                  count, type, indices, basevertex);
+                                  count, type, indices, basevertex, 1);
 }
 
 
@@ -805,7 +863,7 @@ vbo_exec_DrawElements(GLenum mode, GLsizei count, GLenum type,
       return;
 
    vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
-                                  count, type, indices, 0);
+                                  count, type, indices, 0, 1);
 }
 
 
@@ -825,7 +883,27 @@ vbo_exec_DrawElementsBaseVertex(GLenum mode, GLsizei count, GLenum type,
       return;
 
    vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
-                                  count, type, indices, basevertex);
+                                  count, type, indices, basevertex, 1);
+}
+
+
+static void GLAPIENTRY
+vbo_exec_DrawElementsInstanced(GLenum mode, GLsizei count, GLenum type,
+                               const GLvoid *indices, GLsizei primcount)
+{
+   GET_CURRENT_CONTEXT(ctx);
+
+   if (MESA_VERBOSE & VERBOSE_DRAW)
+      _mesa_debug(ctx, "glDrawElementsInstanced(%s, %d, %s, %p, %d)\n",
+                  _mesa_lookup_enum_by_nr(mode), count,
+                  _mesa_lookup_enum_by_nr(type), indices, primcount);
+
+   if (!_mesa_validate_DrawElementsInstanced(ctx, mode, count, type, indices,
+                                             primcount))
+      return;
+
+   vbo_validated_drawrangeelements(ctx, mode, GL_FALSE, ~0, ~0,
+                                  count, type, indices, 0, primcount);
 }
 
 
@@ -926,6 +1004,7 @@ vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode,
         prim[i].start = ((uintptr_t)indices[i] - min_index_ptr) / index_type_size;
         prim[i].count = count[i];
         prim[i].indexed = 1;
+         prim[i].num_instances = 1;
         if (basevertex != NULL)
            prim[i].basevertex = basevertex[i];
         else
@@ -950,6 +1029,7 @@ vbo_validated_multidrawelements(GLcontext *ctx, GLenum mode,
         prim[0].start = 0;
         prim[0].count = count[i];
         prim[0].indexed = 1;
+         prim[0].num_instances = 1;
         if (basevertex != NULL)
            prim[0].basevertex = basevertex[i];
         else
@@ -1024,6 +1104,8 @@ vbo_exec_array_init( struct vbo_exec_context *exec )
    exec->vtxfmt.DrawElementsBaseVertex = vbo_exec_DrawElementsBaseVertex;
    exec->vtxfmt.DrawRangeElementsBaseVertex = vbo_exec_DrawRangeElementsBaseVertex;
    exec->vtxfmt.MultiDrawElementsBaseVertex = vbo_exec_MultiDrawElementsBaseVertex;
+   exec->vtxfmt.DrawArraysInstanced = vbo_exec_DrawArraysInstanced;
+   exec->vtxfmt.DrawElementsInstanced = vbo_exec_DrawElementsInstanced;
 #else
    exec->vtxfmt.DrawArrays = _mesa_noop_DrawArrays;
    exec->vtxfmt.DrawElements = _mesa_noop_DrawElements;
index a5d027982f4fea001abfdae00cb5f389bfbba551..c867cb03f63d9d4b0ac3ac3b00907917c457d743 100644 (file)
@@ -418,6 +418,7 @@ static void _save_wrap_buffers( GLcontext *ctx )
    save->prim[0].pad = 0;
    save->prim[0].start = 0;
    save->prim[0].count = 0;
+   save->prim[0].num_instances = 1;
    save->prim_count = 1;
 }
 
@@ -773,6 +774,7 @@ GLboolean vbo_save_NotifyBegin( GLcontext *ctx, GLenum mode )
    save->prim[i].pad = 0;
    save->prim[i].start = save->vert_count;
    save->prim[i].count = 0;   
+   save->prim[i].num_instances = 1;   
 
    _mesa_install_save_vtxfmt( ctx, &save->vtxfmt );      
    ctx->Driver.SaveNeedFlush = 1;