From 04f2080d89227cda809653ba1e5aec78ceb5f795 Mon Sep 17 00:00:00 2001 From: Gert Wollny Date: Wed, 20 Jun 2018 16:33:36 +0200 Subject: [PATCH] vrend: store offsets into backing ivo for mipmaps and use it when reading data back (v3) In the copy fallback, when a texture can not be rendered, the data that resides in the backing iovec needs to be used. For the non-zero levels of mip-map textures the data is located at an offset. This patch adds storing this offset and using it when data is read from the backing iovec and updating the dst iov. We limit the mip-map levels for which this is done to 1-17, which is enough to cover 32kx32k textures. The patch also fixes the stride when accessing mip-map levels. Fixes: dEQP-GLES3.functional.texture.specification.teximage3d_depth.depth_component24_2d_array dEQP-GLES3.functional.texture.specification.texsubimage3d_depth.depth_component32f_2d_array dEQP-GLES3.functional.texture.specification.texsubimage3d_depth.depth_component24_2d_array dEQP-GLES3.functional.texture.specification.texsubimage3d_depth.depth_component16_2d_array dEQP-GLES3.functional.texture.specification.texsubimage3d_depth.depth32f_stencil8_2d_array dEQP-GLES3.functional.texture.specification.texsubimage3d_depth.depth24_stencil8_2d_array v2: * rebase and remove unused variables * also correct offset when writing to the destination backing iovec v3: * follow mesa/virgl notation and range for storing the mip-map offsets Suggested-by: Gurchetan Singh Reviewed-by: Gurchetan Singh Signed-off-by: Gert Wollny Signed-off-by: Jakob Bornecrantz --- src/vrend_renderer.c | 32 ++++++++++++++++++++++++++------ src/vrend_renderer.h | 6 ++++++ 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c index e3370d0..869be04 100644 --- a/src/vrend_renderer.c +++ b/src/vrend_renderer.c @@ -5414,6 +5414,19 @@ static int vrend_renderer_transfer_write_iov(struct vrend_context *ctx, x = info->box->x; y = invert ? (int)res->base.height0 - info->box->y - info->box->height : info->box->y; + + /* mipmaps are usually passed in one iov, and we need to keep the offset + * into the data in case we want to read back the data of a surface + * that can not be rendered. Since we can not assume that the whole texture + * is filled, we evaluate the offset for origin (0,0,0). Since it is also + * possible that a resource is reused and resized update the offset every time. + */ + if (info->level < VR_MAX_TEXTURE_2D_LEVELS) { + int64_t level_height = u_minify(res->base.height0, info->level); + res->mipmap_offsets[info->level] = info->offset - + ((info->box->z * level_height + y) * stride + x * elsize); + } + 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 @@ -6097,8 +6110,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 */ @@ -6120,12 +6131,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); - /* Sync the dst iovec backing store because + uint64_t src_offset = 0; + uint64_t dst_offset = 0; + if (src_level < VR_MAX_TEXTURE_2D_LEVELS) { + src_offset = src_res->mipmap_offsets[src_level]; + dst_offset = dst_res->mipmap_offsets[src_level]; + } + + 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); + /* When 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..d07d11c 100644 --- a/src/vrend_renderer.h +++ b/src/vrend_renderer.h @@ -44,6 +44,11 @@ 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. + * Value mirrored from mesa/virgl + */ +#define VR_MAX_TEXTURE_2D_LEVELS 15 + struct vrend_resource { struct pipe_resource base; GLuint id; @@ -62,6 +67,7 @@ struct vrend_resource { char *ptr; struct iovec *iov; uint32_t num_iovs; + uint64_t mipmap_offsets[VR_MAX_TEXTURE_2D_LEVELS]; }; /* assume every format is sampler friendly */