gallium/u_blitter: implement buffer clearing
authorMarek Olšák <maraeo@gmail.com>
Sun, 21 Apr 2013 17:39:03 +0000 (19:39 +0200)
committerMarek Olšák <maraeo@gmail.com>
Tue, 23 Apr 2013 18:26:20 +0000 (20:26 +0200)
Although this might be useful for ARB_clear_buffer_object,
I need it for initializating resources in r600g.

Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: Brian Paul <brianp@vmware.com>
v2: comment cleanups

NOTE: This is a candidate for the 9.1 branch.

src/gallium/auxiliary/util/u_blitter.c
src/gallium/auxiliary/util/u_blitter.h

index 2a4a13e9ff46796ef9430568b5f96dd0212a64b6..85e1e979120a609b38bcae934fbc498b0f588162 100644 (file)
@@ -100,7 +100,7 @@ struct blitter_context_priv
    void *velem_state;
    void *velem_uint_state;
    void *velem_sint_state;
-   void *velem_state_readbuf;
+   void *velem_state_readbuf[4]; /**< X, XY, XYZ, XYZW */
 
    /* Sampler state. */
    void *sampler_state;
@@ -285,9 +285,19 @@ struct blitter_context *util_blitter_create(struct pipe_context *pipe)
    }
 
    if (ctx->has_stream_out) {
-      velem[0].src_format = PIPE_FORMAT_R32_UINT;
-      velem[0].vertex_buffer_index = ctx->base.vb_slot;
-      ctx->velem_state_readbuf = pipe->create_vertex_elements_state(pipe, 1, &velem[0]);
+      static enum pipe_format formats[4] = {
+         PIPE_FORMAT_R32_UINT,
+         PIPE_FORMAT_R32G32_UINT,
+         PIPE_FORMAT_R32G32B32_UINT,
+         PIPE_FORMAT_R32G32B32A32_UINT
+      };
+
+      for (i = 0; i < 4; i++) {
+         velem[0].src_format = formats[i];
+         velem[0].vertex_buffer_index = ctx->base.vb_slot;
+         ctx->velem_state_readbuf[i] =
+               pipe->create_vertex_elements_state(pipe, 1, &velem[0]);
+      }
    }
 
    /* fragment shaders are created on-demand */
@@ -352,8 +362,11 @@ void util_blitter_destroy(struct blitter_context *blitter)
       pipe->delete_vertex_elements_state(pipe, ctx->velem_sint_state);
       pipe->delete_vertex_elements_state(pipe, ctx->velem_uint_state);
    }
-   if (ctx->velem_state_readbuf)
-      pipe->delete_vertex_elements_state(pipe, ctx->velem_state_readbuf);
+   for (i = 0; i < 4; i++) {
+      if (ctx->velem_state_readbuf[i]) {
+         pipe->delete_vertex_elements_state(pipe, ctx->velem_state_readbuf[i]);
+      }
+   }
 
    for (i = 0; i < PIPE_MAX_TEXTURE_TYPES; i++) {
       if (ctx->fs_texfetch_col[i])
@@ -1739,7 +1752,7 @@ void util_blitter_copy_buffer(struct blitter_context *blitter,
    vb.stride = 4;
 
    pipe->set_vertex_buffers(pipe, ctx->base.vb_slot, 1, &vb);
-   pipe->bind_vertex_elements_state(pipe, ctx->velem_state_readbuf);
+   pipe->bind_vertex_elements_state(pipe, ctx->velem_state_readbuf[0]);
    pipe->bind_vs_state(pipe, ctx->vs_pos_only);
    if (ctx->has_geometry_shader)
       pipe->bind_gs_state(pipe, NULL);
@@ -1756,6 +1769,66 @@ void util_blitter_copy_buffer(struct blitter_context *blitter,
    pipe_so_target_reference(&so_target, NULL);
 }
 
+void util_blitter_clear_buffer(struct blitter_context *blitter,
+                               struct pipe_resource *dst,
+                               unsigned offset, unsigned size,
+                               unsigned num_channels,
+                               const union pipe_color_union *clear_value)
+{
+   struct blitter_context_priv *ctx = (struct blitter_context_priv*)blitter;
+   struct pipe_context *pipe = ctx->base.pipe;
+   struct pipe_vertex_buffer vb = {0};
+   struct pipe_stream_output_target *so_target;
+
+   assert(num_channels >= 1);
+   assert(num_channels <= 4);
+
+   /* IMPORTANT:  DON'T DO ANY BOUNDS CHECKING HERE!
+    *
+    * R600 uses this to initialize texture resources, so width0 might not be
+    * what you think it is.
+    */
+
+   /* Streamout is required. */
+   if (!ctx->has_stream_out) {
+      assert(!"Streamout unsupported in util_blitter_clear_buffer()");
+      return;
+   }
+
+   /* Some alignment is required. */
+   if (offset % 4 != 0 || size % 4 != 0) {
+      assert(!"Bad alignment in util_blitter_clear_buffer()");
+      return;
+   }
+
+   u_upload_data(ctx->upload, 0, num_channels*4, clear_value,
+                 &vb.buffer_offset, &vb.buffer);
+   vb.stride = 0;
+
+   blitter_set_running_flag(ctx);
+   blitter_check_saved_vertex_states(ctx);
+   blitter_disable_render_cond(ctx);
+
+   pipe->set_vertex_buffers(pipe, ctx->base.vb_slot, 1, &vb);
+   pipe->bind_vertex_elements_state(pipe,
+                                    ctx->velem_state_readbuf[num_channels-1]);
+   pipe->bind_vs_state(pipe, ctx->vs_pos_only);
+   if (ctx->has_geometry_shader)
+      pipe->bind_gs_state(pipe, NULL);
+   pipe->bind_rasterizer_state(pipe, ctx->rs_discard_state);
+
+   so_target = pipe->create_stream_output_target(pipe, dst, offset, size);
+   pipe->set_stream_output_targets(pipe, 1, &so_target, 0);
+
+   util_draw_arrays(pipe, PIPE_PRIM_POINTS, 0, size / 4);
+
+   blitter_restore_vertex_states(ctx);
+   blitter_restore_render_cond(ctx);
+   blitter_unset_running_flag(ctx);
+   pipe_so_target_reference(&so_target, NULL);
+   pipe_resource_reference(&vb.buffer, NULL);
+}
+
 /* probably radeon specific */
 void util_blitter_custom_resolve_color(struct blitter_context *blitter,
                                       struct pipe_resource *dst,
index 20e69ed5b73c7967d9629afd16f16a4d22ef4922..19015844ef706aad52e75081cdf95b460c5cf64a 100644 (file)
@@ -276,7 +276,7 @@ void util_blitter_default_src_texture(struct pipe_sampler_view *src_templ,
 
 /**
  * Copy data from one buffer to another using the Stream Output functionality.
- * Some alignment is required, otherwise software fallback is used.
+ * 4-byte alignment is required, otherwise software fallback is used.
  */
 void util_blitter_copy_buffer(struct blitter_context *blitter,
                               struct pipe_resource *dst,
@@ -285,6 +285,22 @@ void util_blitter_copy_buffer(struct blitter_context *blitter,
                               unsigned srcx,
                               unsigned size);
 
+/**
+ * Clear the contents of a buffer using the Stream Output functionality.
+ * 4-byte alignment is required.
+ *
+ * "num_channels" can be 1, 2, 3, or 4, and specifies if the clear value is
+ * R, RG, RGB, or RGBA.
+ *
+ * For each element, only "num_channels" components of "clear_value" are
+ * copied to the buffer, then the offset is incremented by num_channels*4.
+ */
+void util_blitter_clear_buffer(struct blitter_context *blitter,
+                               struct pipe_resource *dst,
+                               unsigned offset, unsigned size,
+                               unsigned num_channels,
+                               const union pipe_color_union *clear_value);
+
 /**
  * Clear a region of a (color) surface to a constant value.
  *