From d760a9151b73d1998fceff38fb1c642e4d77bf67 Mon Sep 17 00:00:00 2001 From: Adam Jackson Date: Tue, 15 Mar 2022 15:36:28 -0400 Subject: [PATCH] gallium: Learn about kopper Reviewed-by: Mike Blumenkrantz Part-of: --- .../auxiliary/driver_trace/tr_screen.c | 36 ++ .../auxiliary/driver_trace/tr_screen.h | 2 + src/gallium/auxiliary/pipe-loader/meson.build | 4 +- .../auxiliary/pipe-loader/pipe_loader.h | 14 + .../auxiliary/pipe-loader/pipe_loader_sw.c | 126 +++- .../target-helpers/inline_sw_helper.h | 14 +- .../auxiliary/target-helpers/sw_helper.h | 21 +- .../target-helpers/sw_helper_public.h | 4 +- src/gallium/frontends/dri/dri2.c | 37 +- src/gallium/frontends/dri/dri_screen.h | 9 + src/gallium/frontends/dri/dri_util.c | 2 + src/gallium/frontends/dri/dri_util.h | 2 + src/gallium/frontends/dri/drisw.c | 12 +- src/gallium/frontends/dri/kopper.c | 591 ++++++++++++++++++ src/gallium/frontends/dri/meson.build | 6 +- src/gallium/include/frontend/sw_driver.h | 2 +- src/gallium/include/pipe/p_screen.h | 4 + src/gallium/targets/dri/target.c | 8 +- src/gallium/targets/pipe-loader/pipe_swrast.c | 4 +- src/gbm/backends/dri/gbm_dri.c | 25 +- 20 files changed, 894 insertions(+), 29 deletions(-) create mode 100644 src/gallium/frontends/dri/kopper.c diff --git a/src/gallium/auxiliary/driver_trace/tr_screen.c b/src/gallium/auxiliary/driver_trace/tr_screen.c index 6427ff2b511..7a9ec99d17f 100644 --- a/src/gallium/auxiliary/driver_trace/tr_screen.c +++ b/src/gallium/auxiliary/driver_trace/tr_screen.c @@ -667,6 +667,32 @@ trace_screen_resource_create(struct pipe_screen *_screen, return result; } +static struct pipe_resource * +trace_screen_resource_create_drawable(struct pipe_screen *_screen, + const struct pipe_resource *templat, + const void *loader_data) +{ + struct trace_screen *tr_scr = trace_screen(_screen); + struct pipe_screen *screen = tr_scr->screen; + struct pipe_resource *result; + + trace_dump_call_begin("pipe_screen", "resource_create_drawable"); + + trace_dump_arg(ptr, screen); + trace_dump_arg(resource_template, templat); + trace_dump_arg(ptr, loader_data); + + result = screen->resource_create_drawable(screen, templat, loader_data); + + trace_dump_ret(ptr, result); + + trace_dump_call_end(); + + if (result) + result->screen = _screen; + return result; +} + static struct pipe_resource * trace_screen_resource_create_with_modifiers(struct pipe_screen *_screen, const struct pipe_resource *templat, const uint64_t *modifiers, int modifiers_count) @@ -1283,6 +1309,7 @@ trace_screen_create(struct pipe_screen *screen) tr_scr->base.resource_create = trace_screen_resource_create; SCR_INIT(resource_create_with_modifiers); tr_scr->base.resource_create_unbacked = trace_screen_resource_create_unbacked; + SCR_INIT(resource_create_drawable); tr_scr->base.resource_bind_backing = trace_screen_resource_bind_backing; tr_scr->base.resource_from_handle = trace_screen_resource_from_handle; tr_scr->base.allocate_memory = trace_screen_allocate_memory; @@ -1345,3 +1372,12 @@ trace_screen(struct pipe_screen *screen) assert(screen->destroy == trace_screen_destroy); return (struct trace_screen *)screen; } + +struct pipe_screen * +trace_screen_unwrap(struct pipe_screen *_screen) +{ + if (_screen->destroy != trace_screen_destroy) + return _screen; + struct trace_screen *tr_scr = trace_screen(_screen); + return tr_scr->screen; +} diff --git a/src/gallium/auxiliary/driver_trace/tr_screen.h b/src/gallium/auxiliary/driver_trace/tr_screen.h index cce41d3fc20..2350ec95f59 100644 --- a/src/gallium/auxiliary/driver_trace/tr_screen.h +++ b/src/gallium/auxiliary/driver_trace/tr_screen.h @@ -59,6 +59,8 @@ struct trace_screen struct trace_screen * trace_screen(struct pipe_screen *screen); +struct pipe_screen * +trace_screen_unwrap(struct pipe_screen *_screen); #ifdef __cplusplus } diff --git a/src/gallium/auxiliary/pipe-loader/meson.build b/src/gallium/auxiliary/pipe-loader/meson.build index 9df596f9bb4..988947195ec 100644 --- a/src/gallium/auxiliary/pipe-loader/meson.build +++ b/src/gallium/auxiliary/pipe-loader/meson.build @@ -45,7 +45,7 @@ libpipe_loader_static = static_library( files_pipe_loader, include_directories : [ inc_util, inc_loader, inc_gallium, inc_include, inc_src, inc_gallium_aux, - inc_gallium_winsys, + inc_gallium_winsys, inc_gallium_drivers, ], c_args : [libpipe_loader_defines, '-DGALLIUM_STATIC_TARGETS=1'], gnu_symbol_visibility : 'hidden', @@ -59,7 +59,7 @@ libpipe_loader_dynamic = static_library( files_pipe_loader, include_directories : [ inc_util, inc_loader, inc_gallium, inc_include, inc_src, inc_gallium_aux, - inc_gallium_winsys, + inc_gallium_winsys, inc_gallium_drivers, ], c_args : [ libpipe_loader_defines, diff --git a/src/gallium/auxiliary/pipe-loader/pipe_loader.h b/src/gallium/auxiliary/pipe-loader/pipe_loader.h index 8c532e60157..e2522ddf3b5 100644 --- a/src/gallium/auxiliary/pipe-loader/pipe_loader.h +++ b/src/gallium/auxiliary/pipe-loader/pipe_loader.h @@ -143,6 +143,20 @@ bool pipe_loader_sw_probe_dri(struct pipe_loader_device **devs, const struct drisw_loader_funcs *drisw_lf); +/** + * Initialize vk dri device give the drisw_loader_funcs. + * + * This function is platform-specific. + * + * Function does not take ownership of the fd, but duplicates it locally. + * The local fd is closed during pipe_loader_release. + * + * \sa pipe_loader_probe + */ +bool +pipe_loader_vk_probe_dri(struct pipe_loader_device **devs, + const struct drisw_loader_funcs *drisw_lf); + /** * Initialize a kms backed sw device given an fd. * diff --git a/src/gallium/auxiliary/pipe-loader/pipe_loader_sw.c b/src/gallium/auxiliary/pipe-loader/pipe_loader_sw.c index 85f8d94b826..e822eae43b1 100644 --- a/src/gallium/auxiliary/pipe-loader/pipe_loader_sw.c +++ b/src/gallium/auxiliary/pipe-loader/pipe_loader_sw.c @@ -43,7 +43,7 @@ #include "frontend/drisw_api.h" #include "frontend/sw_driver.h" #include "frontend/sw_winsys.h" - +#include "util/driconf.h" struct pipe_loader_sw_device { struct pipe_loader_device base; @@ -58,6 +58,9 @@ struct pipe_loader_sw_device { #define pipe_loader_sw_device(dev) ((struct pipe_loader_sw_device *)dev) static const struct pipe_loader_ops pipe_loader_sw_ops; +#ifdef HAVE_ZINK +static const struct pipe_loader_ops pipe_loader_vk_ops; +#endif #ifdef GALLIUM_STATIC_TARGETS static const struct sw_driver_descriptor driver_descriptors = { @@ -90,6 +93,37 @@ static const struct sw_driver_descriptor driver_descriptors = { }; #endif +#if defined(GALLIUM_STATIC_TARGETS) && defined(HAVE_ZINK) +static const struct sw_driver_descriptor kopper_driver_descriptors = { + .create_screen = sw_screen_create_zink, + .winsys = { +#ifdef HAVE_PIPE_LOADER_DRI + { + .name = "dri", + .create_winsys = dri_create_sw_winsys, + }, +#endif +#ifdef HAVE_PIPE_LOADER_KMS + { + .name = "kms_dri", + .create_winsys = kms_dri_create_winsys, + }, +#endif +#ifndef __ANDROID__ + { + .name = "null", + .create_winsys = null_sw_create, + }, + { + .name = "wrapped", + .create_winsys = wrapper_sw_winsys_wrap_pipe_screen, + }, +#endif + { 0 }, + } +}; +#endif + static bool pipe_loader_sw_probe_init_common(struct pipe_loader_sw_device *sdev) { @@ -124,6 +158,42 @@ pipe_loader_sw_probe_init_common(struct pipe_loader_sw_device *sdev) return true; } +#ifdef HAVE_ZINK +static bool +pipe_loader_vk_probe_init_common(struct pipe_loader_sw_device *sdev) +{ + sdev->base.type = PIPE_LOADER_DEVICE_PLATFORM; + sdev->base.driver_name = "kopper"; + sdev->base.ops = &pipe_loader_vk_ops; + sdev->fd = -1; + +#ifdef GALLIUM_STATIC_TARGETS + sdev->dd = &kopper_driver_descriptors; + if (!sdev->dd) + return false; +#else + const char *search_dir = getenv("GALLIUM_PIPE_SEARCH_DIR"); + if (search_dir == NULL) + search_dir = PIPE_SEARCH_DIR; + + sdev->lib = pipe_loader_find_module("swrast", search_dir); + if (!sdev->lib) + return false; + + sdev->dd = (const struct sw_driver_descriptor *) + util_dl_get_proc_address(sdev->lib, "swrast_driver_descriptor"); + + if (!sdev->dd){ + util_dl_close(sdev->lib); + sdev->lib = NULL; + return false; + } +#endif + + return true; +} +#endif + static void pipe_loader_sw_probe_teardown_common(struct pipe_loader_sw_device *sdev) { @@ -163,6 +233,37 @@ fail: FREE(sdev); return false; } +#ifdef HAVE_ZINK +bool +pipe_loader_vk_probe_dri(struct pipe_loader_device **devs, const struct drisw_loader_funcs *drisw_lf) +{ + struct pipe_loader_sw_device *sdev = CALLOC_STRUCT(pipe_loader_sw_device); + int i; + + if (!sdev) + return false; + + if (!pipe_loader_vk_probe_init_common(sdev)) + goto fail; + + for (i = 0; sdev->dd->winsys[i].name; i++) { + if (strcmp(sdev->dd->winsys[i].name, "dri") == 0) { + sdev->ws = sdev->dd->winsys[i].create_winsys(drisw_lf); + break; + } + } + if (!sdev->ws) + goto fail; + + *devs = &sdev->base; + return true; + +fail: + pipe_loader_sw_probe_teardown_common(sdev); + FREE(sdev); + return false; +} +#endif #endif #ifdef HAVE_PIPE_LOADER_KMS @@ -303,6 +404,19 @@ pipe_loader_sw_get_driconf(struct pipe_loader_device *dev, unsigned *count) return NULL; } +#ifdef HAVE_ZINK +static const driOptionDescription zink_driconf[] = { + #include "zink/driinfo_zink.h" +}; + +static const struct driOptionDescription * +pipe_loader_vk_get_driconf(struct pipe_loader_device *dev, unsigned *count) +{ + *count = ARRAY_SIZE(zink_driconf); + return zink_driconf; +} +#endif + static struct pipe_screen * pipe_loader_sw_create_screen(struct pipe_loader_device *dev, const struct pipe_screen_config *config, bool sw_vk) @@ -310,7 +424,7 @@ pipe_loader_sw_create_screen(struct pipe_loader_device *dev, struct pipe_loader_sw_device *sdev = pipe_loader_sw_device(dev); struct pipe_screen *screen; - screen = sdev->dd->create_screen(sdev->ws, sw_vk); + screen = sdev->dd->create_screen(sdev->ws, config, sw_vk); if (!screen) sdev->ws->destroy(sdev->ws); @@ -322,3 +436,11 @@ static const struct pipe_loader_ops pipe_loader_sw_ops = { .get_driconf = pipe_loader_sw_get_driconf, .release = pipe_loader_sw_release }; + +#ifdef HAVE_ZINK +static const struct pipe_loader_ops pipe_loader_vk_ops = { + .create_screen = pipe_loader_sw_create_screen, + .get_driconf = pipe_loader_vk_get_driconf, + .release = pipe_loader_sw_release +}; +#endif diff --git a/src/gallium/auxiliary/target-helpers/inline_sw_helper.h b/src/gallium/auxiliary/target-helpers/inline_sw_helper.h index 73e8551aa60..cd6f1150aae 100644 --- a/src/gallium/auxiliary/target-helpers/inline_sw_helper.h +++ b/src/gallium/auxiliary/target-helpers/inline_sw_helper.h @@ -3,6 +3,7 @@ #define INLINE_SW_HELPER_H #include "pipe/p_compiler.h" +#include "pipe/p_screen.h" #include "util/u_debug.h" #include "util/debug.h" #include "frontend/sw_winsys.h" @@ -92,9 +93,6 @@ sw_screen_create_vk(struct sw_winsys *winsys, bool sw_vk) #endif #if defined(GALLIUM_SOFTPIPE) (sw_vk ? "" : "softpipe"), -#endif -#if defined(GALLIUM_ZINK) - (sw_vk || only_sw) ? "" : "zink", #endif }; @@ -109,6 +107,16 @@ sw_screen_create_vk(struct sw_winsys *winsys, bool sw_vk) return NULL; } +static inline struct pipe_screen * +sw_screen_create_zink(struct sw_winsys *winsys, const struct pipe_screen_config *config, bool whatever) +{ +#if defined(GALLIUM_ZINK) + return zink_create_screen(winsys, config); +#else + return NULL; +#endif +} + static inline struct pipe_screen * sw_screen_create(struct sw_winsys *winsys) { diff --git a/src/gallium/auxiliary/target-helpers/sw_helper.h b/src/gallium/auxiliary/target-helpers/sw_helper.h index eed5eeab0dc..3ffd9a67877 100644 --- a/src/gallium/auxiliary/target-helpers/sw_helper.h +++ b/src/gallium/auxiliary/target-helpers/sw_helper.h @@ -39,7 +39,7 @@ #endif static inline struct pipe_screen * -sw_screen_create_named(struct sw_winsys *winsys, const char *driver) +sw_screen_create_named(struct sw_winsys *winsys, const struct pipe_screen_config *config, const char *driver) { struct pipe_screen *screen = NULL; @@ -80,7 +80,7 @@ sw_screen_create_named(struct sw_winsys *winsys, const char *driver) } struct pipe_screen * -sw_screen_create_vk(struct sw_winsys *winsys, bool sw_vk) +sw_screen_create_vk(struct sw_winsys *winsys, const struct pipe_screen_config *config, bool sw_vk) { UNUSED bool only_sw = env_var_as_boolean("LIBGL_ALWAYS_SOFTWARE", false); const char *drivers[] = { @@ -96,14 +96,11 @@ sw_screen_create_vk(struct sw_winsys *winsys, bool sw_vk) #endif #if defined(GALLIUM_SOFTPIPE) sw_vk ? "" : "softpipe", -#endif -#if defined(GALLIUM_ZINK) - (sw_vk || only_sw) ? "" : "zink", #endif }; for (unsigned i = 0; i < ARRAY_SIZE(drivers); i++) { - struct pipe_screen *screen = sw_screen_create_named(winsys, drivers[i]); + struct pipe_screen *screen = sw_screen_create_named(winsys, config, drivers[i]); if (screen) return screen; /* If the env var is set, don't keep trying things */ @@ -113,9 +110,19 @@ sw_screen_create_vk(struct sw_winsys *winsys, bool sw_vk) return NULL; } +struct pipe_screen * +sw_screen_create_zink(struct sw_winsys *winsys, const struct pipe_screen_config *config, bool whatever) +{ +#if defined(GALLIUM_ZINK) + return zink_create_screen(winsys); +#else + return NULL; +#endif +} + struct pipe_screen * sw_screen_create(struct sw_winsys *winsys) { - return sw_screen_create_vk(winsys, false); + return sw_screen_create_vk(winsys, NULL, false); } #endif diff --git a/src/gallium/auxiliary/target-helpers/sw_helper_public.h b/src/gallium/auxiliary/target-helpers/sw_helper_public.h index 499813cca4d..438150f1c17 100644 --- a/src/gallium/auxiliary/target-helpers/sw_helper_public.h +++ b/src/gallium/auxiliary/target-helpers/sw_helper_public.h @@ -5,7 +5,9 @@ struct pipe_screen; struct sw_winsys; struct pipe_screen * -sw_screen_create_vk(struct sw_winsys *winsys, bool sw_vk); +sw_screen_create_vk(struct sw_winsys *winsys, const struct pipe_screen_config *config, bool sw_vk); +struct pipe_screen * +sw_screen_create_zink(struct sw_winsys *winsys, const struct pipe_screen_config *config, bool whatever); struct pipe_screen * sw_screen_create(struct sw_winsys *winsys); diff --git a/src/gallium/frontends/dri/dri2.c b/src/gallium/frontends/dri/dri2.c index a679c1c249b..1d96adab987 100644 --- a/src/gallium/frontends/dri/dri2.c +++ b/src/gallium/frontends/dri/dri2.c @@ -209,7 +209,12 @@ dri2_drawable_get_buffers(struct dri_drawable *drawable, return buffers; } -static bool +bool +dri_image_drawable_get_buffers(struct dri_drawable *drawable, + struct __DRIimageList *images, + const enum st_attachment_type *statts, + unsigned statts_count); +bool dri_image_drawable_get_buffers(struct dri_drawable *drawable, struct __DRIimageList *images, const enum st_attachment_type *statts, @@ -1864,6 +1869,36 @@ static const __DRIimageExtension dri2ImageExtensionTempl = { .createImageWithModifiers2 = NULL, }; +const __DRIimageExtension driVkImageExtension = { + .base = { __DRI_IMAGE, 20 }, + + .createImageFromName = dri2_create_image_from_name, + .createImageFromRenderbuffer = dri2_create_image_from_renderbuffer, + .destroyImage = dri2_destroy_image, + .createImage = dri2_create_image, + .queryImage = dri2_query_image, + .dupImage = dri2_dup_image, + .validateUsage = dri2_validate_usage, + .createImageFromNames = dri2_from_names, + .fromPlanar = dri2_from_planar, + .createImageFromTexture = dri2_create_from_texture, + .createImageFromFds = dri2_from_fds, + .createImageFromFds2 = dri2_from_fds2, + .createImageFromDmaBufs = dri2_from_dma_bufs, + .blitImage = dri2_blit_image, + .getCapabilities = dri2_get_capabilities, + .mapImage = dri2_map_image, + .unmapImage = dri2_unmap_image, + .createImageWithModifiers = dri2_create_image_with_modifiers, + .createImageFromDmaBufs2 = dri2_from_dma_bufs2, + .createImageFromDmaBufs3 = dri2_from_dma_bufs3, + .queryDmaBufFormats = dri2_query_dma_buf_formats, + .queryDmaBufModifiers = dri2_query_dma_buf_modifiers, + .queryDmaBufFormatModifierAttribs = dri2_query_dma_buf_format_modifier_attribs, + .createImageFromRenderbuffer2 = dri2_create_image_from_renderbuffer2, + .createImageWithModifiers2 = dri2_create_image_with_modifiers2, +}; + static const __DRIrobustnessExtension dri2Robustness = { .base = { __DRI2_ROBUSTNESS, 1 } }; diff --git a/src/gallium/frontends/dri/dri_screen.h b/src/gallium/frontends/dri/dri_screen.h index a89949e56dc..0ee2feb5616 100644 --- a/src/gallium/frontends/dri/dri_screen.h +++ b/src/gallium/frontends/dri/dri_screen.h @@ -41,6 +41,7 @@ #include "frontend/opencl_interop.h" #include "os/os_thread.h" #include "postprocess/filters.h" +#include "kopper_interface.h" struct dri_context; struct dri_drawable; @@ -106,6 +107,12 @@ dri_screen(__DRIscreen * sPriv) return (struct dri_screen *)sPriv->driverPrivate; } +static inline const __DRIkopperLoaderExtension * +dri_screen_get_kopper(struct dri_screen *screen) +{ + return screen->sPriv->kopper_loader; +} + struct __DRIimageRec { struct pipe_resource *texture; unsigned level; @@ -167,6 +174,8 @@ extern const struct __DriverAPIRec galliumdrm_driver_api; extern const __DRIextension *galliumdrm_driver_extensions[]; extern const struct __DriverAPIRec galliumsw_driver_api; extern const __DRIextension *galliumsw_driver_extensions[]; +extern const struct __DriverAPIRec galliumvk_driver_api; +extern const __DRIextension *galliumvk_driver_extensions[]; extern const __DRIconfigOptionsExtension gallium_config_options; #endif diff --git a/src/gallium/frontends/dri/dri_util.c b/src/gallium/frontends/dri/dri_util.c index 8f77937f672..8d60526f45b 100644 --- a/src/gallium/frontends/dri/dri_util.c +++ b/src/gallium/frontends/dri/dri_util.c @@ -88,6 +88,8 @@ setupLoaderExtensions(__DRIscreen *psp, psp->image.loader = (__DRIimageLoaderExtension *) extensions[i]; if (strcmp(extensions[i]->name, __DRI_MUTABLE_RENDER_BUFFER_LOADER) == 0) psp->mutableRenderBuffer.loader = (__DRImutableRenderBufferLoaderExtension *) extensions[i]; + if (strcmp(extensions[i]->name, __DRI_KOPPER_LOADER) == 0) + psp->kopper_loader = (__DRIkopperLoaderExtension *) extensions[i]; } } diff --git a/src/gallium/frontends/dri/dri_util.h b/src/gallium/frontends/dri/dri_util.h index 7c40b775b55..6b9a71d6f16 100644 --- a/src/gallium/frontends/dri/dri_util.h +++ b/src/gallium/frontends/dri/dri_util.h @@ -55,6 +55,7 @@ #include #include +#include "kopper_interface.h" #include "main/menums.h" #include "main/formats.h" #include "util/xmlconfig.h" @@ -185,6 +186,7 @@ struct __DRIscreenRec { const __DRIextension **extensions; const __DRIswrastLoaderExtension *swrast_loader; + const __DRIkopperLoaderExtension *kopper_loader; struct { /* Flag to indicate that this is a DRI2 screen. Many of the above diff --git a/src/gallium/frontends/dri/drisw.c b/src/gallium/frontends/dri/drisw.c index 76b84893685..5603b612318 100644 --- a/src/gallium/frontends/dri/drisw.c +++ b/src/gallium/frontends/dri/drisw.c @@ -397,9 +397,15 @@ drisw_allocate_textures(struct dri_context *stctx, templ.nr_samples = 0; templ.nr_storage_samples = 0; - if (statts[i] == ST_ATTACHMENT_FRONT_LEFT && - screen->base.screen->resource_create_front && - loader->base.version >= 3) { + if (bind & PIPE_BIND_DISPLAY_TARGET && + screen->base.screen->resource_create_drawable) { + drawable->textures[statts[i]] = + screen->base.screen->resource_create_drawable(screen->base.screen, + &templ, + drawable->dPriv); + } else if (statts[i] == ST_ATTACHMENT_FRONT_LEFT && + screen->base.screen->resource_create_front && + loader->base.version >= 3) { drawable->textures[statts[i]] = screen->base.screen->resource_create_front(screen->base.screen, &templ, (const void *)drawable); } else diff --git a/src/gallium/frontends/dri/kopper.c b/src/gallium/frontends/dri/kopper.c new file mode 100644 index 00000000000..121e6f1c75a --- /dev/null +++ b/src/gallium/frontends/dri/kopper.c @@ -0,0 +1,591 @@ +/* + * Copyright 2020 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "util/format/u_format.h" +#include "util/u_memory.h" +#include "util/u_inlines.h" +#include "util/u_box.h" +#include "pipe/p_context.h" +#include "pipe-loader/pipe_loader.h" +#include "state_tracker/st_context.h" +#include "os/os_process.h" +#include "zink/zink_public.h" +#include "zink/zink_instance.h" +#include "driver_trace/tr_screen.h" + +#include "dri_screen.h" +#include "utils.h" +#include "dri_context.h" +#include "dri_drawable.h" +#include "dri_helpers.h" +#include "dri_query_renderer.h" + +#include + + +struct kopper_drawable { + struct dri_drawable base; + struct kopper_loader_info info; +}; + +struct kopper_screen { + struct dri_screen base; + struct pipe_screen *screen; //unwrapped +}; + +extern const __DRIimageExtension driVkImageExtension; + +static void +kopper_flush_drawable(__DRIdrawable *dPriv) +{ + dri_flush(dPriv->driContextPriv, dPriv, __DRI2_FLUSH_DRAWABLE, -1); +} + +static inline void +kopper_invalidate_drawable(__DRIdrawable *dPriv) +{ + struct dri_drawable *drawable = dri_drawable(dPriv); + + drawable->texture_stamp = dPriv->lastStamp - 1; + + p_atomic_inc(&drawable->base.stamp); +} + +static const __DRI2flushExtension driVkFlushExtension = { + .base = { __DRI2_FLUSH, 4 }, + + .flush = kopper_flush_drawable, + .invalidate = kopper_invalidate_drawable, + .flush_with_flags = dri_flush, +}; + +static const __DRIrobustnessExtension dri2Robustness = { + .base = { __DRI2_ROBUSTNESS, 1 } +}; + +static const __DRIextension *drivk_screen_extensions[] = { + &driTexBufferExtension.base, + &dri2RendererQueryExtension.base, + &dri2ConfigQueryExtension.base, + &dri2FenceExtension.base, + &dri2Robustness.base, + &driVkImageExtension.base, + &dri2FlushControlExtension.base, + &driVkFlushExtension.base, + NULL +}; + +static const __DRIconfig ** +kopper_init_screen(__DRIscreen * sPriv) +{ + const __DRIconfig **configs; + struct dri_screen *screen; + struct kopper_screen *kscreen; + struct pipe_screen *pscreen = NULL; + + assert(sPriv->kopper_loader); + kscreen = CALLOC_STRUCT(kopper_screen); + if (!kscreen) + return NULL; + screen = &kscreen->base; + + screen->sPriv = sPriv; + screen->fd = sPriv->fd; + screen->can_share_buffer = true; + + sPriv->driverPrivate = (void *)kscreen; + + bool success; + if (screen->fd != -1) + success = pipe_loader_drm_probe_fd(&screen->dev, screen->fd); + else + success = pipe_loader_vk_probe_dri(&screen->dev, NULL); + if (success) { + pscreen = pipe_loader_create_screen(screen->dev); + dri_init_options(screen); + } + + if (!pscreen) + goto fail; + + kscreen->screen = trace_screen_unwrap(pscreen); + + configs = dri_init_screen_helper(screen, pscreen); + if (!configs) + goto fail; + + assert(pscreen->get_param(pscreen, PIPE_CAP_DEVICE_RESET_STATUS_QUERY)); + screen->has_reset_status_query = true; + screen->lookup_egl_image = dri2_lookup_egl_image; + sPriv->extensions = drivk_screen_extensions; + + const __DRIimageLookupExtension *image = sPriv->dri2.image; + if (image && + image->base.version >= 2 && + image->validateEGLImage && + image->lookupEGLImageValidated) { + screen->validate_egl_image = dri2_validate_egl_image; + screen->lookup_egl_image_validated = dri2_lookup_egl_image_validated; + } + + return configs; +fail: + dri_destroy_screen_helper(screen); + if (screen->dev) + pipe_loader_release(&screen->dev, 1); + FREE(screen); + return NULL; +} + +// copypasta alert + +static inline void +drisw_present_texture(struct pipe_context *pipe, __DRIdrawable *dPriv, + struct pipe_resource *ptex, struct pipe_box *sub_box) +{ + struct dri_drawable *drawable = dri_drawable(dPriv); + struct dri_screen *screen = dri_screen(drawable->sPriv); + + screen->base.screen->flush_frontbuffer(screen->base.screen, pipe, ptex, 0, 0, drawable, sub_box); +} + +extern bool +dri_image_drawable_get_buffers(struct dri_drawable *drawable, + struct __DRIimageList *images, + const enum st_attachment_type *statts, + unsigned statts_count); + +static void +kopper_allocate_textures(struct dri_context *ctx, + struct dri_drawable *drawable, + const enum st_attachment_type *statts, + unsigned statts_count) +{ + struct dri_screen *screen = dri_screen(drawable->sPriv); + struct pipe_resource templ; + unsigned width, height; + boolean resized; + unsigned i; + struct __DRIimageList images; + __DRIdrawable *dri_drawable = drawable->dPriv; + const __DRIimageLoaderExtension *image = drawable->sPriv->image.loader; + struct kopper_drawable *cdraw = (struct kopper_drawable *)drawable; + + width = drawable->dPriv->w; + height = drawable->dPriv->h; + + resized = (drawable->old_w != width || + drawable->old_h != height); + + /* First get the buffers from the loader */ + if (image) { + if (!dri_image_drawable_get_buffers(drawable, &images, + statts, statts_count)) + return; + } + + if (image) { + if (images.image_mask & __DRI_IMAGE_BUFFER_FRONT) { + struct pipe_resource **buf = + &drawable->textures[ST_ATTACHMENT_FRONT_LEFT]; + struct pipe_resource *texture = images.front->texture; + + dri_drawable->w = texture->width0; + dri_drawable->h = texture->height0; + + pipe_resource_reference(buf, texture); + } + + if (images.image_mask & __DRI_IMAGE_BUFFER_BACK) { + struct pipe_resource **buf = + &drawable->textures[ST_ATTACHMENT_BACK_LEFT]; + struct pipe_resource *texture = images.back->texture; + + dri_drawable->w = texture->width0; + dri_drawable->h = texture->height0; + + pipe_resource_reference(buf, texture); + } + + if (images.image_mask & __DRI_IMAGE_BUFFER_SHARED) { + struct pipe_resource **buf = + &drawable->textures[ST_ATTACHMENT_BACK_LEFT]; + struct pipe_resource *texture = images.back->texture; + + dri_drawable->w = texture->width0; + dri_drawable->h = texture->height0; + + pipe_resource_reference(buf, texture); + + ctx->is_shared_buffer_bound = true; + } else { + ctx->is_shared_buffer_bound = false; + } + } else { + /* remove outdated textures */ + if (resized) { + for (i = 0; i < ST_ATTACHMENT_COUNT; i++) { + if (drawable->textures[i] && i < ST_ATTACHMENT_DEPTH_STENCIL) { + drawable->textures[i]->width0 = width; + drawable->textures[i]->height0 = height; + } else + pipe_resource_reference(&drawable->textures[i], NULL); + pipe_resource_reference(&drawable->msaa_textures[i], NULL); + } + } + } + + memset(&templ, 0, sizeof(templ)); + templ.target = screen->target; + templ.width0 = width; + templ.height0 = height; + templ.depth0 = 1; + templ.array_size = 1; + templ.last_level = 0; + bool is_window = cdraw->info.bos.sType != 0; + + uint32_t attachments = 0; + for (i = 0; i < statts_count; i++) + attachments |= BITFIELD_BIT(statts[i]); + bool front_only = attachments & ST_ATTACHMENT_FRONT_LEFT_MASK && !(attachments & ST_ATTACHMENT_BACK_LEFT_MASK); + + for (i = 0; i < statts_count; i++) { + enum pipe_format format; + unsigned bind; + + dri_drawable_get_format(drawable, statts[i], &format, &bind); + + /* the texture already exists or not requested */ + if (!drawable->textures[statts[i]]) { + if (statts[i] == ST_ATTACHMENT_BACK_LEFT || + (statts[i] == ST_ATTACHMENT_FRONT_LEFT && front_only)) + bind |= PIPE_BIND_DISPLAY_TARGET; + + if (format == PIPE_FORMAT_NONE) + continue; + + templ.format = format; + templ.bind = bind; + templ.nr_samples = 0; + templ.nr_storage_samples = 0; + + if (statts[i] < ST_ATTACHMENT_DEPTH_STENCIL && is_window) { + void *data; + if (statts[i] == ST_ATTACHMENT_BACK_LEFT || (statts[i] == ST_ATTACHMENT_FRONT_LEFT && front_only)) + data = &cdraw->info; + else + data = drawable->textures[ST_ATTACHMENT_BACK_LEFT]; + assert(data); + drawable->textures[statts[i]] = + screen->base.screen->resource_create_drawable(screen->base.screen, &templ, data); + } else + drawable->textures[statts[i]] = + screen->base.screen->resource_create(screen->base.screen, &templ); + } + if (drawable->stvis.samples > 1 && !drawable->msaa_textures[statts[i]]) { + templ.bind = templ.bind & + ~(PIPE_BIND_SCANOUT | PIPE_BIND_SHARED | PIPE_BIND_DISPLAY_TARGET); + templ.nr_samples = drawable->stvis.samples; + templ.nr_storage_samples = drawable->stvis.samples; + drawable->msaa_textures[statts[i]] = + screen->base.screen->resource_create(screen->base.screen, &templ); + + dri_pipe_blit(ctx->st->pipe, + drawable->msaa_textures[statts[i]], + drawable->textures[statts[i]]); + } + } + + drawable->old_w = width; + drawable->old_h = height; +} + +static inline void +get_drawable_info(__DRIdrawable *dPriv, int *x, int *y, int *w, int *h) +{ + __DRIscreen *sPriv = dPriv->driScreenPriv; + const __DRIswrastLoaderExtension *loader = sPriv->swrast_loader; + + if (loader) + loader->getDrawableInfo(dPriv, + x, y, w, h, + dPriv->loaderPrivate); +} + +static void +kopper_update_drawable_info(struct dri_drawable *drawable) +{ + __DRIdrawable *dPriv = drawable->dPriv; + __DRIscreen *sPriv = dPriv->driScreenPriv; + struct kopper_drawable *cdraw = (struct kopper_drawable *)drawable; + bool is_window = cdraw->info.bos.sType != 0; + int x, y; + struct kopper_screen *kscreen = (struct kopper_screen*)sPriv->driverPrivate; + struct pipe_screen *screen = kscreen->screen; + struct pipe_resource *ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT] ? + drawable->textures[ST_ATTACHMENT_BACK_LEFT] : + drawable->textures[ST_ATTACHMENT_FRONT_LEFT]; + +#if 0 + if (is_window && ptex && kscreen->base.fd == -1) + zink_kopper_update(screen, ptex, &dPriv->w, &dPriv->h); + else +#endif + get_drawable_info(dPriv, &x, &y, &dPriv->w, &dPriv->h); +} + +static inline void +kopper_present_texture(struct pipe_context *pipe, __DRIdrawable *dPriv, + struct pipe_resource *ptex, struct pipe_box *sub_box) +{ + struct dri_drawable *drawable = dri_drawable(dPriv); + struct dri_screen *screen = dri_screen(drawable->sPriv); + + screen->base.screen->flush_frontbuffer(screen->base.screen, pipe, ptex, 0, 0, drawable, sub_box); +} + +static inline void +kopper_copy_to_front(struct pipe_context *pipe, + __DRIdrawable * dPriv, + struct pipe_resource *ptex) +{ + kopper_present_texture(pipe, dPriv, ptex, NULL); + + kopper_invalidate_drawable(dPriv); +} + +static bool +kopper_flush_frontbuffer(struct dri_context *ctx, + struct dri_drawable *drawable, + enum st_attachment_type statt) +{ + struct pipe_resource *ptex; + + if (!ctx || statt != ST_ATTACHMENT_FRONT_LEFT) + return false; + + if (drawable) { + /* prevent recursion */ + if (drawable->flushing) + return true; + + drawable->flushing = true; + } + + if (drawable->stvis.samples > 1) { + /* Resolve the front buffer. */ + dri_pipe_blit(ctx->st->pipe, + drawable->textures[ST_ATTACHMENT_FRONT_LEFT], + drawable->msaa_textures[ST_ATTACHMENT_FRONT_LEFT]); + } + ptex = drawable->textures[statt]; + + if (ptex) { + ctx->st->pipe->flush_resource(ctx->st->pipe, drawable->textures[ST_ATTACHMENT_FRONT_LEFT]); + struct pipe_screen *screen = drawable->screen->base.screen; + struct st_context_iface *st; + struct pipe_fence_handle *new_fence = NULL; + st = ctx->st; + if (st->thread_finish) + st->thread_finish(st); + + st->flush(st, ST_FLUSH_FRONT, &new_fence, NULL, NULL); + if (drawable) { + drawable->flushing = false; + } + /* throttle on the previous fence */ + if (drawable->throttle_fence) { + screen->fence_finish(screen, NULL, drawable->throttle_fence, PIPE_TIMEOUT_INFINITE); + screen->fence_reference(screen, &drawable->throttle_fence, NULL); + } + drawable->throttle_fence = new_fence; + kopper_copy_to_front(st->pipe, ctx->dPriv, ptex); + } + + return true; +} + +static void +kopper_update_tex_buffer(struct dri_drawable *drawable, + struct dri_context *ctx, + struct pipe_resource *res) +{ + +} + +static void +kopper_flush_swapbuffers(struct dri_context *ctx, + struct dri_drawable *drawable) +{ + /* does this actually need to do anything? */ +} + +// XXX this frees its second argument as a side effect - regardless of success +// - since the point is to use it as the superclass initializer before we add +// our own state. kindagross but easier than fixing the object model first. +static struct kopper_drawable * +kopper_create_drawable(__DRIdrawable *dPriv, struct dri_drawable *base) +{ + struct kopper_drawable *_ret = CALLOC_STRUCT(kopper_drawable); + + if (!_ret) + goto out; + struct dri_drawable *ret = &_ret->base; + + // copy all the elements + *ret = *base; + + // relocate references to the old struct + ret->base.visual = &ret->stvis; + ret->base.st_manager_private = (void *) ret; + dPriv->driverPrivate = ret; + + // and fill in the vtable + ret->allocate_textures = kopper_allocate_textures; + ret->update_drawable_info = kopper_update_drawable_info; + ret->flush_frontbuffer = kopper_flush_frontbuffer; + ret->update_tex_buffer = kopper_update_tex_buffer; + ret->flush_swapbuffers = kopper_flush_swapbuffers; + +out: + free(base); + return _ret; +} + +static boolean +kopper_create_buffer(__DRIscreen * sPriv, + __DRIdrawable * dPriv, + const struct gl_config *visual, boolean isPixmap) +{ + struct kopper_drawable *drawable = NULL; + + /* always pass !pixmap because it isn't "handled" or relevant */ + if (!dri_create_buffer(sPriv, dPriv, visual, false)) + return FALSE; + + drawable = kopper_create_drawable(dPriv, dPriv->driverPrivate); + if (!drawable) + return FALSE; + + drawable->info.has_alpha = visual->alphaBits > 0; + if (sPriv->kopper_loader->SetSurfaceCreateInfo && !isPixmap) + sPriv->kopper_loader->SetSurfaceCreateInfo(dPriv->loaderPrivate, + &drawable->info); + + return TRUE; +} + +static void +kopper_swap_buffers(__DRIdrawable *dPriv) +{ + struct dri_context *ctx = dri_get_current(dPriv->driScreenPriv); + struct dri_drawable *drawable = dri_drawable(dPriv); + struct pipe_resource *ptex; + + if (!ctx) + return; + + ptex = drawable->textures[ST_ATTACHMENT_BACK_LEFT]; + if (!ptex) + return; + + drawable->texture_stamp = dPriv->lastStamp - 1; + dri_flush(dPriv->driContextPriv, dPriv, __DRI2_FLUSH_DRAWABLE | __DRI2_FLUSH_CONTEXT, __DRI2_THROTTLE_SWAPBUFFER); + kopper_copy_to_front(ctx->st->pipe, dPriv, ptex); + if (!drawable->textures[ST_ATTACHMENT_FRONT_LEFT]) { + return; + } + /* have to manually swap the pointers here to make frontbuffer readback work */ + drawable->textures[ST_ATTACHMENT_BACK_LEFT] = drawable->textures[ST_ATTACHMENT_FRONT_LEFT]; + drawable->textures[ST_ATTACHMENT_FRONT_LEFT] = ptex; +} + +static __DRIdrawable * +kopperCreateNewDrawable(__DRIscreen *screen, + const __DRIconfig *config, + void *data, + int is_pixmap) +{ + __DRIdrawable *pdraw; + + assert(data != NULL); + + pdraw = malloc(sizeof *pdraw); + if (!pdraw) + return NULL; + + pdraw->loaderPrivate = data; + + pdraw->driScreenPriv = screen; + pdraw->driContextPriv = NULL; + pdraw->refcount = 0; + pdraw->lastStamp = 0; + pdraw->w = 0; + pdraw->h = 0; + + //dri_get_drawable(pdraw); + pdraw->refcount++; + + if (!screen->driver->CreateBuffer(screen, pdraw, &config->modes, + is_pixmap)) { + free(pdraw); + return NULL; + } + + pdraw->dri2.stamp = pdraw->lastStamp + 1; + + return pdraw; +} + + +const __DRIkopperExtension driKopperExtension = { + .base = { __DRI_KOPPER, 1 }, + .createNewDrawable = kopperCreateNewDrawable, +}; + +const struct __DriverAPIRec galliumvk_driver_api = { + .InitScreen = kopper_init_screen, + .DestroyScreen = dri_destroy_screen, + .CreateBuffer = kopper_create_buffer, + .DestroyBuffer = dri_destroy_buffer, + .SwapBuffers = kopper_swap_buffers, + .CopySubBuffer = NULL, +}; + +static const struct __DRIDriverVtableExtensionRec galliumvk_vtable = { + .base = { __DRI_DRIVER_VTABLE, 1 }, + .vtable = &galliumvk_driver_api, +}; + +const __DRIextension *galliumvk_driver_extensions[] = { + &driCoreExtension.base, + &driSWRastExtension.base, + &driDRI2Extension.base, + &driImageDriverExtension.base, + &driKopperExtension.base, + &gallium_config_options.base, + &galliumvk_vtable.base, + NULL +}; + +/* vim: set sw=3 ts=8 sts=3 expandtab: */ diff --git a/src/gallium/frontends/dri/meson.build b/src/gallium/frontends/dri/meson.build index 139707ea719..45c5acf0cbe 100644 --- a/src/gallium/frontends/dri/meson.build +++ b/src/gallium/frontends/dri/meson.build @@ -45,6 +45,10 @@ if with_dri2 files_libdri += files('dri2.c') endif +if with_gallium_zink + files_libdri += files('kopper.c') +endif + libdri_c_args = [] if with_gallium_softpipe libdri_c_args += '-DGALLIUM_SOFTPIPE' @@ -55,7 +59,7 @@ libdri = static_library( files_libdri, include_directories : [ inc_include, inc_util, inc_mesa, inc_mapi, inc_src, inc_gallium, - inc_gallium_aux, inc_util, + inc_gallium_aux, inc_util, inc_gallium_drivers, ], c_args : [libdri_c_args], gnu_symbol_visibility : 'hidden', diff --git a/src/gallium/include/frontend/sw_driver.h b/src/gallium/include/frontend/sw_driver.h index a0385c57c4c..d2cb33845f2 100644 --- a/src/gallium/include/frontend/sw_driver.h +++ b/src/gallium/include/frontend/sw_driver.h @@ -9,7 +9,7 @@ struct sw_winsys; struct sw_driver_descriptor { - struct pipe_screen *(*create_screen)(struct sw_winsys *ws, bool sw_vk); + struct pipe_screen *(*create_screen)(struct sw_winsys *ws, const struct pipe_screen_config *config, bool sw_vk); struct { const char * const name; struct sw_winsys *(*create_winsys)(); diff --git a/src/gallium/include/pipe/p_screen.h b/src/gallium/include/pipe/p_screen.h index edb5cc8decb..b1b041e567e 100644 --- a/src/gallium/include/pipe/p_screen.h +++ b/src/gallium/include/pipe/p_screen.h @@ -227,6 +227,10 @@ struct pipe_screen { struct pipe_resource * (*resource_create)(struct pipe_screen *, const struct pipe_resource *templat); + struct pipe_resource * (*resource_create_drawable)(struct pipe_screen *, + const struct pipe_resource *tmpl, + const void *loader_private); + struct pipe_resource * (*resource_create_front)(struct pipe_screen *, const struct pipe_resource *templat, const void *map_front_private); diff --git a/src/gallium/targets/dri/target.c b/src/gallium/targets/dri/target.c index bf157b38094..9b78351fa8f 100644 --- a/src/gallium/targets/dri/target.c +++ b/src/gallium/targets/dri/target.c @@ -124,7 +124,13 @@ DEFINE_LOADER_DRM_ENTRYPOINT(lima) #endif #if defined(GALLIUM_ZINK) && !defined(__APPLE__) -DEFINE_LOADER_DRM_ENTRYPOINT(zink); +const __DRIextension **__driDriverGetExtensions_zink(void); + +PUBLIC const __DRIextension **__driDriverGetExtensions_zink(void) +{ + return galliumvk_driver_extensions; +} + #endif #if defined(GALLIUM_D3D12) diff --git a/src/gallium/targets/pipe-loader/pipe_swrast.c b/src/gallium/targets/pipe-loader/pipe_swrast.c index fcbc904061f..1dc47352b8e 100644 --- a/src/gallium/targets/pipe-loader/pipe_swrast.c +++ b/src/gallium/targets/pipe-loader/pipe_swrast.c @@ -8,10 +8,10 @@ #include "sw/wrapper/wrapper_sw_winsys.h" PUBLIC struct pipe_screen * -swrast_create_screen(struct sw_winsys *ws, bool sw_vk); +swrast_create_screen(struct sw_winsys *ws, const struct pipe_screen_config *config, bool sw_vk); struct pipe_screen * -swrast_create_screen(struct sw_winsys *ws, bool sw_vk) +swrast_create_screen(struct sw_winsys *ws, const struct pipe_screen_config *config, bool sw_vk) { struct pipe_screen *screen; diff --git a/src/gbm/backends/dri/gbm_dri.c b/src/gbm/backends/dri/gbm_dri.c index b8f2e6f5230..644ea3c5639 100644 --- a/src/gbm/backends/dri/gbm_dri.c +++ b/src/gbm/backends/dri/gbm_dri.c @@ -48,6 +48,7 @@ #include "gbmint.h" #include "loader_dri_helper.h" +#include "kopper_interface.h" #include "loader.h" #include "util/debug.h" #include "util/macros.h" @@ -269,12 +270,19 @@ static const __DRIswrastLoaderExtension swrast_loader_extension = { .putImage2 = swrast_put_image2 }; +static const __DRIkopperLoaderExtension kopper_loader_extension = { + .base = { __DRI_KOPPER_LOADER, 1 }, + + .SetSurfaceCreateInfo = NULL, +}; + static const __DRIextension *gbm_dri_screen_extensions[] = { &image_lookup_extension.base, &use_invalidate.base, &dri2_loader_extension.base, &image_loader_extension.base, &swrast_loader_extension.base, + &kopper_loader_extension.base, NULL, }; @@ -509,15 +517,22 @@ dri_screen_create_sw(struct gbm_dri_device *dri) char *driver_name; int ret; - driver_name = strdup("kms_swrast"); + driver_name = strdup("zink"); if (!driver_name) return -errno; ret = dri_screen_create_dri2(dri, driver_name); - if (ret != 0) - ret = dri_screen_create_swrast(dri); - if (ret != 0) - return ret; + if (ret != 0) { + driver_name = strdup("kms_swrast"); + if (!driver_name) + return -errno; + + ret = dri_screen_create_dri2(dri, driver_name); + if (ret != 0) + ret = dri_screen_create_swrast(dri); + if (ret != 0) + return ret; + } dri->software = true; return 0;