virgl: add initial ARB_compute_shader support
authorDave Airlie <airlied@redhat.com>
Fri, 15 Jun 2018 01:20:53 +0000 (11:20 +1000)
committerDave Airlie <airlied@redhat.com>
Wed, 1 Aug 2018 04:00:31 +0000 (14:00 +1000)
This hooks up compute shader creation and launch grid support.

Reviewed-by: Gurchetan Singh <gurchetansingh@chromium.org>
src/gallium/drivers/virgl/virgl_context.c
src/gallium/drivers/virgl/virgl_encode.c
src/gallium/drivers/virgl/virgl_encode.h
src/gallium/drivers/virgl/virgl_hw.h
src/gallium/drivers/virgl/virgl_protocol.h
src/gallium/drivers/virgl/virgl_screen.c
src/gallium/drivers/virgl/virgl_winsys.h

index d224b68cfcd6e79529bf656236302bd7e73ad27b..ae1da337994116c4d42d93fa977870b2f966cfe5 100644 (file)
@@ -506,7 +506,7 @@ static void *virgl_shader_encoder(struct pipe_context *ctx,
    handle = virgl_object_assign_handle();
    /* encode VS state */
    ret = virgl_encode_shader_state(vctx, handle, type,
-                                   &shader->stream_output,
+                                   &shader->stream_output, 0,
                                    new_tokens);
    if (ret) {
       return NULL;
@@ -961,7 +961,7 @@ static void virgl_set_shader_buffers(struct pipe_context *ctx,
       pipe_resource_reference(&vctx->ssbos[shader][idx], NULL);
    }
 
-   uint32_t max_shader_buffer = shader == PIPE_SHADER_FRAGMENT ?
+   uint32_t max_shader_buffer = (shader == PIPE_SHADER_FRAGMENT || shader == PIPE_SHADER_COMPUTE) ?
       rs->caps.caps.v2.max_shader_buffer_frag_compute :
       rs->caps.caps.v2.max_shader_buffer_other_stages;
    if (!max_shader_buffer)
@@ -989,7 +989,7 @@ static void virgl_set_shader_images(struct pipe_context *ctx,
       pipe_resource_reference(&vctx->images[shader][idx], NULL);
    }
 
-   uint32_t max_shader_images = shader == PIPE_SHADER_FRAGMENT ?
+   uint32_t max_shader_images = (shader == PIPE_SHADER_FRAGMENT || shader == PIPE_SHADER_COMPUTE) ?
      rs->caps.caps.v2.max_shader_image_frag_compute :
      rs->caps.caps.v2.max_shader_image_other_stages;
    if (!max_shader_images)
@@ -1008,6 +1008,50 @@ static void virgl_memory_barrier(struct pipe_context *ctx,
    virgl_encode_memory_barrier(vctx, flags);
 }
 
+static void *virgl_create_compute_state(struct pipe_context *ctx,
+                                        const struct pipe_compute_state *state)
+{
+   struct virgl_context *vctx = virgl_context(ctx);
+   uint32_t handle;
+   const struct tgsi_token *new_tokens = state->prog;
+   struct pipe_stream_output_info so_info = {};
+   int ret;
+
+   handle = virgl_object_assign_handle();
+   ret = virgl_encode_shader_state(vctx, handle, PIPE_SHADER_COMPUTE,
+                                   &so_info,
+                                   state->req_local_mem,
+                                   new_tokens);
+   if (ret) {
+      return NULL;
+   }
+
+   return (void *)(unsigned long)handle;
+}
+
+static void virgl_bind_compute_state(struct pipe_context *ctx, void *state)
+{
+   uint32_t handle = (unsigned long)state;
+   struct virgl_context *vctx = virgl_context(ctx);
+
+   virgl_encode_bind_shader(vctx, handle, PIPE_SHADER_COMPUTE);
+}
+
+static void virgl_delete_compute_state(struct pipe_context *ctx, void *state)
+{
+   uint32_t handle = (unsigned long)state;
+   struct virgl_context *vctx = virgl_context(ctx);
+
+   virgl_encode_delete_object(vctx, handle, VIRGL_OBJECT_SHADER);
+}
+
+static void virgl_launch_grid(struct pipe_context *ctx,
+                              const struct pipe_grid_info *info)
+{
+   struct virgl_context *vctx = virgl_context(ctx);
+   virgl_encode_launch_grid(vctx, info);
+}
+
 static void
 virgl_context_destroy( struct pipe_context *ctx )
 {
@@ -1118,6 +1162,11 @@ struct pipe_context *virgl_context_create(struct pipe_screen *pscreen,
    vctx->base.delete_gs_state = virgl_delete_gs_state;
    vctx->base.delete_fs_state = virgl_delete_fs_state;
 
+   vctx->base.create_compute_state = virgl_create_compute_state;
+   vctx->base.bind_compute_state = virgl_bind_compute_state;
+   vctx->base.delete_compute_state = virgl_delete_compute_state;
+   vctx->base.launch_grid = virgl_launch_grid;
+
    vctx->base.clear = virgl_clear;
    vctx->base.draw_vbo = virgl_draw_vbo;
    vctx->base.flush = virgl_flush_from_st;
index 1d193ae6c7f7aafe2bb7f0bf87c34a99df88f17b..0cb5184d1933b54020274709b50e7680599f608f 100644 (file)
@@ -241,6 +241,7 @@ int virgl_encode_shader_state(struct virgl_context *ctx,
                               uint32_t handle,
                               uint32_t type,
                               const struct pipe_stream_output_info *so_info,
+                              uint32_t cs_req_local_mem,
                               const struct tgsi_token *tokens)
 {
    char *str, *sptr;
@@ -298,7 +299,10 @@ int virgl_encode_shader_state(struct virgl_context *ctx,
 
       virgl_emit_shader_header(ctx, handle, len, type, offlen, num_tokens);
 
-      virgl_emit_shader_streamout(ctx, first_pass ? so_info : NULL);
+      if (type == PIPE_SHADER_COMPUTE)
+         virgl_encoder_write_dword(ctx->cbuf, cs_req_local_mem);
+      else
+         virgl_emit_shader_streamout(ctx, first_pass ? so_info : NULL);
 
       virgl_encoder_write_block(ctx->cbuf, (uint8_t *)sptr, length);
 
@@ -980,3 +984,22 @@ int virgl_encode_memory_barrier(struct virgl_context *ctx,
    virgl_encoder_write_dword(ctx->cbuf, flags);
    return 0;
 }
+
+int virgl_encode_launch_grid(struct virgl_context *ctx,
+                             const struct pipe_grid_info *grid_info)
+{
+   virgl_encoder_write_cmd_dword(ctx, VIRGL_CMD0(VIRGL_CCMD_LAUNCH_GRID, 0, VIRGL_LAUNCH_GRID_SIZE));
+   virgl_encoder_write_dword(ctx->cbuf, grid_info->block[0]);
+   virgl_encoder_write_dword(ctx->cbuf, grid_info->block[1]);
+   virgl_encoder_write_dword(ctx->cbuf, grid_info->block[2]);
+   virgl_encoder_write_dword(ctx->cbuf, grid_info->grid[0]);
+   virgl_encoder_write_dword(ctx->cbuf, grid_info->grid[1]);
+   virgl_encoder_write_dword(ctx->cbuf, grid_info->grid[2]);
+   if (grid_info->indirect) {
+      struct virgl_resource *res = virgl_resource(grid_info->indirect);
+      virgl_encoder_write_res(ctx, res);
+   } else
+      virgl_encoder_write_dword(ctx->cbuf, 0);
+   virgl_encoder_write_dword(ctx->cbuf, grid_info->indirect_offset);
+   return 0;
+}
index e353c3d04d51031cb8689da8eaf90e1815f67173..c982eb954f367942168385f6e90426fd9627a862 100644 (file)
@@ -90,6 +90,7 @@ extern int virgl_encode_shader_state(struct virgl_context *ctx,
                                      uint32_t handle,
                                      uint32_t type,
                                      const struct pipe_stream_output_info *so_info,
+                                     uint32_t cs_req_local_mem,
                                      const struct tgsi_token *tokens);
 
 int virgl_encode_stream_output_info(struct virgl_context *ctx,
@@ -269,4 +270,6 @@ int virgl_encode_set_shader_images(struct virgl_context *ctx,
                                    const struct pipe_image_view *images);
 int virgl_encode_memory_barrier(struct virgl_context *ctx,
                                 unsigned flags);
+int virgl_encode_launch_grid(struct virgl_context *ctx,
+                             const struct pipe_grid_info *grid_info);
 #endif
index 6bb11f6598a21fef69ad4d0fb21511f1af631468..d58b347020b5777dc52e733dec4de35240e5b922 100644 (file)
@@ -206,6 +206,7 @@ enum virgl_formats {
 #define VIRGL_CAP_TGSI_PRECISE         (1 << 4)
 #define VIRGL_CAP_TXQS                 (1 << 5)
 #define VIRGL_CAP_MEMORY_BARRIER       (1 << 6)
+#define VIRGL_CAP_COMPUTE_SHADER       (1 << 7)
 
 #define VIRGL_BIND_DEPTH_STENCIL (1 << 0)
 #define VIRGL_BIND_RENDER_TARGET (1 << 1)
@@ -312,6 +313,10 @@ struct virgl_caps_v2 {
         uint32_t max_shader_image_frag_compute;
         uint32_t max_shader_image_other_stages;
         uint32_t max_image_samples;
+        uint32_t max_compute_work_group_invocations;
+        uint32_t max_compute_shared_memory_size;
+        uint32_t max_compute_grid_size[3];
+        uint32_t max_compute_block_size[3];
 };
 
 union virgl_caps {
index 0c38b1fc2edbe88facb99e033bf46330ee9a394c..b94b7528c0c7426fe51cfb7e171267830e1f024e 100644 (file)
@@ -89,6 +89,7 @@ enum virgl_context_cmd {
    VIRGL_CCMD_SET_SHADER_BUFFERS,
    VIRGL_CCMD_SET_SHADER_IMAGES,
    VIRGL_CCMD_MEMORY_BARRIER,
+   VIRGL_CCMD_LAUNCH_GRID,
 };
 
 /*
@@ -518,4 +519,14 @@ enum virgl_context_cmd {
 #define VIRGL_MEMORY_BARRIER_SIZE 1
 #define VIRGL_MEMORY_BARRIER_FLAGS 1
 
+#define VIRGL_LAUNCH_GRID_SIZE 8
+#define VIRGL_LAUNCH_BLOCK_X 1
+#define VIRGL_LAUNCH_BLOCK_Y 2
+#define VIRGL_LAUNCH_BLOCK_Z 3
+#define VIRGL_LAUNCH_GRID_X 4
+#define VIRGL_LAUNCH_GRID_Y 5
+#define VIRGL_LAUNCH_GRID_Z 6
+#define VIRGL_LAUNCH_INDIRECT_HANDLE 7
+#define VIRGL_LAUNCH_INDIRECT_OFFSET 8
+
 #endif
index 1947c6e4880a4949354afea7b3d11844d453f407..a2fa2a4dd26039765a721565c8e9fb088e8abe32 100644 (file)
@@ -139,7 +139,7 @@ virgl_get_param(struct pipe_screen *screen, enum pipe_cap param)
    case PIPE_CAP_QUADS_FOLLOW_PROVOKING_VERTEX_CONVENTION:
       return 0;
    case PIPE_CAP_COMPUTE:
-      return 0;
+      return vscreen->caps.caps.v2.capability_bits & VIRGL_CAP_COMPUTE_SHADER;
    case PIPE_CAP_USER_VERTEX_BUFFERS:
       return 0;
    case PIPE_CAP_CONSTANT_BUFFER_OFFSET_ALIGNMENT:
@@ -328,6 +328,10 @@ virgl_get_shader_param(struct pipe_screen *screen,
        !vscreen->caps.caps.v1.bset.has_tessellation_shaders)
       return 0;
 
+   if (shader == PIPE_SHADER_COMPUTE &&
+       !(vscreen->caps.caps.v2.capability_bits & VIRGL_CAP_COMPUTE_SHADER))
+     return 0;
+
    switch(shader)
    {
    case PIPE_SHADER_FRAGMENT:
@@ -335,6 +339,7 @@ virgl_get_shader_param(struct pipe_screen *screen,
    case PIPE_SHADER_GEOMETRY:
    case PIPE_SHADER_TESS_CTRL:
    case PIPE_SHADER_TESS_EVAL:
+   case PIPE_SHADER_COMPUTE:
       switch (param) {
       case PIPE_SHADER_CAP_MAX_INSTRUCTIONS:
       case PIPE_SHADER_CAP_MAX_ALU_INSTRUCTIONS:
@@ -373,15 +378,17 @@ virgl_get_shader_param(struct pipe_screen *screen,
       case PIPE_SHADER_CAP_MAX_CONST_BUFFER_SIZE:
          return 4096 * sizeof(float[4]);
       case PIPE_SHADER_CAP_MAX_SHADER_BUFFERS:
-         if (shader == PIPE_SHADER_FRAGMENT)
+         if (shader == PIPE_SHADER_FRAGMENT || shader == PIPE_SHADER_COMPUTE)
             return vscreen->caps.caps.v2.max_shader_buffer_frag_compute;
          else
             return vscreen->caps.caps.v2.max_shader_buffer_other_stages;
       case PIPE_SHADER_CAP_MAX_SHADER_IMAGES:
-         if (shader == PIPE_SHADER_FRAGMENT)
+         if (shader == PIPE_SHADER_FRAGMENT || shader == PIPE_SHADER_COMPUTE)
             return vscreen->caps.caps.v2.max_shader_image_frag_compute;
          else
             return vscreen->caps.caps.v2.max_shader_image_other_stages;
+      case PIPE_SHADER_CAP_SUPPORTED_IRS:
+         return (1 << PIPE_SHADER_IR_TGSI);
       case PIPE_SHADER_CAP_LOWER_IF_THRESHOLD:
       case PIPE_SHADER_CAP_TGSI_SKIP_MERGE_REGISTERS:
       case PIPE_SHADER_CAP_INT64_ATOMICS:
@@ -426,6 +433,51 @@ virgl_get_paramf(struct pipe_screen *screen, enum pipe_capf param)
    return 0.0;
 }
 
+static int
+virgl_get_compute_param(struct pipe_screen *screen,
+                        enum pipe_shader_ir ir_type,
+                        enum pipe_compute_cap param,
+                        void *ret)
+{
+   struct virgl_screen *vscreen = virgl_screen(screen);
+   if (!(vscreen->caps.caps.v2.capability_bits & VIRGL_CAP_COMPUTE_SHADER))
+      return 0;
+   switch (param) {
+   case PIPE_COMPUTE_CAP_MAX_GRID_SIZE:
+      if (ret) {
+         uint64_t *grid_size = ret;
+         grid_size[0] = vscreen->caps.caps.v2.max_compute_grid_size[0];
+         grid_size[1] = vscreen->caps.caps.v2.max_compute_grid_size[1];
+         grid_size[2] = vscreen->caps.caps.v2.max_compute_grid_size[2];
+      }
+      return 3 * sizeof(uint64_t) ;
+   case PIPE_COMPUTE_CAP_MAX_BLOCK_SIZE:
+      if (ret) {
+         uint64_t *block_size = ret;
+         block_size[0] = vscreen->caps.caps.v2.max_compute_block_size[0];
+         block_size[1] = vscreen->caps.caps.v2.max_compute_block_size[1];
+         block_size[2] = vscreen->caps.caps.v2.max_compute_block_size[2];
+      }
+      return 3 * sizeof(uint64_t);
+   case PIPE_COMPUTE_CAP_MAX_THREADS_PER_BLOCK:
+      if (ret) {
+         uint64_t *max_threads_per_block = ret;
+         *max_threads_per_block = vscreen->caps.caps.v2.max_compute_work_group_invocations;
+      }
+      return sizeof(uint64_t);
+   case PIPE_COMPUTE_CAP_MAX_LOCAL_SIZE:
+      if (ret) {
+         uint64_t *max_local_size = ret;
+         /* Value reported by the closed source driver. */
+         *max_local_size = vscreen->caps.caps.v2.max_compute_shared_memory_size;
+      }
+      return sizeof(uint64_t);
+   default:
+      break;
+   }
+   return 0;
+}
+
 static boolean
 virgl_is_vertex_format_supported(struct pipe_screen *screen,
                                  enum pipe_format format)
@@ -666,6 +718,7 @@ virgl_create_screen(struct virgl_winsys *vws)
    screen->base.get_vendor = virgl_get_vendor;
    screen->base.get_param = virgl_get_param;
    screen->base.get_shader_param = virgl_get_shader_param;
+   screen->base.get_compute_param = virgl_get_compute_param;
    screen->base.get_paramf = virgl_get_paramf;
    screen->base.is_format_supported = virgl_is_format_supported;
    screen->base.destroy = virgl_destroy_screen;
index 315ca55f954613b16018e0c35f6d40575d289cfb..0e6cb7953f6e1628ac1e8fb11198ead02675fe55 100644 (file)
@@ -138,5 +138,7 @@ static inline void virgl_ws_fill_new_caps_defaults(struct virgl_drm_caps *caps)
    caps->caps.v2.capability_bits = 0;
    caps->caps.v2.max_vertex_attrib_stride = 0;
    caps->caps.v2.max_image_samples = 0;
+   caps->caps.v2.max_compute_work_group_invocations = 0;
+   caps->caps.v2.max_compute_shared_memory_size = 0;
 }
 #endif