diff --git a/src/gallium/auxiliary/target-helpers/drm_helper.h b/src/gallium/auxiliary/target-helpers/drm_helper.h index b63c60e8d64..a508cf4016a 100644 --- a/src/gallium/auxiliary/target-helpers/drm_helper.h +++ b/src/gallium/auxiliary/target-helpers/drm_helper.h @@ -421,7 +421,7 @@ static struct pipe_screen * pipe_zink_create_screen(int fd, const struct pipe_screen_config *config) { struct pipe_screen *screen; - screen = zink_drm_create_screen(fd, config); + screen = zink_drm_create_screen(fd, config, NULL); return screen ? debug_screen_wrap(screen) : NULL; } diff --git a/src/gallium/drivers/zink/zink_public.h b/src/gallium/drivers/zink/zink_public.h index 235769688c5..c2fe87325ed 100644 --- a/src/gallium/drivers/zink/zink_public.h +++ b/src/gallium/drivers/zink/zink_public.h @@ -25,6 +25,7 @@ #define ZINK_PUBLIC_H struct pipe_screen; +struct renderonly; struct sw_winsys; struct pipe_screen_config; @@ -32,7 +33,7 @@ struct pipe_screen * zink_create_screen(struct sw_winsys *winsys, const struct pipe_screen_config *config); struct pipe_screen * -zink_drm_create_screen(int fd, const struct pipe_screen_config *config); +zink_drm_create_screen(int fd, const struct pipe_screen_config *config, struct renderonly *ro); struct pipe_screen * zink_win32_create_screen(uint64_t adapter_luid); #endif diff --git a/src/gallium/drivers/zink/zink_resource.c b/src/gallium/drivers/zink/zink_resource.c index 404dd0e132f..834bfeac433 100644 --- a/src/gallium/drivers/zink/zink_resource.c +++ b/src/gallium/drivers/zink/zink_resource.c @@ -255,6 +255,12 @@ zink_resource_destroy(struct pipe_screen *pscreen, struct zink_resource *res = zink_resource(pres); /* prevent double-free when unrefing internal surfaces */ res->base.b.reference.count = 999; + +#ifdef HAVE_LIBDRM + if (res->ro_scanout) + renderonly_scanout_destroy(res->ro_scanout, screen->ro); +#endif + if (pres->target == PIPE_BUFFER) { util_range_destroy(&res->valid_buffer_range); util_idalloc_mt_free(&screen->buffer_ids, res->base.buffer_id_unique); @@ -1610,8 +1616,52 @@ resource_create(struct pipe_screen *pscreen, if (templ2.flags & PIPE_RESOURCE_FLAG_SPARSE && (util_res_sample_count(templ) == 1 || screen->info.feats.features.shaderStorageImageMultisample)) templ2.bind |= PIPE_BIND_SHADER_IMAGE; + +#ifdef HAVE_LIBDRM + if (!whandle && screen->ro && (templ2.bind & PIPE_BIND_SCANOUT)) { + struct winsys_handle handle; + + assert(screen->info.have_EXT_image_drm_format_modifier); + + /* Only LINEAR is considered the appropriate modifier for scaning out + * now, so sort out it if it's present, and fail if a modifier list is + * present but does not include LINEAR. + */ + for (int i = 0; i < modifiers_count; i++) { + if (res->modifiers[i] == DRM_FORMAT_MOD_LINEAR) { + res->modifiers[0] = DRM_FORMAT_MOD_LINEAR; + res->modifiers_count = 1; + break; + } + } + + if (modifiers_count > 0 && res->modifiers[0] != DRM_FORMAT_MOD_LINEAR) { + /* Failed to find LINEAR in the modifier list */ + free(res->modifiers); + FREE_CL(res); + return NULL; + } + + res->ro_scanout = + renderonly_scanout_for_resource(&templ2, screen->ro, &handle); + + if (!res->ro_scanout) { + free(res->modifiers); + FREE_CL(res); + return NULL; + } + assert(handle.type == WINSYS_HANDLE_TYPE_FD); + assert(handle.modifier == DRM_FORMAT_MOD_LINEAR); + whandle = &handle; + } +#endif + res->obj = resource_object_create(screen, &templ2, whandle, &linear, res->modifiers, res->modifiers_count, loader_private, user_mem); if (!res->obj) { +#ifdef HAVE_LIBDRM + if (res->ro_scanout) + renderonly_scanout_destroy(res->ro_scanout, screen->ro); +#endif free(res->modifiers); FREE_CL(res); return NULL; @@ -1852,6 +1902,12 @@ zink_resource_get_param(struct pipe_screen *pscreen, struct pipe_context *pctx, break; case PIPE_RESOURCE_PARAM_STRIDE: { +#ifdef HAVE_LIBDRM + if (res->ro_scanout) { + *value = res->ro_scanout->stride; + break; + } +#endif VkImageSubresource sub_res = {0}; VkSubresourceLayout sub_res_layout = {0}; @@ -1864,6 +1920,12 @@ zink_resource_get_param(struct pipe_screen *pscreen, struct pipe_context *pctx, } case PIPE_RESOURCE_PARAM_OFFSET: { +#ifdef HAVE_LIBDRM + if (res->ro_scanout) { + *value = 0; + break; + } +#endif VkImageSubresource isr = { aspect, level, @@ -1941,6 +2003,10 @@ zink_resource_get_handle(struct pipe_screen *pscreen, { if (tex->target == PIPE_BUFFER) tc_buffer_disable_cpu_storage(tex); +#ifdef HAVE_LIBDRM + if (whandle->type == WINSYS_HANDLE_TYPE_KMS && zink_screen(pscreen)->ro) + return renderonly_get_handle(zink_resource(tex)->ro_scanout, whandle); +#endif if (whandle->type == WINSYS_HANDLE_TYPE_FD || whandle->type == WINSYS_HANDLE_TYPE_KMS) { #ifdef ZINK_USE_DMABUF while (whandle->plane && tex->next && !zink_resource_is_aux_plane(tex->next)) { @@ -2036,8 +2102,10 @@ zink_resource_from_handle(struct pipe_screen *pscreen, unsigned usage) { #ifdef ZINK_USE_DMABUF + struct zink_screen *screen = zink_screen(pscreen); + if (whandle->modifier != DRM_FORMAT_MOD_INVALID && - !zink_screen(pscreen)->info.have_EXT_image_drm_format_modifier) + !screen->info.have_EXT_image_drm_format_modifier) return NULL; struct pipe_resource templ2 = *templ; @@ -2070,6 +2138,19 @@ zink_resource_from_handle(struct pipe_screen *pscreen, res->obj->immutable_handle = true; res->internal_format = whandle->format; } + +#ifdef HAVE_LIBDRM + if (screen->ro) { + struct zink_resource *res = zink_resource(pres); + + /* Make sure that renderonly has a handle to our buffer in the display's + * fd, so that a later renderonly_get_handle() returns correct handles + * or GEM names. + */ + res->ro_scanout = renderonly_create_gpu_import_for_resource(pres, screen->ro, NULL); + } +#endif + return pres; #else return NULL; diff --git a/src/gallium/drivers/zink/zink_screen.c b/src/gallium/drivers/zink/zink_screen.c index 04bf3e35019..3c792fd149a 100644 --- a/src/gallium/drivers/zink/zink_screen.c +++ b/src/gallium/drivers/zink/zink_screen.c @@ -169,6 +169,14 @@ zink_get_device_vendor(struct pipe_screen *pscreen) return zink_screen(pscreen)->vendor_name; } +static int +zink_get_screen_fd(struct pipe_screen *pscreen) +{ + struct zink_screen *screen = zink_screen(pscreen); + + return screen->drm_fd; +} + static const char * zink_get_name(struct pipe_screen *pscreen) { @@ -1662,6 +1670,11 @@ zink_destroy_screen(struct pipe_screen *pscreen) if (screen->loader_lib) util_dl_close(screen->loader_lib); +#ifdef HAVE_LIBDRM + if (screen->ro) + screen->ro->destroy(screen->ro); +#endif + if (screen->drm_fd != -1) close(screen->drm_fd); @@ -3613,6 +3626,7 @@ zink_internal_create_screen(const struct pipe_screen_config *config, int64_t dev for (unsigned i = 0; i < ARRAY_SIZE(screen->base.nir_options); i++) screen->base.nir_options[i] = &screen->nir_options; + screen->base.get_screen_fd = zink_get_screen_fd; screen->base.get_name = zink_get_name; if (screen->instance_info->have_KHR_external_memory_capabilities) { screen->base.get_device_uuid = zink_get_device_uuid; @@ -3869,25 +3883,44 @@ free_device: } struct pipe_screen * -zink_drm_create_screen(int fd, const struct pipe_screen_config *config) +zink_drm_create_screen(int fd, const struct pipe_screen_config *config, struct renderonly *ro) { int64_t dev_major, dev_minor; - struct zink_screen *ret; + struct zink_screen *ret = NULL; if (zink_render_rdev(fd, &dev_major, &dev_minor)) return NULL; ret = zink_internal_create_screen(config, dev_major, dev_minor, 0); - - if (ret) - ret->drm_fd = os_dupfd_cloexec(fd); - if (ret && !ret->info.have_KHR_external_memory_fd) { - debug_printf("ZINK: KHR_external_memory_fd required!\n"); - zink_destroy_screen(&ret->base); + if (!ret) return NULL; + + ret->drm_fd = os_dupfd_cloexec(fd); +#ifdef HAVE_LIBDRM + ret->ro = ro; +#else + assert(!ro); +#endif + + if (!ret->info.have_KHR_external_memory_fd) { + debug_printf("ZINK: KHR_external_memory_fd required!\n"); + goto fail; + } + + /* + * Renderonly device may allocate buffers with arbitrary stride that + * can only be supported with EXT_image_drm_format_modifier. + */ + if (ro && !ret->info.have_EXT_image_drm_format_modifier) { + debug_printf("ZINK: EXT_image_drm_format_modifier required for renderonly GPUs!\n"); + goto fail; } return &ret->base; + +fail: + zink_destroy_screen(&ret->base); + return NULL; } struct pipe_screen * diff --git a/src/gallium/drivers/zink/zink_types.h b/src/gallium/drivers/zink/zink_types.h index 76857db2bbf..6adc5eb76a7 100644 --- a/src/gallium/drivers/zink/zink_types.h +++ b/src/gallium/drivers/zink/zink_types.h @@ -40,6 +40,11 @@ #include "util/pb_slab.h" #include "util/blob.h" + +#ifdef HAVE_LIBDRM +#include "renderonly/renderonly.h" +#endif + #include "util/disk_cache.h" #include "util/hash_table.h" #include "util/list.h" @@ -1323,6 +1328,10 @@ struct zink_resource { uint8_t modifiers_count; uint64_t *modifiers; + +#ifdef HAVE_LIBDRM + struct renderonly_scanout *ro_scanout; +#endif }; static inline struct zink_resource * @@ -1398,6 +1407,9 @@ struct zink_screen { bool device_lost; int drm_fd; +#ifdef HAVE_LIBDRM + struct renderonly *ro; +#endif struct slab_parent_pool transfer_pool; struct disk_cache *disk_cache;