iris: Support rebinding of stream output targets
authorKenneth Graunke <kenneth@whitecape.org>
Wed, 3 Feb 2021 02:42:41 +0000 (18:42 -0800)
committerKenneth Graunke <kenneth@whitecape.org>
Thu, 4 Mar 2021 21:59:21 +0000 (13:59 -0800)
This enables us to replace the backing storage of resources that have
been used as stream output targets, in case we're invalidating their
entire contents.  This can avoid stalls.  We simply hadn't supported it
because it was going to be tricky to re-emit 3DSTATE_SO_BUFFER without
screwing up "reset offset to zero" vs. "keep appending".  But that
should be working fine with the previous patch's refactor.

Reviewed-by: Zoltán Böszörményi <zboszor@gmail.com>
Reviewed-by: Ian Romanick <ian.d.romanick@intel.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/8964>

src/gallium/drivers/iris/iris_resource.c
src/gallium/drivers/iris/iris_state.c

index 177dc8a..7cf5ecc 100644 (file)
@@ -1359,10 +1359,6 @@ iris_invalidate_resource(struct pipe_context *ctx,
    if (res->bo->userptr)
       return;
 
-   // XXX: We should support this.
-   if (res->bind_history & PIPE_BIND_STREAM_OUTPUT)
-      return;
-
    struct iris_bo *old_bo = res->bo;
    struct iris_bo *new_bo =
       iris_bo_alloc(screen->bufmgr, res->bo->name, resource->width0,
index 00f0397..7bb7af7 100644 (file)
@@ -7204,8 +7204,24 @@ iris_rebind_buffer(struct iris_context *ice,
     */
 
    if (res->bind_history & PIPE_BIND_STREAM_OUTPUT) {
-      /* XXX: be careful about resetting vs appending... */
-      assert(false);
+      uint32_t *so_buffers = genx->so_buffers;
+      for (unsigned i = 0; i < 4; i++,
+           so_buffers += GENX(3DSTATE_SO_BUFFER_length)) {
+
+         /* There are no other fields in bits 127:64 */
+         uint64_t *addr = (uint64_t *) &so_buffers[2];
+         STATIC_ASSERT(GENX(3DSTATE_SO_BUFFER_SurfaceBaseAddress_start) == 66);
+         STATIC_ASSERT(GENX(3DSTATE_SO_BUFFER_SurfaceBaseAddress_bits) == 46);
+
+         struct pipe_stream_output_target *tgt = ice->state.so_target[i];
+         if (tgt) {
+            struct iris_bo *bo = iris_resource_bo(tgt->buffer);
+            if (*addr != bo->gtt_offset + tgt->buffer_offset) {
+               *addr = bo->gtt_offset + tgt->buffer_offset;
+               ice->state.dirty |= IRIS_DIRTY_SO_BUFFERS;
+            }
+         }
+      }
    }
 
    for (int s = MESA_SHADER_VERTEX; s < MESA_SHADER_STAGES; s++) {