iris: chaining not growing
authorKenneth Graunke <kenneth@whitecape.org>
Thu, 3 May 2018 02:54:23 +0000 (19:54 -0700)
committerKenneth Graunke <kenneth@whitecape.org>
Thu, 21 Feb 2019 18:26:06 +0000 (10:26 -0800)
src/gallium/drivers/iris/iris_batch.c
src/gallium/drivers/iris/iris_batch.h
src/gallium/drivers/iris/iris_blorp.c
src/gallium/drivers/iris/iris_draw.c

index 12aea86e9e47d24adbffad5c0dec75582059cb88..fc9b726c5de74b2bf2599848b6bfb8e956e3ca4b 100644 (file)
 
 #define FILE_DEBUG_FLAG DEBUG_BUFMGR
 
-/**
- * Target sizes of the batch and state buffers.  We create the initial
- * buffers at these sizes, and flush when they're nearly full.  If we
- * underestimate how close we are to the end, and suddenly need more space
- * in the middle of a draw, we can grow the buffers, and finish the draw.
- * At that point, we'll be over our target size, so the next operation
- * should flush.  Each time we flush the batch, we recreate both buffers
- * at the original target size, so it doesn't grow without bound.
- */
 #define BATCH_SZ (20 * 1024)
-#define STATE_SZ (18 * 1024)
+
+/* Terminating the batch takes either 4 bytes for MI_BATCH_BUFFER_END
+ * or 12 bytes for MI_BATCH_BUFFER_START (when chaining).  Plus, we may
+ * need an extra 4 bytes to pad out to the nearest QWord.  So reserve 16.
+ */
+#define BATCH_RESERVED 16
 
 static void decode_batch(struct iris_batch *batch);
 
@@ -109,17 +105,6 @@ uint_key_hash(const void *key)
    return (uintptr_t) key;
 }
 
-static void
-create_batch_buffer(struct iris_bufmgr *bufmgr,
-                    struct iris_batch_buffer *buf,
-                    const char *name, unsigned size)
-{
-   buf->bo = iris_bo_alloc(bufmgr, name, size, IRIS_MEMZONE_OTHER);
-   buf->bo->kflags |= EXEC_OBJECT_CAPTURE;
-   buf->map = iris_bo_map(NULL, buf->bo, MAP_READ | MAP_WRITE);
-   buf->map_next = buf->map;
-}
-
 void
 iris_init_batch(struct iris_batch *batch,
                 struct iris_screen *screen,
@@ -208,21 +193,32 @@ add_exec_bo(struct iris_batch *batch, struct iris_bo *bo)
 }
 
 static void
-iris_batch_reset(struct iris_batch *batch)
+create_batch(struct iris_batch *batch)
 {
    struct iris_screen *screen = batch->screen;
    struct iris_bufmgr *bufmgr = screen->bufmgr;
 
-   if (batch->last_cmd_bo != NULL) {
-      iris_bo_unreference(batch->last_cmd_bo);
-      batch->last_cmd_bo = NULL;
-   }
-   batch->last_cmd_bo = batch->cmdbuf.bo;
+   batch->bo = iris_bo_alloc(bufmgr, "command buffer",
+                             BATCH_SZ + BATCH_RESERVED, IRIS_MEMZONE_OTHER);
+   batch->bo->kflags |= EXEC_OBJECT_CAPTURE;
+   batch->map = iris_bo_map(NULL, batch->bo, MAP_READ | MAP_WRITE);
+   batch->map_next = batch->map;
 
-   create_batch_buffer(bufmgr, &batch->cmdbuf, "command buffer", BATCH_SZ);
+   add_exec_bo(batch, batch->bo);
+}
 
-   add_exec_bo(batch, batch->cmdbuf.bo);
-   assert(batch->cmdbuf.bo->index == 0);
+static void
+iris_batch_reset(struct iris_batch *batch)
+{
+   if (batch->last_bo != NULL) {
+      iris_bo_unreference(batch->last_bo);
+      batch->last_bo = NULL;
+   }
+   batch->last_bo = batch->bo;
+   batch->primary_batch_size = 0;
+
+   create_batch(batch);
+   assert(batch->bo->index == 0);
 
    if (batch->state_sizes)
       _mesa_hash_table_clear(batch->state_sizes, NULL);
@@ -230,15 +226,6 @@ iris_batch_reset(struct iris_batch *batch)
    iris_cache_sets_clear(batch);
 }
 
-static void
-free_batch_buffer(struct iris_batch_buffer *buf)
-{
-   iris_bo_unreference(buf->bo);
-   buf->bo = NULL;
-   buf->map = NULL;
-   buf->map_next = NULL;
-}
-
 void
 iris_batch_free(struct iris_batch *batch)
 {
@@ -247,9 +234,12 @@ iris_batch_free(struct iris_batch *batch)
    }
    free(batch->exec_bos);
    free(batch->validation_list);
-   free_batch_buffer(&batch->cmdbuf);
+   iris_bo_unreference(batch->bo);
+   batch->bo = NULL;
+   batch->map = NULL;
+   batch->map_next = NULL;
 
-   iris_bo_unreference(batch->last_cmd_bo);
+   iris_bo_unreference(batch->last_bo);
 
    _mesa_hash_table_destroy(batch->cache.render, NULL);
    _mesa_set_destroy(batch->cache.depth, NULL);
@@ -261,41 +251,51 @@ iris_batch_free(struct iris_batch *batch)
 }
 
 static unsigned
-buffer_bytes_used(struct iris_batch_buffer *buf)
+batch_bytes_used(struct iris_batch *batch)
 {
-   return buf->map_next - buf->map;
+   return batch->map_next - batch->map;
 }
 
-static void
-require_buffer_space(struct iris_batch *batch,
-                     struct iris_batch_buffer *buf,
-                     unsigned size,
-                     unsigned flush_threshold,
-                     unsigned max_buffer_size)
+/**
+ * If we've chained to a secondary batch, or are getting near to the end,
+ * then flush.  This should only be called between draws.
+ */
+void
+iris_batch_maybe_flush(struct iris_batch *batch, unsigned estimate)
 {
-   const unsigned required_bytes = buffer_bytes_used(buf) + size;
-
-   if (!batch->no_wrap && required_bytes >= flush_threshold) {
+   if (batch->bo != batch->exec_bos[0] ||
+       batch_bytes_used(batch) + estimate >= BATCH_SZ) {
       iris_batch_flush(batch);
-   } else if (required_bytes >= buf->bo->size) {
-      assert(!"Can't grow");
    }
 }
 
-
 void
 iris_require_command_space(struct iris_batch *batch, unsigned size)
 {
-   require_buffer_space(batch, &batch->cmdbuf, size, BATCH_SZ, MAX_BATCH_SIZE);
+   const unsigned required_bytes = batch_bytes_used(batch) + size;
+
+   if (required_bytes >= BATCH_SZ) {
+      /* No longer held by batch->bo, still held by validation list */
+      iris_bo_unreference(batch->bo);
+      batch->primary_batch_size = batch_bytes_used(batch);
+
+      const uint32_t MI_BATCH_BUFFER_START = (0x31 << 23) | (1 << 8);
+
+      uint32_t *cmd  = batch->map += sizeof(uint32_t);
+      uint64_t *addr = batch->map += sizeof(uint64_t);
+
+      create_batch(batch);
+
+      *cmd = MI_BATCH_BUFFER_START;
+      *addr = batch->bo->gtt_offset;
+   }
 }
 
 void *
 iris_get_command_space(struct iris_batch *batch, unsigned bytes)
 {
    iris_require_command_space(batch, bytes);
-   void *map = batch->cmdbuf.map_next;
-   batch->cmdbuf.map_next += bytes;
-   return map;
+   return batch->map_next += bytes;
 }
 
 void
@@ -315,8 +315,6 @@ iris_batch_emit(struct iris_batch *batch, const void *data, unsigned size)
 static void
 iris_finish_batch(struct iris_batch *batch)
 {
-   batch->no_wrap = true;
-
    // XXX: ISP DIS
 
    /* Emit MI_BATCH_BUFFER_END to finish our batch.  Note that execbuf2
@@ -324,16 +322,14 @@ iris_finish_batch(struct iris_batch *batch)
     * necessary by emitting an extra MI_NOOP after the end.
     */
    const uint32_t MI_BATCH_BUFFER_END_AND_NOOP[2]  = { (0xA << 23), 0 };
-   const bool qword_aligned = (buffer_bytes_used(&batch->cmdbuf) % 8) == 0;
+   const bool qword_aligned = (batch_bytes_used(batch) % 8) == 0;
    iris_batch_emit(batch, MI_BATCH_BUFFER_END_AND_NOOP, qword_aligned ? 8 : 4);
-
-   batch->no_wrap = false;
 }
 
 static int
 submit_batch(struct iris_batch *batch, int in_fence_fd, int *out_fence_fd)
 {
-   iris_bo_unmap(batch->cmdbuf.bo);
+   iris_bo_unmap(batch->bo);
 
    /* The requirement for using I915_EXEC_NO_RELOC are:
     *
@@ -351,7 +347,8 @@ submit_batch(struct iris_batch *batch, int in_fence_fd, int *out_fence_fd)
       .buffers_ptr = (uintptr_t) batch->validation_list,
       .buffer_count = batch->exec_count,
       .batch_start_offset = 0,
-      .batch_len = buffer_bytes_used(&batch->cmdbuf),
+      .batch_len = batch->bo == batch->exec_bos[0] ? batch_bytes_used(batch)
+                                                   : batch->primary_batch_size,
       .flags = batch->ring |
                I915_EXEC_NO_RELOC |
                I915_EXEC_BATCH_FIRST |
@@ -405,16 +402,15 @@ _iris_batch_flush_fence(struct iris_batch *batch,
                         int in_fence_fd, int *out_fence_fd,
                         const char *file, int line)
 {
-   if (buffer_bytes_used(&batch->cmdbuf) == 0)
+   if (batch_bytes_used(batch) == 0)
       return 0;
 
-   /* Check that we didn't just wrap our batchbuffer at a bad time. */
-   assert(!batch->no_wrap);
-
    iris_finish_batch(batch);
 
    if (unlikely(INTEL_DEBUG & (DEBUG_BATCH | DEBUG_SUBMIT))) {
-      int bytes_for_commands = buffer_bytes_used(&batch->cmdbuf);
+      int bytes_for_commands = batch_bytes_used(batch);
+      if (batch->bo != batch->exec_bos[0])
+         bytes_for_commands += batch->primary_batch_size;
       fprintf(stderr, "%19s:%-3d: Batchbuffer flush with %5db (%0.1f%%), "
               "%4d BOs (%0.1fMb aperture)\n",
               file, line,
@@ -424,8 +420,9 @@ _iris_batch_flush_fence(struct iris_batch *batch,
       dump_validation_list(batch);
    }
 
-   if (unlikely(INTEL_DEBUG & DEBUG_BATCH))
+   if (unlikely(INTEL_DEBUG & DEBUG_BATCH)) {
       decode_batch(batch);
+   }
 
    int ret = submit_batch(batch, in_fence_fd, out_fence_fd);
 
@@ -439,7 +436,7 @@ _iris_batch_flush_fence(struct iris_batch *batch,
 
    if (unlikely(INTEL_DEBUG & DEBUG_SYNC)) {
       dbg_printf("waiting for idle\n");
-      iris_bo_wait_rendering(batch->cmdbuf.bo);
+      iris_bo_wait_rendering(batch->bo);
    }
 
    /* Clean up after the batch we submitted and prepare for a new one. */
@@ -486,7 +483,12 @@ iris_use_pinned_bo(struct iris_batch *batch,
 static void
 decode_batch(struct iris_batch *batch)
 {
-   gen_print_batch(&batch->decoder, batch->cmdbuf.map,
-                   buffer_bytes_used(&batch->cmdbuf),
-                   batch->cmdbuf.bo->gtt_offset);
+   if (batch->bo != batch->exec_bos[0]) {
+      void *map = iris_bo_map(batch->dbg, batch->exec_bos[0], MAP_READ);
+      gen_print_batch(&batch->decoder, map, batch->primary_batch_size,
+                      batch->exec_bos[0]->gtt_offset);
+   }
+
+   gen_print_batch(&batch->decoder, batch->map, batch_bytes_used(batch),
+                   batch->bo->gtt_offset);
 }
index a5bdb06e7e21fbd5aa2ff61bdb23f3ad0ba634e0..13525a4d4dd4bd0164e46776426a9d83e6078423 100644 (file)
@@ -38,30 +38,27 @@ struct iris_address {
    bool write;
 };
 
-struct iris_batch_buffer {
-   struct iris_bo *bo;
-   void *map;
-   void *map_next;
-};
-
 struct iris_batch {
    struct iris_screen *screen;
    struct iris_vtable *vtbl;
    struct pipe_debug_callback *dbg;
 
    /** Current batchbuffer being queued up. */
-   struct iris_batch_buffer cmdbuf;
+   struct iris_bo *bo;
+   void *map;
+   void *map_next;
+   /** Size of the primary batch if we've moved on to a secondary. */
+   unsigned primary_batch_size;
+
 
    /** Last BO submitted to the hardware.  Used for glFinish(). */
-   struct iris_bo *last_cmd_bo;
+   struct iris_bo *last_bo;
 
    uint32_t hw_ctx_id;
 
    /** Which ring this batch targets - a I915_EXEC_RING_MASK value */
    uint8_t ring;
 
-   bool no_wrap;
-
    /** The validation list */
    struct drm_i915_gem_exec_object2 *validation_list;
    struct iris_bo **exec_bos;
@@ -101,6 +98,7 @@ void iris_init_batch(struct iris_batch *batch,
                      struct pipe_debug_callback *dbg,
                      uint8_t ring);
 void iris_batch_free(struct iris_batch *batch);
+void iris_batch_maybe_flush(struct iris_batch *batch, unsigned estimate);
 void iris_require_command_space(struct iris_batch *batch, unsigned size);
 void *iris_get_command_space(struct iris_batch *batch, unsigned bytes);
 void iris_batch_emit(struct iris_batch *batch, const void *data, unsigned size);
index 6b75d5f1eb8378084d563394cc701503762560dd..06ba830de75fd0036ede1c9daff751ee93795b20 100644 (file)
@@ -274,8 +274,6 @@ iris_blorp_exec(struct blorp_batch *blorp_batch,
       iris_cache_flush_for_depth(batch, params->stencil.addr.buffer);
 
    iris_require_command_space(batch, 1400);
-   //iris_require_statebuffer_space(ice, 600); // XXX: THIS.  Need this.
-   batch->no_wrap = true;
 
    // XXX: Emit L3 state
 
@@ -287,8 +285,6 @@ iris_blorp_exec(struct blorp_batch *blorp_batch,
 
    blorp_exec(blorp_batch, params);
 
-   batch->no_wrap = false;
-
    // XXX: aperture checks?
 
    /* We've smashed all state compared to what the normal 3D pipeline
index ccb55164387d6d376fbc74009b1c150881016e44..df95e0300146ef6e803e038cdedd0935e43c19c8 100644 (file)
@@ -35,21 +35,24 @@ void
 iris_draw_vbo(struct pipe_context *ctx, const struct pipe_draw_info *info)
 {
    struct iris_context *ice = (struct iris_context *) ctx;
+   struct iris_batch *batch = &ice->render_batch;
+
+   iris_batch_maybe_flush(batch, 1500);
 
    // XXX: actually do brw_cache_flush_for_*
-   iris_emit_pipe_control_flush(&ice->render_batch,
+   iris_emit_pipe_control_flush(batch,
                                 PIPE_CONTROL_DEPTH_CACHE_FLUSH |
                                 PIPE_CONTROL_RENDER_TARGET_FLUSH |
                                 PIPE_CONTROL_CS_STALL);
 
-   iris_emit_pipe_control_flush(&ice->render_batch,
+   iris_emit_pipe_control_flush(batch,
                                 PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE |
                                 PIPE_CONTROL_CONST_CACHE_INVALIDATE);
 
-   iris_cache_sets_clear(&ice->render_batch);
+   iris_cache_sets_clear(batch);
    // XXX: ^^^
 
 
    iris_update_compiled_shaders(ice);
-   ice->vtbl.upload_render_state(ice, &ice->render_batch, info);
+   ice->vtbl.upload_render_state(ice, batch, info);
 }