diff --git a/src/virgl_egl.h b/src/virgl_egl.h index 73df209..b52041b 100644 --- a/src/virgl_egl.h +++ b/src/virgl_egl.h @@ -54,5 +54,6 @@ int virgl_egl_get_fd_for_texture2(struct virgl_egl *egl, uint32_t tex_id, int *f int *offset); void *virgl_egl_image_from_dmabuf(struct virgl_egl *egl, struct gbm_bo *bo); +void *virgl_egl_aux_plane_image_from_dmabuf(struct virgl_egl *egl, struct gbm_bo *bo, int plane); void virgl_egl_image_destroy(struct virgl_egl *egl, void *image); #endif diff --git a/src/virgl_egl_context.c b/src/virgl_egl_context.c index 2d81c09..5e191f9 100644 --- a/src/virgl_egl_context.c +++ b/src/virgl_egl_context.c @@ -381,7 +381,7 @@ void *virgl_egl_image_from_dmabuf(struct virgl_egl *egl, struct gbm_bo *bo) { int ret; EGLImageKHR image; - int fds[4] = {-1, -1, -1, -1}; + int fds[VIRGL_GBM_MAX_PLANES] = {-1, -1, -1, -1}; int num_planes = gbm_bo_get_plane_count(bo); // When the bo has 3 planes with modifier support, it requires 37 components. EGLint khr_image_attrs[37] = { @@ -394,7 +394,7 @@ void *virgl_egl_image_from_dmabuf(struct virgl_egl *egl, struct gbm_bo *bo) EGL_NONE, }; - if (num_planes < 0 || num_planes > 4) + if (num_planes < 0 || num_planes > VIRGL_GBM_MAX_PLANES) return (void *)EGL_NO_IMAGE_KHR; for (int plane = 0; plane < num_planes; plane++) { @@ -437,6 +437,55 @@ out_close: return (void*)image; } +void *virgl_egl_aux_plane_image_from_dmabuf(struct virgl_egl *egl, struct gbm_bo *bo, int plane) +{ + int ret; + EGLImageKHR image = EGL_NO_IMAGE_KHR; + int fd = -1; + + int bytes_per_pixel = virgl_gbm_get_plane_bytes_per_pixel(bo, plane); + if (bytes_per_pixel != 1 && bytes_per_pixel != 2) + return (void *)EGL_NO_IMAGE_KHR; + + uint32_t handle = gbm_bo_get_handle_for_plane(bo, plane).u32; + ret = drmPrimeHandleToFD(gbm_device_get_fd(egl->gbm->device), handle, DRM_CLOEXEC, &fd); + if (ret < 0) { + vrend_printf("failed to export plane handle %d\n", errno); + return (void *)EGL_NO_IMAGE_KHR; + } + + EGLint khr_image_attrs[17] = { + EGL_WIDTH, + virgl_gbm_get_plane_width(bo, plane), + EGL_HEIGHT, + virgl_gbm_get_plane_height(bo, plane), + EGL_LINUX_DRM_FOURCC_EXT, + (int) (bytes_per_pixel == 1 ? GBM_FORMAT_R8 : GBM_FORMAT_GR88), + EGL_DMA_BUF_PLANE0_FD_EXT, + fd, + EGL_DMA_BUF_PLANE0_OFFSET_EXT, + gbm_bo_get_offset(bo, plane), + EGL_DMA_BUF_PLANE0_PITCH_EXT, + gbm_bo_get_stride_for_plane(bo, plane), + }; + + if (egl->have_ext_image_dma_buf_import_modifiers) { + const uint64_t modifier = gbm_bo_get_modifier(bo); + khr_image_attrs[12] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT; + khr_image_attrs[13] = modifier & 0xfffffffful; + khr_image_attrs[14] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT; + khr_image_attrs[15] = modifier >> 32; + khr_image_attrs[16] = EGL_NONE; + } else { + khr_image_attrs[12] = EGL_NONE; + } + + image = eglCreateImageKHR(egl->egl_display, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, khr_image_attrs); + + close(fd); + return (void*)image; +} + void virgl_egl_image_destroy(struct virgl_egl *egl, void *image) { eglDestroyImageKHR(egl->egl_display, image); diff --git a/src/virgl_gbm.c b/src/virgl_gbm.c index 7764c10..ef22fa8 100644 --- a/src/virgl_gbm.c +++ b/src/virgl_gbm.c @@ -44,9 +44,9 @@ struct planar_layout { size_t num_planes; - int horizontal_subsampling[4]; - int vertical_subsampling[4]; - int bytes_per_pixel[4]; + int horizontal_subsampling[VIRGL_GBM_MAX_PLANES]; + int vertical_subsampling[VIRGL_GBM_MAX_PLANES]; + int bytes_per_pixel[VIRGL_GBM_MAX_PLANES]; }; struct format_conversion { @@ -404,16 +404,16 @@ int virgl_gbm_export_fd(struct gbm_device *gbm, uint32_t handle, int32_t *out_fd int virgl_gbm_export_query(struct gbm_bo *bo, struct virgl_renderer_export_query *query) { int ret = -1; - uint32_t handles[4] = {0, 0, 0, 0}; + uint32_t handles[VIRGL_GBM_MAX_PLANES] = { 0 }; struct gbm_device *gbm = gbm_bo_get_device(bo); int num_planes = gbm_bo_get_plane_count(bo); - if (num_planes < 0 || num_planes > 4) + if (num_planes < 0 || num_planes > VIRGL_GBM_MAX_PLANES) return ret; query->out_num_fds = 0; query->out_fourcc = 0; query->out_modifier = 0; - for (int plane = 0; plane < 4; plane++) { + for (int plane = 0; plane < VIRGL_GBM_MAX_PLANES; plane++) { query->out_fds[plane] = -1; query->out_strides[plane] = 0; query->out_offsets[plane] = 0; @@ -446,7 +446,7 @@ int virgl_gbm_export_query(struct gbm_bo *bo, struct virgl_renderer_export_query return 0; err_close: - for (int plane = 0; plane < 4; plane++) { + for (int plane = 0; plane < VIRGL_GBM_MAX_PLANES; plane++) { if (query->out_fds[plane] >= 0) { close(query->out_fds[plane]); query->out_fds[plane] = -1; @@ -459,3 +459,27 @@ err_close: query->out_num_fds = 0; return ret; } + +int virgl_gbm_get_plane_width(struct gbm_bo *bo, int plane) { + uint32_t format = gbm_bo_get_format(bo); + const struct planar_layout *layout = layout_from_format(format); + if (!layout) + return -1; + return gbm_bo_get_width(bo) / layout->horizontal_subsampling[plane]; +} + +int virgl_gbm_get_plane_height(struct gbm_bo *bo, int plane) { + uint32_t format = gbm_bo_get_format(bo); + const struct planar_layout *layout = layout_from_format(format); + if (!layout) + return -1; + return gbm_bo_get_height(bo) / layout->vertical_subsampling[plane]; +} + +int virgl_gbm_get_plane_bytes_per_pixel(struct gbm_bo *bo, int plane) { + uint32_t format = gbm_bo_get_format(bo); + const struct planar_layout *layout = layout_from_format(format); + if (!layout) + return -1; + return layout->bytes_per_pixel[plane]; +} diff --git a/src/virgl_gbm.h b/src/virgl_gbm.h index ee53338..08469fe 100644 --- a/src/virgl_gbm.h +++ b/src/virgl_gbm.h @@ -29,6 +29,12 @@ #include "vrend_iov.h" #include "virglrenderer.h" +#ifdef GBM_MAX_PLANES +#define VIRGL_GBM_MAX_PLANES GBM_MAX_PLANES +#else +#define VIRGL_GBM_MAX_PLANES 4 +#endif + /* * If fd >= 0, virglrenderer owns the fd since it was opened via a rendernode * query. If fd < 0, the gbm device was opened with the fd provided by the @@ -54,4 +60,8 @@ int virgl_gbm_export_fd(struct gbm_device *gbm, uint32_t handle, int32_t *out_fd int virgl_gbm_export_query(struct gbm_bo *bo, struct virgl_renderer_export_query *query); +int virgl_gbm_get_plane_width(struct gbm_bo *bo, int plane); +int virgl_gbm_get_plane_height(struct gbm_bo *bo, int plane); +int virgl_gbm_get_plane_bytes_per_pixel(struct gbm_bo *bo, int plane); + #endif diff --git a/src/vrend_renderer.c b/src/vrend_renderer.c index c0c8e4b..6083e7c 100644 --- a/src/vrend_renderer.c +++ b/src/vrend_renderer.c @@ -2125,6 +2125,13 @@ int vrend_create_sampler_view(struct vrend_context *ctx, view->srgb_decode); } glBindTexture(view->target, 0); + } else if (needs_view && view->val0 && view->val0 <= ARRAY_SIZE(res->aux_plane_egl_image) && + res->aux_plane_egl_image[view->val0 - 1]) { + void *image = res->aux_plane_egl_image[view->val0 - 1]; + glGenTextures(1, &view->id); + glBindTexture(view->target, view->id); + glEGLImageTargetTexture2DOES(view->target, (GLeglImageOES) image); + glBindTexture(view->target, 0); } } @@ -6523,6 +6530,15 @@ static int vrend_renderer_resource_allocate_texture(struct vrend_resource *gr, glBindTexture(gr->target, 0); + if (image_oes && gr->gbm_bo) { +#ifdef ENABLE_GBM_ALLOCATION + for (int i = 0; i < gbm_bo_get_plane_count(gr->gbm_bo) - 1; i++) { + gr->aux_plane_egl_image[i] = + virgl_egl_aux_plane_image_from_dmabuf(egl, gr->gbm_bo, i + 1); + } +#endif + } + gt->state.max_lod = -1; gt->cur_swizzle_r = gt->cur_swizzle_g = gt->cur_swizzle_b = gt->cur_swizzle_a = -1; gt->cur_base = -1; @@ -6648,8 +6664,14 @@ void vrend_renderer_resource_destroy(struct vrend_resource *res) } #ifdef ENABLE_GBM_ALLOCATION - if (res->egl_image) + if (res->egl_image) { virgl_egl_image_destroy(egl, res->egl_image); + for (unsigned i = 0; i < ARRAY_SIZE(res->aux_plane_egl_image); i++) { + if (res->aux_plane_egl_image[i]) { + virgl_egl_image_destroy(egl, res->aux_plane_egl_image[i]); + } + } + } if (res->gbm_bo) gbm_bo_destroy(res->gbm_bo); #endif diff --git a/src/vrend_renderer.h b/src/vrend_renderer.h index d73b1ab..c544635 100644 --- a/src/vrend_renderer.h +++ b/src/vrend_renderer.h @@ -31,6 +31,7 @@ #include "vrend_debug.h" #include "vrend_tweaks.h" #include "vrend_iov.h" +#include "virgl_gbm.h" #include "virgl_hw.h" #include @@ -98,6 +99,7 @@ struct vrend_resource { uint32_t num_iovs; uint64_t mipmap_offsets[VR_MAX_TEXTURE_2D_LEVELS]; void *gbm_bo, *egl_image; + void *aux_plane_egl_image[VIRGL_GBM_MAX_PLANES - 1]; }; #define VIRGL_TEXTURE_NEED_SWIZZLE (1 << 0)