Merge branch 'master' of ssh://git.freedesktop.org/git/mesa/mesa into r600_state_predict
[mesa.git] / src / mesa / drivers / dri / i965 / brw_draw_upload.c
index 760b22fa9d12658553d7d41279c5fd0dc5b75443..d49fb0fd951bf63b297d898caa8b6dadd563cfb8 100644 (file)
@@ -383,7 +383,6 @@ static void brw_prepare_vertices(struct brw_context *brw)
       struct brw_vertex_element *input = brw->vb.enabled[i];
 
       input->element_size = get_size(input->glarray->Type) * input->glarray->Size;
-      input->count = input->glarray->StrideB ? max_index + 1 - min_index : 1;
 
       if (input->glarray->BufferObj->Name != 0) {
         struct intel_buffer_object *intel_buffer =
@@ -396,6 +395,7 @@ static void brw_prepare_vertices(struct brw_context *brw)
         dri_bo_reference(input->bo);
         input->offset = (unsigned long)input->glarray->Ptr;
         input->stride = input->glarray->StrideB;
+        input->count = input->glarray->_MaxElement;
 
         /* This is a common place to reach if the user mistakenly supplies
          * a pointer in place of a VBO offset.  If we just let it go through,
@@ -411,6 +411,7 @@ static void brw_prepare_vertices(struct brw_context *brw)
          */
         assert(input->offset < input->bo->size);
       } else {
+        input->count = input->glarray->StrideB ? max_index + 1 - min_index : 1;
         if (input->bo != NULL) {
            /* Already-uploaded vertex data is present from a previous
             * prepare_vertices, but we had to re-validate state due to
@@ -546,7 +547,7 @@ static void brw_emit_vertices(struct brw_context *brw)
                         input->offset + input->element_size);
           }
       } else
-          OUT_BATCH(brw->vb.max_index);
+          OUT_BATCH(input->stride ? input->count : 0);
       OUT_BATCH(0); /* Instance data step rate */
    }
    ADVANCE_BATCH();
@@ -611,17 +612,20 @@ static void brw_prepare_indices(struct brw_context *brw)
    dri_bo *bo = NULL;
    struct gl_buffer_object *bufferobj;
    GLuint offset;
+   GLuint ib_type_size;
 
    if (index_buffer == NULL)
       return;
 
-   ib_size = get_size(index_buffer->type) * index_buffer->count;
+   ib_type_size = get_size(index_buffer->type);
+   ib_size = ib_type_size * index_buffer->count;
    bufferobj = index_buffer->obj;;
 
    /* Turn into a proper VBO:
     */
    if (!bufferobj->Name) {
-     
+      brw->ib.start_vertex_offset = 0;
+
       /* Get new bufferobj, offset:
        */
       get_space(brw, ib_size, &bo, &offset);
@@ -637,6 +641,7 @@ static void brw_prepare_indices(struct brw_context *brw)
       }
    } else {
       offset = (GLuint) (unsigned long) index_buffer->ptr;
+      brw->ib.start_vertex_offset = 0;
 
       /* If the index buffer isn't aligned to its element size, we have to
        * rebase it into a temporary.
@@ -657,39 +662,62 @@ static void brw_prepare_indices(struct brw_context *brw)
          bo = intel_bufferobj_buffer(intel, intel_buffer_object(bufferobj),
                                      INTEL_READ);
          dri_bo_reference(bo);
+
+         /* Use CMD_3D_PRIM's start_vertex_offset to avoid re-uploading
+          * the index buffer state when we're just moving the start index
+          * of our drawing.
+          */
+         brw->ib.start_vertex_offset = offset / ib_type_size;
+         offset = 0;
+         ib_size = bo->size;
        }
    }
 
-   dri_bo_unreference(brw->ib.bo);
-   brw->ib.bo = bo;
-   brw->ib.offset = offset;
+   if (brw->ib.bo != bo ||
+       brw->ib.offset != offset ||
+       brw->ib.size != ib_size)
+   {
+      drm_intel_bo_unreference(brw->ib.bo);
+      brw->ib.bo = bo;
+      brw->ib.offset = offset;
+      brw->ib.size = ib_size;
+
+      brw->state.dirty.brw |= BRW_NEW_INDEX_BUFFER;
+   } else {
+      drm_intel_bo_unreference(bo);
+   }
 
    brw_add_validated_bo(brw, brw->ib.bo);
 }
 
-static void brw_emit_indices(struct brw_context *brw)
+const struct brw_tracked_state brw_indices = {
+   .dirty = {
+      .mesa = 0,
+      .brw = BRW_NEW_INDICES,
+      .cache = 0,
+   },
+   .prepare = brw_prepare_indices,
+};
+
+static void brw_emit_index_buffer(struct brw_context *brw)
 {
    struct intel_context *intel = &brw->intel;
    const struct _mesa_index_buffer *index_buffer = brw->ib.ib;
-   GLuint ib_size;
 
    if (index_buffer == NULL)
       return;
 
-   ib_size = get_size(index_buffer->type) * index_buffer->count - 1;
-
    /* Emit the indexbuffer packet:
     */
    {
       struct brw_indexbuffer ib;
 
       memset(&ib, 0, sizeof(ib));
-   
+
       ib.header.bits.opcode = CMD_INDEX_BUFFER;
       ib.header.bits.length = sizeof(ib)/4 - 2;
       ib.header.bits.index_format = get_index_type(index_buffer->type);
       ib.header.bits.cut_index_enable = 0;
-   
 
       BEGIN_BATCH(4, IGNORE_CLIPRECTS);
       OUT_BATCH( ib.header.dword );
@@ -698,18 +726,17 @@ static void brw_emit_indices(struct brw_context *brw)
                brw->ib.offset);
       OUT_RELOC(brw->ib.bo,
                I915_GEM_DOMAIN_VERTEX, 0,
-               brw->ib.offset + ib_size);
+               brw->ib.offset + brw->ib.size);
       OUT_BATCH( 0 );
       ADVANCE_BATCH();
    }
 }
 
-const struct brw_tracked_state brw_indices = {
+const struct brw_tracked_state brw_index_buffer = {
    .dirty = {
       .mesa = 0,
-      .brw = BRW_NEW_BATCH | BRW_NEW_INDICES,
+      .brw = BRW_NEW_BATCH | BRW_NEW_INDEX_BUFFER,
       .cache = 0,
    },
-   .prepare = brw_prepare_indices,
-   .emit = brw_emit_indices,
+   .emit = brw_emit_index_buffer,
 };