[virglrenderer-devel] [PATCH 3/5] vrend: store offsets into backing ivo for mipmaps and use it when reading data back (v2)

Gurchetan Singh gurchetansingh at chromium.org
Mon Jun 18 16:50:16 UTC 2018


On Sun, Jun 17, 2018 at 11:14 PM Gert Wollny <gert.wollny at collabora.com> wrote:
>
> Am Freitag, den 15.06.2018, 15:50 -0700 schrieb Gurchetan Singh:
>
> Patches 1, 2, 4, and 5 are:
>
>
> Thanks for the review.
>
>
> +         if (info->level> 0 && info->level <= MAX_READBACK_MIPMAP_LEVELS) {
>
>
> Why don't you just have a case for level 0?  Right now it's a little confusing to follow.  It's also consistent with EGL_EXT_image_dma_buf_import offsets.
>
>
> The size of the offset array is limied, so I have to check the upper bound, otherwise we might later try to read from unallocated memory. I can think of how to make it more clear but in the end it's the same.
>

Essentially, you're trying to re-create the level_offset array from
the guest side on the host.  Since that has case for level 0, I think
we should have one too.  Using the the same naming convention
(res->level_offsets[level], VR_MAX_TEXTURE_2D_LEVELS) would make the
code a little clearer has well.

> +            int64_t level_height = u_minify(res->base.height0, info->level);
> +            res->mipmap_offsets[info->level-1] = info->offset -
> +                                               ((info->box->z * level_height + y) * stride + x * elsize);
>
>
> I don't fully understand this calculation.  From  virgl_texture_transfer_map it seems info->offset represents the start of the transfer from with given {x, y, z} coordination in the texture.  So:
> info->offset == info->box->z * level_height + y * level_stride + x * elsize
>
>
> level_height is the numbers of rows in the mip-map level, you still have to multiply with
> the stride to get the number of bytes for a full slice, hence for info->box->z slices
> you have an offset of ( info->box->z * level_height * level_stride) bytes, adding the bytes
> per y rows you get
>
> ( info->box->z * level_height * level_stride) + y * level_stride =
> ( info->box->z * level_height + y) * level_stride (reduce four operations to three)
> and to this you add the number of bytes to get to x (= x* elsize).

Got it.  So that's essentially:

image_stride * box->z + stride * y + x * elsize

That's the offset into transfer at a particular mipmap level (level =
0, level = 1 etc.).  But we just want the start of the mipmap level,
so we subtract this value.


>
>
> So won't mipmap_offsets always be zero?
>
>
> The offset for the mipmap data is only zero for the 0-level, if it would alway be zero the tests would pass
> without this patch.
>
>
> Also nit: parens would make more sense like this -- info->offset - (info->box->z * level_height + y * stride + x * elsize);
>
> Same as above, you forgot that for a slice the number of bytes is (level_height*stride).
>
>
> Best,
> Gert
>
>
>
> +         }
> +
>           if (res->base.format == (enum pipe_format)VIRGL_FORMAT_Z24X8_UNORM) {
>              /* we get values from the guest as 24-bit scaled integers
>                 but we give them to the host GL and it interprets them
> @@ -6088,8 +6102,6 @@ static void vrend_resource_copy_fallback(struct vrend_resource *src_res,
>
>     box = *src_box;
>     box.depth = vrend_get_texture_depth(src_res, src_level);
> -
> -   src_stride = util_format_get_stride(src_res->base.format, src_res->base.width0);
>     dst_stride = util_format_get_stride(dst_res->base.format, dst_res->base.width0);
>
>     /* this is ugly need to do a full GetTexImage */
> @@ -6111,12 +6123,21 @@ static void vrend_resource_copy_fallback(struct vrend_resource *src_res,
>      * iovec to have the data we need, otherwise we can use glGetTexture
>      */
>     if (vrend_state.use_gles) {
> -      read_transfer_data(&src_res->base, src_res->iov, src_res->num_iovs,
> -                         tptr, src_stride, &box, src_level, 0, false);
> +      uint64_t src_offset = 0;
> +      uint64_t dst_offset = 0;
> +      if (src_level > 0 && src_level <= MAX_READBACK_MIPMAP_LEVELS) {
> +         src_offset = src_res->mipmap_offsets[src_level-1];
> +         dst_offset = dst_res->mipmap_offsets[src_level-1];
> +      }
> +
> +      src_stride = util_format_get_nblocksx(src_res->base.format,
> +                                            u_minify(src_res->base.width0, src_level)) * elsize;
> +      read_transfer_data(&src_res->base, src_res->iov, src_res->num_iovs, tptr,
> +                         src_stride, &box, src_level, src_offset, false);
>        /* In on GLES Sync the iov that backs the dst resource because
>         * we might need it in a chain copy A->B, B->C */
>        write_transfer_data(&dst_res->base, dst_res->iov, dst_res->num_iovs, tptr,
> -                          dst_stride, &box, src_level, 0, false);
> +                          dst_stride, &box, src_level, dst_offset, false);
>        /* we get values from the guest as 24-bit scaled integers
>           but we give them to the host GL and it interprets them
>           as 32-bit scaled integers, so we need to scale them here */
> diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h
> index 042d439..258c439 100644
> --- a/src/vrend_renderer.h
> +++ b/src/vrend_renderer.h
> @@ -44,6 +44,9 @@ struct virgl_gl_ctx_param {
>  extern int vrend_dump_shaders;
>  struct vrend_context;
>
> +/* Number of mipmap levels for which to keep the backing iov offsets */
> +#define MAX_READBACK_MIPMAP_LEVELS 16
> +
>  struct vrend_resource {
>     struct pipe_resource base;
>     GLuint id;
> @@ -62,6 +65,7 @@ struct vrend_resource {
>     char *ptr;
>     struct iovec *iov;
>     uint32_t num_iovs;
> +   uint64_t mipmap_offsets[MAX_READBACK_MIPMAP_LEVELS];
>  };
>
>  /* assume every format is sampler friendly */


More information about the virglrenderer-devel mailing list