virgl/gbm: fix guest plane offset/layer_stride

We should honor info->offset and info->layer_stride.  This brings
virgl_gbm_transfer closer to
vrend_renderer_transfer_{write,send}_iov.

minigbm has a bug and never sets info->offset.  The bug went
unnoticed before virgl_gbm_transfer was added.  I suppose fixing
virgl_gbm_transfer now should not suddenly make the bug
user-visible.

v2: With virgl_gbm_transfer, we added planar YUV support that was
not available before. We have to make a special case for YUV to not
regress minigbm.

Signed-off-by: Chia-I Wu <olvaffe@gmail.com>
Reviewed-by: David Riley <davidriley@chromium.org> (v1)
Tested-by: David Riley <davidriley@chromium.org> (v1)
Acked-by: Gurchetan Singh <gurchetansingh@chromium.org>
macos/master
Chia-I Wu 5 years ago
parent 2e85b7b93c
commit 979653e73c
  1. 22
      src/virgl_gbm.c

@ -321,13 +321,16 @@ int virgl_gbm_transfer(struct gbm_bo *bo, uint32_t direction, struct iovec *iove
if (!layout) if (!layout)
return -1; return -1;
guest_plane_offset = host_map_stride0 = guest_stride0 = 0; host_map_stride0 = 0;
uint32_t map_flags = (direction == VIRGL_TRANSFER_TO_HOST) ? GBM_BO_TRANSFER_WRITE : uint32_t map_flags = (direction == VIRGL_TRANSFER_TO_HOST) ? GBM_BO_TRANSFER_WRITE :
GBM_BO_TRANSFER_READ; GBM_BO_TRANSFER_READ;
void *addr = gbm_bo_map(bo, 0, 0, width, height, map_flags, &host_map_stride0, &map_data); void *addr = gbm_bo_map(bo, 0, 0, width, height, map_flags, &host_map_stride0, &map_data);
if (!addr) if (!addr)
return -1; return -1;
guest_plane_offset = info->offset;
guest_stride0 = 0;
/* /*
* Unfortunately, the kernel doesn't actually pass the guest layer_stride and * Unfortunately, the kernel doesn't actually pass the guest layer_stride and
* guest stride to the host (compare virtio_gpu.h and virtgpu_drm.h). We can use * guest stride to the host (compare virtio_gpu.h and virtgpu_drm.h). We can use
@ -359,19 +362,32 @@ int virgl_gbm_transfer(struct gbm_bo *bo, uint32_t direction, struct iovec *iove
uint32_t host_plane_stride = plane == 0 uint32_t host_plane_stride = plane == 0
? host_map_stride0 : gbm_bo_get_stride_for_plane(bo, plane); ? host_map_stride0 : gbm_bo_get_stride_for_plane(bo, plane);
uint32_t guest_resource_offset = guest_plane_offset + (subsampled_y * guest_plane_stride) uint32_t guest_resource_offset = guest_plane_offset;
+ subsampled_x * layout->bytes_per_pixel[plane];
uint32_t host_resource_offset = host_plane_offset + (subsampled_y * host_plane_stride) uint32_t host_resource_offset = host_plane_offset + (subsampled_y * host_plane_stride)
+ subsampled_x * layout->bytes_per_pixel[plane]; + subsampled_x * layout->bytes_per_pixel[plane];
uint8_t *host_address = (uint8_t*)addr + host_resource_offset; uint8_t *host_address = (uint8_t*)addr + host_resource_offset;
/*
* Here we apply another hack. info->offset does not account for
* info->box for planar resources and we need to make adjustments.
*/
if (plane_count > 1) {
guest_resource_offset += (subsampled_y * guest_plane_stride)
+ subsampled_x * layout->bytes_per_pixel[plane];
}
virgl_gbm_transfer_internal(layout->bytes_per_pixel[plane], subsampled_width, virgl_gbm_transfer_internal(layout->bytes_per_pixel[plane], subsampled_width,
subsampled_height, guest_plane_stride, guest_resource_offset, subsampled_height, guest_plane_stride, guest_resource_offset,
host_plane_stride, host_address, iovecs, num_iovecs, direction); host_plane_stride, host_address, iovecs, num_iovecs, direction);
if (info->layer_stride) {
guest_plane_offset += (info->layer_stride * plane_byte_ratio)
/ (layout->horizontal_subsampling[plane] * layout->vertical_subsampling[plane]);
} else {
guest_plane_offset += plane_height * guest_plane_stride; guest_plane_offset += plane_height * guest_plane_stride;
} }
}
gbm_bo_unmap(bo, map_data); gbm_bo_unmap(bo, map_data);
return 0; return 0;

Loading…
Cancel
Save