[virglrenderer-devel] [PATCH 2/6] decode/renderer: handle compute shader creation

Dave Airlie airlied at gmail.com
Mon Jul 30 18:54:00 UTC 2018


From: Dave Airlie <airlied at redhat.com>

For compute shaders we put the req local memory into the streamout
places in the protocol, and we create compute shaders in a separate
lookup function
---
 src/vrend_decode.c   | 20 ++++++++-----
 src/vrend_renderer.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++-----
 src/vrend_renderer.h |  1 +
 3 files changed, 88 insertions(+), 15 deletions(-)

diff --git a/src/vrend_decode.c b/src/vrend_decode.c
index b3ae095..42ec832 100644
--- a/src/vrend_decode.c
+++ b/src/vrend_decode.c
@@ -68,7 +68,7 @@ static int vrend_decode_create_shader(struct vrend_decode_ctx *ctx,
    struct pipe_stream_output_info so_info;
    uint i;
    int ret;
-   uint32_t shader_offset;
+   uint32_t shader_offset, req_local_mem = 0;
    unsigned num_tokens, num_so_outputs, offlen;
    uint8_t *shd_text;
    uint32_t type;
@@ -79,12 +79,18 @@ static int vrend_decode_create_shader(struct vrend_decode_ctx *ctx,
    type = get_buf_entry(ctx, VIRGL_OBJ_SHADER_TYPE);
    num_tokens = get_buf_entry(ctx, VIRGL_OBJ_SHADER_NUM_TOKENS);
    offlen = get_buf_entry(ctx, VIRGL_OBJ_SHADER_OFFSET);
-   num_so_outputs = get_buf_entry(ctx, VIRGL_OBJ_SHADER_SO_NUM_OUTPUTS);
 
-   if (length < VIRGL_OBJ_SHADER_HDR_SIZE(num_so_outputs))
-      return EINVAL;
-   if (num_so_outputs > PIPE_MAX_SO_OUTPUTS)
-      return EINVAL;
+   if (type == PIPE_SHADER_COMPUTE) {
+      req_local_mem = get_buf_entry(ctx, VIRGL_OBJ_SHADER_SO_NUM_OUTPUTS);
+      num_so_outputs = 0;
+   } else {
+      num_so_outputs = get_buf_entry(ctx, VIRGL_OBJ_SHADER_SO_NUM_OUTPUTS);
+      if (length < VIRGL_OBJ_SHADER_HDR_SIZE(num_so_outputs))
+         return EINVAL;
+
+      if (num_so_outputs > PIPE_MAX_SO_OUTPUTS)
+         return EINVAL;
+   }
 
    shader_offset = 6;
    if (num_so_outputs) {
@@ -109,7 +115,7 @@ static int vrend_decode_create_shader(struct vrend_decode_ctx *ctx,
      memset(&so_info, 0, sizeof(so_info));
 
    shd_text = get_buf_ptr(ctx, shader_offset);
-   ret = vrend_create_shader(ctx->grctx, handle, &so_info, (const char *)shd_text, offlen, num_tokens, type, length - shader_offset + 1);
+   ret = vrend_create_shader(ctx->grctx, handle, &so_info, req_local_mem, (const char *)shd_text, offlen, num_tokens, type, length - shader_offset + 1);
 
    return ret;
 }
diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c
index 576cecb..63862d5 100644
--- a/src/vrend_renderer.c
+++ b/src/vrend_renderer.c
@@ -291,6 +291,7 @@ struct vrend_shader_selector {
    struct vrend_shader *current;
    struct tgsi_token *tokens;
 
+   uint32_t req_local_mem;
    char *tmp_buf;
    uint32_t buf_len;
    uint32_t buf_offset;
@@ -439,6 +440,7 @@ struct vrend_sub_context {
 
    bool vbo_dirty;
    bool shader_dirty;
+   bool cs_shader_dirty;
    bool sampler_state_dirty;
    bool stencil_state_dirty;
    bool image_state_dirty;
@@ -605,6 +607,7 @@ static inline const char *pipe_shader_to_prefix(int shader_type)
    case PIPE_SHADER_GEOMETRY: return "gs";
    case PIPE_SHADER_TESS_CTRL: return "tc";
    case PIPE_SHADER_TESS_EVAL: return "te";
+   case PIPE_SHADER_COMPUTE: return "cs";
    default:
       return NULL;
    };
@@ -1173,6 +1176,43 @@ static void bind_image_locs(struct vrend_linked_shader_program *sprog,
    sprog->images_used_mask[id] = mask;
 }
 
+static struct vrend_linked_shader_program *add_cs_shader_program(struct vrend_context *ctx,
+                                                                 struct vrend_shader *cs)
+{
+   struct vrend_linked_shader_program *sprog = CALLOC_STRUCT(vrend_linked_shader_program);
+   GLuint prog_id;
+   GLint lret;
+   prog_id = glCreateProgram();
+   glAttachShader(prog_id, cs->id);
+   glLinkProgram(prog_id);
+
+   glGetProgramiv(prog_id, GL_LINK_STATUS, &lret);
+   if (lret == GL_FALSE) {
+      char infolog[65536];
+      int len;
+      glGetProgramInfoLog(prog_id, 65536, &len, infolog);
+      fprintf(stderr,"got error linking\n%s\n", infolog);
+      /* dump shaders */
+      report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_SHADER, 0);
+      fprintf(stderr,"compute shader: %d GLSL\n%s\n", cs->id, cs->glsl_prog);
+      glDeleteProgram(prog_id);
+      free(sprog);
+      return NULL;
+   }
+   sprog->ss[PIPE_SHADER_COMPUTE] = cs;
+
+   list_add(&sprog->sl[PIPE_SHADER_COMPUTE], &cs->programs);
+   sprog->id = prog_id;
+   list_addtail(&sprog->head, &ctx->sub->programs);
+
+   bind_sampler_locs(sprog, PIPE_SHADER_COMPUTE);
+   bind_ubo_locs(sprog, PIPE_SHADER_COMPUTE);
+   bind_ssbo_locs(sprog, PIPE_SHADER_COMPUTE);
+   bind_const_locs(sprog, PIPE_SHADER_COMPUTE);
+   bind_image_locs(sprog, PIPE_SHADER_COMPUTE);
+   return sprog;
+}
+
 static struct vrend_linked_shader_program *add_shader_program(struct vrend_context *ctx,
                                                               struct vrend_shader *vs,
                                                               struct vrend_shader *fs,
@@ -1344,6 +1384,19 @@ static struct vrend_linked_shader_program *add_shader_program(struct vrend_conte
    return sprog;
 }
 
+static struct vrend_linked_shader_program *lookup_cs_shader_program(struct vrend_context *ctx,
+                                                                    GLuint cs_id)
+{
+   struct vrend_linked_shader_program *ent;
+   LIST_FOR_EACH_ENTRY(ent, &ctx->sub->programs, head) {
+      if (!ent->ss[PIPE_SHADER_COMPUTE])
+         continue;
+      if (ent->ss[PIPE_SHADER_COMPUTE]->id == cs_id)
+         return ent;
+   }
+   return NULL;
+}
+
 static struct vrend_linked_shader_program *lookup_shader_program(struct vrend_context *ctx,
                                                                  GLuint vs_id,
                                                                  GLuint fs_id,
@@ -1356,7 +1409,8 @@ static struct vrend_linked_shader_program *lookup_shader_program(struct vrend_co
    LIST_FOR_EACH_ENTRY(ent, &ctx->sub->programs, head) {
       if (ent->dual_src_linked != dual_src)
          continue;
-
+      if (ent->ss[PIPE_SHADER_COMPUTE])
+         continue;
       if (ent->ss[PIPE_SHADER_VERTEX]->id != vs_id)
         continue;
       if (ent->ss[PIPE_SHADER_FRAGMENT]->id != fs_id)
@@ -1381,7 +1435,7 @@ static void vrend_destroy_program(struct vrend_linked_shader_program *ent)
    glDeleteProgram(ent->id);
    list_del(&ent->head);
 
-   for (i = PIPE_SHADER_VERTEX; i <= PIPE_SHADER_TESS_EVAL; i++) {
+   for (i = PIPE_SHADER_VERTEX; i <= PIPE_SHADER_COMPUTE; i++) {
       if (ent->ss[i])
          list_del(&ent->sl[i]);
       free(ent->shadow_samp_mask_locs[i]);
@@ -2701,6 +2755,7 @@ static inline int conv_shader_type(int type)
    case PIPE_SHADER_GEOMETRY: return GL_GEOMETRY_SHADER;
    case PIPE_SHADER_TESS_CTRL: return GL_TESS_CONTROL_SHADER;
    case PIPE_SHADER_TESS_EVAL: return GL_TESS_EVALUATION_SHADER;
+   case PIPE_SHADER_COMPUTE: return GL_COMPUTE_SHADER;
    default:
       return 0;
    };
@@ -2718,7 +2773,7 @@ static int vrend_shader_create(struct vrend_context *ctx,
 
    shader->id = glCreateShader(conv_shader_type(shader->sel->type));
    shader->compiled_fs_id = 0;
-   shader->glsl_prog = vrend_convert_shader(&ctx->shader_cfg, shader->sel->tokens, 0, &key, &shader->sel->sinfo);
+   shader->glsl_prog = vrend_convert_shader(&ctx->shader_cfg, shader->sel->tokens, shader->sel->req_local_mem, &key, &shader->sel->sinfo);
    if (!shader->glsl_prog) {
       report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_SHADER, 0);
       glDeleteShader(shader->id);
@@ -2787,6 +2842,7 @@ static int vrend_shader_select(struct vrend_context *ctx,
 
 static void *vrend_create_shader_state(UNUSED struct vrend_context *ctx,
                                        const struct pipe_stream_output_info *so_info,
+                                       uint32_t req_local_mem,
                                        unsigned pipe_shader_type)
 {
    struct vrend_shader_selector *sel = CALLOC_STRUCT(vrend_shader_selector);
@@ -2794,6 +2850,7 @@ static void *vrend_create_shader_state(UNUSED struct vrend_context *ctx,
    if (!sel)
       return NULL;
 
+   sel->req_local_mem = req_local_mem;
    sel->type = pipe_shader_type;
    sel->sinfo.so_info = *so_info;
    pipe_reference_init(&sel->reference, 1);
@@ -2819,6 +2876,7 @@ static int vrend_finish_shader(struct vrend_context *ctx,
 int vrend_create_shader(struct vrend_context *ctx,
                         uint32_t handle,
                         const struct pipe_stream_output_info *so_info,
+                        uint32_t req_local_mem,
                         const char *shd_text, uint32_t offlen, uint32_t num_tokens,
                         uint32_t type, uint32_t pkt_length)
 {
@@ -2828,7 +2886,7 @@ int vrend_create_shader(struct vrend_context *ctx,
    bool finished = false;
    int ret;
 
-   if (type > PIPE_SHADER_TESS_EVAL)
+   if (type > PIPE_SHADER_COMPUTE)
       return EINVAL;
 
    if (!has_feature(feat_geometry_shader) &&
@@ -2855,7 +2913,7 @@ int vrend_create_shader(struct vrend_context *ctx,
    }
 
    if (new_shader) {
-     sel = vrend_create_shader_state(ctx, so_info, type);
+      sel = vrend_create_shader_state(ctx, so_info, req_local_mem, type);
      if (sel == NULL)
        return ENOMEM;
 
@@ -2964,11 +3022,14 @@ void vrend_bind_shader(struct vrend_context *ctx,
 {
    struct vrend_shader_selector *sel;
 
-   if (type > PIPE_SHADER_TESS_EVAL)
+   if (type > PIPE_SHADER_COMPUTE)
       return;
 
    if (handle == 0) {
-      ctx->sub->shader_dirty = true;
+      if (type == PIPE_SHADER_COMPUTE)
+         ctx->sub->cs_shader_dirty = true;
+      else
+         ctx->sub->shader_dirty = true;
       vrend_shader_state_reference(&ctx->sub->shaders[type], NULL);
       return;
    }
@@ -2981,7 +3042,10 @@ void vrend_bind_shader(struct vrend_context *ctx,
       return;
 
    if (ctx->sub->shaders[sel->type] != sel) {
-      ctx->sub->shader_dirty = true;
+      if (type == PIPE_SHADER_COMPUTE)
+         ctx->sub->cs_shader_dirty = true;
+      else
+         ctx->sub->shader_dirty = true;
       ctx->sub->prog_ids[sel->type] = 0;
    }
 
@@ -5057,6 +5121,7 @@ static void vrend_destroy_sub_context(struct vrend_sub_context *sub)
    vrend_shader_state_reference(&sub->shaders[PIPE_SHADER_GEOMETRY], NULL);
    vrend_shader_state_reference(&sub->shaders[PIPE_SHADER_TESS_CTRL], NULL);
    vrend_shader_state_reference(&sub->shaders[PIPE_SHADER_TESS_EVAL], NULL);
+   vrend_shader_state_reference(&sub->shaders[PIPE_SHADER_COMPUTE], NULL);
 
    vrend_free_programs(sub);
    for (i = 0; i < PIPE_SHADER_TYPES; i++) {
@@ -5110,6 +5175,7 @@ bool vrend_destroy_context(struct vrend_context *ctx)
    vrend_set_num_sampler_views(ctx, PIPE_SHADER_GEOMETRY, 0, 0);
    vrend_set_num_sampler_views(ctx, PIPE_SHADER_TESS_CTRL, 0, 0);
    vrend_set_num_sampler_views(ctx, PIPE_SHADER_TESS_EVAL, 0, 0);
+   vrend_set_num_sampler_views(ctx, PIPE_SHADER_COMPUTE, 0, 0);
 
    vrend_set_streamout_targets(ctx, 0, 0, NULL);
    vrend_set_num_vbo(ctx, 0);
diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h
index fe05fcc..a0766dd 100644
--- a/src/vrend_renderer.h
+++ b/src/vrend_renderer.h
@@ -112,6 +112,7 @@ const struct vrend_format_table *vrend_get_format_table_entry(enum virgl_formats
 int vrend_create_shader(struct vrend_context *ctx,
                         uint32_t handle,
                         const struct pipe_stream_output_info *stream_output,
+                        uint32_t req_local_mem,
                         const char *shd_text, uint32_t offlen, uint32_t num_tokens,
                         uint32_t type, uint32_t pkt_length);
 
-- 
2.14.3



More information about the virglrenderer-devel mailing list