mesa: add/update comments in _mesa_copy_buffer_subdata()
[mesa.git] / src / mesa / drivers / dri / i965 / brw_draw.c
index c02b2bc78529d23a4dde343ba49d381a4dc150f2..621195d02292e0bc2d0c43bf9360ea4965bd072f 100644 (file)
@@ -25,6 +25,7 @@
  * 
  **************************************************************************/
 
+#include <sys/errno.h>
 
 #include "main/glheader.h"
 #include "main/context.h"
 #include "main/samplerobj.h"
 #include "main/state.h"
 #include "main/enums.h"
+#include "main/macros.h"
 #include "tnl/tnl.h"
 #include "vbo/vbo_context.h"
 #include "swrast/swrast.h"
 #include "swrast_setup/swrast_setup.h"
+#include "drivers/common/meta.h"
 
 #include "brw_draw.h"
 #include "brw_defines.h"
@@ -43,6 +46,9 @@
 #include "brw_state.h"
 
 #include "intel_batchbuffer.h"
+#include "intel_fbo.h"
+#include "intel_mipmap_tree.h"
+#include "intel_regions.h"
 
 #define FILE_DEBUG_FLAG DEBUG_PRIMS
 
@@ -116,10 +122,17 @@ static void brw_set_prim(struct brw_context *brw,
 static void gen6_set_prim(struct brw_context *brw,
                           const struct _mesa_prim *prim)
 {
-   uint32_t hw_prim = prim_to_hw_prim[prim->mode];
+   uint32_t hw_prim;
 
    DBG("PRIM: %s\n", _mesa_lookup_enum_by_nr(prim->mode));
 
+   if (brw->hiz.op) {
+      assert(prim->mode == GL_TRIANGLES);
+      hw_prim = _3DPRIM_RECTLIST;
+   } else {
+      hw_prim = prim_to_hw_prim[prim->mode];
+   }
+
    if (hw_prim != brw->primitive) {
       brw->primitive = hw_prim;
       brw->state.dirty.brw |= BRW_NEW_PRIMITIVE;
@@ -279,6 +292,147 @@ static void brw_merge_inputs( struct brw_context *brw,
       brw->state.dirty.brw |= BRW_NEW_INPUT_DIMENSIONS;
 }
 
+/*
+ * \brief Resolve buffers before drawing.
+ *
+ * Resolve the depth buffer's HiZ buffer and resolve the depth buffer of each
+ * enabled depth texture.
+ *
+ * (In the future, this will also perform MSAA resolves).
+ */
+static void
+brw_predraw_resolve_buffers(struct brw_context *brw)
+{
+   struct gl_context *ctx = &brw->intel.ctx;
+   struct intel_context *intel = &brw->intel;
+   struct intel_renderbuffer *depth_irb;
+   struct intel_texture_object *tex_obj;
+   bool did_resolve = false;
+
+   /* Avoid recursive HiZ op. */
+   if (brw->hiz.op) {
+      return;
+   }
+
+   /* Resolve the depth buffer's HiZ buffer. */
+   depth_irb = intel_get_renderbuffer(ctx->DrawBuffer, BUFFER_DEPTH);
+   if (depth_irb && depth_irb->mt) {
+      did_resolve |= intel_renderbuffer_resolve_hiz(intel, depth_irb);
+   }
+
+   /* Resolve depth buffer of each enabled depth texture. */
+   for (int i = 0; i < BRW_MAX_TEX_UNIT; i++) {
+      if (!ctx->Texture.Unit[i]._ReallyEnabled)
+        continue;
+      tex_obj = intel_texture_object(ctx->Texture.Unit[i]._Current);
+      if (!tex_obj || !tex_obj->mt)
+        continue;
+      did_resolve |= intel_miptree_all_slices_resolve_depth(intel, tex_obj->mt);
+   }
+
+   if (did_resolve) {
+      /* Call vbo_bind_array() to synchronize the vbo module's vertex
+       * attributes to the gl_context's.
+       *
+       * Details
+       * -------
+       * The vbo module tracks vertex attributes separately from the
+       * gl_context.  Specifically, the vbo module maintins vertex attributes
+       * in vbo_exec_context::array::inputs, which is synchronized with
+       * gl_context::Array::ArrayObj::VertexAttrib by vbo_bind_array().
+       * vbo_draw_arrays() calls vbo_bind_array() to perform the
+       * synchronization before calling the real draw call,
+       * vbo_context::draw_arrays.
+       *
+       * At this point (after performing a resolve meta-op but before calling
+       * vbo_bind_array), the gl_context's vertex attributes have been
+       * restored to their original state (that is, their state before the
+       * meta-op began), but the vbo module's vertex attribute are those used
+       * in the last meta-op. Therefore we must manually synchronize the two with
+       * vbo_bind_array() before continuing with the original draw command.
+       */
+      _mesa_update_state(ctx);
+      vbo_bind_arrays(ctx);
+      _mesa_update_state(ctx);
+   }
+}
+
+/**
+ * \brief Call this after drawing to mark which buffers need resolving
+ *
+ * If the depth buffer was written to and if it has an accompanying HiZ
+ * buffer, then mark that it needs a depth resolve.
+ *
+ * (In the future, this will also mark needed MSAA resolves).
+ */
+static void brw_postdraw_set_buffers_need_resolve(struct brw_context *brw)
+{
+   struct gl_context *ctx = &brw->intel.ctx;
+   struct gl_framebuffer *fb = ctx->DrawBuffer;
+   struct intel_renderbuffer *depth_irb =
+        intel_get_renderbuffer(fb, BUFFER_DEPTH);
+
+   if (depth_irb &&
+       ctx->Depth.Mask &&
+       !brw->hiz.op) {
+      intel_renderbuffer_set_needs_depth_resolve(depth_irb);
+   }
+}
+
+static int
+verts_per_prim(GLenum mode)
+{
+   switch (mode) {
+   case GL_POINTS:
+      return 1;
+   case GL_LINE_STRIP:
+   case GL_LINE_LOOP:
+   case GL_LINES:
+      return 2;
+   case GL_TRIANGLE_STRIP:
+   case GL_TRIANGLE_FAN:
+   case GL_POLYGON:
+   case GL_TRIANGLES:
+   case GL_QUADS:
+   case GL_QUAD_STRIP:
+      return 3;
+   default:
+      _mesa_problem(NULL,
+                   "unknown prim type in transform feedback primitive count");
+      return 0;
+   }
+}
+
+/**
+ * Update internal counters based on the the drawing operation described in
+ * prim.
+ */
+static void
+brw_update_primitive_count(struct brw_context *brw,
+                           const struct _mesa_prim *prim)
+{
+   uint32_t count = count_tessellated_primitives(prim);
+   brw->sol.primitives_generated += count;
+   if (brw->intel.ctx.TransformFeedback.CurrentObject->Active &&
+       !brw->intel.ctx.TransformFeedback.CurrentObject->Paused) {
+      /* Update brw->sol.svbi_0_max_index to reflect the amount by which the
+       * hardware is going to increment SVBI 0 when this drawing operation
+       * occurs.  This is necessary because the kernel does not (yet) save and
+       * restore GPU registers when context switching, so we'll need to be
+       * able to reload SVBI 0 with the correct value in case we have to start
+       * a new batch buffer.
+       */
+      unsigned verts = verts_per_prim(prim->mode);
+      uint32_t space_avail =
+         (brw->sol.svbi_0_max_index - brw->sol.svbi_0_starting_index) / verts;
+      uint32_t primitives_written = MIN2 (space_avail, count);
+      brw->sol.svbi_0_starting_index += verts * primitives_written;
+
+      /* And update the TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN query. */
+      brw->sol.primitives_written += primitives_written;
+   }
+}
+
 /* May fail if out of video memory for texture or vbo upload, or on
  * fallback conditions.
  */
@@ -292,9 +446,9 @@ static bool brw_try_draw_prims( struct gl_context *ctx,
 {
    struct intel_context *intel = intel_context(ctx);
    struct brw_context *brw = brw_context(ctx);
-   bool retval = false;
-   bool warn = false;
+   bool retval = true;
    GLuint i;
+   bool fail_next = false;
 
    if (ctx->NewState)
       _mesa_update_state( ctx );
@@ -308,6 +462,11 @@ static bool brw_try_draw_prims( struct gl_context *ctx,
     */
    brw_validate_textures( brw );
 
+   /* Resolves must occur after updating state and finalizing textures but
+    * before setting up any hardware state for this draw call.
+    */
+   brw_predraw_resolve_buffers(brw);
+
    /* Bind all inputs, derive varying and size information:
     */
    brw_merge_inputs( brw, arrays );
@@ -344,44 +503,28 @@ static bool brw_try_draw_prims( struct gl_context *ctx,
        * primitives.
        */
       intel_batchbuffer_require_space(intel, estimated_max_prim_size, false);
+      intel_batchbuffer_save_state(intel);
 
       if (intel->gen < 6)
         brw_set_prim(brw, &prim[i]);
       else
         gen6_set_prim(brw, &prim[i]);
 
+retry:
+      /* Note that before the loop, brw->state.dirty.brw was set to != 0, and
+       * that the state updated in the loop outside of this block is that in
+       * *_set_prim or intel_batchbuffer_flush(), which only impacts
+       * brw->state.dirty.brw.
+       */
       if (brw->state.dirty.brw) {
-        brw_validate_state(brw);
+        intel->no_batch_wrap = true;
+        brw_upload_state(brw);
 
-        /* Various fallback checks:  */
-        if (brw->intel.Fallback)
+        if (unlikely(brw->intel.Fallback)) {
+           intel->no_batch_wrap = false;
+           retval = false;
            goto out;
-
-        /* Check that we can fit our state in with our existing batchbuffer, or
-         * flush otherwise.
-         */
-        if (dri_bufmgr_check_aperture_space(brw->state.validated_bos,
-                                            brw->state.validated_bo_count)) {
-           static bool warned;
-           intel_batchbuffer_flush(intel);
-
-           /* Validate the state after we flushed the batch (which would have
-            * changed the set of dirty state).  If we still fail to
-            * check_aperture, warn of what's happening, but attempt to continue
-            * on since it may succeed anyway, and the user would probably rather
-            * see a failure and a warning than a fallback.
-            */
-           brw_validate_state(brw);
-           if (!warned &&
-               dri_bufmgr_check_aperture_space(brw->state.validated_bos,
-                                               brw->state.validated_bo_count)) {
-              warn = true;
-              warned = true;
-           }
         }
-
-        intel->no_batch_wrap = true;
-        brw_upload_state(brw);
       }
 
       if (intel->gen >= 7)
@@ -391,7 +534,29 @@ static bool brw_try_draw_prims( struct gl_context *ctx,
 
       intel->no_batch_wrap = false;
 
-      retval = true;
+      if (dri_bufmgr_check_aperture_space(&intel->batch.bo, 1)) {
+        if (!fail_next) {
+           intel_batchbuffer_reset_to_saved(intel);
+           intel_batchbuffer_flush(intel);
+           fail_next = true;
+           goto retry;
+        } else {
+           if (intel_batchbuffer_flush(intel) == -ENOSPC) {
+              static bool warned = false;
+
+              if (!warned) {
+                 fprintf(stderr, "i965: Single primitive emit exceeded"
+                         "available aperture space\n");
+                 warned = true;
+              }
+
+              retval = false;
+           }
+        }
+      }
+
+      if (!_mesa_meta_in_progress(ctx))
+         brw_update_primitive_count(brw, &prim[i]);
    }
 
    if (intel->always_flush_batch)
@@ -399,13 +564,7 @@ static bool brw_try_draw_prims( struct gl_context *ctx,
  out:
 
    brw_state_cache_check_size(brw);
-
-   if (warn)
-      fprintf(stderr, "i965: Single primitive emit potentially exceeded "
-             "available aperture space\n");
-
-   if (!retval)
-      DBG("%s failed\n", __FUNCTION__);
+   brw_postdraw_set_buffers_need_resolve(brw);
 
    return retval;
 }
@@ -417,7 +576,8 @@ void brw_draw_prims( struct gl_context *ctx,
                     const struct _mesa_index_buffer *ib,
                     GLboolean index_bounds_valid,
                     GLuint min_index,
-                    GLuint max_index )
+                    GLuint max_index,
+                    struct gl_transform_feedback_object *tfb_vertcount )
 {
    bool retval;