[2/3] renderer: Add support for TGSI_FILE_HW_ATOMIC

Submitted by Tomeu Vizoso on July 19, 2018, 1:41 p.m.

Details

Message ID 20180719134142.21407-3-tomeu.vizoso@collabora.com
State New
Series "TGSI_FILE_HW_ATOMIC support"
Headers show

Commit Message

Tomeu Vizoso July 19, 2018, 1:41 p.m.
Add support for TGSI's HW atomic counters, implemented here with
atomic_uint.

Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
---
 src/virgl_hw.h       |  2 ++
 src/virgl_protocol.h |  8 +++++++
 src/vrend_decode.c   | 29 ++++++++++++++++++++++
 src/vrend_renderer.c | 57 ++++++++++++++++++++++++++++++++++++++++++++
 src/vrend_renderer.h |  4 ++++
 5 files changed, 100 insertions(+)

Patch hide | download patch | download mbox

diff --git a/src/virgl_hw.h b/src/virgl_hw.h
index 1ca49c772fa1..c8deca90431a 100644
--- a/src/virgl_hw.h
+++ b/src/virgl_hw.h
@@ -320,6 +320,8 @@  struct virgl_caps_v2 {
         uint32_t max_compute_shared_memory_size;
         uint32_t max_ssbo;
         uint32_t max_images;
+        uint32_t max_atomic_counters;
+        uint32_t max_atomic_counter_buffers;
 };
 
 union virgl_caps {
diff --git a/src/virgl_protocol.h b/src/virgl_protocol.h
index 53a36588879e..8dc33ea734cf 100644
--- a/src/virgl_protocol.h
+++ b/src/virgl_protocol.h
@@ -87,6 +87,7 @@  enum virgl_context_cmd {
    VIRGL_CCMD_SET_MIN_SAMPLES,
    VIRGL_CCMD_SET_SHADER_IMAGES,
    VIRGL_CCMD_SET_SHADER_BUFFERS,
+   VIRGL_CCMD_SET_ATOMIC_BUFFERS,
    VIRGL_CCMD_MEMORY_BARRIER,
    VIRGL_CCMD_LAUNCH_GRID,
    VIRGL_CCMD_GET_QUERY_RESULT_QBO,
@@ -506,6 +507,13 @@  enum virgl_context_cmd {
 #define VIRGL_SET_SHADER_IMAGE_LEVEL_SIZE(x) ((x) * VIRGL_SET_SHADER_IMAGE_ELEMENT_SIZE + 5)
 #define VIRGL_SET_SHADER_IMAGE_RES_HANDLE(x) ((x) * VIRGL_SET_SHADER_IMAGE_ELEMENT_SIZE + 6)
 
+#define VIRGL_SET_ATOMIC_BUFFER_ELEMENT_SIZE 3
+#define VIRGL_SET_ATOMIC_BUFFER_SIZE(x) (VIRGL_SET_ATOMIC_BUFFER_ELEMENT_SIZE * (x)) + 1
+#define VIRGL_SET_ATOMIC_BUFFER_START_SLOT 1
+#define VIRGL_SET_ATOMIC_BUFFER_OFFSET(x) ((x) * VIRGL_SET_ATOMIC_BUFFER_ELEMENT_SIZE + 2)
+#define VIRGL_SET_ATOMIC_BUFFER_LENGTH(x) ((x) * VIRGL_SET_ATOMIC_BUFFER_ELEMENT_SIZE + 3)
+#define VIRGL_SET_ATOMIC_BUFFER_RES_HANDLE(x) ((x) * VIRGL_SET_ATOMIC_BUFFER_ELEMENT_SIZE + 4)
+
 #define VIRGL_MEMORY_BARRIER_FLAGS 1
 
 /* tess state */
diff --git a/src/vrend_decode.c b/src/vrend_decode.c
index bf2ee86550e3..e2f38a8b3620 100644
--- a/src/vrend_decode.c
+++ b/src/vrend_decode.c
@@ -1132,6 +1132,32 @@  static int vrend_decode_set_shader_buffers(struct vrend_decode_ctx *ctx, uint16_
    return 0;
 }
 
+static int vrend_decode_set_atomic_buffers(struct vrend_decode_ctx *ctx, uint16_t length)
+{
+   int num_abo;
+   uint32_t start_slot;
+
+   if (length < 2)
+      return EINVAL;
+
+   num_abo = (length - 2) / VIRGL_SET_ATOMIC_BUFFER_ELEMENT_SIZE;
+   start_slot = get_buf_entry(ctx, VIRGL_SET_ATOMIC_BUFFER_START_SLOT);
+   if (num_abo < 1)
+      return 0;
+
+   if (start_slot + num_abo > PIPE_MAX_HW_ATOMIC_BUFFERS)
+      return EINVAL;
+
+   for (int i = 0; i < num_abo; i++) {
+      uint32_t offset = get_buf_entry(ctx, i * VIRGL_SET_ATOMIC_BUFFER_ELEMENT_SIZE + 2);
+      uint32_t buf_len = get_buf_entry(ctx, i * VIRGL_SET_ATOMIC_BUFFER_ELEMENT_SIZE + 3);
+      uint32_t handle = get_buf_entry(ctx, i * VIRGL_SET_ATOMIC_BUFFER_ELEMENT_SIZE + 4);
+      vrend_set_single_abo(ctx->grctx, start_slot + i, offset, buf_len, handle);
+   }
+
+   return 0;
+}
+
 static int vrend_decode_set_shader_images(struct vrend_decode_ctx *ctx, uint16_t length)
 {
    int num_images;
@@ -1429,6 +1455,9 @@  int vrend_decode_block(uint32_t ctx_id, uint32_t *block, int ndw)
       case VIRGL_CCMD_SET_SHADER_BUFFERS:
          ret = vrend_decode_set_shader_buffers(gdctx, len);
          break;
+      case VIRGL_CCMD_SET_ATOMIC_BUFFERS:
+         ret = vrend_decode_set_atomic_buffers(gdctx, len);
+         break;
       case VIRGL_CCMD_MEMORY_BARRIER:
          ret = vrend_decode_memory_barrier(gdctx, len);
          break;
diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c
index f143f1acde51..0afa60993dae 100644
--- a/src/vrend_renderer.c
+++ b/src/vrend_renderer.c
@@ -275,6 +275,12 @@  struct vrend_ssbo {
    unsigned buffer_offset;
 };
 
+struct vrend_abo {
+   struct vrend_resource *res;
+   unsigned buffer_size;
+   unsigned buffer_offset;
+};
+
 struct vrend_vertex_element {
    struct pipe_vertex_element base;
    GLenum type;
@@ -421,6 +427,9 @@  struct vrend_sub_context {
 
    struct vrend_ssbo ssbo[PIPE_SHADER_TYPES][PIPE_MAX_SHADER_BUFFERS];
    uint32_t ssbo_used_mask[PIPE_SHADER_TYPES];
+
+   struct vrend_abo abo[PIPE_MAX_HW_ATOMIC_BUFFERS];
+   uint32_t abo_used_mask;
 };
 
 struct vrend_context {
@@ -2469,6 +2478,31 @@  void vrend_set_num_ssbo(struct vrend_context *ctx,
 
 }
 
+void vrend_set_single_abo(struct vrend_context *ctx,
+			  int index,
+			  uint32_t offset, uint32_t length,
+			  uint32_t handle)
+{
+   struct vrend_abo *abo = &ctx->sub->abo[index];
+   struct vrend_resource *res;
+   if (handle) {
+      res = vrend_renderer_ctx_res_lookup(ctx, handle);
+      if (!res) {
+         report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE, handle);
+         return;
+      }
+      abo->res = res;
+      abo->buffer_offset = offset;
+      abo->buffer_size = length;
+      ctx->sub->abo_used_mask |= (1 << index);
+   } else {
+      abo->res = 0;
+      abo->buffer_offset = 0;
+      abo->buffer_size = 0;
+      ctx->sub->abo_used_mask &= ~(1 << index);
+   }
+}
+
 void vrend_memory_barrier(struct vrend_context *ctx,
 			  unsigned flags)
 {
@@ -3408,6 +3442,24 @@  static void vrend_draw_bind_ssbo_shader(struct vrend_context *ctx, int shader_ty
    }
 }
 
+static void vrend_draw_bind_abo_shader(struct vrend_context *ctx)
+{
+   uint32_t mask;
+   struct vrend_abo *abo;
+   struct vrend_resource *res;
+   int i;
+
+   mask = ctx->sub->abo_used_mask;
+   while (mask) {
+      i = u_bit_scan(&mask);
+
+      abo = &ctx->sub->abo[i];
+      res = (struct vrend_resource *)abo->res;
+      glBindBufferRange(GL_ATOMIC_COUNTER_BUFFER, i, res->id,
+                        abo->buffer_offset, abo->buffer_size);
+   }
+}
+
 static void vrend_draw_bind_images_shader(struct vrend_context *ctx, int shader_type)
 {
    struct vrend_image_view *iview;
@@ -3447,6 +3499,8 @@  static void vrend_draw_bind_objects(struct vrend_context *ctx, bool new_program)
       vrend_draw_bind_ssbo_shader(ctx, shader_type);
    }
 
+   vrend_draw_bind_abo_shader(ctx);
+
    if (vrend_state.use_core_profile && ctx->sub->prog->fs_stipple_loc != -1) {
       glActiveTexture(GL_TEXTURE0 + sampler_id);
       glBindTexture(GL_TEXTURE_2D, ctx->pstipple_tex_id);
@@ -3765,6 +3819,7 @@  void vrend_launch_grid(struct vrend_context *ctx,
    vrend_draw_bind_samplers_shader(ctx, PIPE_SHADER_COMPUTE, &sampler_id);
    vrend_draw_bind_images_shader(ctx, PIPE_SHADER_COMPUTE);
    vrend_draw_bind_ssbo_shader(ctx, PIPE_SHADER_COMPUTE);
+   vrend_draw_bind_abo_shader(ctx);
 
    if (indirect_handle) {
       indirect_res = vrend_renderer_ctx_res_lookup(ctx, indirect_handle);
@@ -8058,6 +8113,8 @@  void vrend_renderer_fill_caps(uint32_t set, uint32_t version,
       glGetIntegerv(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT, (GLint*)&caps->v2.texture_buffer_offset_alignment);
       glGetIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, (GLint*)&caps->v2.shader_buffer_offset_alignment);
       glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, (GLint*)&caps->v2.max_ssbo);
+      glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTERS, (GLint*)&caps->v2.max_atomic_counters);
+      glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, (GLint*)&caps->v2.max_atomic_counter_buffers);
       glGetIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, (GLint*)&caps->v2.max_images);
    }
 
diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h
index cadb9b6927d0..61d067fe8dc5 100644
--- a/src/vrend_renderer.h
+++ b/src/vrend_renderer.h
@@ -268,6 +268,10 @@  void vrend_set_num_ssbo(struct vrend_context *ctx,
 			uint32_t shader_type,
 			uint32_t start_slot,
 			uint32_t count);
+void vrend_set_single_abo(struct vrend_context *ctx,
+			   int index,
+			   uint32_t offset, uint32_t length,
+			   uint32_t handle);
 void vrend_memory_barrier(struct vrend_context *ctx,
 			  unsigned flags);
 void vrend_launch_grid(struct vrend_context *ctx,