Squashed commit of the following:
[mesa.git] / src / mesa / state_tracker / st_draw.c
index 337c21a6c49b63b8b1fe4718882523aabf1bcb48..0ebc462ced4efe8e590bf9f32fdcd15ddd2482cc 100644 (file)
  * 
  **************************************************************************/
 
- /*
-  * Authors:
-  *   Keith Whitwell <keith@tungstengraphics.com>
-  */
+/*
+ * This file implements the st_draw_vbo() function which is called from
+ * Mesa's VBO module.  All point/line/triangle rendering is done through
+ * this function whether the user called glBegin/End, glDrawArrays,
+ * glDrawElements, glEvalMesh, or glCalList, etc.
+ *
+ * We basically convert the VBO's vertex attribute/array information into
+ * Gallium vertex state, bind the vertex buffer objects and call
+ * pipe->draw_elements(), pipe->draw_range_elements() or pipe->draw_arrays().
+ *
+ * Authors:
+ *   Keith Whitwell <keith@tungstengraphics.com>
+ */
+
 
 #include "main/imports.h"
 #include "main/image.h"
@@ -45,7 +55,9 @@
 
 #include "pipe/p_context.h"
 #include "pipe/p_defines.h"
-#include "pipe/p_inlines.h"
+#include "util/u_inlines.h"
+#include "util/u_format.h"
+#include "cso_cache/cso_context.h"
 
 
 static GLuint double_types[4] = {
@@ -207,59 +219,7 @@ st_pipe_vertex_format(GLenum type, GLuint size, GLenum format,
 }
 
 
-/*
- * If edge flags are needed, setup an bitvector of flags and call
- * pipe->set_edgeflags().
- * XXX memleak: need to free the returned pointer at some point
- */
-static void *
-setup_edgeflags(GLcontext *ctx, GLenum primMode, GLint start, GLint count,
-                const struct gl_client_array *array)
-{
-   struct pipe_context *pipe = ctx->st->pipe;
-
-   if ((primMode == GL_TRIANGLES ||
-        primMode == GL_QUADS ||
-        primMode == GL_POLYGON) &&
-       (ctx->Polygon.FrontMode != GL_FILL ||
-        ctx->Polygon.BackMode != GL_FILL)) {
-      /* need edge flags */
-      GLint i;
-      unsigned *vec;
-      struct st_buffer_object *stobj = st_buffer_object(array->BufferObj);
-      ubyte *map;
-
-      if (!stobj || stobj->Base.Name == 0) {
-         /* edge flags are not in a VBO */
-         return NULL;
-      }
 
-      vec = (unsigned *) _mesa_calloc(sizeof(unsigned) * ((count + 31) / 32));
-      if (!vec)
-         return NULL;
-
-      map = pipe_buffer_map(pipe->screen, stobj->buffer, PIPE_BUFFER_USAGE_CPU_READ);
-      map = ADD_POINTERS(map, array->Ptr);
-
-      for (i = 0; i < count; i++) {
-         if (*((float *) map))
-            vec[i/32] |= 1 << (i % 32);
-
-         map += array->StrideB;
-      }
-
-      pipe_buffer_unmap(pipe->screen, stobj->buffer);
-
-      pipe->set_edgeflags(pipe, vec);
-
-      return vec;
-   }
-   else {
-      /* edge flags not needed */
-      pipe->set_edgeflags(pipe, NULL);
-      return NULL;
-   }
-}
 
 
 /**
@@ -269,6 +229,7 @@ setup_edgeflags(GLcontext *ctx, GLenum primMode, GLint start, GLint count,
  */
 static GLboolean
 is_interleaved_arrays(const struct st_vertex_program *vp,
+                      const struct st_vp_varient *vpv,
                       const struct gl_client_array **arrays,
                       GLboolean *userSpace)
 {
@@ -278,7 +239,7 @@ is_interleaved_arrays(const struct st_vertex_program *vp,
    GLuint num_client_arrays = 0;
    const GLubyte *client_addr = NULL;
 
-   for (attr = 0; attr < vp->num_inputs; attr++) {
+   for (attr = 0; attr < vpv->num_inputs; attr++) {
       const GLuint mesaAttr = vp->index_to_input[attr];
       const struct gl_buffer_object *bufObj = arrays[mesaAttr]->BufferObj;
       const GLsizei stride = arrays[mesaAttr]->StrideB; /* in bytes */
@@ -311,8 +272,9 @@ is_interleaved_arrays(const struct st_vertex_program *vp,
       }
    }
 
-   *userSpace = (num_client_arrays == vp->num_inputs);
-   /* printf("user space: %d (%d %d)\n", (int) *userSpace,num_client_arrays,vp->num_inputs); */
+   *userSpace = (num_client_arrays == vpv->num_inputs);
+   /* debug_printf("user space: %s (%d arrays, %d inputs)\n",
+      (int)*userSpace ? "Yes" : "No", num_client_arrays, vp->num_inputs); */
 
    return GL_TRUE;
 }
@@ -323,15 +285,18 @@ is_interleaved_arrays(const struct st_vertex_program *vp,
  */
 static void
 get_arrays_bounds(const struct st_vertex_program *vp,
-                       const struct gl_client_array **arrays,
-                       GLuint max_index,
-                       const GLubyte **low, const GLubyte **high)
+                  const struct st_vp_varient *vpv,
+                  const struct gl_client_array **arrays,
+                  GLuint max_index,
+                  const GLubyte **low, const GLubyte **high)
 {
    const GLubyte *low_addr = NULL;
    const GLubyte *high_addr = NULL;
    GLuint attr;
 
-   for (attr = 0; attr < vp->num_inputs; attr++) {
+   /* debug_printf("get_arrays_bounds: Handling %u attrs\n", vpv->num_inputs); */
+
+   for (attr = 0; attr < vpv->num_inputs; attr++) {
       const GLuint mesaAttr = vp->index_to_input[attr];
       const GLint stride = arrays[mesaAttr]->StrideB;
       const GLubyte *start = arrays[mesaAttr]->Ptr;
@@ -339,6 +304,9 @@ get_arrays_bounds(const struct st_vertex_program *vp,
                            _mesa_sizeof_type(arrays[mesaAttr]->Type));
       const GLubyte *end = start + (max_index * stride) + sz;
 
+      /* debug_printf("attr %u: stride %d size %u start %p end %p\n",
+         attr, stride, sz, start, end); */
+
       if (attr == 0) {
          low_addr = start;
          high_addr = end;
@@ -363,6 +331,7 @@ get_arrays_bounds(const struct st_vertex_program *vp,
 static void
 setup_interleaved_attribs(GLcontext *ctx,
                           const struct st_vertex_program *vp,
+                          const struct st_vp_varient *vpv,
                           const struct gl_client_array **arrays,
                           GLuint max_index,
                           GLboolean userSpace,
@@ -371,9 +340,9 @@ setup_interleaved_attribs(GLcontext *ctx,
 {
    struct pipe_context *pipe = ctx->st->pipe;
    GLuint attr;
-   const GLubyte *offset0;
+   const GLubyte *offset0 = NULL;
 
-   for (attr = 0; attr < vp->num_inputs; attr++) {
+   for (attr = 0; attr < vpv->num_inputs; attr++) {
       const GLuint mesaAttr = vp->index_to_input[attr];
       struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj;
       struct st_buffer_object *stobj = st_buffer_object(bufobj);
@@ -384,18 +353,20 @@ setup_interleaved_attribs(GLcontext *ctx,
       if (attr == 0) {
          const GLubyte *low, *high;
 
-         get_arrays_bounds(vp, arrays, max_index, &low, &high);
-         /*printf("buffer range: %p %p  %d\n", low, high, high-low);*/
+         get_arrays_bounds(vp, vpv, arrays, max_index, &low, &high);
+         /* debug_printf("buffer range: %p %p range %d max index %u\n",
+            low, high, high - low, max_index); */
 
          offset0 = low;
          if (userSpace) {
             vbuffer->buffer =
-               pipe_user_buffer_create(pipe->screen, (void *) low, high - low);
+               pipe_user_buffer_create(pipe->screen, (void *) low, high - low,
+                                      PIPE_BIND_VERTEX_BUFFER);
             vbuffer->buffer_offset = 0;
          }
          else {
             vbuffer->buffer = NULL;
-            pipe_buffer_reference(&vbuffer->buffer, stobj->buffer);
+            pipe_resource_reference(&vbuffer->buffer, stobj->buffer);
             vbuffer->buffer_offset = pointer_to_offset(low);
          }
          vbuffer->stride = stride; /* in bytes */
@@ -404,8 +375,8 @@ setup_interleaved_attribs(GLcontext *ctx,
 
       velements[attr].src_offset =
          (unsigned) (arrays[mesaAttr]->Ptr - offset0);
+      velements[attr].instance_divisor = 0;
       velements[attr].vertex_buffer_index = 0;
-      velements[attr].nr_components = arrays[mesaAttr]->Size;
       velements[attr].src_format =
          st_pipe_vertex_format(arrays[mesaAttr]->Type,
                                arrays[mesaAttr]->Size,
@@ -425,6 +396,7 @@ setup_interleaved_attribs(GLcontext *ctx,
 static void
 setup_non_interleaved_attribs(GLcontext *ctx,
                               const struct st_vertex_program *vp,
+                              const struct st_vp_varient *vpv,
                               const struct gl_client_array **arrays,
                               GLuint max_index,
                               GLboolean *userSpace,
@@ -434,7 +406,7 @@ setup_non_interleaved_attribs(GLcontext *ctx,
    struct pipe_context *pipe = ctx->st->pipe;
    GLuint attr;
 
-   for (attr = 0; attr < vp->num_inputs; attr++) {
+   for (attr = 0; attr < vpv->num_inputs; attr++) {
       const GLuint mesaAttr = vp->index_to_input[attr];
       struct gl_buffer_object *bufobj = arrays[mesaAttr]->BufferObj;
       GLsizei stride = arrays[mesaAttr]->StrideB;
@@ -451,7 +423,7 @@ setup_non_interleaved_attribs(GLcontext *ctx,
          /*printf("stobj %u = %p\n", attr, (void*) stobj);*/
 
          vbuffer[attr].buffer = NULL;
-         pipe_buffer_reference(&vbuffer[attr].buffer, stobj->buffer);
+         pipe_resource_reference(&vbuffer[attr].buffer, stobj->buffer);
          vbuffer[attr].buffer_offset = pointer_to_offset(arrays[mesaAttr]->Ptr);
          velements[attr].src_offset = 0;
       }
@@ -472,14 +444,19 @@ setup_non_interleaved_attribs(GLcontext *ctx,
                bytes = arrays[mesaAttr]->Size
                   * _mesa_sizeof_type(arrays[mesaAttr]->Type);
             }
-            vbuffer[attr].buffer = pipe_user_buffer_create(pipe->screen,
-                           (void *) arrays[mesaAttr]->Ptr, bytes);
+            vbuffer[attr].buffer = 
+              pipe_user_buffer_create(pipe->screen,
+                                      (void *) arrays[mesaAttr]->Ptr, bytes,
+                                      PIPE_BIND_VERTEX_BUFFER);
          }
          else {
             /* no array, use ctx->Current.Attrib[] value */
             bytes = sizeof(ctx->Current.Attrib[0]);
-            vbuffer[attr].buffer = pipe_user_buffer_create(pipe->screen,
-                           (void *) ctx->Current.Attrib[mesaAttr], bytes);
+            vbuffer[attr].buffer = 
+              pipe_user_buffer_create(pipe->screen,
+                                      (void *) ctx->Current.Attrib[mesaAttr],
+                                      bytes,
+                                      PIPE_BIND_VERTEX_BUFFER);
             stride = 0;
          }
 
@@ -492,8 +469,8 @@ setup_non_interleaved_attribs(GLcontext *ctx,
       /* common-case setup */
       vbuffer[attr].stride = stride; /* in bytes */
       vbuffer[attr].max_index = max_index;
+      velements[attr].instance_divisor = 0;
       velements[attr].vertex_buffer_index = attr;
-      velements[attr].nr_components = arrays[mesaAttr]->Size;
       velements[attr].src_format
          = st_pipe_vertex_format(arrays[mesaAttr]->Type,
                                  arrays[mesaAttr]->Size,
@@ -528,6 +505,20 @@ check_uniforms(GLcontext *ctx)
 }
 
 
+static unsigned translate_prim( GLcontext *ctx,
+                                unsigned prim )
+{
+   /* Avoid quadstrips if it's easy to do so:
+    */
+   if (prim == GL_QUAD_STRIP &&
+       ctx->Light.ShadeModel != GL_FLAT &&
+       ctx->Polygon.FrontMode == GL_FILL &&
+       ctx->Polygon.BackMode == GL_FILL)
+      prim = GL_TRIANGLE_STRIP;
+
+   return prim;
+}
+
 /**
  * This function gets plugged into the VBO module and is called when
  * we have something to render.
@@ -545,25 +536,37 @@ st_draw_vbo(GLcontext *ctx,
 {
    struct pipe_context *pipe = ctx->st->pipe;
    const struct st_vertex_program *vp;
-   const struct pipe_shader_state *vs;
+   const struct st_vp_varient *vpv;
    struct pipe_vertex_buffer vbuffer[PIPE_MAX_SHADER_INPUTS];
    GLuint attr;
    struct pipe_vertex_element velements[PIPE_MAX_ATTRIBS];
    unsigned num_vbuffers, num_velements;
-   GLboolean userSpace;
+   GLboolean userSpace = GL_FALSE;
+   GLboolean vertDataEdgeFlags;
+
+   /* Mesa core state should have been validated already */
+   assert(ctx->NewState == 0x0);
 
    /* Gallium probably doesn't want this in some cases. */
    if (!index_bounds_valid)
-      vbo_get_minmax_index(ctx, prims, ib, &min_index, &max_index);
+      if (!vbo_all_varyings_in_vbos(arrays))
+        vbo_get_minmax_index(ctx, prims, ib, &min_index, &max_index);
 
    /* sanity check for pointer arithmetic below */
    assert(sizeof(arrays[0]->Ptr[0]) == 1);
 
+   vertDataEdgeFlags = arrays[VERT_ATTRIB_EDGEFLAG]->BufferObj &&
+                       arrays[VERT_ATTRIB_EDGEFLAG]->BufferObj->Name;
+   if (vertDataEdgeFlags != ctx->st->vertdata_edgeflags) {
+      ctx->st->vertdata_edgeflags = vertDataEdgeFlags;
+      ctx->st->dirty.st |= ST_NEW_EDGEFLAGS_DATA;
+   }
+
    st_validate_state(ctx->st);
 
    /* must get these after state validation! */
    vp = ctx->st->vp;
-   vs = &ctx->st->vp_varient->state;
+   vpv = ctx->st->vp_varient;
 
 #if 0
    if (MESA_VERBOSE & VERBOSE_GLSL) {
@@ -573,24 +576,25 @@ st_draw_vbo(GLcontext *ctx,
    (void) check_uniforms;
 #endif
 
+   memset(velements, 0, sizeof(struct pipe_vertex_element) * vpv->num_inputs);
    /*
     * Setup the vbuffer[] and velements[] arrays.
     */
-   if (is_interleaved_arrays(vp, arrays, &userSpace)) {
+   if (is_interleaved_arrays(vp, vpv, arrays, &userSpace)) {
       /*printf("Draw interleaved\n");*/
-      setup_interleaved_attribs(ctx, vp, arrays, max_index, userSpace,
+      setup_interleaved_attribs(ctx, vp, vpv, arrays, max_index, userSpace,
                                 vbuffer, velements);
       num_vbuffers = 1;
-      num_velements = vp->num_inputs;
+      num_velements = vpv->num_inputs;
       if (num_velements == 0)
          num_vbuffers = 0;
    }
    else {
       /*printf("Draw non-interleaved\n");*/
-      setup_non_interleaved_attribs(ctx, vp, arrays, max_index,
+      setup_non_interleaved_attribs(ctx, vp, vpv, arrays, max_index,
                                     &userSpace, vbuffer, velements);
-      num_vbuffers = vp->num_inputs;
-      num_velements = vp->num_inputs;
+      num_vbuffers = vpv->num_inputs;
+      num_velements = vpv->num_inputs;
    }
 
 #if 0
@@ -605,14 +609,13 @@ st_draw_vbo(GLcontext *ctx,
       for (i = 0; i < num_velements; i++) {
          printf("vlements[%d].vbuffer_index = %u\n", i, velements[i].vertex_buffer_index);
          printf("vlements[%d].src_offset = %u\n", i, velements[i].src_offset);
-         printf("vlements[%d].nr_comps = %u\n", i, velements[i].nr_components);
-         printf("vlements[%d].format = %s\n", i, pf_name(velements[i].src_format));
+         printf("vlements[%d].format = %s\n", i, util_format_name(velements[i].src_format));
       }
    }
 #endif
 
    pipe->set_vertex_buffers(pipe, num_vbuffers, vbuffer);
-   pipe->set_vertex_elements(pipe, num_velements, velements);
+   cso_set_vertex_elements(ctx->st->cso_context, num_velements, velements);
 
    if (num_vbuffers == 0 || num_velements == 0)
       return;
@@ -621,8 +624,9 @@ st_draw_vbo(GLcontext *ctx,
    if (ib) {
       /* indexed primitive */
       struct gl_buffer_object *bufobj = ib->obj;
-      struct pipe_buffer *indexBuf = NULL;
+      struct pipe_resource *indexBuf = NULL;
       unsigned indexSize, indexOffset, i;
+      unsigned prim;
 
       switch (ib->type) {
       case GL_UNSIGNED_INT:
@@ -643,63 +647,73 @@ st_draw_vbo(GLcontext *ctx,
       if (bufobj && bufobj->Name) {
          /* elements/indexes are in a real VBO */
          struct st_buffer_object *stobj = st_buffer_object(bufobj);
-         pipe_buffer_reference(&indexBuf, stobj->buffer);
+         pipe_resource_reference(&indexBuf, stobj->buffer);
          indexOffset = pointer_to_offset(ib->ptr) / indexSize;
       }
       else {
          /* element/indicies are in user space memory */
          indexBuf = pipe_user_buffer_create(pipe->screen, (void *) ib->ptr,
-                                            ib->count * indexSize);
+                                            ib->count * indexSize,
+                                           PIPE_BIND_INDEX_BUFFER);
          indexOffset = 0;
       }
 
       /* draw */
-      if (nr_prims == 1 && pipe->draw_range_elements != NULL) {
-         i = 0;
-
+      if (pipe->draw_range_elements && min_index != ~0 && max_index != ~0) {
          /* XXX: exercise temporary path to pass min/max directly
           * through to driver & draw module.  These interfaces still
           * need a bit of work...
           */
-         setup_edgeflags(ctx, prims[i].mode,
-                         prims[i].start + indexOffset, prims[i].count,
-                         arrays[VERT_ATTRIB_EDGEFLAG]);
-
-         pipe->draw_range_elements(pipe, indexBuf, indexSize,
-                                   min_index,
-                                   max_index,
-                                   prims[i].mode,
-                                   prims[i].start + indexOffset, prims[i].count);
+         for (i = 0; i < nr_prims; i++) {
+            prim = translate_prim( ctx, prims[i].mode );
+
+            pipe->draw_range_elements(pipe, indexBuf, indexSize,
+                                      min_index, max_index, prim,
+                                      prims[i].start + indexOffset, prims[i].count);
+         }
       }
       else {
          for (i = 0; i < nr_prims; i++) {
-            setup_edgeflags(ctx, prims[i].mode,
-                            prims[i].start + indexOffset, prims[i].count,
-                            arrays[VERT_ATTRIB_EDGEFLAG]);
+            prim = translate_prim( ctx, prims[i].mode );
             
-            pipe->draw_elements(pipe, indexBuf, indexSize,
-                                prims[i].mode,
-                                prims[i].start + indexOffset, prims[i].count);
+            if (prims[i].num_instances == 1) {
+               pipe->draw_elements(pipe, indexBuf, indexSize, prim,
+                                   prims[i].start + indexOffset,
+                                   prims[i].count);
+            }
+            else {
+               pipe->draw_elements_instanced(pipe, indexBuf, indexSize, prim,
+                                             prims[i].start + indexOffset,
+                                             prims[i].count,
+                                             0, prims[i].num_instances);
+            }
          }
       }
 
-      pipe_buffer_reference(&indexBuf, NULL);
+      pipe_resource_reference(&indexBuf, NULL);
    }
    else {
       /* non-indexed */
       GLuint i;
+      GLuint prim;
+
       for (i = 0; i < nr_prims; i++) {
-         setup_edgeflags(ctx, prims[i].mode,
-                         prims[i].start, prims[i].count,
-                         arrays[VERT_ATTRIB_EDGEFLAG]);
+         prim = translate_prim( ctx, prims[i].mode );
 
-         pipe->draw_arrays(pipe, prims[i].mode, prims[i].start, prims[i].count);
+         if (prims[i].num_instances == 1) {
+            pipe->draw_arrays(pipe, prim, prims[i].start, prims[i].count);
+         }
+         else {
+            pipe->draw_arrays_instanced(pipe, prim, prims[i].start,
+                                        prims[i].count,
+                                        0, prims[i].num_instances);
+         }
       }
    }
 
    /* unreference buffers (frees wrapped user-space buffer objects) */
    for (attr = 0; attr < num_vbuffers; attr++) {
-      pipe_buffer_reference(&vbuffer[attr].buffer, NULL);
+      pipe_resource_reference(&vbuffer[attr].buffer, NULL);
       assert(!vbuffer[attr].buffer);
    }