diff --git a/src/gallium/auxiliary/renderonly/renderonly.c b/src/gallium/auxiliary/renderonly/renderonly.c index d3ed214f4e4..da91f12b2ea 100644 --- a/src/gallium/auxiliary/renderonly/renderonly.c +++ b/src/gallium/auxiliary/renderonly/renderonly.c @@ -50,27 +50,12 @@ renderonly_dup(const struct renderonly *ro) return copy; } -struct renderonly_scanout * -renderonly_scanout_for_prime(struct pipe_resource *rsc, struct renderonly *ro) -{ - struct renderonly_scanout *scanout; - - scanout = CALLOC_STRUCT(renderonly_scanout); - if (!scanout) - return NULL; - - scanout->prime = rsc; - - return scanout; -} - void renderonly_scanout_destroy(struct renderonly_scanout *scanout, struct renderonly *ro) { struct drm_mode_destroy_dumb destroy_dumb = { }; - pipe_resource_reference(&scanout->prime, NULL); if (ro->kms_fd != -1) { destroy_dumb.handle = scanout->handle; drmIoctl(ro->kms_fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_dumb); @@ -80,12 +65,11 @@ renderonly_scanout_destroy(struct renderonly_scanout *scanout, struct renderonly_scanout * renderonly_create_kms_dumb_buffer_for_resource(struct pipe_resource *rsc, - struct renderonly *ro) + struct renderonly *ro, + struct winsys_handle *out_handle) { - struct pipe_screen *screen = rsc->screen; struct renderonly_scanout *scanout; - struct winsys_handle handle; - int prime_fd, err; + int err; struct drm_mode_create_dumb create_dumb = { .width = rsc->width0, .height = rsc->height0, @@ -108,30 +92,21 @@ renderonly_create_kms_dumb_buffer_for_resource(struct pipe_resource *rsc, scanout->handle = create_dumb.handle; scanout->stride = create_dumb.pitch; - /* export dumb buffer */ + if (!out_handle) + return scanout; + + /* fill in winsys handle */ + memset(out_handle, 0, sizeof(*out_handle)); + out_handle->type = DRM_API_HANDLE_TYPE_FD; + out_handle->stride = create_dumb.pitch; + err = drmPrimeHandleToFD(ro->kms_fd, create_dumb.handle, O_CLOEXEC, - &prime_fd); + (int *)&out_handle->handle); if (err < 0) { fprintf(stderr, "failed to export dumb buffer: %s\n", strerror(errno)); goto free_dumb; } - /* import dumb buffer */ - memset(&handle, 0, sizeof(handle)); - handle.type = DRM_API_HANDLE_TYPE_FD; - handle.handle = prime_fd; - handle.stride = create_dumb.pitch; - - scanout->prime = screen->resource_from_handle(screen, rsc, - &handle, PIPE_HANDLE_USAGE_READ_WRITE); - - close(prime_fd); - - if (!scanout->prime) { - fprintf(stderr, "failed to create resource_from_handle: %s\n", strerror(errno)); - goto free_dumb; - } - return scanout; free_dumb: @@ -146,7 +121,8 @@ free_scanout: struct renderonly_scanout * renderonly_create_gpu_import_for_resource(struct pipe_resource *rsc, - struct renderonly *ro) + struct renderonly *ro, + struct winsys_handle *out_handle) { struct pipe_screen *screen = rsc->screen; struct renderonly_scanout *scanout; diff --git a/src/gallium/auxiliary/renderonly/renderonly.h b/src/gallium/auxiliary/renderonly/renderonly.h index 70641c45878..6a89c29e2ef 100644 --- a/src/gallium/auxiliary/renderonly/renderonly.h +++ b/src/gallium/auxiliary/renderonly/renderonly.h @@ -34,8 +34,6 @@ struct renderonly_scanout { uint32_t handle; uint32_t stride; - - struct pipe_resource *prime; }; struct renderonly { @@ -59,7 +57,8 @@ struct renderonly { * to be done in flush_resource(..) like a resolve to linear. */ struct renderonly_scanout *(*create_for_resource)(struct pipe_resource *rsc, - struct renderonly *ro); + struct renderonly *ro, + struct winsys_handle *out_handle); int kms_fd; int gpu_fd; }; @@ -68,14 +67,13 @@ struct renderonly * renderonly_dup(const struct renderonly *ro); static inline struct renderonly_scanout * -renderonly_scanout_for_resource(struct pipe_resource *rsc, struct renderonly *ro) +renderonly_scanout_for_resource(struct pipe_resource *rsc, + struct renderonly *ro, + struct winsys_handle *out_handle) { - return ro->create_for_resource(rsc, ro); + return ro->create_for_resource(rsc, ro, out_handle); } -struct renderonly_scanout * -renderonly_scanout_for_prime(struct pipe_resource *rsc, struct renderonly *ro); - void renderonly_scanout_destroy(struct renderonly_scanout *scanout, struct renderonly *ro); @@ -99,13 +97,15 @@ renderonly_get_handle(struct renderonly_scanout *scanout, */ struct renderonly_scanout * renderonly_create_kms_dumb_buffer_for_resource(struct pipe_resource *rsc, - struct renderonly *ro); + struct renderonly *ro, + struct winsys_handle *out_handle); /** * Import GPU resource into scanout hw. */ struct renderonly_scanout * renderonly_create_gpu_import_for_resource(struct pipe_resource *rsc, - struct renderonly *ro); + struct renderonly *ro, + struct winsys_handle *out_handle); #endif /* RENDERONLY_H_ */ diff --git a/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c b/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c index d9ff9624fa4..b832dd8f263 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c +++ b/src/gallium/drivers/etnaviv/etnaviv_clear_blit.c @@ -610,10 +610,10 @@ etna_flush_resource(struct pipe_context *pctx, struct pipe_resource *prsc) { struct etna_resource *rsc = etna_resource(prsc); - if (rsc->scanout) { - if (etna_resource_older(etna_resource(rsc->scanout->prime), rsc)) { - etna_copy_resource(pctx, rsc->scanout->prime, prsc, 0, 0); - etna_resource(rsc->scanout->prime)->seqno = rsc->seqno; + if (rsc->external) { + if (etna_resource_older(etna_resource(rsc->external), rsc)) { + etna_copy_resource(pctx, rsc->external, prsc, 0, 0); + etna_resource(rsc->external)->seqno = rsc->seqno; } } else if (etna_resource_needs_flush(rsc)) { etna_copy_resource(pctx, prsc, prsc, 0, 0); diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.c b/src/gallium/drivers/etnaviv/etnaviv_resource.c index a709482c1b6..8d96baf2a04 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_resource.c +++ b/src/gallium/drivers/etnaviv/etnaviv_resource.c @@ -214,8 +214,20 @@ etna_resource_alloc(struct pipe_screen *pscreen, unsigned layout, rsc->bo = bo; rsc->ts_bo = 0; /* TS is only created when first bound to surface */ - if (templat->bind & PIPE_BIND_SCANOUT) - rsc->scanout = renderonly_scanout_for_resource(&rsc->base, screen->ro); + if (templat->bind & PIPE_BIND_SCANOUT) { + struct winsys_handle handle; + rsc->scanout = renderonly_scanout_for_resource(&rsc->base, screen->ro, + &handle); + if (!rsc->scanout) + goto free_rsc; + + rsc->external = pscreen->resource_from_handle(pscreen, &rsc->base, + &handle, + PIPE_HANDLE_USAGE_WRITE); + close(handle.handle); + if (!rsc->external) + goto free_rsc; + } if (DBG_ENABLED(ETNA_DBG_ZERO)) { void *map = etna_bo_map(bo); @@ -310,6 +322,7 @@ etna_resource_destroy(struct pipe_screen *pscreen, struct pipe_resource *prsc) list_delinit(&rsc->list); pipe_resource_reference(&rsc->texture, NULL); + pipe_resource_reference(&rsc->external, NULL); FREE(rsc); } @@ -379,16 +392,12 @@ etna_resource_from_handle(struct pipe_screen *pscreen, /* Render targets are linear in Xorg but must be tiled * here. It would be nice if dri_drawable_get_format() * set scanout for these buffers too. */ - struct etna_resource *tiled; ptiled = etna_resource_create(pscreen, tmpl); if (!ptiled) goto fail; - tiled = etna_resource(ptiled); - tiled->scanout = renderonly_scanout_for_prime(prsc, screen->ro); - if (!tiled->scanout) - goto fail; + etna_resource(ptiled)->external = prsc; return ptiled; } @@ -410,9 +419,18 @@ etna_resource_get_handle(struct pipe_screen *pscreen, struct winsys_handle *handle, unsigned usage) { struct etna_resource *rsc = etna_resource(prsc); + /* Scanout is always attached to the base resource */ + struct renderonly_scanout *scanout = rsc->scanout; + + /* + * External resources are preferred, so a import->export chain of + * render/sampler incompatible buffers yield the same handle. + */ + if (rsc->external) + rsc = etna_resource(rsc->external); if (handle->type == DRM_API_HANDLE_TYPE_KMS && - renderonly_get_handle(rsc->scanout, handle)) + renderonly_get_handle(scanout, handle)) return TRUE; return etna_screen_bo_get_handle(pscreen, rsc->bo, rsc->levels[0].stride, diff --git a/src/gallium/drivers/etnaviv/etnaviv_resource.h b/src/gallium/drivers/etnaviv/etnaviv_resource.h index 3507e5ccecb..5f563c06adc 100644 --- a/src/gallium/drivers/etnaviv/etnaviv_resource.h +++ b/src/gallium/drivers/etnaviv/etnaviv_resource.h @@ -75,6 +75,11 @@ struct etna_resource { /* When we are rendering to a texture, we need a differently tiled resource */ struct pipe_resource *texture; + /* + * If imported resources have an render/sampler incompatible tiling, we keep + * them as an external resource, which is blitted as needed. + */ + struct pipe_resource *external; enum etna_resource_status status; diff --git a/src/gallium/drivers/vc4/vc4_resource.c b/src/gallium/drivers/vc4/vc4_resource.c index 94301bd4114..2018dc36d93 100644 --- a/src/gallium/drivers/vc4/vc4_resource.c +++ b/src/gallium/drivers/vc4/vc4_resource.c @@ -671,7 +671,7 @@ vc4_resource_create_with_modifiers(struct pipe_screen *pscreen, if (screen->ro && tmpl->bind & PIPE_BIND_SCANOUT) { rsc->scanout = - renderonly_scanout_for_resource(prsc, screen->ro); + renderonly_scanout_for_resource(prsc, screen->ro, NULL); if (!rsc->scanout) goto fail; } @@ -769,7 +769,8 @@ vc4_resource_from_handle(struct pipe_screen *pscreen, */ rsc->scanout = renderonly_create_gpu_import_for_resource(prsc, - screen->ro); + screen->ro, + NULL); if (!rsc->scanout) goto fail; }