include swrast_setup/swrast_setup.h to silence warning
[mesa.git] / src / mesa / drivers / dri / i965 / brw_draw.c
index 104404b3019b65ce80dd7d09ce52821b85e3580a..0c64d7e756dca93369bb14ce211ae6ffcb142e61 100644 (file)
@@ -35,7 +35,6 @@
 
 #include "brw_draw.h"
 #include "brw_defines.h"
-#include "brw_attrib.h"
 #include "brw_context.h"
 #include "brw_aub.h"
 #include "brw_state.h"
 #include "intel_batchbuffer.h"
 #include "intel_buffer_objects.h"
 
-
-
+#include "tnl/tnl.h"
+#include "vbo/vbo_context.h"
+#include "swrast/swrast.h"
+#include "swrast_setup/swrast_setup.h"
 
 
 
@@ -123,10 +124,27 @@ static GLuint trim(GLenum prim, GLuint length)
 }
 
 
+static void brw_emit_cliprect( struct brw_context *brw, 
+                              const drm_clip_rect_t *rect )
+{
+   struct brw_drawrect bdr;
+
+   bdr.header.opcode = CMD_DRAW_RECT;
+   bdr.header.length = sizeof(bdr)/4 - 2;
+   bdr.xmin = rect->x1;
+   bdr.xmax = rect->x2 - 1;
+   bdr.ymin = rect->y1;
+   bdr.ymax = rect->y2 - 1;
+   bdr.xorg = brw->intel.drawX;
+   bdr.yorg = brw->intel.drawY;
+
+   intel_batchbuffer_data( brw->intel.batch, &bdr, sizeof(bdr), 
+                          INTEL_BATCH_NO_CLIPRECTS);
+}
 
 
 static void brw_emit_prim( struct brw_context *brw, 
-                          const struct brw_draw_prim *prim )
+                          const struct _mesa_prim *prim )
 
 {
    struct brw_3d_primitive prim_packet;
@@ -149,38 +167,13 @@ static void brw_emit_prim( struct brw_context *brw,
 
    if (prim_packet.verts_per_instance) {
       intel_batchbuffer_data( brw->intel.batch, &prim_packet, sizeof(prim_packet), 
-                             INTEL_BATCH_CLIPRECTS);
+                             INTEL_BATCH_NO_CLIPRECTS);
    }
 }
 
-
-
-static void update_current_size( struct gl_client_array *array)
-{
-   const GLfloat *ptr = (const GLfloat *)array->Ptr;
-
-   assert(array->StrideB == 0);
-   assert(array->Type == GL_FLOAT || array->Type == GL_UNSIGNED_BYTE);
-
-   if (ptr[3] != 1.0) 
-      array->Size = 4;
-   else if (ptr[2] != 0.0) 
-      array->Size = 3;
-   else if (ptr[1] != 0.0) 
-      array->Size = 2;
-   else
-      array->Size = 1;
-}
-
-
-
-/* Fill in any gaps in passed arrays with pointers to current
- * attributes:
- */
 static void brw_merge_inputs( struct brw_context *brw,
                       const struct gl_client_array *arrays[])
 {
-   struct gl_client_array *current_values = brw->vb.current_values;
    struct brw_vertex_element *inputs = brw->vb.inputs;
    struct brw_vertex_info old = brw->vb.info;
    GLuint i;
@@ -188,19 +181,16 @@ static void brw_merge_inputs( struct brw_context *brw,
    memset(inputs, 0, sizeof(*inputs));
    memset(&brw->vb.info, 0, sizeof(brw->vb.info));
 
-   for (i = 0; i < BRW_ATTRIB_MAX; i++) {
-      if (arrays[i] && arrays[i]->Enabled)
-      {
-        brw->vb.inputs[i].glarray = arrays[i];
-        brw->vb.info.varying |= 1 << i;
-      }
-      else 
-      {
-        brw->vb.inputs[i].glarray = &current_values[i];
-        update_current_size(&current_values[i]);
-      }
+   for (i = 0; i < VERT_ATTRIB_MAX; i++) {
+      brw->vb.inputs[i].glarray = arrays[i];
+
+      /* XXX: metaops passes null arrays */
+      if (arrays[i]) {
+        if (arrays[i]->StrideB != 0)
+           brw->vb.info.varying |= 1 << i;
 
-      brw->vb.info.sizes[i/16] |= (inputs[i].glarray->Size - 1) << ((i%16) * 2);
+        brw->vb.info.sizes[i/16] |= (inputs[i].glarray->Size - 1) << ((i%16) * 2);
+      }
    }
 
    /* Raise statechanges if input sizes and varying have changed: 
@@ -212,8 +202,11 @@ static void brw_merge_inputs( struct brw_context *brw,
       brw->state.dirty.brw |= BRW_NEW_INPUT_VARYING;
 }
 
+/* XXX: could split the primitive list to fallback only on the
+ * non-conformant primitives.
+ */
 static GLboolean check_fallbacks( struct brw_context *brw,
-                                 const struct brw_draw_prim *prim,
+                                 const struct _mesa_prim *prim,
                                  GLuint nr_prims )
 {
    GLuint i;
@@ -264,28 +257,29 @@ static GLboolean check_fallbacks( struct brw_context *brw,
    return GL_FALSE;
 }
 
-
-GLboolean brw_draw_prims( GLcontext *ctx,
-                         const struct gl_client_array *arrays[],
-                         const struct brw_draw_prim *prim,
-                         GLuint nr_prims,
-                         const struct brw_draw_index_buffer *ib,
-                         GLuint min_index,
-                         GLuint max_index,
-                         GLuint flags )
+/* May fail if out of video memory for texture or vbo upload, or on
+ * fallback conditions.
+ */
+static GLboolean brw_try_draw_prims( GLcontext *ctx,
+                                    const struct gl_client_array *arrays[],
+                                    const struct _mesa_prim *prim,
+                                    GLuint nr_prims,
+                                    const struct _mesa_index_buffer *ib,
+                                    GLuint min_index,
+                                    GLuint max_index )
 {
    struct intel_context *intel = intel_context(ctx);
    struct brw_context *brw = brw_context(ctx);
    GLboolean retval = GL_FALSE;
-   GLuint i;
+   GLuint i, j;
 
    if (ctx->NewState)
       _mesa_update_state( ctx );
-      
+
    /* Bind all inputs, derive varying and size information:
     */
    brw_merge_inputs( brw, arrays );
-
+      
    /* Have to validate state quite late.  Will rebuild tnl_program,
     * which depends on varying information.  
     * 
@@ -294,9 +288,14 @@ GLboolean brw_draw_prims( GLcontext *ctx,
     */
 
    LOCK_HARDWARE(intel);
-   {
-      assert(intel->locked);
 
+   if (brw->intel.numClipRects == 0) {
+      assert(intel->batch->ptr == intel->batch->map + intel->batch->offset);
+      UNLOCK_HARDWARE(intel);
+      return GL_TRUE;
+   }
+
+   {
       /* Set the first primitive early, ahead of validate_state:
        */
       brw_set_prim(brw, prim[0].mode);
@@ -322,12 +321,28 @@ GLboolean brw_draw_prims( GLcontext *ctx,
         goto out;
       }
 
-      /* Emit prims to batchbuffer
+      /* For single cliprect, state is already emitted
        */
-      for (i = 0; i < nr_prims; i++) {
-        brw_emit_prim(brw, &prim[i]);   
+      if (brw->intel.numClipRects == 1) {
+        for (i = 0; i < nr_prims; i++) {
+           brw_emit_prim(brw, &prim[i]);   
+        }
+      }
+      else {
+        /* Otherwise, explicitly do the cliprects at this point:
+         */
+        for (j = 0; j < brw->intel.numClipRects; j++) {
+           brw_emit_cliprect(brw, &brw->intel.pClipRects[j]);
+
+           /* Emit prims to batchbuffer: 
+            */
+           for (i = 0; i < nr_prims; i++) {
+              brw_emit_prim(brw, &prim[i]);   
+           }
+        }
       }
       
+      intel->need_flush = GL_TRUE;
       retval = GL_TRUE;
    }
 
@@ -338,9 +353,12 @@ GLboolean brw_draw_prims( GLcontext *ctx,
     * way around this, as not every flush is due to a buffer filling
     * up.
     */
-   intel_batchbuffer_flush( brw->intel.batch );
+   if (!intel_batchbuffer_flush( brw->intel.batch )) {
+      DBG("%s intel_batchbuffer_flush failed\n", __FUNCTION__);
+      retval = GL_FALSE;
+   }
 
-   if (intel->thrashing) {
+   if (retval && intel->thrashing) {
       bmSetFence(intel);
    }
 
@@ -359,9 +377,99 @@ GLboolean brw_draw_prims( GLcontext *ctx,
    }
 
    UNLOCK_HARDWARE(intel);
+
+   if (!retval)
+      DBG("%s failed\n", __FUNCTION__);
+
    return retval;
 }
 
+static GLboolean brw_need_rebase( GLcontext *ctx,
+                                 const struct gl_client_array *arrays[],
+                                 const struct _mesa_index_buffer *ib,
+                                 GLuint min_index )
+{
+   if (min_index == 0) 
+      return GL_FALSE;
+
+   if (ib) {
+      if (!vbo_all_varyings_in_vbos(arrays))
+        return GL_TRUE;
+      else
+        return GL_FALSE;
+   }
+   else {
+      /* Hmm.  This isn't quite what I wanted.  BRW can actually
+       * handle the mixed case well enough that we shouldn't need to
+       * rebase.  However, it's probably not very common, nor hugely
+       * expensive to do it this way:
+       */
+      if (!vbo_all_varyings_in_vbos(arrays))
+        return GL_TRUE;
+      else
+        return GL_FALSE;
+   }
+}
+                                 
+
+void brw_draw_prims( GLcontext *ctx,
+                    const struct gl_client_array *arrays[],
+                    const struct _mesa_prim *prim,
+                    GLuint nr_prims,
+                    const struct _mesa_index_buffer *ib,
+                    GLuint min_index,
+                    GLuint max_index )
+{
+   struct intel_context *intel = intel_context(ctx);
+   GLboolean retval;
+
+   /* Decide if we want to rebase.  If so we end up recursing once
+    * only into this function.
+    */
+   if (brw_need_rebase( ctx, arrays, ib, min_index )) {
+      vbo_rebase_prims( ctx, arrays, 
+                       prim, nr_prims, 
+                       ib, min_index, max_index, 
+                       brw_draw_prims );
+      
+      return;
+   }
+
+
+   /* Make a first attempt at drawing:
+    */
+   retval = brw_try_draw_prims(ctx, arrays, prim, nr_prims, ib, min_index, max_index);
+
+   
+   /* This looks like out-of-memory but potentially we have
+    * situation where there is enough memory but it has become
+    * fragmented.  Clear out all heaps and start from scratch by
+    * faking a contended lock event:  (done elsewhere)
+    */
+   if (!retval && !intel->Fallback && bmError(intel)) {
+      DBG("retrying\n");
+      /* Then try a second time only to upload textures and draw the
+       * primitives:
+       */
+      retval = brw_try_draw_prims(ctx, arrays, prim, nr_prims, ib, min_index, max_index);
+   }
+
+   /* Otherwise, we really are out of memory.  Pass the drawing
+    * command to the software tnl module and which will in turn call
+    * swrast to do the drawing.
+    */
+   if (!retval) {
+       _swsetup_Wakeup(ctx);
+      _tnl_draw_prims(ctx, arrays, prim, nr_prims, ib, min_index, max_index);
+   }
+
+   if (intel->aub_file && (INTEL_DEBUG & DEBUG_SYNC)) {
+      intelFinish( &intel->ctx );
+      intel->aub_wrap = 1;
+   }
+}
+
+
 static void brw_invalidate_vbo_cb( struct intel_context *intel, void *ptr )
 {
    /* nothing to do, we don't rely on the contents being preserved */
@@ -371,21 +479,25 @@ static void brw_invalidate_vbo_cb( struct intel_context *intel, void *ptr )
 void brw_draw_init( struct brw_context *brw )
 {
    GLcontext *ctx = &brw->intel.ctx;
+   struct vbo_context *vbo = vbo_context(ctx);
    GLuint i;
    
+   /* Register our drawing function: 
+    */
+   vbo->draw_prims = brw_draw_prims;
+
    brw->vb.upload.size = BRW_UPLOAD_INIT_SIZE;
 
    for (i = 0; i < BRW_NR_UPLOAD_BUFS; i++) {
       brw->vb.upload.vbo[i] = ctx->Driver.NewBufferObject(ctx, 1, GL_ARRAY_BUFFER_ARB);
       
-      /* XXX: Set these to no-backing-store
+      /* NOTE:  These are set to no-backing-store.
        */
       bmBufferSetInvalidateCB(&brw->intel,
                              intel_bufferobj_buffer(intel_buffer_object(brw->vb.upload.vbo[i])),
                              brw_invalidate_vbo_cb,
                              &brw->intel,
                              GL_TRUE);
-
    }
 
    ctx->Driver.BufferData( ctx, 
@@ -394,9 +506,6 @@ void brw_draw_init( struct brw_context *brw )
                           NULL,
                           GL_DYNAMIC_DRAW_ARB,
                           brw->vb.upload.vbo[0] );
-                                                    
-   
-   brw_init_current_values(ctx, brw->vb.current_values);
 }
 
 void brw_draw_destroy( struct brw_context *brw )