diff --git a/src/freedreno/drm/freedreno_drmif.h b/src/freedreno/drm/freedreno_drmif.h index 16b027570913..930a476ab039 100644 --- a/src/freedreno/drm/freedreno_drmif.h +++ b/src/freedreno/drm/freedreno_drmif.h @@ -191,6 +191,7 @@ void fd_device_disable_explicit_sync_heuristic(struct fd_device *dev); enum fd_features { FD_FEATURE_DIRECT_RESET = 1, FD_FEATURE_IMPORT_DMABUF = 2, + FD_FEATURE_KGSL = 4, }; uint32_t fd_get_features(struct fd_device *dev); diff --git a/src/freedreno/drm/kgsl/kgsl_bo.c b/src/freedreno/drm/kgsl/kgsl_bo.c index d42400207ad8..c676b8197a5f 100644 --- a/src/freedreno/drm/kgsl/kgsl_bo.c +++ b/src/freedreno/drm/kgsl/kgsl_bo.c @@ -108,6 +108,10 @@ kgsl_bo_map(struct fd_bo *bo) static int kgsl_bo_dmabuf(struct fd_bo *bo) { struct kgsl_bo *kgsl_bo = to_kgsl_bo(bo); + + if (kgsl_bo->bo_type != KGSL_BO_IMPORT || kgsl_bo->import_fd < 0) + return -1; + return os_dupfd_cloexec(kgsl_bo->import_fd); } diff --git a/src/freedreno/drm/kgsl/kgsl_device.c b/src/freedreno/drm/kgsl/kgsl_device.c index 702b6666731b..76bd7de162da 100644 --- a/src/freedreno/drm/kgsl/kgsl_device.c +++ b/src/freedreno/drm/kgsl/kgsl_device.c @@ -28,7 +28,7 @@ kgsl_device_new(int fd) dev->funcs = &funcs; dev->fd = fd; dev->version = FD_VERSION_ROBUSTNESS; - dev->features = FD_FEATURE_DIRECT_RESET | FD_FEATURE_IMPORT_DMABUF; + dev->features = FD_FEATURE_DIRECT_RESET | FD_FEATURE_IMPORT_DMABUF | FD_FEATURE_KGSL; /* async submit_queue used for softpin deffered submits */ util_queue_init(&dev->submit_queue, "sq", 8, 1, 0, NULL); diff --git a/src/gallium/drivers/freedreno/freedreno_resource.c b/src/gallium/drivers/freedreno/freedreno_resource.c index 75b3f6f5ccf1..eefbad2282e3 100644 --- a/src/gallium/drivers/freedreno/freedreno_resource.c +++ b/src/gallium/drivers/freedreno/freedreno_resource.c @@ -1080,6 +1080,15 @@ fd_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc) static uint64_t fd_resource_modifier(struct fd_resource *rsc) { + struct fd_screen *screen = fd_screen(rsc->b.b.screen); + + if (screen->kgsl_dmabuf) { + if (rsc->layout.tile_mode == 0 && !rsc->layout.ubwc_layer_size) + return DRM_FORMAT_MOD_LINEAR; + + return DRM_FORMAT_MOD_INVALID; + } + if (rsc->layout.ubwc_layer_size) return DRM_FORMAT_MOD_QCOM_COMPRESSED; @@ -1106,6 +1115,23 @@ fd_resource_get_handle(struct pipe_screen *pscreen, struct pipe_context *pctx, handle->modifier = fd_resource_modifier(rsc); + if (fd_screen(pscreen)->kgsl_dmabuf) { + handle->modifier = DRM_FORMAT_MOD_LINEAR; + + if (!(prsc->bind & PIPE_BIND_SHARED)) { + struct fd_context *ctx = fd_screen_aux_context_get(pscreen); + + prsc->bind |= PIPE_BIND_SHARED; + + bool ret = fd_try_shadow_resource(ctx, rsc, 0, NULL, handle->modifier); + + fd_screen_aux_context_put(pscreen); + + if (!ret) + return false; + } + } + if (prsc->target != PIPE_BUFFER) { struct fdl_metadata metadata = { .modifier = handle->modifier, @@ -1311,6 +1337,20 @@ get_best_layout(struct fd_screen *screen, if (FD_DBG(NOTILE)) return FD_LAYOUT_LINEAR; + if (screen->kgsl_dmabuf && + (tmpl->bind & (PIPE_BIND_SHARED | PIPE_BIND_SCANOUT))) { + if (has_implicit_modifier(modifiers, count) || + drm_find_modifier(DRM_FORMAT_MOD_LINEAR, modifiers, count)) { + perf_debug("%" PRSC_FMT ": forcing linear: kgsl shared/scanout resource", + PRSC_ARGS(tmpl)); + return FD_LAYOUT_LINEAR; + } + + perf_debug("%" PRSC_FMT ": kgsl shared/scanout resource requires linear", + PRSC_ARGS(tmpl)); + return FD_LAYOUT_ERROR; + } + /* Shared resources without explicit modifiers must always be linear */ if (!can_explicit && (tmpl->bind & PIPE_BIND_SHARED)) { perf_debug("%" PRSC_FMT @@ -1529,6 +1569,15 @@ fd_resource_from_handle(struct pipe_screen *pscreen, DBG("%" PRSC_FMT ", modifier=%" PRIx64, PRSC_ARGS(prsc), handle->modifier); + if (screen->kgsl_dmabuf && + handle->modifier != DRM_FORMAT_MOD_LINEAR && + handle->modifier != DRM_FORMAT_MOD_INVALID) { + if (FD_DBG(LAYOUT)) + mesa_loge("kgsl cannot import non-linear modifier %" PRIx64, + handle->modifier); + goto fail; + } + rsc->b.is_shared = true; struct fd_bo *bo = fd_screen_bo_from_handle(pscreen, handle); diff --git a/src/gallium/drivers/freedreno/freedreno_screen.c b/src/gallium/drivers/freedreno/freedreno_screen.c index 70a90d6a367a..1d854b0b6e5e 100644 --- a/src/gallium/drivers/freedreno/freedreno_screen.c +++ b/src/gallium/drivers/freedreno/freedreno_screen.c @@ -91,6 +91,13 @@ DEBUG_GET_ONCE_FLAGS_OPTION(fd_mesa_debug, "FD_MESA_DEBUG", fd_debug_options, 0) int fd_mesa_debug = 0; bool fd_binning_enabled = true; +static bool +fd_kgsl_dmabuf_enabled(void) +{ + return debug_get_bool_option("FD_KGSL_ENABLE_DMABUF", false) || + debug_get_bool_option("XWAYLAND_FORCE_KGSL_SURFACELESS", false); +} + static const char * fd_screen_get_name(struct pipe_screen *pscreen) { @@ -383,14 +390,15 @@ fd_init_screen_caps(struct fd_screen *screen) u_init_pipe_screen_caps(&screen->base, 1); - /* On the kgsl stack the screen's control fd is the sde-kms display node - * (renderD128); drmGetCap(DRM_CAP_PRIME) there does not report the GPU's - * real PRIME import/export support, so u_init_pipe_screen_caps() leaves - * caps.dmabuf unset and EGL never advertises EGL_EXT_image_dma_buf_import - * (which kwin/GL compositors need to import client buffers). The kgsl - * backend does support dmabuf import/export (FD_FEATURE_IMPORT_DMABUF), so - * force the cap on. */ - caps->dmabuf = 0x1 /*DRM_PRIME_CAP_IMPORT*/ | 0x2 /*DRM_PRIME_CAP_EXPORT*/; + /* On the kgsl stack the screen's control fd may be a display/controller fd + * rather than the kgsl GPU fd, so drmGetCap(DRM_CAP_PRIME) cannot describe + * the backend's real import/export support. The kgsl backend allocates + * shared buffers from dma-heap/ION and imports them into KGSL, so advertise + * dmabuf support only for that path. */ + if (screen->kgsl_dmabuf) { + caps->dmabuf = + 0x1 /*DRM_PRIME_CAP_IMPORT*/ | 0x2 /*DRM_PRIME_CAP_EXPORT*/; + } /* this is probably not totally correct.. but it's a start: */ @@ -819,6 +827,23 @@ fd_screen_query_dmabuf_modifiers(struct pipe_screen *pscreen, uint64_t *modifiers, unsigned int *external_only, int *count) { + struct fd_screen *screen = fd_screen(pscreen); + + if (screen->kgsl_dmabuf) { + *count = is_format_supported(pscreen, format, + DRM_FORMAT_MOD_LINEAR) ? 1 : 0; + + if (*count && max > 0) { + if (modifiers) + modifiers[0] = DRM_FORMAT_MOD_LINEAR; + + if (external_only) + external_only[0] = !is_rendering_supported(pscreen, format); + } + + return; + } + const uint64_t all_modifiers[] = { DRM_FORMAT_MOD_LINEAR, DRM_FORMAT_MOD_QCOM_COMPRESSED, @@ -851,6 +876,13 @@ fd_screen_is_dmabuf_modifier_supported(struct pipe_screen *pscreen, enum pipe_format format, bool *external_only) { + struct fd_screen *screen = fd_screen(pscreen); + + if (screen->kgsl_dmabuf && + modifier != DRM_FORMAT_MOD_LINEAR && + modifier != DRM_FORMAT_MOD_INVALID) + return false; + return is_format_supported(pscreen, format, modifier); } @@ -951,6 +983,8 @@ fd_screen_create(int fd, pscreen = &screen->base; screen->dev = dev; + screen->is_kgsl = fd_get_features(dev) & FD_FEATURE_KGSL; + screen->kgsl_dmabuf = screen->is_kgsl && fd_kgsl_dmabuf_enabled(); screen->ro = ro; // maybe this should be in context? diff --git a/src/gallium/drivers/freedreno/freedreno_screen.h b/src/gallium/drivers/freedreno/freedreno_screen.h index f9e239ab1296..d3276c87a57d 100644 --- a/src/gallium/drivers/freedreno/freedreno_screen.h +++ b/src/gallium/drivers/freedreno/freedreno_screen.h @@ -75,6 +75,8 @@ struct fd_screen { bool has_timestamp; bool has_robustness; bool has_syncobj; + bool is_kgsl; + bool kgsl_dmabuf; struct { /* Conservative LRZ (default true) invalidates LRZ on draws with