[virglrenderer-devel] [PATCH 07/10] renderer: add image support. (v3)

Gert Wollny gert.wollny at collabora.com
Thu Jul 26 15:01:42 UTC 2018


Am Mittwoch, den 25.07.2018, 09:00 +1000 schrieb Dave Airlie:
> From: Dave Airlie <airlied at redhat.com>
> 
> This adds support for tracking images, and binding them
> to the GL context.
> 
> includes:
> vrend_renderer: create texture when TBO is used as image
> vrend_renderer: specify correct access to glBindImageTexture
> 
> v2:
> vrend_renderer: invert glBindImageTexture layered logic
> 
> v3: fix decode macros (Gert pointed out for ssbo)
> 
> Co-authors: Gurchetan Singh <gurchetansingh at chromium.org>
> Signed-off-by: Dave Airlie <airlied at redhat.com>
> ---
>  src/virgl_hw.h       |   2 +
>  src/virgl_protocol.h |  12 ++++
>  src/vrend_decode.c   |  34 +++++++++++
>  src/vrend_renderer.c | 163
> +++++++++++++++++++++++++++++++++++++++++++++++++++
>  src/vrend_renderer.h |   6 ++
>  5 files changed, 217 insertions(+)
> 
> diff --git a/src/virgl_hw.h b/src/virgl_hw.h
> index 51a3255..bba622f 100644
> --- a/src/virgl_hw.h
> +++ b/src/virgl_hw.h
> @@ -332,6 +332,8 @@ struct virgl_caps_v2 {
>          uint32_t max_vertex_attrib_stride;
>          uint32_t max_shader_buffer_frag_compute;
>          uint32_t max_shader_buffer_other_stages;
> +        uint32_t max_shader_image_frag_compute;
> +        uint32_t max_shader_image_other_stages;
>  };
>  
>  union virgl_caps {
> diff --git a/src/virgl_protocol.h b/src/virgl_protocol.h
> index 6c73dfb..a23e318 100644
> --- a/src/virgl_protocol.h
> +++ b/src/virgl_protocol.h
> @@ -86,6 +86,7 @@ enum virgl_context_cmd {
>     VIRGL_CCMD_SET_TESS_STATE,
>     VIRGL_CCMD_SET_MIN_SAMPLES,
>     VIRGL_CCMD_SET_SHADER_BUFFERS,
> +   VIRGL_CCMD_SET_SHADER_IMAGES,
>  };
>  
>  /*
> @@ -500,4 +501,15 @@ enum virgl_context_cmd {
>  #define VIRGL_SET_SHADER_BUFFER_LENGTH(x) ((x) *
> VIRGL_SET_SHADER_BUFFER_ELEMENT_SIZE + 3)
>  #define VIRGL_SET_SHADER_BUFFER_RES_HANDLE(x) ((x) *
> VIRGL_SET_SHADER_BUFFER_ELEMENT_SIZE + 4)
>  
> +/* set shader images */
> +#define VIRGL_SET_SHADER_IMAGE_ELEMENT_SIZE 5
> +#define VIRGL_SET_SHADER_IMAGE_SIZE(x)
> (VIRGL_SET_SHADER_IMAGE_ELEMENT_SIZE * (x)) + 2
> +#define VIRGL_SET_SHADER_IMAGE_SHADER_TYPE 1
> +#define VIRGL_SET_SHADER_IMAGE_START_SLOT 2
> +#define VIRGL_SET_SHADER_IMAGE_FORMAT(x) ((x) *
> VIRGL_SET_SHADER_IMAGE_ELEMENT_SIZE + 3)
> +#define VIRGL_SET_SHADER_IMAGE_ACCESS(x) ((x) *
> VIRGL_SET_SHADER_IMAGE_ELEMENT_SIZE + 4)
> +#define VIRGL_SET_SHADER_IMAGE_LAYER_OFFSET(x) ((x) *
> VIRGL_SET_SHADER_IMAGE_ELEMENT_SIZE + 5)
> +#define VIRGL_SET_SHADER_IMAGE_LEVEL_SIZE(x) ((x) *
> VIRGL_SET_SHADER_IMAGE_ELEMENT_SIZE + 6)
> +#define VIRGL_SET_SHADER_IMAGE_RES_HANDLE(x) ((x) *
> VIRGL_SET_SHADER_IMAGE_ELEMENT_SIZE + 7)
> +
>  #endif
> diff --git a/src/vrend_decode.c b/src/vrend_decode.c
> index 54d066e..4cf56d7 100644
> --- a/src/vrend_decode.c
> +++ b/src/vrend_decode.c
> @@ -1106,6 +1106,37 @@ static int
> vrend_decode_set_shader_buffers(struct vrend_decode_ctx *ctx, uint16_
>     return 0;
>  }
>  
> +static int vrend_decode_set_shader_images(struct vrend_decode_ctx
> *ctx, uint16_t length)
> +{
> +   int num_images;
> +   uint32_t shader_type, start_slot;
> +   if (length < 2)
> +      return EINVAL;
> +
> +   num_images = (length - 2) / VIRGL_SET_SHADER_IMAGE_ELEMENT_SIZE;
> +   shader_type = get_buf_entry(ctx,
> VIRGL_SET_SHADER_IMAGE_SHADER_TYPE);
> +   start_slot = get_buf_entry(ctx,
> VIRGL_SET_SHADER_IMAGE_START_SLOT);
> +   if (shader_type >= PIPE_SHADER_TYPES)
> +      return EINVAL;
> +
> +   if (num_images < 1) {
> +      return 0;
> +   }
> +   if (start_slot + num_images > PIPE_MAX_SHADER_IMAGES)
> +      return EINVAL;
> +
> +   for (int i = 0; i < num_images; i++) {
> +      uint32_t format = get_buf_entry(ctx,
> VIRGL_SET_SHADER_IMAGE_FORMAT(i));
> +      uint32_t access = get_buf_entry(ctx,
> VIRGL_SET_SHADER_IMAGE_ACCESS(i));
> +      uint32_t layer_offset = get_buf_entry(ctx,
> VIRGL_SET_SHADER_IMAGE_LAYER_OFFSET(i));
> +      uint32_t level_size = get_buf_entry(ctx,
> VIRGL_SET_SHADER_IMAGE_LEVEL_SIZE(i));
> +      uint32_t handle = get_buf_entry(ctx,
> VIRGL_SET_SHADER_IMAGE_RES_HANDLE(i));
> +      vrend_set_single_image_view(ctx->grctx, shader_type,
> start_slot + i, format, access,
> +                                  layer_offset, level_size, handle);
> +   }
> +   return 0;
> +}
> +
>  static int vrend_decode_set_streamout_targets(struct
> vrend_decode_ctx *ctx,
>                                                uint16_t length)
>  {
> @@ -1337,6 +1368,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_SHADER_IMAGES:
> +         ret = vrend_decode_set_shader_images(gdctx, len);
> +         break;
>        default:
>           ret = EINVAL;
>        }
> diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c
> index 19c199b..a2042a4 100644
> --- a/src/vrend_renderer.c
> +++ b/src/vrend_renderer.c
> @@ -104,6 +104,7 @@ enum features_id
>     feat_gl_prim_restart,
>     feat_gles_khr_robustness,
>     feat_gles31_vertex_attrib_binding,
> +   feat_images,
>     feat_indep_blend,
>     feat_indep_blend_func,
>     feat_indirect_draw,
> @@ -155,6 +156,7 @@ static const  struct {
>     [feat_gl_prim_restart] = { 31, UNAVAIL, {} },
>     [feat_gles_khr_robustness] = { UNAVAIL, UNAVAIL, {
> "GL_KHR_robustness" } },
>     [feat_gles31_vertex_attrib_binding] = { 43, 31, {
> "GL_ARB_vertex_attrib_binding" } },
> +   [feat_images] = { 42, 31, { "GL_ARB_shader_image_load_store" } },
>     [feat_indep_blend] = { 30, UNAVAIL, { "GL_EXT_draw_buffers2" } },
>     [feat_indep_blend_func] = { 40, UNAVAIL, {
> "GL_ARB_draw_buffers_blend" } },
>     [feat_indirect_draw] = { 40, UNAVAIL, { "GL_ARB_indirect_draw" }
> },
> @@ -253,6 +255,9 @@ struct vrend_linked_shader_program {
>  
>     GLuint clip_locs[8];
>  
> +   uint32_t images_used_mask[PIPE_SHADER_TYPES];
> +   GLuint *img_locs[PIPE_SHADER_TYPES];
> +
>     uint32_t ssbo_used_mask[PIPE_SHADER_TYPES];
>     GLuint *ssbo_locs[PIPE_SHADER_TYPES];
>  };
> @@ -332,6 +337,24 @@ struct vrend_sampler_view {
>     struct vrend_resource *texture;
>  };
>  
> +struct vrend_image_view {
> +   GLuint id;
> +   GLenum access;
> +   GLenum format;
> +   union {
> +      struct {
> +         unsigned first_layer:16;     /**< first layer to use for
> array textures */
> +         unsigned last_layer:16;      /**< last layer to use for
> array textures */
> +         unsigned level:8;            /**< mipmap level to use */
> +      } tex;
> +      struct {
> +         unsigned offset;   /**< offset in bytes */
> +         unsigned size;     /**< size of the accessible sub-range in
> bytes */
> +      } buf;
> +   } u;
> +   struct vrend_resource *texture;
> +};
> +
>  struct vrend_ssbo {
>     struct vrend_resource *res;
>     unsigned buffer_size;
> @@ -410,6 +433,7 @@ struct vrend_sub_context {
>     bool shader_dirty;
>     bool sampler_state_dirty;
>     bool stencil_state_dirty;
> +   bool image_state_dirty;
>  
>     uint32_t long_shader_in_progress_handle[PIPE_SHADER_TYPES];
>     struct vrend_shader_selector *shaders[PIPE_SHADER_TYPES];
> @@ -477,6 +501,9 @@ struct vrend_sub_context {
>     uint32_t cond_render_q_id;
>     GLenum cond_render_gl_mode;
>  
> +   struct vrend_image_view
> image_views[PIPE_SHADER_TYPES][PIPE_MAX_SHADER_IMAGES];
> +   uint32_t images_used_mask[PIPE_SHADER_TYPES];
> +
>     struct vrend_ssbo
> ssbo[PIPE_SHADER_TYPES][PIPE_MAX_SHADER_BUFFERS];
>     uint32_t ssbo_used_mask[PIPE_SHADER_TYPES];
>  };
> @@ -1092,6 +1119,36 @@ static void bind_ssbo_locs(struct
> vrend_linked_shader_program *sprog,
>     sprog->ssbo_used_mask[id] = sprog->ss[id]->sel-
> >sinfo.ssbo_used_mask;
>  }
>  
> +static void bind_image_locs(struct vrend_linked_shader_program
> *sprog,
> +                            int id)
> +{
> +   int i;
> +   char name[32];
> +
> +   if (!has_feature(feat_images))
> +      return;
> +
> +   if (sprog->ss[id]->sel->sinfo.images_used_mask) {
> +      uint32_t mask = sprog->ss[id]->sel->sinfo.images_used_mask;
> +      int nsamp = util_bitcount(sprog->ss[id]->sel-
> >sinfo.images_used_mask);
Why not move 
    uint32_t mask = sprog->ss[id]->sel->sinfo.images_used_mask;
out of the if and use it there and inside the scope, instead of the
using the same pointer chain three times? 

> +      int index;
> +      sprog->img_locs[id] = calloc(nsamp, sizeof(uint32_t));
> +      if (sprog->img_locs[id]) {
> +         const char *prefix = pipe_shader_to_prefix(id);
> +         index = 0;
> +         while(mask) {
> +            i = u_bit_scan(&mask);
> +            snprintf(name, 32, "%simg%d", prefix, i);
> +            sprog->img_locs[id][index] = glGetUniformLocation(sprog-
> >id, name);
> +            index++;
> +         }
> +      }
Logging an error message in case of failure would be nice (even though
it's unlikely) 

> +   } else {
> +      sprog->img_locs[id] = NULL;
> +   }
> +   sprog->images_used_mask[id] = sprog->ss[id]->sel-
> >sinfo.images_used_mask;
> +}
> +
>  static struct vrend_linked_shader_program *add_shader_program(struct
> vrend_context *ctx,
>                                                                struct
> vrend_shader *vs,
>                                                                struct
> vrend_shader *fs,
> @@ -1237,6 +1294,7 @@ static struct vrend_linked_shader_program
> *add_shader_program(struct vrend_conte
>        bind_sampler_locs(sprog, id);
>        bind_const_locs(sprog, id);
>        bind_ubo_locs(sprog, id);
> +      bind_image_locs(sprog, id);
>        bind_ssbo_locs(sprog, id);
>     }
>  
> @@ -1306,6 +1364,7 @@ static void vrend_destroy_program(struct
> vrend_linked_shader_program *ent)
>        free(ent->shadow_samp_add_locs[i]);
>        free(ent->samp_locs[i]);
>        free(ent->ssbo_locs[i]);
> +      free(ent->img_locs[i]);
>        free(ent->const_locs[i]);
>        free(ent->ubo_locs[i]);
>     }
> @@ -2397,6 +2456,38 @@ void vrend_set_num_sampler_views(struct
> vrend_context *ctx,
>     ctx->sub->views[shader_type].num_views = last_slot;
>  }
>  
> +void vrend_set_single_image_view(struct vrend_context *ctx,
> +                                 uint32_t shader_type,
> +                                 int index,
> +                                 uint32_t format, uint32_t access,
> +                                 uint32_t layer_offset, uint32_t
> level_size,
> +                                 uint32_t handle)
> +{
> +   struct vrend_image_view *iview = &ctx->sub-
> >image_views[shader_type][index];
> +   struct vrend_resource *res;
> +
> +   if (!has_feature(feat_images))
> +      return;
+
> +   if (handle) {
> +      res = vrend_renderer_ctx_res_lookup(ctx, handle);
> +      if (!res) {
> +         report_context_error(ctx, VIRGL_ERROR_CTX_ILLEGAL_RESOURCE,
> handle);
> +         return;
> +      }
> +      iview->texture = res;
> +      iview->format = tex_conv_table[format].internalformat;
> +      iview->access = access;
> +      iview->u.buf.offset = layer_offset;
> +      iview->u.buf.size = level_size;
> +      ctx->sub->images_used_mask[shader_type] |= (1 << index);
> +   } else {
> +      iview->texture = NULL;
> +      iview->format = 0;
> +      ctx->sub->images_used_mask[shader_type] &= ~(1 << index);
> +   }
> +}
> +
>  void vrend_set_single_ssbo(struct vrend_context *ctx,
>                             uint32_t shader_type,
>                             int index,
> @@ -3359,6 +3450,66 @@ static void vrend_draw_bind_ssbo_shader(struct
> vrend_context *ctx, int shader_ty
>     }
>  }
>  
> +static void vrend_draw_bind_images_shader(struct vrend_context *ctx,
> int shader_type)
> +{
> +   struct vrend_image_view *iview;
> +   uint32_t mask;
> +   uint32_t tex_id;
> +   GLenum access;
> +
> +   if (!has_feature(feat_images))
> +      return;
> +
> +   if (!ctx->sub->images_used_mask[shader_type])
> +      return;
> +
> +   if (!ctx->sub->prog->img_locs[shader_type])
> +      return;
> +
> +   mask = ctx->sub->images_used_mask[shader_type];
> +   while (mask) {
> +      unsigned i = u_bit_scan(&mask);
> +
> +      iview = &ctx->sub->image_views[shader_type][i];
> +      tex_id = iview->texture->id;
> +      if (iview->texture->is_buffer) {
> +         if (!iview->texture->tbo_tex_id)
> +            glGenTextures(1, &iview->texture->tbo_tex_id);
> +
> +         glBindBufferARB(GL_TEXTURE_BUFFER, iview->texture->id);
> +         glBindTexture(GL_TEXTURE_BUFFER, iview->texture-
> >tbo_tex_id);
> +         glTexBuffer(GL_TEXTURE_BUFFER, iview->format, iview-
> >texture->id);
> +         tex_id = iview->texture->tbo_tex_id;
> +      }
> +
> +      glUniform1i(ctx->sub->prog->img_locs[shader_type][i], i);
> +      GLboolean layered = !((iview->texture->base.array_size > 1 ||
> +                             iview->texture->base.depth0 > 1) &&
> (iview->u.tex.first_layer == iview->u.tex.last_layer));
> +
> +      switch (iview->access) {
> +      case PIPE_IMAGE_ACCESS_READ:
> +         access = GL_READ_ONLY;
> +         break;
> +      case PIPE_IMAGE_ACCESS_WRITE:
> +         access = GL_WRITE_ONLY;
> +         break;
> +      case PIPE_IMAGE_ACCESS_READ_WRITE:
> +         access = GL_READ_WRITE;
> +         break;
> +      default:
> +         fprintf(stderr, "Invalid access specified\n");
> +         return;
> +      }
> +
> +      glBindImageTexture(i, tex_id,
> +                         iview->u.tex.level,
> +                         layered,
> +                         iview->u.tex.first_layer,
> +                         access,
> +                         iview->format);
> +   }
> +}
> +
>  static void vrend_draw_bind_objects(struct vrend_context *ctx, bool
> new_program)
>  {
>     int ubo_id = 0, sampler_id = 0;
> @@ -3366,6 +3517,7 @@ static void vrend_draw_bind_objects(struct
> vrend_context *ctx, bool new_program)
>        vrend_draw_bind_ubo_shader(ctx, shader_type, &ubo_id);
>        vrend_draw_bind_const_shader(ctx, shader_type, new_program);
>        vrend_draw_bind_samplers_shader(ctx, shader_type,
> &sampler_id);
> +      vrend_draw_bind_images_shader(ctx, shader_type);
>        vrend_draw_bind_ssbo_shader(ctx, shader_type);
>     }
>  
> @@ -7850,6 +8002,17 @@ void vrend_renderer_fill_caps(uint32_t set,
> uint32_t version,
>        caps->v2.max_shader_buffer_frag_compute = max;
>     }
>  
> +   if (has_feature(feat_images)) {
> +      glGetIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &max);
> +      if (max > PIPE_MAX_SHADER_IMAGES)
> +         max = PIPE_MAX_SHADER_IMAGES;
> +      caps->v2.max_shader_image_other_stages = max;
> +      glGetIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &max);
> +      if (max > PIPE_MAX_SHADER_IMAGES)
> +         max = PIPE_MAX_SHADER_IMAGES;
> +      caps->v2.max_shader_image_frag_compute = max;
> +   }
> +
>     caps->v1.max_samples = vrend_renderer_query_multisample_caps(max,
> &caps->v2);
>  
>     caps->v2.capability_bits |= VIRGL_CAP_TGSI_INVARIANT |
> VIRGL_CAP_SET_MIN_SAMPLES | VIRGL_CAP_TGSI_PRECISE;
> diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h
> index 8f1192e..9e0bcdf 100644
> --- a/src/vrend_renderer.h
> +++ b/src/vrend_renderer.h
> @@ -229,6 +229,12 @@ void vrend_set_index_buffer(struct vrend_context
> *ctx,
>                              uint32_t res_handle,
>                              uint32_t index_size,
>                              uint32_t offset);
> +void vrend_set_single_image_view(struct vrend_context *ctx,
> +                                 uint32_t shader_type,
> +                                 int index,
> +                                 uint32_t format, uint32_t access,
> +                                 uint32_t layer_offset, uint32_t
> level_size,
> +                                 uint32_t handle);
>  void vrend_set_single_ssbo(struct vrend_context *ctx,
>                             uint32_t shader_type,
>                             int index,


More information about the virglrenderer-devel mailing list