From b5fd6835345e802132080a6a28cb73932b365db2 Mon Sep 17 00:00:00 2001 From: James Deng Date: Fri, 1 Mar 2024 19:54:36 +0800 Subject: [PATCH] Update for v1.0alpha2 --- .gitlab-ci/common/init-stage2.sh | 12 + docs/drivers/zink.rst | 15 - docs/gallium/context.rst | 5 + include/EGL/eglmesaext.h | 5 + include/GL/internal/dri_interface.h | 107 +- include/drm-uapi/drm_fourcc.h | 1 + meson.build | 53 +- meson_options.txt | 20 +- src/compiler/nir/meson.build | 1 + src/compiler/nir/nir.h | 4 + src/compiler/nir/nir_passthrough_gs.c | 108 + src/egl/drivers/dri2/egl_dri2.c | 271 +- src/egl/drivers/dri2/egl_dri2.h | 118 +- src/egl/drivers/dri2/platform_drm.c | 129 +- src/egl/drivers/dri2/platform_null.c | 2210 +++++++++++++++++ src/egl/drivers/dri2/platform_wayland.c | 453 +++- src/egl/drivers/dri2/platform_x11.c | 3 + src/egl/drivers/dri2/platform_x11_dri3.c | 34 +- src/egl/drivers/haiku/egl_haiku.cpp | 9 + src/egl/main/eglapi.c | 22 +- src/egl/main/eglconfig.c | 255 +- src/egl/main/eglconfig.h | 12 + src/egl/main/eglcontext.c | 14 +- src/egl/main/eglcurrent.h | 7 +- src/egl/main/egldisplay.c | 1 + src/egl/main/egldisplay.h | 5 + src/egl/main/egldriver.h | 1 + src/egl/main/eglimage.c | 14 + src/egl/main/eglimage.h | 3 + src/egl/meson.build | 10 + src/egl/wayland/wayland-drm/meson.build | 15 + src/egl/wayland/wayland-drm/wayland-drm.pc.in | 7 + src/gallium/auxiliary/draw/draw_pipe_aaline.c | 70 +- src/gallium/auxiliary/nir/nir_draw_helpers.c | 124 +- src/gallium/auxiliary/nir/nir_draw_helpers.h | 4 +- .../auxiliary/util/u_transfer_helper.c | 244 +- .../drivers/llvmpipe/ci/traces-llvmpipe.yml | 4 +- src/gallium/drivers/pvr/meson.build | 23 + src/gallium/drivers/pvr_alias/meson.build | 23 + .../drivers/zink/VP_ZINK_requirements.json | 73 +- .../drivers/zink/ci/zink-anv-tgl-fails.txt | 813 ++++++ .../drivers/zink/ci/zink-lvp-fails.txt | 50 - .../drivers/zink/nir_to_spirv/nir_to_spirv.c | 60 +- src/gallium/drivers/zink/zink_batch.c | 25 +- src/gallium/drivers/zink/zink_bo.c | 25 +- src/gallium/drivers/zink/zink_compiler.c | 976 +++++++- src/gallium/drivers/zink/zink_compiler.h | 3 +- src/gallium/drivers/zink/zink_context.c | 233 +- src/gallium/drivers/zink/zink_context.h | 3 + src/gallium/drivers/zink/zink_descriptors.c | 12 +- src/gallium/drivers/zink/zink_device_info.py | 248 +- src/gallium/drivers/zink/zink_draw.cpp | 61 +- src/gallium/drivers/zink/zink_kopper.c | 25 +- src/gallium/drivers/zink/zink_pipeline.c | 20 +- src/gallium/drivers/zink/zink_program.c | 261 +- src/gallium/drivers/zink/zink_program.h | 68 +- .../drivers/zink/zink_program_state.hpp | 37 +- src/gallium/drivers/zink/zink_render_pass.c | 39 +- src/gallium/drivers/zink/zink_render_pass.h | 4 +- src/gallium/drivers/zink/zink_resource.c | 8 + src/gallium/drivers/zink/zink_screen.c | 108 +- src/gallium/drivers/zink/zink_screen.h | 3 + src/gallium/drivers/zink/zink_shader_keys.h | 73 +- src/gallium/drivers/zink/zink_state.c | 37 +- src/gallium/drivers/zink/zink_surface.c | 64 +- src/gallium/drivers/zink/zink_types.h | 41 +- src/gallium/frontends/dri/dri2.c | 10 +- .../frontends/dri/dri_query_renderer.c | 2 +- .../frontends/dri/dri_query_renderer.h | 3 + src/gallium/frontends/dri/dri_screen.c | 125 +- src/gallium/frontends/dri/dri_screen.h | 14 + src/gallium/frontends/dri/dri_util.c | 77 +- src/gallium/frontends/dri/dri_util.h | 23 + src/gallium/frontends/dri/drisw.c | 4 + src/gallium/frontends/dri/kopper.c | 6 +- src/gallium/frontends/dri/meson.build | 4 + src/gallium/frontends/pvr/dri_support.h | 638 +++++ src/gallium/frontends/pvr/img_drm_fourcc.h | 113 + src/gallium/frontends/pvr/imgpixfmts.h | 307 +++ src/gallium/frontends/pvr/imgyuv.h | 58 + src/gallium/frontends/pvr/mesa_context.c | 208 ++ src/gallium/frontends/pvr/meson.build | 46 + src/gallium/frontends/pvr/pvrcb.c | 344 +++ src/gallium/frontends/pvr/pvrcompat.c | 912 +++++++ src/gallium/frontends/pvr/pvrdri.c | 630 +++++ src/gallium/frontends/pvr/pvrdri.h | 190 ++ src/gallium/frontends/pvr/pvrdri_support.h | 233 ++ src/gallium/frontends/pvr/pvrext.c | 796 ++++++ src/gallium/frontends/pvr/pvrmesa.h | 36 + src/gallium/frontends/pvr/pvrutil.c | 272 ++ src/gallium/include/pipe/p_format.h | 4 + src/gallium/meson.build | 15 + src/gallium/targets/dri/meson.build | 8 +- src/gallium/targets/dri/target.c | 18 + src/gbm/backends/dri/gbm_dri.c | 100 +- src/gbm/backends/dri/gbm_driint.h | 8 + src/gbm/main/gbm.c | 32 + src/gbm/main/gbm.h | 29 + src/gbm/main/gbm_abi_check.c | 20 +- src/gbm/main/gbm_backend_abi.h | 8 + src/glx/dri3_glx.c | 170 +- src/glx/dri3_priv.h | 1 + src/glx/meson.build | 20 +- src/loader/loader_dri3_helper.c | 15 + src/loader/loader_dri3_helper.h | 3 + src/mapi/glapi/gen/ARB_geometry_shader4.xml | 97 + src/mapi/glapi/gen/EXT_framebuffer_object.xml | 30 +- .../gen/EXT_shader_pixel_local_storage2.xml | 35 + src/mapi/glapi/gen/EXT_sparse_texture.xml | 44 + .../glapi/gen/IMG_framebuffer_downsample.xml | 37 + ...ltiview_multisampled_render_to_texture.xml | 21 + src/mapi/glapi/gen/api_exec_init.py | 1 + src/mapi/glapi/gen/es_EXT.xml | 72 +- src/mapi/glapi/gen/gl_API.xml | 19 +- src/mapi/glapi/gen/static_data.py | 35 + src/mesa/main/context.h | 23 + src/mesa/main/fbobject.c | 83 + src/mesa/main/format_info.py | 2 +- src/mesa/main/formats.c | 13 + src/mesa/main/formats.csv | 6 + src/mesa/main/formats.h | 15 + src/mesa/main/genmipmap.c | 6 + src/mesa/main/glconfig.h | 14 + src/mesa/main/queryobj.c | 49 +- src/mesa/main/version.c | 5 +- src/mesa/state_tracker/st_context.c | 2 + src/mesa/state_tracker/st_context.h | 1 + src/meson.build | 7 +- src/pvr/meson.build | 23 + src/pvr/wsi/meson.build | 82 + src/pvr/wsi/pvr_mesa_wsi_interface.h | 330 +++ src/pvr/wsi/pvr_wsi.c | 368 +++ src/pvr/wsi/pvr_wsi.h | 81 + src/pvr/wsi/pvr_wsi_display.c | 293 +++ src/pvr/wsi/pvr_wsi_wayland.c | 45 + src/pvr/wsi/pvr_wsi_x11.c | 62 + src/util/u_dynarray.h | 10 + src/vulkan/wsi/meson.build | 2 + src/vulkan/wsi/wsi_common.c | 415 +++- src/vulkan/wsi/wsi_common.h | 92 + src/vulkan/wsi/wsi_common_display.c | 484 +++- src/vulkan/wsi/wsi_common_display.h | 126 + src/vulkan/wsi/wsi_common_drm.c | 27 +- src/vulkan/wsi/wsi_common_private.h | 14 +- src/vulkan/wsi/wsi_common_wayland.c | 222 +- src/vulkan/wsi/wsi_common_wayland.h | 35 + src/vulkan/wsi/wsi_common_win32.c | 4 +- src/vulkan/wsi/wsi_common_x11.c | 116 +- src/vulkan/wsi/wsi_common_x11.h | 41 + 149 files changed, 15373 insertions(+), 1404 deletions(-) create mode 100644 src/compiler/nir/nir_passthrough_gs.c create mode 100644 src/egl/drivers/dri2/platform_null.c create mode 100644 src/egl/wayland/wayland-drm/wayland-drm.pc.in create mode 100644 src/gallium/drivers/pvr/meson.build create mode 100644 src/gallium/drivers/pvr_alias/meson.build create mode 100644 src/gallium/frontends/pvr/dri_support.h create mode 100644 src/gallium/frontends/pvr/img_drm_fourcc.h create mode 100644 src/gallium/frontends/pvr/imgpixfmts.h create mode 100644 src/gallium/frontends/pvr/imgyuv.h create mode 100644 src/gallium/frontends/pvr/mesa_context.c create mode 100644 src/gallium/frontends/pvr/meson.build create mode 100644 src/gallium/frontends/pvr/pvrcb.c create mode 100644 src/gallium/frontends/pvr/pvrcompat.c create mode 100644 src/gallium/frontends/pvr/pvrdri.c create mode 100644 src/gallium/frontends/pvr/pvrdri.h create mode 100644 src/gallium/frontends/pvr/pvrdri_support.h create mode 100644 src/gallium/frontends/pvr/pvrext.c create mode 100644 src/gallium/frontends/pvr/pvrmesa.h create mode 100644 src/gallium/frontends/pvr/pvrutil.c create mode 100644 src/mapi/glapi/gen/ARB_geometry_shader4.xml create mode 100644 src/mapi/glapi/gen/EXT_shader_pixel_local_storage2.xml create mode 100644 src/mapi/glapi/gen/EXT_sparse_texture.xml create mode 100644 src/mapi/glapi/gen/IMG_framebuffer_downsample.xml create mode 100644 src/mapi/glapi/gen/OVR_multiview_multisampled_render_to_texture.xml create mode 100644 src/pvr/meson.build create mode 100644 src/pvr/wsi/meson.build create mode 100644 src/pvr/wsi/pvr_mesa_wsi_interface.h create mode 100644 src/pvr/wsi/pvr_wsi.c create mode 100644 src/pvr/wsi/pvr_wsi.h create mode 100644 src/pvr/wsi/pvr_wsi_display.c create mode 100644 src/pvr/wsi/pvr_wsi_wayland.c create mode 100644 src/pvr/wsi/pvr_wsi_x11.c create mode 100644 src/vulkan/wsi/wsi_common_wayland.h create mode 100644 src/vulkan/wsi/wsi_common_x11.h diff --git a/.gitlab-ci/common/init-stage2.sh b/.gitlab-ci/common/init-stage2.sh index a0718bf..f80cc7f 100755 --- a/.gitlab-ci/common/init-stage2.sh +++ b/.gitlab-ci/common/init-stage2.sh @@ -118,6 +118,7 @@ BACKGROUND_PIDS="$! $BACKGROUND_PIDS" if [ -n "$HWCI_START_XORG" ]; then echo "touch /xorg-started; sleep 100000" > /xorg-script env \ + VK_ICD_FILENAMES=/install/share/vulkan/icd.d/${VK_DRIVER}_icd.`uname -m`.json \ xinit /bin/sh /xorg-script -- /usr/bin/Xorg -noreset -s 0 -dpms -logfile /Xorg.0.log & BACKGROUND_PIDS="$! $BACKGROUND_PIDS" @@ -131,6 +132,17 @@ if [ -n "$HWCI_START_XORG" ]; then export DISPLAY=:0 fi +if [ -n "$HWCI_START_WESTON" ]; then + export XDG_RUNTIME_DIR=/run/user + mkdir -p $XDG_RUNTIME_DIR + + env \ + VK_ICD_FILENAMES=/install/share/vulkan/icd.d/${VK_DRIVER}_icd.`uname -m`.json \ + weston -Bheadless-backend.so --use-gl -Swayland-0 & + export WAYLAND_DISPLAY=wayland-0 + sleep 1 +fi + RESULT=fail set +e sh -c "$HWCI_TEST_SCRIPT" diff --git a/docs/drivers/zink.rst b/docs/drivers/zink.rst index 157ecc8..8450815 100644 --- a/docs/drivers/zink.rst +++ b/docs/drivers/zink.rst @@ -117,7 +117,6 @@ supported, although some of these might not actually get verified: * ``VkPhysicalDeviceFeatures``: - * ``occlusionQueryPrecise`` * ``dualSrcBlend`` * Device extensions: @@ -240,26 +239,12 @@ are required to be supported * ``VkPhysicalDeviceFeatures``: * ``samplerAnisotropy`` - * ``pipelineStatisticsQuery`` * ``depthBiasClamp`` * Device extensions: * `VK_KHR_draw_indirect_count`_ -Performance ------------ - -If you notice poor performance and high CPU usage while running an application, -changing the descriptor manager may improve performance: - -.. envvar:: ZINK_DESCRIPTORS ("auto") - -``auto`` - Automatically detect best mode. This is the default. -``lazy`` - Attempt to use the least amount of CPU by binding descriptors opportunistically. - Debugging --------- diff --git a/docs/gallium/context.rst b/docs/gallium/context.rst index 612bdac..c1d184f 100644 --- a/docs/gallium/context.rst +++ b/docs/gallium/context.rst @@ -699,6 +699,11 @@ the box region, not the beginning of the resource. If transfer_map fails, the returned pointer to the buffer memory is NULL, and the pointer to the transfer object remains unchanged (i.e. it can be non-NULL). +When mapping an MSAA surface, the samples are implicitly resolved to +single-sampled for reads (returning the first sample for depth/stencil/integer, +averaged for others). See u_transfer_helper's U_TRANSFER_HELPER_MSAA_MAP for a +way to get that behavior using a resolve blit. + ``transfer_unmap`` remove the memory mapping for and destroy the transfer object. The pointer into the resource should be considered invalid and discarded. diff --git a/include/EGL/eglmesaext.h b/include/EGL/eglmesaext.h index f0395a8..5d11f3e 100644 --- a/include/EGL/eglmesaext.h +++ b/include/EGL/eglmesaext.h @@ -49,6 +49,11 @@ typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSREGIONNOK) (EGLDisplay dpy, EG #define EGL_DRM_BUFFER_FORMAT_RGB565_MESA 0x3292 #endif /* EGL_MESA_drm_image_formats */ +#ifndef EGL_IMG_cl_image +#define EGL_IMG_cl_image 1 +#define EGL_CL_IMAGE_IMG 0x6010 +#endif /* Experimental eglCreateImageKHR target */ + #ifdef __cplusplus } #endif diff --git a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h index 7f1f482..f213843 100644 --- a/include/GL/internal/dri_interface.h +++ b/include/GL/internal/dri_interface.h @@ -730,7 +730,13 @@ struct __DRIuseInvalidateExtensionRec { #define __DRI_ATTRIB_GREEN_SHIFT 51 #define __DRI_ATTRIB_BLUE_SHIFT 52 #define __DRI_ATTRIB_ALPHA_SHIFT 53 -#define __DRI_ATTRIB_MAX 54 +#define __DRI_ATTRIB_YUV_ORDER 54 +#define __DRI_ATTRIB_YUV_NUMBER_OF_PLANES 55 +#define __DRI_ATTRIB_YUV_SUBSAMPLE 56 +#define __DRI_ATTRIB_YUV_DEPTH_RANGE 57 +#define __DRI_ATTRIB_YUV_CSC_STANDARD 58 +#define __DRI_ATTRIB_YUV_PLANE_BPP 59 +#define __DRI_ATTRIB_MAX 60 /* __DRI_ATTRIB_RENDER_TYPE */ #define __DRI_ATTRIB_RGBA_BIT 0x01 @@ -738,6 +744,7 @@ struct __DRIuseInvalidateExtensionRec { #define __DRI_ATTRIB_LUMINANCE_BIT 0x04 #define __DRI_ATTRIB_FLOAT_BIT 0x08 #define __DRI_ATTRIB_UNSIGNED_FLOAT_BIT 0x10 +#define __DRI_ATTRIB_YUV_BIT 0x20 /* __DRI_ATTRIB_CONFIG_CAVEAT */ #define __DRI_ATTRIB_SLOW_BIT 0x01 @@ -764,6 +771,39 @@ struct __DRIuseInvalidateExtensionRec { #define __DRI_ATTRIB_SWAP_COPY 0x8062 #define __DRI_ATTRIB_SWAP_UNDEFINED 0x8063 +/* __DRI_ATTRIB_YUV_ORDER */ +#define __DRI_ATTRIB_YUV_ORDER_NONE 0x0 +#define __DRI_ATTRIB_YUV_ORDER_YUV_BIT 0x1 +#define __DRI_ATTRIB_YUV_ORDER_YVU_BIT 0x2 +#define __DRI_ATTRIB_YUV_ORDER_YUYV_BIT 0x4 +#define __DRI_ATTRIB_YUV_ORDER_UYVY_BIT 0x8 +#define __DRI_ATTRIB_YUV_ORDER_YVYU_BIT 0x10 +#define __DRI_ATTRIB_YUV_ORDER_VYUY_BIT 0x20 +#define __DRI_ATTRIB_YUV_ORDER_AYUV_BIT 0x40 + +/* __DRI_ATTRIB_YUV_SUBSAMPLE */ +#define __DRI_ATTRIB_YUV_SUBSAMPLE_NONE 0x0 +#define __DRI_ATTRIB_YUV_SUBSAMPLE_4_2_0_BIT 0x1 +#define __DRI_ATTRIB_YUV_SUBSAMPLE_4_2_2_BIT 0x2 +#define __DRI_ATTRIB_YUV_SUBSAMPLE_4_4_4_BIT 0x4 + +/* __DRI_ATTRIB_YUV_DEPTH_RANGE */ +#define __DRI_ATTRIB_YUV_DEPTH_RANGE_NONE 0x0 +#define __DRI_ATTRIB_YUV_DEPTH_RANGE_LIMITED_BIT 0x1 +#define __DRI_ATTRIB_YUV_DEPTH_RANGE_FULL_BIT 0x2 + +/* __DRI_ATTRIB_YUV_CSC_STANDARD */ +#define __DRI_ATTRIB_YUV_CSC_STANDARD_NONE 0x0 +#define __DRI_ATTRIB_YUV_CSC_STANDARD_601_BIT 0x1 +#define __DRI_ATTRIB_YUV_CSC_STANDARD_709_BIT 0x2 +#define __DRI_ATTRIB_YUV_CSC_STANDARD_2020_BIT 0x4 + +/* __DRI_ATTRIB_YUV_PLANE_BPP */ +#define __DRI_ATTRIB_YUV_PLANE_BPP_NONE 0x0 +#define __DRI_ATTRIB_YUV_PLANE_BPP_0_BIT 0x1 +#define __DRI_ATTRIB_YUV_PLANE_BPP_8_BIT 0x2 +#define __DRI_ATTRIB_YUV_PLANE_BPP_10_BIT 0x4 + /** * This extension defines the core DRI functionality. * @@ -975,7 +1015,7 @@ struct __DRIbufferRec { }; #define __DRI_DRI2_LOADER "DRI_DRI2Loader" -#define __DRI_DRI2_LOADER_VERSION 5 +#define __DRI_DRI2_LOADER_VERSION 6 enum dri_loader_cap { /* Whether the loader handles RGBA channel ordering correctly. If not, @@ -983,6 +1023,7 @@ enum dri_loader_cap { */ DRI_LOADER_CAP_RGBA_ORDERING, DRI_LOADER_CAP_FP16, + DRI_LOADER_CAP_YUV_SURFACE_IMG = 0x7001, }; struct __DRIdri2LoaderExtensionRec { @@ -1055,6 +1096,17 @@ struct __DRIdri2LoaderExtensionRec { * \since 5 */ void (*destroyLoaderImageState)(void *loaderPrivate); + + /** + * Get the display FD + * + * Get the FD of the display device. + * + * \param loaderPrivate The last parameter of createNewScreen or + * createNewScreen2. + * \since 6 + */ + int (*getDisplayFD)(void *loaderPrivate); }; /** @@ -1229,6 +1281,16 @@ struct __DRIdri2ExtensionRec { #define __DRI_IMAGE_FORMAT_SXRGB8 0x1016 #define __DRI_IMAGE_FORMAT_ABGR16161616 0x1017 #define __DRI_IMAGE_FORMAT_XBGR16161616 0x1018 +#define __DRI_IMAGE_FORMAT_ARGB4444 0x1019 +#define __DRI_IMAGE_FORMAT_YVU444_PACK10_IMG 0x101a +#define __DRI_IMAGE_FORMAT_BGR888 0x101b +#define __DRI_IMAGE_FORMAT_NV12 0x101c +#define __DRI_IMAGE_FORMAT_NV21 0x101d +#define __DRI_IMAGE_FORMAT_YU12 0x101e +#define __DRI_IMAGE_FORMAT_YV12 0x101f +#define __DRI_IMAGE_FORMAT_YVYU 0x1020 +#define __DRI_IMAGE_FORMAT_VYUY 0x1021 +#define __DRI_IMAGE_FORMAT_AXBXGXRX106106106106 0x1022 #define __DRI_IMAGE_USE_SHARE 0x0001 #define __DRI_IMAGE_USE_SCANOUT 0x0002 @@ -1260,6 +1322,8 @@ struct __DRIdri2ExtensionRec { #define __DRI_IMAGE_FOURCC_SARGB8888 0x83324258 #define __DRI_IMAGE_FOURCC_SABGR8888 0x84324258 #define __DRI_IMAGE_FOURCC_SXRGB8888 0x85324258 +#define __DRI_IMAGE_FOURCC_RGBA16161616 0x38344152 /* fourcc_code('R', 'A', '4', '8' ) */ +#define __DRI_IMAGE_FOURCC_SBGR888 0xff324742 /** * Queryable on images created by createImageFromNames. @@ -1279,11 +1343,12 @@ struct __DRIdri2ExtensionRec { #define __DRI_IMAGE_COMPONENTS_Y_U_V 0x3003 #define __DRI_IMAGE_COMPONENTS_Y_UV 0x3004 #define __DRI_IMAGE_COMPONENTS_Y_XUXV 0x3005 +#define __DRI_IMAGE_COMPONENTS_R 0x3006 +#define __DRI_IMAGE_COMPONENTS_RG 0x3007 #define __DRI_IMAGE_COMPONENTS_Y_UXVX 0x3008 #define __DRI_IMAGE_COMPONENTS_AYUV 0x3009 #define __DRI_IMAGE_COMPONENTS_XYUV 0x300A -#define __DRI_IMAGE_COMPONENTS_R 0x3006 -#define __DRI_IMAGE_COMPONENTS_RG 0x3007 +#define __DRI_IMAGE_COMPONENTS_EXTERNAL 0x300B /** @@ -1352,6 +1417,8 @@ enum __DRIChromaSiting { */ /*@{*/ #define __DRI_IMAGE_CAP_GLOBAL_NAMES 1 +#define __DRI_IMAGE_CAP_PRIME_IMPORT 0x2000 +#define __DRI_IMAGE_CAP_PRIME_EXPORT 0x4000 /*@}*/ /** @@ -1718,6 +1785,19 @@ struct __DRIimageExtensionRec { * \since 21 */ void (*setInFenceFd)(__DRIimage *image, int fd); + + /** + * Support for experimental EGL_CL_IMAGE_IMG. + * Like createImageFromTexture, but from a buffer, the contents + * of which depend on the target. + * + * \since 8 + */ + __DRIimage *(*createImageFromBuffer)(__DRIcontext *context, + int target, + void *buffer, + unsigned *error, + void *loaderPrivate); }; @@ -1913,6 +1993,8 @@ typedef struct __DRIDriverVtableExtensionRec { #define __DRI2_RENDERER_HAS_PROTECTED_CONTEXT 0x0020 +#define __DRI2_RENDERER_OPENGL_ES2_CONTEXT_CLIENT_VERSION_IMG 0x7001 + typedef struct __DRI2rendererQueryExtensionRec __DRI2rendererQueryExtension; struct __DRI2rendererQueryExtensionRec { __DRIextension base; @@ -1976,16 +2058,20 @@ enum __DRIimageBufferMask { * OpenGL ES API and little change to the SurfaceFlinger API. */ __DRI_IMAGE_BUFFER_SHARED = (1 << 2), +#define DRI_IMAGE_HAS_BUFFER_PREV + __DRI_IMAGE_BUFFER_PREV = (1 << 31), + }; struct __DRIimageList { uint32_t image_mask; __DRIimage *back; __DRIimage *front; + __DRIimage *prev; }; #define __DRI_IMAGE_LOADER "DRI_IMAGE_LOADER" -#define __DRI_IMAGE_LOADER_VERSION 4 +#define __DRI_IMAGE_LOADER_VERSION 5 struct __DRIimageLoaderExtensionRec { __DRIextension base; @@ -2053,6 +2139,17 @@ struct __DRIimageLoaderExtensionRec { * \since 4 */ void (*destroyLoaderImageState)(void *loaderPrivate); + + /** + * Get the display FD + * + * Get the FD of the display device. + * + * \param loaderPrivate The last parameter of createNewScreen or + * createNewScreen2. + * \since 5 + */ + int (*getDisplayFD)(void *loaderPrivate); }; /** diff --git a/include/drm-uapi/drm_fourcc.h b/include/drm-uapi/drm_fourcc.h index b8f59ae..fd84dec 100644 --- a/include/drm-uapi/drm_fourcc.h +++ b/include/drm-uapi/drm_fourcc.h @@ -383,6 +383,7 @@ extern "C" { #define DRM_FORMAT_YUV444 fourcc_code('Y', 'U', '2', '4') /* non-subsampled Cb (1) and Cr (2) planes */ #define DRM_FORMAT_YVU444 fourcc_code('Y', 'V', '2', '4') /* non-subsampled Cr (1) and Cb (2) planes */ +#define DRM_FORMAT_YVU444_PACK10_IMG fourcc_code('I', 'M', 'G', '2') /* * Format Modifiers: diff --git a/meson.build b/meson.build index 302fc62..53019fc 100644 --- a/meson.build +++ b/meson.build @@ -41,6 +41,12 @@ endif cc = meson.get_compiler('c') cpp = meson.get_compiler('cpp') +if not cpp.compiles('thread_local int x = 0;', name : 'thread_local') + if cpp.has_argument('-std=c++11') + add_project_arguments('-std=c++11', language : 'cpp') + endif +endif + null_dep = dependency('', required : false) if get_option('layout') != 'mirror' @@ -192,16 +198,16 @@ if gallium_drivers.contains('auto') if ['x86', 'x86_64'].contains(host_machine.cpu_family()) gallium_drivers = [ 'r300', 'r600', 'radeonsi', 'nouveau', 'virgl', 'svga', 'swrast', - 'iris', 'crocus', 'i915' + 'iris', 'crocus', 'i915', 'pvr' ] elif ['arm', 'aarch64'].contains(host_machine.cpu_family()) gallium_drivers = [ - 'v3d', 'vc4', 'freedreno', 'etnaviv', 'nouveau', 'svga', - 'tegra', 'virgl', 'lima', 'panfrost', 'swrast' + 'v3d', 'vc4', 'freedreno', 'etnaviv', 'nouveau', + 'tegra', 'virgl', 'lima', 'panfrost', 'swrast', 'pvr' ] elif ['mips', 'mips64', 'riscv32', 'riscv64'].contains(host_machine.cpu_family()) gallium_drivers = [ - 'r300', 'r600', 'radeonsi', 'nouveau', 'virgl', 'swrast' + 'r300', 'r600', 'radeonsi', 'nouveau', 'virgl', 'swrast', 'pvr' ] else error('Unknown architecture @0@. Please pass -Dgallium-drivers to set driver options. Patches gladly accepted to fix this.'.format( @@ -234,6 +240,7 @@ with_gallium_lima = gallium_drivers.contains('lima') with_gallium_zink = gallium_drivers.contains('zink') with_gallium_d3d12 = gallium_drivers.contains('d3d12') with_gallium_asahi = gallium_drivers.contains('asahi') +with_gallium_pvr = gallium_drivers.contains('pvr') foreach gallium_driver : gallium_drivers pre_args += '-DHAVE_@0@'.format(gallium_driver.to_upper()) endforeach @@ -245,6 +252,17 @@ if not system_has_kms_drm with_gallium_kmsro = false endif +if with_gallium_pvr + gallium_pvr_alias = get_option('gallium-pvr-alias') + if gallium_pvr_alias == 'pvr' + gallium_pvr_alias = '' + endif + with_gallium_pvr_alias = gallium_pvr_alias != '' +else + gallium_pvr_alias = '' + with_gallium_pvr_alias = false +endif + with_dri = false if with_gallium and system_has_kms_drm _glx = get_option('glx') @@ -288,6 +306,7 @@ with_broadcom_vk = _vulkan_drivers.contains('broadcom') with_imagination_vk = _vulkan_drivers.contains('imagination-experimental') with_imagination_srv = get_option('imagination-srv') with_microsoft_vk = _vulkan_drivers.contains('microsoft-experimental') +with_pvr_vk = _vulkan_drivers.contains('pvr') with_any_vk = _vulkan_drivers.length() != 0 with_any_broadcom = with_gallium_vc4 or with_gallium_v3d or with_broadcom_vk @@ -342,7 +361,7 @@ endforeach _platforms = get_option('platforms') if _platforms.contains('auto') if system_has_kms_drm - _platforms = ['x11', 'wayland'] + _platforms = ['x11', 'wayland', 'null'] elif ['darwin', 'cygwin'].contains(host_machine.system()) _platforms = ['x11'] elif ['haiku'].contains(host_machine.system()) @@ -360,6 +379,11 @@ with_platform_x11 = _platforms.contains('x11') with_platform_wayland = _platforms.contains('wayland') with_platform_haiku = _platforms.contains('haiku') with_platform_windows = _platforms.contains('windows') +with_platform_null = _platforms.contains('null') + +if with_platform_null + null_dri_driver_name = get_option('null-dri-driver-name') +endif with_glx = get_option('glx') if with_glx == 'auto' @@ -484,7 +508,7 @@ elif _egl == 'enabled' error('EGL requires dri, haiku, or windows') elif not with_shared_glapi error('EGL requires shared-glapi') - elif not ['disabled', 'dri'].contains(with_glx) + elif not ['disabled', 'dri', 'null'].contains(with_glx) error('EGL requires dri, but a GLX is being built without dri') elif host_machine.system() == 'darwin' error('EGL is not available on MacOS') @@ -510,6 +534,10 @@ if with_egl and not _platforms.contains(egl_native_platform) error('-Degl-native-platform does not specify an enabled platform') endif +if with_egl and with_opengl and with_glx != 'disabled' + pre_args += '-DEGL_WITH_OPENGL' +endif + if 'x11' in _platforms _platforms += 'xcb' endif @@ -538,7 +566,7 @@ endforeach if not have_mtls_dialect # need .run to check libc support. meson aborts when calling .run when # cross-compiling, but because this is just an optimization we can skip it - if meson.is_cross_build() and not meson.has_exe_wrapper() + if meson.is_cross_build() warning('cannot auto-detect -mtls-dialect when cross-compiling, using compiler default') else # -fpic to force dynamic tls, otherwise TLS relaxation defeats check @@ -561,7 +589,7 @@ if not have_mtls_dialect endif endif -if with_glx != 'disabled' +if with_glx != 'disabled' and with_glx != 'null' if not (with_platform_x11 and with_any_opengl) error('Cannot build GLX support without X11 platform support and at least one OpenGL API') elif with_glx == 'xlib' @@ -619,7 +647,7 @@ if with_any_vk and (with_platform_x11 and not with_dri3) error('Vulkan drivers require dri3 for X11 support') endif if with_dri - if with_glx == 'disabled' and not with_egl and not with_gbm + if (with_glx == 'disabled' or with_glx == 'null') and not with_egl and not with_gbm error('building dri drivers require at least one windowing system') endif endif @@ -991,6 +1019,10 @@ if with_platform_android ] endif +if with_platform_null + pre_args += '-DHAVE_NULL_PLATFORM' +endif + prog_python = import('python').find_installation('python3') has_mako = run_command( prog_python, '-c', @@ -1710,7 +1742,8 @@ with_gallium_drisw_kms = false dep_libdrm = dependency( 'libdrm', version : '>=' + _drm_ver, # GNU/Hurd includes egl_dri2, without drm. - required : (with_dri2 and host_machine.system() != 'gnu') or with_dri3 + required : (with_dri2 and host_machine.system() != 'gnu') or with_dri3 or + with_platform_null ) if dep_libdrm.found() pre_args += '-DHAVE_LIBDRM' diff --git a/meson_options.txt b/meson_options.txt index 6f30701..1597664 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -23,7 +23,7 @@ option( type : 'array', value : ['auto'], choices : [ - 'auto', 'x11', 'wayland', 'haiku', 'android', 'windows', + 'auto', 'x11', 'wayland', 'haiku', 'android', 'windows', 'null', ], description : 'window systems to support. If this is set to `auto`, all platforms applicable will be enabled.' ) @@ -37,6 +37,12 @@ option( ], description : 'the window system EGL assumes for EGL_DEFAULT_DISPLAY', ) +option( + 'null-dri-driver-name', + type : 'string', + value : '', + description : 'For the null platform, ignore all dri drivers apart from this one. By default, no dri drivers are ignored.' +) option( 'android-stub', type : 'boolean', @@ -75,10 +81,16 @@ option( choices : [ 'auto', 'kmsro', 'radeonsi', 'r300', 'r600', 'nouveau', 'freedreno', 'swrast', 'v3d', 'vc4', 'etnaviv', 'tegra', 'i915', 'svga', 'virgl', - 'panfrost', 'iris', 'lima', 'zink', 'd3d12', 'asahi', 'crocus' + 'panfrost', 'iris', 'lima', 'zink', 'd3d12', 'asahi', 'crocus', 'pvr' ], description : 'List of gallium drivers to build. If this is set to auto all drivers applicable to the target OS/architecture will be built' ) +option( + 'gallium-pvr-alias', + type : 'string', + value : '', + description : 'Gallium PVR alias. This must match the name of the kernel display driver.' +) option( 'gallium-extra-hud', type : 'boolean', @@ -185,7 +197,7 @@ option( 'vulkan-drivers', type : 'array', value : ['auto'], - choices : ['auto', 'amd', 'broadcom', 'freedreno', 'imagination-experimental', 'intel', 'intel_hasvk', 'microsoft-experimental', 'panfrost', 'swrast', 'virtio-experimental'], + choices : ['auto', 'amd', 'broadcom', 'freedreno', 'imagination-experimental', 'intel', 'intel_hasvk', 'microsoft-experimental', 'panfrost', 'pvr', 'swrast', 'virtio-experimental'], description : 'List of vulkan drivers to build. If this is set to auto all drivers applicable to the target OS/architecture will be built' ) option( @@ -293,7 +305,7 @@ option( 'glx', type : 'combo', value : 'auto', - choices : ['auto', 'disabled', 'dri', 'xlib'], + choices : ['auto', 'disabled', 'dri', 'xlib', 'null'], description : 'Build support for GLX platform' ) option( diff --git a/src/compiler/nir/meson.build b/src/compiler/nir/meson.build index f1a1879..133e64a 100644 --- a/src/compiler/nir/meson.build +++ b/src/compiler/nir/meson.build @@ -262,6 +262,7 @@ files_libnir = files( 'nir_opt_undef.c', 'nir_opt_uniform_atomics.c', 'nir_opt_vectorize.c', + 'nir_passthrough_gs.c', 'nir_passthrough_tcs.c', 'nir_phi_builder.c', 'nir_phi_builder.h', diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h index 4258343..851a993 100644 --- a/src/compiler/nir/nir.h +++ b/src/compiler/nir/nir.h @@ -4925,6 +4925,10 @@ nir_shader * nir_create_passthrough_tcs_impl(const nir_shader_compiler_options * uint8_t patch_vertices); nir_shader * nir_create_passthrough_tcs(const nir_shader_compiler_options *options, const nir_shader *vs, uint8_t patch_vertices); +nir_shader * nir_create_passthrough_gs(const nir_shader_compiler_options *options, + const nir_shader *prev_stage, + enum shader_prim primitive_type, + unsigned vertices); bool nir_lower_fragcolor(nir_shader *shader, unsigned max_cbufs); bool nir_lower_fragcoord_wtrans(nir_shader *shader); diff --git a/src/compiler/nir/nir_passthrough_gs.c b/src/compiler/nir/nir_passthrough_gs.c new file mode 100644 index 0000000..b13b890 --- /dev/null +++ b/src/compiler/nir/nir_passthrough_gs.c @@ -0,0 +1,108 @@ +/* + * Copyright © 2022 Collabora Ltc. + * + * 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 "nir.h" +#include "nir_builder.h" + +/* + * A helper to create a passthrough GS shader for drivers that needs to lower + * some rendering tasks to the GS. + */ + +nir_shader * +nir_create_passthrough_gs(const nir_shader_compiler_options *options, + const nir_shader *prev_stage, + enum shader_prim primitive_type, + unsigned vertices) +{ + nir_builder b = nir_builder_init_simple_shader(MESA_SHADER_GEOMETRY, + options, + "gs passthrough"); + + nir_shader *nir = b.shader; + nir->info.gs.input_primitive = primitive_type; + nir->info.gs.output_primitive = primitive_type; + nir->info.gs.vertices_in = vertices; + nir->info.gs.vertices_out = vertices; + nir->info.gs.invocations = 1; + nir->info.gs.active_stream_mask = 1; + + nir_variable *in_vars[VARYING_SLOT_MAX]; + nir_variable *out_vars[VARYING_SLOT_MAX]; + unsigned num_vars = 0; + + /* Create input/output variables. */ + nir_foreach_shader_out_variable(var, prev_stage) { + assert(!var->data.patch); + + char name[100]; + if (var->name) + snprintf(name, sizeof(name), "in_%s", var->name); + else + snprintf(name, sizeof(name), "in_%d", var->data.driver_location); + + nir_variable *in = nir_variable_create(nir, nir_var_shader_in, + glsl_array_type(var->type, + vertices, + false), + name); + in->data.location = var->data.location; + in->data.location_frac = var->data.location_frac; + in->data.driver_location = var->data.driver_location; + in->data.interpolation = var->data.interpolation; + in->data.compact = var->data.compact; + + if (var->name) + snprintf(name, sizeof(name), "out_%s", var->name); + else + snprintf(name, sizeof(name), "out_%d", var->data.driver_location); + + nir_variable *out = nir_variable_create(nir, nir_var_shader_out, + var->type, name); + out->data.location = var->data.location; + out->data.location_frac = var->data.location_frac; + out->data.driver_location = var->data.driver_location; + out->data.interpolation = var->data.interpolation; + out->data.compact = var->data.compact; + + in_vars[num_vars] = in; + out_vars[num_vars++] = out; + } + + for (unsigned i = 0; i < vertices; ++i) { + /* Copy inputs to outputs. */ + for (unsigned j = 0; j < num_vars; ++j) { + /* no need to use copy_var to save a lower pass */ + nir_ssa_def *value = nir_load_array_var_imm(&b, in_vars[j], i); + nir_store_var(&b, out_vars[j], value, + (1u << value->num_components) - 1); + } + nir_emit_vertex(&b, 0); + } + + nir_end_primitive(&b, 0); + nir_shader_gather_info(nir, nir_shader_get_entrypoint(nir)); + nir_validate_shader(nir, "in nir_create_passthrough_gs"); + + return nir; +} diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c index 8e2767a..4c52c9a 100644 --- a/src/egl/drivers/dri2/egl_dri2.c +++ b/src/egl/drivers/dri2/egl_dri2.c @@ -316,6 +316,7 @@ static const EGLint dri2_to_egl_attribute_map[__DRI_ATTRIB_MAX] = { [__DRI_ATTRIB_MAX_SWAP_INTERVAL] = EGL_MAX_SWAP_INTERVAL, [__DRI_ATTRIB_MIN_SWAP_INTERVAL] = EGL_MIN_SWAP_INTERVAL, [__DRI_ATTRIB_YINVERTED] = EGL_Y_INVERTED_NOK, + [__DRI_ATTRIB_YUV_NUMBER_OF_PLANES] = EGL_YUV_NUMBER_OF_PLANES_EXT, }; const __DRIconfig * @@ -416,6 +417,7 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); _EGLConfig base; unsigned int attrib, value, double_buffer; + unsigned int pbuffer_width = 0, pbuffer_height = 0, pbuffer_pixels = 0; bool srgb = false; EGLint key, bind_to_texture_rgb, bind_to_texture_rgba; int dri_shifts[4] = { -1, -1, -1, -1 }; @@ -442,6 +444,8 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, value = EGL_RGB_BUFFER; else if (value & __DRI_ATTRIB_LUMINANCE_BIT) value = EGL_LUMINANCE_BUFFER; + else if (value & __DRI_ATTRIB_YUV_BIT) + value = EGL_YUV_BUFFER_EXT; else return NULL; base.ColorBufferType = value; @@ -537,15 +541,88 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, break; case __DRI_ATTRIB_MAX_PBUFFER_WIDTH: - base.MaxPbufferWidth = _EGL_MAX_PBUFFER_WIDTH; + pbuffer_width = (value != 0) ? value : _EGL_MAX_PBUFFER_WIDTH; break; + case __DRI_ATTRIB_MAX_PBUFFER_HEIGHT: - base.MaxPbufferHeight = _EGL_MAX_PBUFFER_HEIGHT; + pbuffer_height = (value != 0) ? value : _EGL_MAX_PBUFFER_HEIGHT; break; + + case __DRI_ATTRIB_MAX_PBUFFER_PIXELS: + pbuffer_pixels = value; + break; + case __DRI_ATTRIB_MUTABLE_RENDER_BUFFER: if (disp->Extensions.KHR_mutable_render_buffer) surface_type |= EGL_MUTABLE_RENDER_BUFFER_BIT_KHR; break; + + case __DRI_ATTRIB_YUV_ORDER: + if (value & __DRI_ATTRIB_YUV_ORDER_YUV_BIT) + value = EGL_YUV_ORDER_YUV_EXT; + else if (value & __DRI_ATTRIB_YUV_ORDER_YVU_BIT) + value = EGL_YUV_ORDER_YVU_EXT; + else if (value & __DRI_ATTRIB_YUV_ORDER_YUYV_BIT) + value = EGL_YUV_ORDER_YUYV_EXT; + else if (value & __DRI_ATTRIB_YUV_ORDER_UYVY_BIT) + value = EGL_YUV_ORDER_UYVY_EXT; + else if (value & __DRI_ATTRIB_YUV_ORDER_YVYU_BIT) + value = EGL_YUV_ORDER_YVYU_EXT; + else if (value & __DRI_ATTRIB_YUV_ORDER_VYUY_BIT) + value = EGL_YUV_ORDER_VYUY_EXT; + else if (value & __DRI_ATTRIB_YUV_ORDER_AYUV_BIT) + value = EGL_YUV_ORDER_AYUV_EXT; + else + value = EGL_NONE; + _eglSetConfigKey(&base, EGL_YUV_ORDER_EXT, value); + break; + + case __DRI_ATTRIB_YUV_SUBSAMPLE: + if (value & __DRI_ATTRIB_YUV_SUBSAMPLE_4_2_0_BIT) + value = EGL_YUV_SUBSAMPLE_4_2_0_EXT; + else if (value & __DRI_ATTRIB_YUV_SUBSAMPLE_4_2_2_BIT) + value = EGL_YUV_SUBSAMPLE_4_2_2_EXT; + else if (value & __DRI_ATTRIB_YUV_SUBSAMPLE_4_4_4_BIT) + value = EGL_YUV_SUBSAMPLE_4_4_4_EXT; + else + value = EGL_NONE; + _eglSetConfigKey(&base, EGL_YUV_SUBSAMPLE_EXT, value); + break; + + case __DRI_ATTRIB_YUV_DEPTH_RANGE: + if (value & __DRI_ATTRIB_YUV_DEPTH_RANGE_LIMITED_BIT) + value = EGL_YUV_DEPTH_RANGE_LIMITED_EXT; + else if (value & __DRI_ATTRIB_YUV_DEPTH_RANGE_FULL_BIT) + value = EGL_YUV_DEPTH_RANGE_FULL_EXT; + else + value = EGL_NONE; + _eglSetConfigKey(&base, EGL_YUV_DEPTH_RANGE_EXT, value); + break; + + case __DRI_ATTRIB_YUV_CSC_STANDARD: + if (value & __DRI_ATTRIB_YUV_CSC_STANDARD_601_BIT) + value = EGL_YUV_CSC_STANDARD_601_EXT; + else if (value & __DRI_ATTRIB_YUV_CSC_STANDARD_709_BIT) + value = EGL_YUV_CSC_STANDARD_709_EXT; + else if (value & __DRI_ATTRIB_YUV_CSC_STANDARD_2020_BIT) + value = EGL_YUV_CSC_STANDARD_2020_EXT; + else + value = EGL_NONE; + _eglSetConfigKey(&base, EGL_YUV_CSC_STANDARD_EXT, value); + break; + + case __DRI_ATTRIB_YUV_PLANE_BPP: + if (value & __DRI_ATTRIB_YUV_PLANE_BPP_0_BIT) + value = EGL_YUV_PLANE_BPP_0_EXT; + else if (value & __DRI_ATTRIB_YUV_PLANE_BPP_8_BIT) + value = EGL_YUV_PLANE_BPP_8_EXT; + else if (value & __DRI_ATTRIB_YUV_PLANE_BPP_10_BIT) + value = EGL_YUV_PLANE_BPP_10_EXT; + else + value = EGL_NONE; + _eglSetConfigKey(&base, EGL_YUV_PLANE_BPP_EXT, value); + break; + default: key = dri2_to_egl_attribute_map[attrib]; if (key != 0) @@ -554,6 +631,15 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, } } + if (surface_type & EGL_PBUFFER_BIT) { + if (pbuffer_pixels == 0) + pbuffer_pixels = pbuffer_width * pbuffer_height; + + base.MaxPbufferWidth = pbuffer_width; + base.MaxPbufferHeight = pbuffer_height; + base.MaxPbufferPixels = pbuffer_pixels; + } + if (attr_list) for (int i = 0; attr_list[i] != EGL_NONE; i += 2) _eglSetConfigKey(&base, attr_list[i], attr_list[i+1]); @@ -584,6 +670,17 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, base.RenderableType = disp->ClientAPIs; base.Conformant = disp->ClientAPIs; + /* + * We assume that if dri_config is YUV then GL_EXT_YUV_target must be + * supported, which requires OpenGL ES 3.0. + */ + if (base.ColorBufferType == EGL_YUV_BUFFER_EXT) { + base.RenderableType &= EGL_OPENGL_ES3_BIT; + base.Conformant &= EGL_OPENGL_ES3_BIT; + } + if (!base.RenderableType) + return NULL; + base.MinSwapInterval = dri2_dpy->min_swap_interval; base.MaxSwapInterval = dri2_dpy->max_swap_interval; @@ -1024,6 +1121,13 @@ dri2_setup_screen(_EGLDisplay *disp) disp->Extensions.EXT_image_dma_buf_import_modifiers = EGL_TRUE; } #endif + if (dri2_dpy->image->base.version >= 8 && + dri2_dpy->image->createImageFromBuffer) { + disp->Extensions.IMG_cl_image = EGL_TRUE; + } + + if (disp->Extensions.KHR_gl_colorspace) + disp->Extensions.EXT_image_gl_colorspace = EGL_TRUE; } if (dri2_dpy->flush_control) @@ -1038,6 +1142,8 @@ dri2_setup_screen(_EGLDisplay *disp) disp->Extensions.EXT_protected_content = dri2_renderer_query_integer(dri2_dpy, __DRI2_RENDERER_HAS_PROTECTED_CONTEXT); + + disp->Extensions.EXT_yuv_surface = EGL_TRUE; } void @@ -1194,6 +1300,9 @@ dri2_initialize(_EGLDisplay *disp) case _EGL_PLATFORM_DEVICE: ret = dri2_initialize_device(disp); break; + case _EGL_PLATFORM_NULL: + ret = dri2_initialize_null(disp); + break; case _EGL_PLATFORM_X11: case _EGL_PLATFORM_XCB: ret = dri2_initialize_x11(disp); @@ -1255,8 +1364,6 @@ dri2_display_destroy(_EGLDisplay *disp) dri2_dpy->vtbl->close_screen_notify(disp); dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen); } - if (dri2_dpy->fd >= 0) - close(dri2_dpy->fd); /* Don't dlclose the driver when building with the address sanitizer, so you * get good symbols from the leak reports. @@ -1282,11 +1389,29 @@ dri2_display_destroy(_EGLDisplay *disp) case _EGL_PLATFORM_WAYLAND: dri2_teardown_wayland(dri2_dpy); break; + case _EGL_PLATFORM_NULL: + dri2_teardown_null(dri2_dpy); + break; default: /* TODO: add teardown for other platforms */ break; } + switch (disp->Platform) { + case _EGL_PLATFORM_DRM: + case _EGL_PLATFORM_NULL: + case _EGL_PLATFORM_WAYLAND: + case _EGL_PLATFORM_X11: + if (dri2_dpy->fd_dpy >= 0 && dri2_dpy->fd_dpy != dri2_dpy->fd) + close(dri2_dpy->fd_dpy); + break; + default: + break; + } + + if (dri2_dpy->fd >= 0) + close(dri2_dpy->fd); + /* The drm platform does not create the screen/driver_configs but reuses * the ones from the gbm device. As such the gbm itself is responsible * for the cleanup. @@ -1937,6 +2062,26 @@ dri2_make_current(_EGLDisplay *disp, _EGLSurface *dsurf, return EGL_TRUE; } +static EGLint +dri2_query_context_client_version(_EGLDisplay *disp, _EGLContext *ctx) +{ + struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + + switch (dri2_ctx->base.ClientAPI) { + case EGL_OPENGL_ES_API: + switch (dri2_ctx->base.ClientMajorVersion) { + case 2: + return dri2_renderer_query_integer(dri2_dpy, + __DRI2_RENDERER_OPENGL_ES2_CONTEXT_CLIENT_VERSION_IMG); + default: + return 0; + } + default: + return 0; + } +} + __DRIdrawable * dri2_surface_get_dri_drawable(_EGLSurface *surf) { @@ -2399,6 +2544,7 @@ static const struct wl_drm_components_descriptor { { __DRI_IMAGE_COMPONENTS_Y_U_V, EGL_TEXTURE_Y_U_V_WL, 3 }, { __DRI_IMAGE_COMPONENTS_Y_UV, EGL_TEXTURE_Y_UV_WL, 2 }, { __DRI_IMAGE_COMPONENTS_Y_XUXV, EGL_TEXTURE_Y_XUXV_WL, 2 }, + { __DRI_IMAGE_COMPONENTS_EXTERNAL, EGL_TEXTURE_EXTERNAL_WL, 1 }, }; static _EGLImage * @@ -2421,6 +2567,11 @@ dri2_create_image_wayland_wl_buffer(_EGLDisplay *disp, _EGLContext *ctx, if (!_eglParseImageAttribList(&attrs, disp, attr_list)) return NULL; + if (attrs.GLColorspace != EGL_GL_COLORSPACE_DEFAULT_EXT) { + _eglError(EGL_BAD_MATCH, "unsupported colorspace"); + return NULL; + } + plane = attrs.PlaneWL; f = buffer->driver_format; if (plane < 0 || plane >= f->nplanes) { @@ -2465,17 +2616,13 @@ dri2_get_msc_rate_angle(_EGLDisplay *disp, _EGLSurface *surf, return dri2_dpy->vtbl->get_msc_rate(disp, surf, numerator, denominator); } -/** - * Set the error code after a call to - * dri2_egl_image::dri_image::createImageFromTexture. - */ static void -dri2_create_image_khr_texture_error(int dri_error) +dri2_create_image_khr_error(int dri_error) { EGLint egl_error = egl_error_from_dri_image_error(dri_error); if (egl_error != EGL_SUCCESS) - _eglError(egl_error, "dri2_create_image_khr_texture"); + _eglError(egl_error, "dri2_create_image_khr"); } static _EGLImage * @@ -2501,6 +2648,11 @@ dri2_create_image_khr_texture(_EGLDisplay *disp, _EGLContext *ctx, if (!_eglParseImageAttribList(&attrs, disp, attr_list)) return EGL_NO_IMAGE_KHR; + if (attrs.GLColorspace != EGL_GL_COLORSPACE_DEFAULT_EXT) { + _eglError(EGL_BAD_MATCH, "unsupported colorspace"); + return EGL_NO_IMAGE_KHR; + } + switch (target) { case EGL_GL_TEXTURE_2D_KHR: if (!disp->Extensions.KHR_gl_texture_2D_image) { @@ -2554,7 +2706,49 @@ dri2_create_image_khr_texture(_EGLDisplay *disp, _EGLContext *ctx, attrs.GLTextureLevel, &error, NULL); - dri2_create_image_khr_texture_error(error); + dri2_create_image_khr_error(error); + + if (!dri2_img->dri_image) { + free(dri2_img); + return EGL_NO_IMAGE_KHR; + } + return &dri2_img->base; +} + +static _EGLImage * +dri2_create_image_img_buffer(_EGLDisplay *disp, _EGLContext *ctx, + EGLenum target, + EGLClientBuffer buffer, + const EGLint *attr_list) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); + struct dri2_egl_image *dri2_img; + unsigned error; + + switch (target) { + case EGL_CL_IMAGE_IMG: + break; + default: + _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr"); + return EGL_NO_IMAGE_KHR; + } + + dri2_img = malloc(sizeof *dri2_img); + if (!dri2_img) { + _eglError(EGL_BAD_ALLOC, "dri2_create_image_khr"); + return EGL_NO_IMAGE_KHR; + } + + _eglInitImage(&dri2_img->base, disp); + + dri2_img->dri_image = + dri2_dpy->image->createImageFromBuffer(dri2_ctx->dri_context, + target, + buffer, + &error, + NULL); + dri2_create_image_khr_error(error); if (!dri2_img->dri_image) { free(dri2_img); @@ -2615,6 +2809,11 @@ dri2_create_image_mesa_drm_buffer(_EGLDisplay *disp, _EGLContext *ctx, return NULL; } + if (attrs.GLColorspace != EGL_GL_COLORSPACE_DEFAULT_EXT) { + _eglError(EGL_BAD_MATCH, "unsupported colorspace"); + return NULL; + } + switch (attrs.DRMBufferFormatMESA) { case EGL_DRM_BUFFER_FORMAT_ARGB32_MESA: format = __DRI_IMAGE_FORMAT_ARGB8888; @@ -2758,6 +2957,7 @@ dri2_num_fourcc_format_planes(EGLint format) case DRM_FORMAT_XBGR16161616: case DRM_FORMAT_XBGR16161616F: case DRM_FORMAT_ABGR16161616F: + case DRM_FORMAT_AXBXGXRX106106106106: case DRM_FORMAT_YUYV: case DRM_FORMAT_YVYU: case DRM_FORMAT_UYVY: @@ -2770,6 +2970,7 @@ dri2_num_fourcc_format_planes(EGLint format) case DRM_FORMAT_Y410: case DRM_FORMAT_Y412: case DRM_FORMAT_Y416: + case DRM_FORMAT_YVU444_PACK10_IMG: return 1; case DRM_FORMAT_NV12: @@ -2798,6 +2999,23 @@ dri2_num_fourcc_format_planes(EGLint format) } } +static int +dri2_get_srgb_fourcc(int drm_fourcc) +{ + switch (drm_fourcc) { + case DRM_FORMAT_ARGB8888: + return __DRI_IMAGE_FOURCC_SARGB8888; + case DRM_FORMAT_ABGR8888: + return __DRI_IMAGE_FOURCC_SABGR8888; + case DRM_FORMAT_BGR888: + return __DRI_IMAGE_FOURCC_SBGR888; + default: + _eglLog(_EGL_DEBUG, "%s: no matching sRGB FourCC for %#x", + __func__, drm_fourcc); + return 0; + } +} + /* Returns the total number of file descriptors. Zero indicates an error. */ static unsigned dri2_check_dma_buf_format(const _EGLImageAttribs *attrs) @@ -2955,6 +3173,7 @@ dri2_create_image_dma_buf(_EGLDisplay *disp, _EGLContext *ctx, int fds[DMA_BUF_MAX_PLANES]; int pitches[DMA_BUF_MAX_PLANES]; int offsets[DMA_BUF_MAX_PLANES]; + int fourcc; uint64_t modifier; bool has_modifier = false; unsigned error; @@ -2981,6 +3200,18 @@ dri2_create_image_dma_buf(_EGLDisplay *disp, _EGLContext *ctx, if (!num_fds) return NULL; + if (attrs.GLColorspace == EGL_GL_COLORSPACE_SRGB_KHR) { + fourcc = dri2_get_srgb_fourcc(attrs.DMABufFourCC.Value); + if (fourcc == 0) { + _eglError(EGL_BAD_MATCH, "unsupported colorspace"); + return NULL; + } + } else { + assert(attrs.GLColorspace == EGL_GL_COLORSPACE_LINEAR_KHR || + attrs.GLColorspace == EGL_GL_COLORSPACE_DEFAULT_EXT); + fourcc = attrs.DMABufFourCC.Value; + } + for (unsigned i = 0; i < num_fds; ++i) { fds[i] = attrs.DMABufPlaneFds[i].Value; pitches[i] = attrs.DMABufPlanePitches[i].Value; @@ -3025,7 +3256,7 @@ dri2_create_image_dma_buf(_EGLDisplay *disp, _EGLContext *ctx, } dri_image = dri2_dpy->image->createImageFromDmaBufs2(dri2_dpy->dri_screen, - attrs.Width, attrs.Height, attrs.DMABufFourCC.Value, + attrs.Width, attrs.Height, fourcc, modifier, fds, num_fds, pitches, offsets, attrs.DMABufYuvColorSpaceHint.Value, attrs.DMABufSampleRangeHint.Value, @@ -3037,7 +3268,7 @@ dri2_create_image_dma_buf(_EGLDisplay *disp, _EGLContext *ctx, else { dri_image = dri2_dpy->image->createImageFromDmaBufs(dri2_dpy->dri_screen, - attrs.Width, attrs.Height, attrs.DMABufFourCC.Value, + attrs.Width, attrs.Height, fourcc, fds, num_fds, pitches, offsets, attrs.DMABufYuvColorSpaceHint.Value, attrs.DMABufSampleRangeHint.Value, @@ -3299,6 +3530,8 @@ dri2_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target, case EGL_WAYLAND_BUFFER_WL: return dri2_create_image_wayland_wl_buffer(disp, ctx, buffer, attr_list); #endif + case EGL_CL_IMAGE_IMG: + return dri2_create_image_img_buffer(disp, ctx, target, buffer, attr_list); default: _eglError(EGL_BAD_PARAMETER, "dri2_create_image_khr"); return EGL_NO_IMAGE_KHR; @@ -3391,7 +3624,7 @@ dri2_bind_wayland_display_wl(_EGLDisplay *disp, struct wl_display *wl_dpy) if (dri2_dpy->wl_server_drm) goto fail; - device_name = drmGetRenderDeviceNameFromFd(dri2_dpy->fd); + device_name = drmGetRenderDeviceNameFromFd(dri2_dpy->fd_dpy); if (!device_name) device_name = strdup(dri2_dpy->device_name); if (!device_name) @@ -3402,6 +3635,15 @@ dri2_bind_wayland_display_wl(_EGLDisplay *disp, struct wl_display *wl_dpy) dri2_dpy->image->base.version >= 7 && dri2_dpy->image->createImageFromFds != NULL) flags |= WAYLAND_DRM_PRIME; + else if (dri2_dpy->image->base.version >= 10 && + dri2_dpy->image->getCapabilities != NULL) { + int capabilities; + + capabilities = dri2_dpy->image->getCapabilities(dri2_dpy->dri_screen); + if ((capabilities & __DRI_IMAGE_CAP_PRIME_IMPORT) != 0 && + (capabilities & __DRI_IMAGE_CAP_PRIME_EXPORT) != 0) + flags |= WAYLAND_DRM_PRIME; + } dri2_dpy->wl_server_drm = wayland_drm_init(wl_dpy, device_name, @@ -3848,6 +4090,7 @@ const _EGLDriver _eglDriver = { .CreateContext = dri2_create_context, .DestroyContext = dri2_destroy_context, .MakeCurrent = dri2_make_current, + .QueryContextClientVersion = dri2_query_context_client_version, .CreateWindowSurface = dri2_create_window_surface, .CreatePixmapSurface = dri2_create_pixmap_surface, .CreatePbufferSurface = dri2_create_pbuffer_surface, diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h index 40c2a14..21e77a1 100644 --- a/src/egl/drivers/dri2/egl_dri2.h +++ b/src/egl/drivers/dri2/egl_dri2.h @@ -78,6 +78,10 @@ struct zwp_linux_dmabuf_feedback_v1; #endif /* HAVE_ANDROID_PLATFORM */ +#ifdef HAVE_NULL_PLATFORM +#include +#endif + #include "eglconfig.h" #include "eglcontext.h" #include "egldevice.h" @@ -95,6 +99,25 @@ struct zwp_linux_dmabuf_feedback_v1; struct wl_buffer; +#ifdef HAVE_NULL_PLATFORM +struct display_output { + bool in_use; + bool in_fence_supported; + uint32_t connector_id; + drmModePropertyRes **connector_prop_res; + uint32_t crtc_id; + drmModePropertyRes **crtc_prop_res; + uint32_t plane_id; + drmModePropertyRes **plane_prop_res; + drmModeModeInfo mode; + uint32_t mode_blob_id; + unsigned formats; + drmModeAtomicReq *atomic_state; + uint32_t in_formats_id; + struct u_vector modifiers; +}; +#endif + struct dri2_egl_display_vtbl { /* mandatory on Wayland, unused otherwise */ int (*authenticate)(_EGLDisplay *disp, uint32_t id); @@ -244,6 +267,7 @@ struct dri2_egl_display const __DRIconfigOptionsExtension *configOptions; const __DRImutableRenderBufferDriverExtension *mutable_render_buffer; int fd; + int fd_dpy; /* dri2_initialize/dri2_terminate increment/decrement this count, so does * dri2_make_current (tracks if there are active contexts/surfaces). */ @@ -296,6 +320,13 @@ struct dri2_egl_display char *device_name; #endif +#ifdef HAVE_NULL_PLATFORM + bool atomic_enabled; + bool in_formats_enabled; + bool async_flip_enabled; + struct display_output output; +#endif + #ifdef HAVE_ANDROID_PLATFORM const gralloc_module_t *gralloc; /* gralloc vendor usage bit for front rendering */ @@ -312,6 +343,26 @@ struct dri2_egl_context __DRIcontext *dri_context; }; +#define DRI2_SURFACE_NUM_COLOR_BUFFERS 4 + +#ifdef HAVE_NULL_PLATFORM +struct swap_queue_elem +{ + uint32_t swap_interval; + uint32_t back_id; + uint32_t fb_id; + int kms_in_fence_fd; +}; + +enum { + SWAP_IDLE, + SWAP_FLIP, + SWAP_VBLANK, + SWAP_POLL, + SWAP_ERROR, +}; +#endif + struct dri2_egl_surface { _EGLSurface base; @@ -340,24 +391,43 @@ struct dri2_egl_surface struct zwp_linux_dmabuf_feedback_v1 *wl_dmabuf_feedback; struct dmabuf_feedback dmabuf_feedback, pending_dmabuf_feedback; bool compositor_using_another_device; - int format; bool resized; bool received_dmabuf_feedback; #endif +#if defined(HAVE_WAYLAND_PLATFORM) || defined(HAVE_NULL_PLATFORM) + int format; +#endif + #ifdef HAVE_DRM_PLATFORM struct gbm_dri_surface *gbm_surf; #endif +#if defined(HAVE_NULL_PLATFORM) + /* + * Protects swap_queue_idx_head, swap_queue_idx_tail and + * color_buffers.locked. + */ + pthread_mutex_t mutex; + pthread_cond_t swap_queue_cond; + pthread_cond_t swap_unlock_buffer_cond; + int swap_queue_idx_head; + int swap_queue_idx_tail; + pthread_t swap_queue_processor; +#endif + /* EGL-owned buffers */ __DRIbuffer *local_buffers[__DRI_BUFFER_COUNT]; -#if defined(HAVE_WAYLAND_PLATFORM) || defined(HAVE_DRM_PLATFORM) +#if defined(HAVE_WAYLAND_PLATFORM) || defined(HAVE_DRM_PLATFORM) || \ + defined(HAVE_NULL_PLATFORM) struct { +#if defined(HAVE_WAYLAND_PLATFORM) || defined(HAVE_NULL_PLATFORM) + __DRIimage *dri_image; +#endif #ifdef HAVE_WAYLAND_PLATFORM struct wl_buffer *wl_buffer; bool wl_release; - __DRIimage *dri_image; /* for is_different_gpu case. NULL else */ __DRIimage *linear_copy; /* for swrast */ @@ -366,10 +436,17 @@ struct dri2_egl_surface #endif #ifdef HAVE_DRM_PLATFORM struct gbm_bo *bo; +#endif +#ifdef HAVE_NULL_PLATFORM + uint32_t fb_id; #endif bool locked; int age; - } color_buffers[4], *back, *current; +#ifdef HAVE_NULL_PLATFORM + } color_buffers[DRI2_SURFACE_NUM_COLOR_BUFFERS], *back, *current, front_buffer; +#else + } color_buffers[DRI2_SURFACE_NUM_COLOR_BUFFERS], *back, *current; +#endif #endif #ifdef HAVE_ANDROID_PLATFORM @@ -397,6 +474,24 @@ struct dri2_egl_surface /* surfaceless and device */ __DRIimage *front; unsigned int visual; +#ifdef HAVE_DRM_PLATFORM + struct gbm_bo *front_bo; +#endif + +#ifdef HAVE_WAYLAND_PLATFORM + void *swrast_front; +#endif + +#ifdef HAVE_NULL_PLATFORM + struct swap_queue_elem swap_queue[DRI2_SURFACE_NUM_COLOR_BUFFERS]; + struct swap_queue_elem *swap_data; + int swap_state; + bool mutex_init; + bool cond_init; + bool front_render_enabled; + bool front_render_init; + bool cond_init_unlock_buffer; +#endif int out_fence_fd; EGLBoolean enable_out_fence; @@ -588,6 +683,21 @@ dri2_initialize_android(_EGLDisplay *disp) EGLBoolean dri2_initialize_surfaceless(_EGLDisplay *disp); +#ifdef HAVE_NULL_PLATFORM +EGLBoolean +dri2_initialize_null(_EGLDisplay *disp); +void +dri2_teardown_null(struct dri2_egl_display *dri2_dpy); +#else +static inline EGLBoolean +dri2_initialize_null(_EGLDisplay *disp) +{ + return _eglError(EGL_NOT_INITIALIZED, "Null platform not built"); +} +static inline void +dri2_teardown_null(struct dri2_egl_display *dri2_dpy) {} +#endif + EGLBoolean dri2_initialize_device(_EGLDisplay *disp); static inline void diff --git a/src/egl/drivers/dri2/platform_drm.c b/src/egl/drivers/dri2/platform_drm.c index 45895a8..19c50c2 100644 --- a/src/egl/drivers/dri2/platform_drm.c +++ b/src/egl/drivers/dri2/platform_drm.c @@ -41,6 +41,38 @@ #include "egl_dri2.h" #include "loader.h" +static bool +dri2_drm_alloc_front_image(struct dri2_egl_surface *dri2_surf) +{ + if (!dri2_surf->front_bo) { + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + + struct gbm_dri_surface *surf = dri2_surf->gbm_surf; + + dri2_surf->front_bo = gbm_bo_create(&dri2_dpy->gbm_dri->base, + surf->base.v0.width, + surf->base.v0.height, + surf->base.v0.format, + surf->base.v0.flags); + if (!dri2_surf->front_bo) { + _eglError(EGL_BAD_ALLOC, "failed to allocate front buffer"); + return false; + } + } + + return true; +} + +static void +dri2_drm_free_front_image(struct dri2_egl_surface *dri2_surf) +{ + if (dri2_surf->front_bo) { + gbm_bo_destroy(dri2_surf->front_bo); + dri2_surf->front_bo = NULL; + } +} + static struct gbm_bo * lock_front_buffer(struct gbm_surface *_surf) { @@ -138,8 +170,8 @@ dri2_drm_config_is_compatible(struct dri2_egl_display *dri2_dpy, } static _EGLSurface * -dri2_drm_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf, - void *native_surface, const EGLint *attrib_list) +dri2_drm_create_surface(_EGLDisplay *disp, EGLint type, _EGLConfig *conf, + void *native_surface, const EGLint *attrib_list) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_config *dri2_conf = dri2_egl_config(conf); @@ -154,11 +186,25 @@ dri2_drm_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf, return NULL; } - if (!dri2_init_surface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf, + if (!dri2_init_surface(&dri2_surf->base, disp, type, conf, attrib_list, false, native_surface)) goto cleanup_surf; - config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT, + if (type == EGL_PBUFFER_BIT) { + struct gbm_device *gbm = disp->PlatformDisplay; + _EGLSurface *surf = &dri2_surf->base; + + assert(!surface); + + surface = gbm_surface_create(gbm, surf->Width, surf->Height, + conf->NativeVisualID, GBM_BO_USE_RENDERING); + if (!surface) { + _eglError(EGL_BAD_ALLOC, "Failed to allocate pbuffer GBM surface"); + goto cleanup_surf; + } + } + + config = dri2_get_dri_config(dri2_conf, type, dri2_surf->base.GLColorspace); if (!config) { @@ -183,11 +229,22 @@ dri2_drm_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf, return &dri2_surf->base; cleanup_surf: + if (type == EGL_PBUFFER_BIT && surface != NULL) + gbm_surface_destroy(surface); + free(dri2_surf); return NULL; } +static _EGLSurface * +dri2_drm_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf, + void *native_surface, const EGLint *attrib_list) +{ + return dri2_drm_create_surface(disp, EGL_WINDOW_BIT, conf, + native_surface, attrib_list); +} + static _EGLSurface * dri2_drm_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf, void *native_window, const EGLint *attrib_list) @@ -202,6 +259,14 @@ dri2_drm_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf, return NULL; } +static _EGLSurface * +dri2_drm_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf, + const EGLint *attrib_list) +{ + return dri2_drm_create_surface(disp, EGL_PBUFFER_BIT, conf, + NULL, attrib_list); +} + static EGLBoolean dri2_drm_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf) { @@ -217,6 +282,11 @@ dri2_drm_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf) dri2_egl_surface_free_local_buffers(dri2_surf); + dri2_drm_free_front_image(dri2_surf); + + if (surf->Type == EGL_PBUFFER_BIT) + gbm_surface_destroy(&dri2_surf->gbm_surf->base); + dri2_fini_surface(surf); free(surf); @@ -402,12 +472,27 @@ dri2_drm_image_get_buffers(__DRIdrawable *driDrawable, struct dri2_egl_surface *dri2_surf = loaderPrivate; struct gbm_dri_bo *bo; - if (get_back_bo(dri2_surf) < 0) - return 0; + buffers->image_mask = 0; + buffers->front = NULL; + buffers->back = NULL; - bo = gbm_dri_bo(dri2_surf->back->bo); - buffers->image_mask = __DRI_IMAGE_BUFFER_BACK; - buffers->back = bo->image; + if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) { + if (!dri2_drm_alloc_front_image(dri2_surf)) + return 0; + + bo = gbm_dri_bo(dri2_surf->front_bo); + buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT; + buffers->front = bo->image; + } + + if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) { + if (get_back_bo(dri2_surf) < 0) + return 0; + + bo = gbm_dri_bo(dri2_surf->back->bo); + buffers->image_mask |= __DRI_IMAGE_BUFFER_BACK; + buffers->back = bo->image; + } return 1; } @@ -425,6 +510,9 @@ dri2_drm_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw) struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); + if (dri2_surf->base.Type != EGL_WINDOW_BIT) + return EGL_TRUE; + if (!dri2_dpy->flush) { dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable); return EGL_TRUE; @@ -507,7 +595,7 @@ dri2_drm_authenticate(_EGLDisplay *disp, uint32_t id) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); - return drmAuthMagic(dri2_dpy->fd, id); + return drmAuthMagic(dri2_dpy->fd_dpy, id); } static void @@ -648,7 +736,8 @@ drm_add_configs_for_visuals(_EGLDisplay *disp) }; dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i], - config_count + 1, EGL_WINDOW_BIT, attr_list, NULL, NULL); + config_count + 1, EGL_WINDOW_BIT | EGL_PBUFFER_BIT, + attr_list, NULL, NULL); if (dri2_conf) { if (dri2_conf->base.ConfigID == config_count + 1) config_count++; @@ -672,6 +761,7 @@ static const struct dri2_egl_display_vtbl dri2_drm_display_vtbl = { .authenticate = dri2_drm_authenticate, .create_window_surface = dri2_drm_create_window_surface, .create_pixmap_surface = dri2_drm_create_pixmap_surface, + .create_pbuffer_surface = dri2_drm_create_pbuffer_surface, .destroy_surface = dri2_drm_destroy_surface, .create_image = dri2_drm_create_image_khr, .swap_buffers = dri2_drm_swap_buffers, @@ -692,6 +782,7 @@ dri2_initialize_drm(_EGLDisplay *disp) return _eglError(EGL_BAD_ALLOC, "eglInitialize"); dri2_dpy->fd = -1; + dri2_dpy->fd_dpy = -1; disp->DriverData = (void *) dri2_dpy; gbm = disp->PlatformDisplay; @@ -699,16 +790,16 @@ dri2_initialize_drm(_EGLDisplay *disp) char buf[64]; int n = snprintf(buf, sizeof(buf), DRM_DEV_NAME, DRM_DIR_NAME, 0); if (n != -1 && n < sizeof(buf)) - dri2_dpy->fd = loader_open_device(buf); - gbm = gbm_create_device(dri2_dpy->fd); + dri2_dpy->fd_dpy = loader_open_device(buf); + gbm = gbm_create_device(dri2_dpy->fd_dpy); if (gbm == NULL) { err = "DRI2: failed to create gbm device"; goto cleanup; } dri2_dpy->own_device = true; } else { - dri2_dpy->fd = os_dupfd_cloexec(gbm_device_get_fd(gbm)); - if (dri2_dpy->fd < 0) { + dri2_dpy->fd_dpy = os_dupfd_cloexec(gbm_device_get_fd(gbm)); + if (dri2_dpy->fd_dpy < 0) { err = "DRI2: failed to fcntl() existing gbm device"; goto cleanup; } @@ -720,6 +811,12 @@ dri2_initialize_drm(_EGLDisplay *disp) goto cleanup; } + if (gbm_dri_device_get_fd(dri2_dpy->gbm_dri) == + gbm_device_get_fd(gbm)) + dri2_dpy->fd = dri2_dpy->fd_dpy; + else + dri2_dpy->fd = os_dupfd_cloexec(gbm_dri_device_get_fd(dri2_dpy->gbm_dri)); + dev = _eglAddDevice(dri2_dpy->fd, dri2_dpy->gbm_dri->software); if (!dev) { err = "DRI2: failed to find EGLDevice"; @@ -785,7 +882,7 @@ dri2_initialize_drm(_EGLDisplay *disp) disp->Extensions.EXT_buffer_age = EGL_TRUE; #ifdef HAVE_WAYLAND_PLATFORM - dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd); + dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd_dpy); #endif dri2_set_WL_bind_wayland_display(disp); diff --git a/src/egl/drivers/dri2/platform_null.c b/src/egl/drivers/dri2/platform_null.c new file mode 100644 index 0000000..7e631e0 --- /dev/null +++ b/src/egl/drivers/dri2/platform_null.c @@ -0,0 +1,2210 @@ +/* + * Copyright (c) Imagination Technologies Ltd. + * + * Parts based on platform_wayland, which has: + * + * Copyright © 2011-2012 Intel Corporation + * Copyright © 2012 Collabora, Ltd. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "egl_dri2.h" +#include "loader.h" +#include "util/os_file.h" + +#define NULL_CARD_MINOR_MAX 63U + +/* + * Need at least version 4 for __DRI_IMAGE_ATTRIB_WIDTH and + * __DRI_IMAGE_ATTRIB_HEIGHT + */ +#define NULL_IMAGE_EXTENSION_VERSION_MIN 4 + +struct object_property { + uint32_t object_id; + uint32_t prop_id; + uint64_t prop_value; +}; + +static inline +uint32_t get_back_buffer_id(struct dri2_egl_surface *dri2_surf) +{ + uintptr_t offset = ((uintptr_t) dri2_surf->back) - + ((uintptr_t) &dri2_surf->color_buffers[0]); + + assert(dri2_surf->back && !(offset >> 32)); + + return (uint32_t) (offset / sizeof(dri2_surf->color_buffers[0])); +} + +#define object_property_set_named(output, object_type, prop_name, value) \ + { \ + .object_id = (output)->object_type##_id, \ + .prop_id = property_id_get_for_name((output)->object_type##_prop_res, \ + prop_name), \ + .prop_value = value, \ + } + +static const struct dri2_null_yuv_attrib { + uint32_t order; + uint32_t subsample; + uint32_t num_planes; + uint32_t plane_bpp; +} dri2_null_yuv_attribs[] = { + { + /* __DRI_IMAGE_FORMAT_YUYV */ + .order = __DRI_ATTRIB_YUV_ORDER_YUYV_BIT, + .subsample = __DRI_ATTRIB_YUV_SUBSAMPLE_4_2_2_BIT, + .num_planes = 1, + .plane_bpp = __DRI_ATTRIB_YUV_PLANE_BPP_8_BIT, + }, + { + /* __DRI_IMAGE_FORMAT_NV12 */ + .order = __DRI_ATTRIB_YUV_ORDER_YUV_BIT, + .subsample = __DRI_ATTRIB_YUV_SUBSAMPLE_4_2_0_BIT, + .num_planes = 2, + .plane_bpp = __DRI_ATTRIB_YUV_PLANE_BPP_8_BIT, + }, + { + /* __DRI_IMAGE_FORMAT_NV21 */ + .order = __DRI_ATTRIB_YUV_ORDER_YVU_BIT, + .subsample = __DRI_ATTRIB_YUV_SUBSAMPLE_4_2_0_BIT, + .num_planes = 2, + .plane_bpp = __DRI_ATTRIB_YUV_PLANE_BPP_8_BIT, + }, + { + /* __DRI_IMAGE_FORMAT_YU12 */ + .order = __DRI_ATTRIB_YUV_ORDER_YUV_BIT, + .subsample = __DRI_ATTRIB_YUV_SUBSAMPLE_4_2_0_BIT, + .num_planes = 3, + .plane_bpp = __DRI_ATTRIB_YUV_PLANE_BPP_8_BIT, + }, + { + /* __DRI_IMAGE_FORMAT_YV12 */ + .order = __DRI_ATTRIB_YUV_ORDER_YVU_BIT, + .subsample = __DRI_ATTRIB_YUV_SUBSAMPLE_4_2_0_BIT, + .num_planes = 3, + .plane_bpp = __DRI_ATTRIB_YUV_PLANE_BPP_8_BIT, + }, + { + /* __DRI_IMAGE_FORMAT_UYVY */ + .order = __DRI_ATTRIB_YUV_ORDER_UYVY_BIT, + .subsample = __DRI_ATTRIB_YUV_SUBSAMPLE_4_2_2_BIT, + .num_planes = 1, + .plane_bpp = __DRI_ATTRIB_YUV_PLANE_BPP_8_BIT, + }, + { + /* __DRI_IMAGE_FORMAT_YVYU */ + .order = __DRI_ATTRIB_YUV_ORDER_YVYU_BIT, + .subsample = __DRI_ATTRIB_YUV_SUBSAMPLE_4_2_2_BIT, + .num_planes = 1, + .plane_bpp = __DRI_ATTRIB_YUV_PLANE_BPP_8_BIT, + }, + { + /* __DRI_IMAGE_FORMAT_VYUY */ + .order = __DRI_ATTRIB_YUV_ORDER_VYUY_BIT, + .subsample = __DRI_ATTRIB_YUV_SUBSAMPLE_4_2_2_BIT, + .num_planes = 1, + .plane_bpp = __DRI_ATTRIB_YUV_PLANE_BPP_8_BIT, + }, +}; + +/* + * The index of entries in this table is used as a bitmask in + * dri2_dpy->formats, which tracks the formats supported by the display. + */ +static const struct dri2_null_format { + uint32_t drm_format; + int dri_image_format; + int rgba_shifts[4]; + unsigned int rgba_sizes[4]; + const struct dri2_null_yuv_attrib *yuv; +} dri2_null_formats[] = { + { + .drm_format = DRM_FORMAT_XRGB8888, + .dri_image_format = __DRI_IMAGE_FORMAT_XRGB8888, + .rgba_shifts = { 16, 8, 0, -1 }, + .rgba_sizes = { 8, 8, 8, 0 }, + .yuv = NULL, + }, + { + .drm_format = DRM_FORMAT_ARGB8888, + .dri_image_format = __DRI_IMAGE_FORMAT_ARGB8888, + .rgba_shifts = { 16, 8, 0, 24 }, + .rgba_sizes = { 8, 8, 8, 8 }, + .yuv = NULL, + }, + { + .drm_format = DRM_FORMAT_RGB565, + .dri_image_format = __DRI_IMAGE_FORMAT_RGB565, + .rgba_shifts = { 11, 5, 0, -1 }, + .rgba_sizes = { 5, 6, 5, 0 }, + .yuv = NULL, + }, + { + .drm_format = DRM_FORMAT_YUYV, + .dri_image_format = __DRI_IMAGE_FORMAT_YUYV, + .rgba_shifts = { -1, -1, -1, -1 }, + .rgba_sizes = { 0, 0, 0, 0 }, + .yuv = &dri2_null_yuv_attribs[0], + }, + { + .drm_format = DRM_FORMAT_NV12, + .dri_image_format = __DRI_IMAGE_FORMAT_NV12, + .rgba_shifts = { -1, -1, -1, -1 }, + .rgba_sizes = { 0, 0, 0, 0 }, + .yuv = &dri2_null_yuv_attribs[1], + }, + { + .drm_format = DRM_FORMAT_NV21, + .dri_image_format = __DRI_IMAGE_FORMAT_NV21, + .rgba_shifts = { -1, -1, -1, -1 }, + .rgba_sizes = { 0, 0, 0, 0 }, + .yuv = &dri2_null_yuv_attribs[2], + }, + { + .drm_format = DRM_FORMAT_YUV420, + .dri_image_format = __DRI_IMAGE_FORMAT_YU12, + .rgba_shifts = { -1, -1, -1, -1 }, + .rgba_sizes = { 0, 0, 0, 0 }, + .yuv = &dri2_null_yuv_attribs[3], + }, + { + .drm_format = DRM_FORMAT_YVU420, + .dri_image_format = __DRI_IMAGE_FORMAT_YV12, + .rgba_shifts = { -1, -1, -1, -1 }, + .rgba_sizes = { 0, 0, 0, 0 }, + .yuv = &dri2_null_yuv_attribs[4], + }, + { + .drm_format = DRM_FORMAT_UYVY, + .dri_image_format = __DRI_IMAGE_FORMAT_UYVY, + .rgba_shifts = { -1, -1, -1, -1 }, + .rgba_sizes = { 0, 0, 0, 0 }, + .yuv = &dri2_null_yuv_attribs[5], + }, + { + .drm_format = DRM_FORMAT_YVYU, + .dri_image_format = __DRI_IMAGE_FORMAT_YVYU, + .rgba_shifts = { -1, -1, -1, -1 }, + .rgba_sizes = { 0, 0, 0, 0 }, + .yuv = &dri2_null_yuv_attribs[6], + }, + { + .drm_format = DRM_FORMAT_VYUY, + .dri_image_format = __DRI_IMAGE_FORMAT_VYUY, + .rgba_shifts = { -1, -1, -1, -1 }, + .rgba_sizes = { 0, 0, 0, 0 }, + .yuv = &dri2_null_yuv_attribs[7], + }, +}; + + +static int +format_idx_get_from_config(struct dri2_egl_display *dri2_dpy, + const __DRIconfig *config) +{ + int shifts[4]; + unsigned int sizes[4]; + + dri2_get_shifts_and_sizes(dri2_dpy->core, config, shifts, sizes); + + for (unsigned int i = 0; i < ARRAY_SIZE(dri2_null_formats); i++) { + const struct dri2_null_format *format = &dri2_null_formats[i]; + + if (shifts[0] == format->rgba_shifts[0] && + shifts[1] == format->rgba_shifts[1] && + shifts[2] == format->rgba_shifts[2] && + shifts[3] == format->rgba_shifts[3] && + sizes[0] == format->rgba_sizes[0] && + sizes[1] == format->rgba_sizes[1] && + sizes[2] == format->rgba_sizes[2] && + sizes[3] == format->rgba_sizes[3]) { + return i; + } + } + + return -1; +} + +static int +yuv_format_idx_get_from_config(struct dri2_egl_display *dri2_dpy, + const __DRIconfig *dri_config) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(dri2_null_formats); i++) { + const struct dri2_null_yuv_attrib *yuv = dri2_null_formats[i].yuv; + unsigned order, subsample, num_planes, plane_bpp; + + if (!yuv) + continue; + + dri2_dpy->core->getConfigAttrib(dri_config, __DRI_ATTRIB_YUV_ORDER, + &order); + dri2_dpy->core->getConfigAttrib(dri_config, __DRI_ATTRIB_YUV_SUBSAMPLE, + &subsample); + dri2_dpy->core->getConfigAttrib(dri_config, __DRI_ATTRIB_YUV_NUMBER_OF_PLANES, + &num_planes); + dri2_dpy->core->getConfigAttrib(dri_config, __DRI_ATTRIB_YUV_PLANE_BPP, + &plane_bpp); + + if (order != yuv->order || subsample != yuv->subsample || + num_planes != yuv->num_planes || plane_bpp != yuv->plane_bpp) + continue; + + return i; + } + + return -1; +} + +static int +format_idx_get_from_dri_image_format(uint32_t dri_image_format) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(dri2_null_formats); i++) + if (dri2_null_formats[i].dri_image_format == dri_image_format) + return i; + + return -1; +} + +static int +format_idx_get_from_drm_format(uint32_t drm_format) +{ + for (unsigned int i = 0; i < ARRAY_SIZE(dri2_null_formats); i++) + if (dri2_null_formats[i].drm_format == drm_format) + return i; + + return -1; +} + +static inline uint32_t +blob_id_from_property_value(uint64_t prop_value) +{ + /* The KMS properties documetation, 01.org/linuxgraphics, says: + * + * For all property types except blob properties the value is a 64-bit + * unsigned integer. + */ + assert(!(prop_value >> 32)); + return (uint32_t) prop_value; +} + +static int +atomic_state_add_object_properties(drmModeAtomicReq *atomic_state, + const struct object_property *props, + const unsigned prop_count) +{ + for (unsigned i = 0; i < prop_count; i++) { + int err; + + if (props[i].prop_id == 0) + return -EINVAL; + + err = drmModeAtomicAddProperty(atomic_state, props[i].object_id, + props[i].prop_id, props[i].prop_value); + if (err < 0) + return err; + } + + return 0; +} + + +static uint32_t +property_id_get_for_name(drmModePropertyRes **prop_res, const char *prop_name) +{ + if (prop_res) + for (unsigned i = 0; prop_res[i]; i++) + if (!strcmp(prop_res[i]->name, prop_name)) + return prop_res[i]->prop_id; + + return 0; +} + +static drmModePropertyRes ** +object_get_property_resources(int fd, uint32_t object_id, uint32_t object_type) +{ + drmModeObjectProperties *props; + drmModePropertyRes **prop_res; + + props = drmModeObjectGetProperties(fd, object_id, object_type); + if (!props) + return NULL; + + prop_res = malloc((props->count_props + 1) * sizeof(*prop_res)); + if (prop_res) { + prop_res[props->count_props] = NULL; + + for (unsigned i = 0; i < props->count_props; i++) { + prop_res[i] = drmModeGetProperty(fd, props->props[i]); + if (!prop_res[i]) { + while (i--) { + drmModeFreeProperty(prop_res[i]); + free(prop_res); + prop_res = NULL; + } + break; + } + } + } + + drmModeFreeObjectProperties(props); + + return prop_res; +} + +static void +object_free_property_resources(int fd, drmModePropertyRes **prop_res) +{ + for (unsigned i = 0; prop_res[i]; i++) + drmModeFreeProperty(prop_res[i]); + free(prop_res); +} + +static bool +object_property_value_for_name(int fd, uint32_t object_id, uint32_t object_type, + const char *prop_name, uint64_t *value_out) +{ + drmModeObjectProperties *plane_props; + bool found = false; + + plane_props = drmModeObjectGetProperties(fd, object_id, object_type); + if (!plane_props) + return false; + + for (unsigned i = 0; i < plane_props->count_props; i++) { + drmModePropertyRes *prop; + + prop = drmModeGetProperty(fd, plane_props->props[i]); + if (!prop) + continue; + + found = !strcmp(prop->name, prop_name); + drmModeFreeProperty(prop); + if (found) { + *value_out = plane_props->prop_values[i]; + break; + } + } + + drmModeFreeObjectProperties(plane_props); + + return found; +} + +static int +connector_choose_mode(drmModeConnector *connector) +{ + if (!connector->count_modes) + return -1; + + for (unsigned i = 0; i < connector->count_modes; i++) { + if (connector->modes[i].flags & DRM_MODE_FLAG_INTERLACE) + continue; + + if (connector->modes[i].type & DRM_MODE_TYPE_PREFERRED) + return i; + } + + return 0; +} + +static drmModeConnector * +connector_get(int fd, drmModeRes *resources) +{ + /* Find the first connected connector */ + for (unsigned i = 0; i < resources->count_connectors; i++) { + drmModeConnector *connector; + + connector = drmModeGetConnector(fd, resources->connectors[i]); + if (!connector) + continue; + + if (connector->connection == DRM_MODE_CONNECTED) + return connector; + + drmModeFreeConnector(connector); + } + + return NULL; +} + +static drmModeCrtc * +crtc_get_for_connector(int fd, drmModeRes *resources, + drmModeConnector *connector) +{ + for (unsigned i = 0; i < connector->count_encoders; i++) { + drmModeEncoder *encoder; + + encoder = drmModeGetEncoder(fd, connector->encoders[i]); + if (!encoder) + continue; + + for (unsigned j = 0; j < resources->count_crtcs; j++) { + if (encoder->possible_crtcs & (1 << j)) { + drmModeCrtc *crtc; + + crtc = drmModeGetCrtc(fd, resources->crtcs[j]); + if (crtc) { + drmModeFreeEncoder(encoder); + return crtc; + } + } + } + + drmModeFreeEncoder(encoder); + } + + return NULL; +} + +static drmModePlane * +primary_plane_get_for_crtc(int fd, drmModeRes *resources, drmModeCrtc *crtc) +{ + drmModePlaneRes *plane_resources; + unsigned crtc_idx; + + plane_resources = drmModeGetPlaneResources(fd); + if (!plane_resources) + return NULL; + + for (crtc_idx = 0; crtc_idx < resources->count_crtcs; crtc_idx++) + if (resources->crtcs[crtc_idx] == crtc->crtc_id) + break; + assert(crtc_idx != resources->count_crtcs); + + for (unsigned i = 0; i < plane_resources->count_planes; i++) { + const uint32_t crtc_bit = 1 << crtc_idx; + drmModePlane *plane; + + plane = drmModeGetPlane(fd, plane_resources->planes[i]); + if (!plane) + continue; + + if (plane->possible_crtcs & crtc_bit) { + uint64_t type; + bool res; + + res = object_property_value_for_name(fd, plane->plane_id, + DRM_MODE_OBJECT_PLANE, + "type", &type); + if (res && type == DRM_PLANE_TYPE_PRIMARY) { + drmModeFreePlaneResources(plane_resources); + return plane; + } + } + + drmModeFreePlane(plane); + } + + drmModeFreePlaneResources(plane_resources); + + return NULL; +} + +static bool +display_output_atomic_init(int fd, struct display_output *output) +{ + drmModePropertyRes **connector_prop_res; + drmModePropertyRes **crtc_prop_res; + drmModePropertyRes **plane_prop_res; + int err; + + connector_prop_res = object_get_property_resources(fd, output->connector_id, + DRM_MODE_OBJECT_CONNECTOR); + if (!connector_prop_res) + return false; + + crtc_prop_res = object_get_property_resources(fd, output->crtc_id, + DRM_MODE_OBJECT_CRTC); + if (!crtc_prop_res) + goto err_free_connector_prop_res; + + plane_prop_res = object_get_property_resources(fd, output->plane_id, + DRM_MODE_OBJECT_PLANE); + if (!plane_prop_res) + goto err_free_crtc_prop_res; + + err = drmModeCreatePropertyBlob(fd, &output->mode, sizeof(output->mode), + &output->mode_blob_id); + if (err) + goto err_free_plane_prop_res; + + output->atomic_state = drmModeAtomicAlloc(); + if (!output->atomic_state) + goto err_destroy_mode_prop_blob; + + if (property_id_get_for_name(plane_prop_res, "IN_FENCE_FD")) + output->in_fence_supported = true; + + output->connector_prop_res = connector_prop_res; + output->crtc_prop_res = crtc_prop_res; + output->plane_prop_res = plane_prop_res; + + return true; + +err_destroy_mode_prop_blob: + drmModeDestroyPropertyBlob(fd, output->mode_blob_id); +err_free_plane_prop_res: + object_free_property_resources(fd, plane_prop_res); +err_free_crtc_prop_res: + object_free_property_resources(fd, crtc_prop_res); +err_free_connector_prop_res: + object_free_property_resources(fd, connector_prop_res); + return false; +} + +static void +display_output_atomic_add_in_fence(struct display_output *output, + int kms_in_fence_fd) +{ + const struct object_property obj_sync_props[] = { + object_property_set_named(output, plane, "IN_FENCE_FD", kms_in_fence_fd), + }; + int err; + + /* Explicit synchronisation is not being used */ + if (kms_in_fence_fd < 0) + return; + + err = atomic_state_add_object_properties(output->atomic_state, + obj_sync_props, + ARRAY_SIZE(obj_sync_props)); + if (err) + _eglLog(_EGL_DEBUG, "%s: failed to add props ERR = %d", __func__, err); +} + +static void +atomic_claim_in_fence_fd(struct dri2_egl_surface *dri2_surf, + struct swap_queue_elem *swap_data) +{ + /* Explicit synchronisation is not being used */ + if (!dri2_surf->enable_out_fence) + return; + + if (dri2_surf->out_fence_fd < 0) { + _eglLog(_EGL_DEBUG, "%s: missing 'in' fence", __func__); + return; + } + + /* Take ownership of the fd */ + swap_data->kms_in_fence_fd = dri2_surf->out_fence_fd; + dri2_surf->out_fence_fd = -1; +} + +static void +atomic_relinquish_in_fence_fd(struct dri2_egl_surface *dri2_surf, + struct swap_queue_elem *swap_data) +{ + /* KMS is now in control of the fence (post drmModeAtomicCommit) */ + close(swap_data->kms_in_fence_fd); + swap_data->kms_in_fence_fd = -1; +} + +static int +display_output_atomic_flip(int fd, struct display_output *output, uint32_t fb_id, + uint32_t flags, void *flip_data) +{ + const struct object_property obj_props[] = { + object_property_set_named(output, plane, "FB_ID", fb_id), + }; + struct dri2_egl_surface *dri2_surf = flip_data; + struct swap_queue_elem *swap_data = dri2_surf->swap_data; + int err; + + /* Reset atomic state */ + drmModeAtomicSetCursor(output->atomic_state, 0); + + err = atomic_state_add_object_properties(output->atomic_state, obj_props, + ARRAY_SIZE(obj_props)); + if (err) + return err; + + display_output_atomic_add_in_fence(output, swap_data->kms_in_fence_fd); + + /* + * Don't block - like drmModePageFlip, drmModeAtomicCommit will return + * -EBUSY if the commit can't be queued in the kernel. + */ + flags |= DRM_MODE_ATOMIC_NONBLOCK; + + err = drmModeAtomicCommit(fd, output->atomic_state, flags, flip_data); + + atomic_relinquish_in_fence_fd(dri2_surf, swap_data); + + return err; +} + +static int +display_output_atomic_modeset(int fd, struct display_output *output, uint32_t fb_id) +{ + /* SRC_W and SRC_H in 16.16 fixed point */ + const struct object_property obj_props[] = { + object_property_set_named(output, connector, "CRTC_ID", output->crtc_id), + object_property_set_named(output, crtc, "ACTIVE", 1), + object_property_set_named(output, crtc, "MODE_ID", output->mode_blob_id), + object_property_set_named(output, plane, "FB_ID", fb_id), + object_property_set_named(output, plane, "CRTC_ID", output->crtc_id), + object_property_set_named(output, plane, "CRTC_X", 0), + object_property_set_named(output, plane, "CRTC_Y", 0), + object_property_set_named(output, plane, "CRTC_W", output->mode.hdisplay), + object_property_set_named(output, plane, "CRTC_H", output->mode.vdisplay), + object_property_set_named(output, plane, "SRC_X", 0), + object_property_set_named(output, plane, "SRC_Y", 0), + object_property_set_named(output, plane, "SRC_W", output->mode.hdisplay << 16), + object_property_set_named(output, plane, "SRC_H", output->mode.vdisplay << 16), + }; + int err; + + /* Reset atomic state */ + drmModeAtomicSetCursor(output->atomic_state, 0); + + err = atomic_state_add_object_properties(output->atomic_state, obj_props, + ARRAY_SIZE(obj_props)); + if (err) + return false; + + return drmModeAtomicCommit(fd, output->atomic_state, + DRM_MODE_ATOMIC_ALLOW_MODESET, NULL); +} + +static void +swap_enqueue_data(struct dri2_egl_surface *dri2_surf, uint32_t back_id, + uint32_t interval) +{ + struct swap_queue_elem *swap_data; + + pthread_mutex_lock(&dri2_surf->mutex); + swap_data = &dri2_surf->swap_queue[dri2_surf->swap_queue_idx_tail]; + swap_data->swap_interval = interval; + swap_data->fb_id = dri2_surf->back->fb_id; + swap_data->back_id = back_id; + + atomic_claim_in_fence_fd(dri2_surf, swap_data); + + dri2_surf->swap_queue_idx_tail++; + dri2_surf->swap_queue_idx_tail %= ARRAY_SIZE(dri2_surf->swap_queue); + + /* Notify the swap thread there is new work to do */ + pthread_cond_signal(&dri2_surf->swap_queue_cond); + pthread_mutex_unlock(&dri2_surf->mutex); +} + +static void +swap_dequeue_data_start(struct dri2_egl_surface *dri2_surf) +{ + pthread_mutex_lock(&dri2_surf->mutex); + while (dri2_surf->swap_queue_idx_head == dri2_surf->swap_queue_idx_tail) + pthread_cond_wait(&dri2_surf->swap_queue_cond, &dri2_surf->mutex); + + dri2_surf->swap_data = + &dri2_surf->swap_queue[dri2_surf->swap_queue_idx_head]; + pthread_mutex_unlock(&dri2_surf->mutex); +} + +static void +swap_dequeue_data_finish(struct dri2_egl_surface *dri2_surf) +{ + pthread_mutex_lock(&dri2_surf->mutex); + + if (dri2_surf->current) + dri2_surf->current->locked = false; + + dri2_surf->current = + &dri2_surf->color_buffers[dri2_surf->swap_data->back_id]; + dri2_surf->swap_state = SWAP_IDLE; + + dri2_surf->swap_queue_idx_head++; + dri2_surf->swap_queue_idx_head %= ARRAY_SIZE(dri2_surf->swap_queue); + + /* Notify get_back_bo that a buffer has become available */ + pthread_cond_signal(&dri2_surf->swap_unlock_buffer_cond); + pthread_mutex_unlock(&dri2_surf->mutex); +} + +static void +swap_drain_queue_data(struct dri2_egl_surface *dri2_surf) +{ + pthread_mutex_lock(&dri2_surf->mutex); + while (dri2_surf->swap_queue_idx_head != dri2_surf->swap_queue_idx_tail) + pthread_cond_wait(&dri2_surf->swap_unlock_buffer_cond, &dri2_surf->mutex); + pthread_mutex_unlock(&dri2_surf->mutex); +} + +static void +flip_handler(int fd, unsigned int sequence, unsigned int tv_sec, + unsigned int tv_usec, void *flip_data) +{ + struct dri2_egl_surface *dri2_surf = flip_data; + + (void) tv_sec; + (void) tv_usec; + (void) sequence; + + /* Ultimate queueing ops */ + swap_dequeue_data_finish(dri2_surf); +} + +static void +vblank_handler(int fd, unsigned int sequence, unsigned int tv_sec, + unsigned int tv_usec, void *vblank_data) +{ + struct dri2_egl_surface *dri2_surf = vblank_data; + + (void) tv_sec; + (void) tv_usec; + (void) sequence; + + dri2_surf->swap_state = SWAP_FLIP; +} + +static int +drm_event_process(int fd) +{ + static drmEventContext evctx = { + .version = 2, + .page_flip_handler = flip_handler, + .vblank_handler = vblank_handler + }; + struct pollfd pfd = {.fd = fd, .events = POLLIN}; + int ret; + + do { + ret = poll(&pfd, 1, -1); + } while (ret > 0 && pfd.revents != pfd.events); + + if (ret <= 0) + /* Man says: + * + * On error, -1 is returned, and errno is set to indicate the + * cause of the error. + */ + return -1; + + drmHandleEvent(fd, &evctx); + + return 0; +} + +static bool +plane_init_in_formats(int fd, drmModePlane *plane, struct u_vector *modifiers, + uint32_t *in_formats_id_out, unsigned *formats_out) +{ + uint32_t blob_id, prev_fmt = DRM_FORMAT_INVALID, count_formats = 0; + drmModeFormatModifierIterator drm_iter = {0}; + drmModePropertyBlobRes *blob; + uint64_t prop_value; + int idx, err; + + assert(plane && in_formats_id_out && formats_out); + + err = !object_property_value_for_name(fd, plane->plane_id, + DRM_MODE_OBJECT_PLANE, + "IN_FORMATS", &prop_value); + if (err) + return false; + + blob_id = blob_id_from_property_value(prop_value); + blob = drmModeGetPropertyBlob(fd, blob_id); + + while (drmModeFormatModifierBlobIterNext(blob, &drm_iter)) { + if (drm_iter.fmt != prev_fmt) { + prev_fmt = drm_iter.fmt; + count_formats++; + + idx = format_idx_get_from_drm_format(drm_iter.fmt); + if (idx < 0) + continue; + + *formats_out |= (1 << idx); + } + } + + drmModeFreePropertyBlob(blob); + + if (!count_formats) { + /* None of the formats in the IN_FORMATS blob has associated modifiers */ + _eglLog(_EGL_WARNING, "no format-modifiers found in IN_FORMATS"); + return false; + } + + if (plane->count_formats != count_formats) + /* Only some of the formats in the IN_FORMATS blob have associated modifiers, + * try to use this subset. + */ + _eglLog(_EGL_WARNING, "discarding formats without modifiers"); + + /* Allocate space for modifiers, if ENOMEM fallback to plane formats */ + if (!u_vector_init(modifiers, sizeof(uint64_t), 64)) { + _eglLog(_EGL_WARNING, "failed to allocate modifiers"); + return false; + } + + *in_formats_id_out = blob_id; + return true; +} + +static bool +display_output_init(int fd, struct display_output *output, bool use_atomic, + bool prefer_in_formats, bool *in_formats_enabled_out) +{ + drmModeRes *resources; + drmModeConnector *connector; + drmModeCrtc *crtc; + drmModePlane *plane; + unsigned mode_idx; + + resources = drmModeGetResources(fd); + if (!resources) + return false; + + connector = connector_get(fd, resources); + if (!connector) + goto err_free_resources; + + crtc = crtc_get_for_connector(fd, resources, connector); + if (!crtc) + goto err_free_connector; + + plane = primary_plane_get_for_crtc(fd, resources, crtc); + if (!plane) + goto err_free_crtc; + + mode_idx = connector_choose_mode(connector); + if (mode_idx < 0) + goto err_free_plane; + output->mode = connector->modes[mode_idx]; + + assert(in_formats_enabled_out && !(*in_formats_enabled_out)); + + /* Track display supported formats. Look them up from IN_FORMATS blobs + * if they are available, otherwise use plane formats. + */ + if (prefer_in_formats) + *in_formats_enabled_out = plane_init_in_formats(fd, plane, + &output->modifiers, + &output->in_formats_id, + &output->formats); + + if (!*in_formats_enabled_out) { + _eglLog(_EGL_WARNING, "fallback to plane formats"); + + for (unsigned i = 0; i < plane->count_formats; i++) { + int format_idx; + + format_idx = format_idx_get_from_drm_format(plane->formats[i]); + if (format_idx == -1) + continue; + + output->formats |= (1 << format_idx); + } + } + + /* At this point we can only shut down if the look up failed and + * it is safe to pass NULL to drmModeFreeFormats(). + */ + if (!output->formats) + goto err_free_plane; + + output->connector_id = connector->connector_id; + output->crtc_id = crtc->crtc_id; + output->plane_id = plane->plane_id; + + drmModeFreePlane(plane); + drmModeFreeCrtc(crtc); + drmModeFreeConnector(connector); + drmModeFreeResources(resources); + + if (use_atomic) { + if (!display_output_atomic_init(fd, output)) { + _eglLog(_EGL_DEBUG, + "failed to initialise atomic support (using legacy mode)"); + } + } + + return true; + +err_free_plane: + drmModeFreePlane(plane); +err_free_crtc: + drmModeFreeCrtc(crtc); +err_free_connector: + drmModeFreeConnector(connector); +err_free_resources: + drmModeFreeResources(resources); + return false; +} + +static int +display_output_flip(int fd, struct display_output *output, uint32_t fb_id, + uint32_t flags, void *flip_data) +{ + int err; + + do { + if (output->atomic_state) + err = display_output_atomic_flip(fd, output, fb_id, flags, flip_data); + else + err = drmModePageFlip(fd, output->crtc_id, fb_id, flags, flip_data); + } while (err == -EBUSY); + + return err; +} + +static int +display_request_vblank(int fd, uint32_t target_frame, uint32_t flags, + void *vblank_data) +{ + drmVBlank vblank = { + .request = { + .type = flags, + .sequence = target_frame, + .signal = (unsigned long)vblank_data, + } + }; + + return drmWaitVBlank(fd, &vblank); +} + +static int +display_get_vblank_sequence(int fd, uint32_t *current_vblank_out) +{ + drmVBlank vblank = { .request = { .type = DRM_VBLANK_RELATIVE } }; + int err; + + err = drmWaitVBlank(fd, &vblank); + if (err) + return err; + + *current_vblank_out = vblank.reply.sequence; + + return 0; +} + +static int +display_output_modeset(int fd, struct display_output *output, uint32_t fb_id) +{ + if (output->atomic_state) + return display_output_atomic_modeset(fd, output, fb_id); + + return drmModeSetCrtc(fd, output->crtc_id, fb_id, 0, 0, + &output->connector_id, 1, &output->mode); +} + +static int +swap_idle_get_target_frame(struct dri2_egl_surface *dri2_surf, + uint32_t *current_vblank_out, uint32_t *target_frame_out) +{ + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + int err; + + /* For intarvals bigger than 1, always update current_vblank. The + * spec isn't fully clear, nonetheless page 25 and 26 of the PDF of the + * EGL 1.5 spec say: + * + * "[the parameter interval] indicates the number of swap intervals + * that will elapse before a buffer swap takes place after calling + * eglSwapBuffers." + * + * We need to guarantee that the target frame is always ahead of the + * current vblank by the number of intervals set at the time swapBuffer + * is called. For intervals of 1 or 0, we don't need a target frame. + */ + err = display_get_vblank_sequence(dri2_dpy->fd_dpy, current_vblank_out); + if (err) + return err; + + assert(dri2_surf->swap_data->swap_interval > 0); + + /* -1 accounts for vsync locked flip, so get a vblank one frame earlier */ + *target_frame_out = + *current_vblank_out + dri2_surf->swap_data->swap_interval - 1; + + return 0; +} + +static int +swap_idle_state_transition(struct dri2_egl_surface *dri2_surf, + uint32_t *target_frame_out) +{ + uint32_t current_vblank = 0; + uint32_t target_frame = 0; + int err; + + /* update dri2_surf->swap_data */ + swap_dequeue_data_start(dri2_surf); + + /* update next target frame */ + if (dri2_surf->swap_data->swap_interval > 1) { + err = swap_idle_get_target_frame(dri2_surf, ¤t_vblank, + &target_frame); + if (err) { + dri2_surf->swap_state = SWAP_ERROR; + return err; + } + } + + dri2_surf->swap_state = + target_frame <= current_vblank ? SWAP_FLIP : SWAP_VBLANK; + *target_frame_out = target_frame; + + return 0; +} + +static int +swap_vblank_state_transition(struct dri2_egl_surface *dri2_surf, + uint32_t target_frame) +{ + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + uint32_t flags = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; + int err; + + err = display_request_vblank(dri2_dpy->fd_dpy, target_frame, + flags, dri2_surf); + if (err) { + dri2_surf->swap_state = SWAP_ERROR; + return err; + } + + dri2_surf->swap_state = SWAP_POLL; + + return 0; +} + +static int +swap_flip_state_transition(struct dri2_egl_surface *dri2_surf) +{ + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + uint32_t flags; + int err; + + flags = DRM_MODE_PAGE_FLIP_EVENT; + if (dri2_surf->swap_data->swap_interval == 0) { + assert(!dri2_dpy->atomic_enabled); + flags |= DRM_MODE_PAGE_FLIP_ASYNC; + } + + err = display_output_flip(dri2_dpy->fd_dpy, &dri2_dpy->output, + dri2_surf->swap_data->fb_id, flags, dri2_surf); + if (err) { + dri2_surf->swap_state = SWAP_ERROR; + return err; + } + + dri2_surf->swap_state = SWAP_POLL; + + return 0; +} + +static int +swap_poll_state_transition(struct dri2_egl_surface *dri2_surf) +{ + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + int err; + + /* dri2_surf->swap_state is being set inside the handler */ + err = drm_event_process(dri2_dpy->fd_dpy); + if (err) { + dri2_surf->swap_state = SWAP_ERROR; + return err; + } + + return 0; +} + +static inline void +swap_error_print_message(const int state, const int err) +{ + switch (state) { + case SWAP_IDLE: + _eglLog(_EGL_WARNING, + "failed to get a target frame (err=%d)", err); + break; + case SWAP_FLIP: + _eglLog(_EGL_WARNING, + "failed to schedule a pageflip (err=%d)", err); + break; + case SWAP_VBLANK: + _eglLog(_EGL_WARNING, + "failed to request a vblank event (err=%d)", err); + break; + case SWAP_POLL: + _eglLog(_EGL_WARNING, + "failed to poll for drm event (err=%d)", err); + break; + case SWAP_ERROR: + _eglLog(_EGL_WARNING, + "failed to swap buffers, unknown swap state"); + break; + default: + _eglLog(_EGL_FATAL, + "failed to swap buffers (unknown error)"); + }; +} + +static void +swap_error_state_handler(struct dri2_egl_surface *dri2_surf, + int state, int err) +{ + static bool do_log = true; + + if (do_log) { + swap_error_print_message(state, err); + do_log = false; + } + + swap_dequeue_data_finish(dri2_surf); +} + +static void * +swap_queue_processor_worker(void *data) +{ + struct dri2_egl_surface *dri2_surf = data; + int state = SWAP_IDLE, err = SWAP_ERROR; + uint32_t target_frame = 0; + + assert(dri2_surf->swap_state == SWAP_IDLE); + + while (1) { + switch (dri2_surf->swap_state) { + case SWAP_IDLE: + err = swap_idle_state_transition(dri2_surf, &target_frame); + break; + case SWAP_VBLANK: + err = swap_vblank_state_transition(dri2_surf, target_frame); + break; + case SWAP_FLIP: + err = swap_flip_state_transition(dri2_surf); + break; + case SWAP_POLL: + err = swap_poll_state_transition(dri2_surf); + break; + case SWAP_ERROR: + swap_error_state_handler(dri2_surf, state, err); + break; + default: + dri2_surf->swap_state = SWAP_ERROR; + break; + } + + if (!err) + state = dri2_surf->swap_state; + } + + return NULL; +} + +static bool +add_fb_for_dri_image(struct dri2_egl_display *dri2_dpy, __DRIimage *image, + uint32_t *fb_id_out) +{ + int handle, stride, width, height, format, l_mod, h_mod, offset; + uint64_t modifier = DRM_FORMAT_MOD_INVALID; + uint64_t *modifiers = NULL, mods[4] = {0}; + uint32_t handles[4] = {0}; + uint32_t pitches[4] = {0}; + uint32_t offsets[4] = {0}; + __DRIimage *p_image; + uint32_t flags = 0; + int format_idx; + int num_planes; + + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width); + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT, &height); + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &format); + + format_idx = format_idx_get_from_dri_image_format(format); + assert(format_idx != -1); + + if (dri2_dpy->in_formats_enabled) { + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_MODIFIER_UPPER, &h_mod); + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_MODIFIER_LOWER, &l_mod); + + modifier = combine_u32_into_u64((uint32_t) h_mod, (uint32_t) l_mod); + modifiers = mods; + + flags |= DRM_MODE_FB_MODIFIERS; + } + + dri2_dpy->image->queryImage(image, + __DRI_IMAGE_ATTRIB_NUM_PLANES, &num_planes); + if (num_planes <= 0) + num_planes = 1; + + for (int i = 0; i < num_planes; i++) { + if (dri2_dpy->in_formats_enabled) { + assert(modifiers && modifier != DRM_FORMAT_MOD_INVALID); + modifiers[i] = modifier; + } + + p_image = dri2_dpy->image->fromPlanar(image, i, NULL); + if (!p_image) { + assert(i == 0); + p_image = image; + } + + dri2_dpy->image->queryImage(p_image, __DRI_IMAGE_ATTRIB_STRIDE, + &stride); + dri2_dpy->image->queryImage(p_image, __DRI_IMAGE_ATTRIB_OFFSET, + &offset); + dri2_dpy->image->queryImage(p_image, __DRI_IMAGE_ATTRIB_HANDLE, + &handle); + + if (p_image != image) + dri2_dpy->image->destroyImage(p_image); + + pitches[i] = (uint32_t) stride; + offsets[i] = (uint32_t) offset; + handles[i] = (uint32_t) handle; + } + + return !drmModeAddFB2WithModifiers(dri2_dpy->fd_dpy, width, height, + dri2_null_formats[format_idx].drm_format, + handles, pitches, offsets, modifiers, + fb_id_out, flags); +} + +static __DRIimage * +create_image(struct dri2_egl_surface *dri2_surf, uint32_t flags) +{ + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + uint32_t count_modifiers; + uint64_t *modifiers; + + if (dri2_dpy->in_formats_enabled) { + count_modifiers = u_vector_length(&dri2_dpy->output.modifiers); + modifiers = u_vector_tail(&dri2_dpy->output.modifiers); + + return dri2_dpy->image->createImageWithModifiers(dri2_dpy->dri_screen, + dri2_surf->base.Width, + dri2_surf->base.Height, + dri2_surf->format, + modifiers, + count_modifiers, + NULL); + } + + return dri2_dpy->image->createImage(dri2_dpy->dri_screen, + dri2_surf->base.Width, + dri2_surf->base.Height, + dri2_surf->format, + flags, + NULL); +} + +static bool +get_front_bo(struct dri2_egl_surface *dri2_surf) +{ + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + unsigned int use = 0; + + if (dri2_surf->base.Type == EGL_WINDOW_BIT) + use |= __DRI_IMAGE_USE_SCANOUT; + + dri2_surf->front_buffer.dri_image = create_image(dri2_surf, use); + if (!dri2_surf->front_buffer.dri_image) + return false; + + if (dri2_surf->base.Type == EGL_WINDOW_BIT) { + if (!add_fb_for_dri_image(dri2_dpy, dri2_surf->front_buffer.dri_image, + &dri2_surf->front_buffer.fb_id)) { + dri2_dpy->image->destroyImage(dri2_surf->front_buffer.dri_image); + dri2_surf->front_buffer.dri_image = NULL; + return false; + } + } + + return true; +} + +static bool +get_back_bo(struct dri2_egl_surface *dri2_surf) +{ + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + + pthread_mutex_lock(&dri2_surf->mutex); + while (!dri2_surf->back) { + for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { + if (!dri2_surf->color_buffers[i].locked) { + dri2_surf->back = &dri2_surf->color_buffers[i]; + break; + } + } + + /* Wait for a flip to get a buffer off the screen and unlock it */ + if (!dri2_surf->back) + pthread_cond_wait(&dri2_surf->swap_unlock_buffer_cond, &dri2_surf->mutex); + } + + if (!dri2_surf->back->dri_image) { + dri2_surf->back->dri_image = create_image(dri2_surf, + __DRI_IMAGE_USE_SCANOUT); + if (!dri2_surf->back->dri_image) + goto err_unlock; + } + + if (!dri2_surf->back->fb_id) { + if (!add_fb_for_dri_image(dri2_dpy, dri2_surf->back->dri_image, + &dri2_surf->back->fb_id)) + goto err_unlock; + } + + dri2_surf->back->locked = 1; + pthread_mutex_unlock(&dri2_surf->mutex); + + return true; + +err_unlock: + pthread_mutex_unlock(&dri2_surf->mutex); + return false; +} + +static void surface_swap_queue_init(struct dri2_egl_surface *dri2_surf) +{ + struct swap_queue_elem *swap_queue = &dri2_surf->swap_queue[0]; + const int num_el = ARRAY_SIZE(dri2_surf->swap_queue); + + for (int i = 0; i < num_el; i++) + swap_queue[i].kms_in_fence_fd = -1; +} + +static bool +in_formats_get_modifiers(const int fd, const uint32_t in_formats_id, + const int drm_format, struct u_vector *modifiers) +{ + drmModeFormatModifierIterator drm_iter = {0}; + drmModePropertyBlobRes *blob; + uint64_t *mod = NULL; + + blob = drmModeGetPropertyBlob(fd, in_formats_id); + + while (drmModeFormatModifierBlobIterNext(blob, &drm_iter)) { + if (drm_iter.fmt == drm_format) { + assert(drm_iter.mod != DRM_FORMAT_MOD_INVALID); + + mod = u_vector_add(modifiers); + *mod = drm_iter.mod; + } + } + + drmModeFreePropertyBlob(blob); + + return mod != NULL; +} + +static _EGLSurface * +create_surface(_EGLDisplay *disp, _EGLConfig *config, EGLint type, + const EGLint *attrib_list) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct display_output *output = &dri2_dpy->output; + struct dri2_egl_config *dri2_config = dri2_egl_config(config); + struct dri2_egl_surface *dri2_surf; + const __DRIconfig *dri_config; + unsigned int render_type; + _EGLSurface *surf; + int format_idx; + bool ret; + + dri2_surf = calloc(1, sizeof(*dri2_surf)); + if (!dri2_surf) { + _eglError(EGL_BAD_ALLOC, "failed to create surface"); + return NULL; + } + surf = &dri2_surf->base; + + if (!dri2_init_surface(surf, disp, type, config, attrib_list, + output->in_fence_supported, NULL)) + goto err_free_surface; + + dri_config = dri2_get_dri_config(dri2_config, type, + dri2_surf->base.GLColorspace); + if (!dri_config) { + _eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration"); + goto err_free_surface; + } + + dri2_surf->dri_drawable = + dri2_dpy->image_driver->createNewDrawable(dri2_dpy->dri_screen, + dri_config, dri2_surf); + if (!dri2_surf->dri_drawable) { + _eglError(EGL_BAD_ALLOC, "failed to create drawable"); + goto err_free_surface; + } + + if (!dri2_dpy->core->getConfigAttrib(dri_config, __DRI_ATTRIB_RENDER_TYPE, + &render_type)) + goto err_free_surface; + + if (render_type & __DRI_ATTRIB_YUV_BIT) + format_idx = yuv_format_idx_get_from_config(dri2_dpy, dri_config); + else + format_idx = format_idx_get_from_config(dri2_dpy, dri_config); + assert(format_idx != -1); + + dri2_surf->format = dri2_null_formats[format_idx].dri_image_format; + + if (dri2_dpy->in_formats_enabled) { + ret = in_formats_get_modifiers(dri2_dpy->fd_dpy, + dri2_dpy->output.in_formats_id, + dri2_null_formats[format_idx].drm_format, + &dri2_dpy->output.modifiers); + if (!ret) + goto err_free_surface; + } + + surface_swap_queue_init(dri2_surf); + + return surf; + +err_free_surface: + free(dri2_surf); + return NULL; +} + +static void +destroy_surface(_EGLSurface *surf) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(surf->Resource.Display); + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); + + dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable); + dri2_fini_surface(surf); + free(surf); +} + +static EGLBoolean +dri2_null_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf); + +static _EGLSurface * +dri2_null_create_window_surface(_EGLDisplay *disp, _EGLConfig *config, + void *native_window, const EGLint *attrib_list) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_surface *dri2_surf; + _EGLSurface *surf; + int err; + + if (dri2_dpy->output.in_use) { + _eglError(EGL_BAD_NATIVE_WINDOW, "window in use"); + return NULL; + } + + surf = create_surface(disp, config, EGL_WINDOW_BIT, attrib_list); + if (!surf) + return NULL; + dri2_surf = dri2_egl_surface(surf); + + dri2_surf->base.Width = dri2_dpy->output.mode.hdisplay; + dri2_surf->base.Height = dri2_dpy->output.mode.vdisplay; + + /* After the dri2_surf is created, init thread's data */ + dri2_surf->mutex_init = !pthread_mutex_init(&dri2_surf->mutex, NULL); + if (!dri2_surf->mutex_init) { + _eglError(EGL_BAD_ALLOC, "failed to init swap thread mutex"); + goto err_destroy_surface; + } + + dri2_surf->cond_init = !pthread_cond_init(&dri2_surf->swap_queue_cond, NULL); + if (!dri2_surf->cond_init) { + _eglError(EGL_BAD_ALLOC, "failed to init swap queue condition"); + goto err_destroy_surface; + } + + dri2_surf->cond_init_unlock_buffer = + !pthread_cond_init(&dri2_surf->swap_unlock_buffer_cond, NULL); + if (!dri2_surf->cond_init_unlock_buffer) { + _eglError(EGL_BAD_ALLOC, "failed to init swap buffer unlock condition"); + goto err_destroy_surface; + } + + if (!get_front_bo(dri2_surf)) { + _eglError(EGL_BAD_NATIVE_WINDOW, "window get buffer"); + goto err_destroy_surface; + } + + err = display_output_modeset(dri2_dpy->fd_dpy, &dri2_dpy->output, + dri2_surf->front_buffer.fb_id); + if (err) { + _eglError(EGL_BAD_NATIVE_WINDOW, "window set mode"); + goto err_destroy_surface; + } + + dri2_dpy->output.in_use = true; + dri2_surf->swap_state = SWAP_IDLE; + + err = pthread_create(&dri2_surf->swap_queue_processor, NULL, + swap_queue_processor_worker, dri2_surf); + if (err) { + _eglError(EGL_BAD_ALLOC, "failed to create swap thread"); + goto err_destroy_surface; + } + + return surf; + +err_destroy_surface: + dri2_null_destroy_surface(disp, surf); + return NULL; +} + +static _EGLSurface * +dri2_null_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *config, + const EGLint *attrib_list) +{ + return create_surface(disp, config, EGL_PBUFFER_BIT, attrib_list); +} + +static void +dri2_null_init_front_buffer_render(_EGLSurface *draw) +{ + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); + + dri2_surf->front_render_init = true; + + /* Drain the queue. swap_buffer_unlock_cond signals for the last time + * when the last back buffer in the queue went on screen and it's being + * tracked as current by then. + */ + swap_drain_queue_data(dri2_surf); + + /* If previously flipped, take a reference to the current buffer */ + if (dri2_surf->current) { + assert(dri2_surf->current->dri_image); + dri2_surf->back = dri2_surf->current; + + for (unsigned i = 0; i < DRI2_SURFACE_NUM_COLOR_BUFFERS; i++) + dri2_surf->color_buffers[i].age = 0; + + return; + } + + /* If the application hasn't yet fetched a back buffer, then it's not too + * late to use front buffer's dri_image and fb_id. + */ + if (!dri2_surf->back) { + assert(dri2_surf->front_buffer.dri_image); + dri2_surf->back = &dri2_surf->front_buffer; + + /* Don't need to reset buffer age since no flip was requested yet */ + + return; + } + + /* In order to initialise one color buffer for front buffer rendering, + * one page flip must occur. + */ + swap_enqueue_data(dri2_surf, get_back_buffer_id(dri2_surf), 1); + + return dri2_null_init_front_buffer_render(draw); +} + +static void +dri2_null_disable_front_buffer_render(_EGLSurface *draw) +{ + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); + + dri2_surf->front_render_enabled = false; + dri2_surf->front_render_init = false; + dri2_surf->back = NULL; +} + +static EGLBoolean +dri2_null_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); + EGLint type = surf->Type; + + /* If there's a current surface then a page flip has been performed, so make + * sure we process the flip event. + */ + if (dri2_surf->swap_queue_processor) { + swap_drain_queue_data(dri2_surf); + pthread_cancel(dri2_surf->swap_queue_processor); + pthread_join(dri2_surf->swap_queue_processor, NULL); + } + + if (dri2_surf->cond_init) + pthread_cond_destroy(&dri2_surf->swap_queue_cond); + + if (dri2_surf->cond_init_unlock_buffer) + pthread_cond_destroy(&dri2_surf->swap_unlock_buffer_cond); + + if (dri2_surf->mutex_init) + pthread_mutex_destroy(&dri2_surf->mutex); + + if (dri2_surf->front_buffer.dri_image) + dri2_dpy->image->destroyImage(dri2_surf->front_buffer.dri_image); + + if (dri2_surf->front_buffer.fb_id) + drmModeRmFB(dri2_dpy->fd_dpy, dri2_surf->front_buffer.fb_id); + + for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { + if (dri2_surf->color_buffers[i].fb_id) + drmModeRmFB(dri2_dpy->fd_dpy, dri2_surf->color_buffers[i].fb_id); + if (dri2_surf->color_buffers[i].dri_image) + dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image); + } + + destroy_surface(surf); + + if (type == EGL_WINDOW_BIT) + dri2_dpy->output.in_use = false; + + return EGL_TRUE; +} + +static EGLBoolean +dri2_null_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); + uint32_t back_id; + + if (dri2_surf->base.Type != EGL_WINDOW_BIT) + return EGL_TRUE; + + /* Flush and early return, no swap takes place */ + if (dri2_surf->front_render_enabled) { + dri2_flush_drawable_for_swapbuffers(disp, draw); + + if (!dri2_surf->front_render_init) + dri2_null_init_front_buffer_render(draw); + + return EGL_TRUE; + } + + for (unsigned i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) + if (dri2_surf->color_buffers[i].age > 0) + dri2_surf->color_buffers[i].age++; + + /* Make sure we have a back buffer in case we're swapping without + * ever rendering. */ + if (!get_back_bo(dri2_surf)) { + _eglError(EGL_BAD_ALLOC, "dri2_null_swap_buffers"); + return EGL_FALSE; + } + + dri2_flush_drawable_for_swapbuffers(disp, draw); + dri2_dpy->flush->invalidate(dri2_surf->dri_drawable); + + back_id = get_back_buffer_id(dri2_surf); + assert(dri2_surf->back == &dri2_surf->color_buffers[back_id]); + + swap_enqueue_data(dri2_surf, back_id, draw->SwapInterval); + + /* This back buffer is tracked in the swap_data, safe to drop it now */ + dri2_surf->back->age = 1; + dri2_surf->back = NULL; + + return EGL_TRUE; +} + +static EGLint +dri2_null_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surface) +{ + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface); + + if (!get_back_bo(dri2_surf)) { + _eglError(EGL_BAD_ALLOC, "failed to get back buffer to query age"); + return -1; + } + + return dri2_surf->back->age; +} + +static EGLBoolean +dri2_null_swap_interval(_EGLDisplay *dpy, _EGLSurface *draw, EGLint interval) +{ + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + + /* dri2_dpy tracks whether the display driver is async flip capable. + * If it isn't, enable front buffer rendering when swap interval + * 0 is passed in from the application. + */ + if (!interval && !dri2_dpy->async_flip_enabled) { + if (!dri2_surf->front_render_enabled) + dri2_surf->front_render_enabled = true; + } else { + if (dri2_surf->front_render_enabled) + dri2_null_disable_front_buffer_render(draw); + } + + _eglLog(_EGL_DEBUG, "DRI2: set swap interval to %d", interval); + draw->SwapInterval = interval; + return EGL_TRUE; +} + +static struct dri2_egl_display_vtbl dri2_null_display_vtbl = { + .create_window_surface = dri2_null_create_window_surface, + .create_pbuffer_surface = dri2_null_create_pbuffer_surface, + .destroy_surface = dri2_null_destroy_surface, + .create_image = dri2_create_image_khr, + .swap_interval = dri2_null_swap_interval, + .swap_buffers = dri2_null_swap_buffers, + .query_buffer_age = dri2_null_query_buffer_age, + .get_dri_drawable = dri2_surface_get_dri_drawable, +}; + +static int +dri2_null_image_get_buffers(__DRIdrawable *driDrawable, unsigned int format, + uint32_t *stamp, void *loaderPrivate, + uint32_t buffer_mask, struct __DRIimageList *buffers) +{ + struct dri2_egl_surface *dri2_surf = loaderPrivate; + + buffers->image_mask = 0; + buffers->back = NULL; + buffers->front = NULL; + + if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) + if (!get_front_bo(dri2_surf)) + return 0; + + if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) + if (!get_back_bo(dri2_surf)) + return 0; + + if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) { + buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT; + buffers->front = dri2_surf->front_buffer.dri_image; + } + + if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) { + buffers->image_mask |= __DRI_IMAGE_BUFFER_BACK; + buffers->back = dri2_surf->back->dri_image; + } + + return 1; +} + +static unsigned +dri2_null_get_capability(void *loaderPrivate, enum dri_loader_cap cap) +{ + switch (cap) { + case DRI_LOADER_CAP_YUV_SURFACE_IMG: + return 1; + default: + return 0; + } +} + +static void +dri2_null_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate) +{ + (void) driDrawable; + (void) loaderPrivate; +} + +static int +dri2_null_get_display_fd(void *loaderPrivate) +{ + _EGLDisplay *disp = loaderPrivate; + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + + return dri2_dpy->fd_dpy; +} + +static const __DRIimageLoaderExtension image_loader_extension = { + .base = { __DRI_IMAGE_LOADER, 5 }, + + .getBuffers = dri2_null_image_get_buffers, + .flushFrontBuffer = dri2_null_flush_front_buffer, + .getCapability = dri2_null_get_capability, + .getDisplayFD = dri2_null_get_display_fd, +}; + +static const __DRIextension *image_loader_extensions[] = { + &image_loader_extension.base, + &image_lookup_extension.base, + &use_invalidate.base, + NULL, +}; + +static bool +dri2_null_device_is_kms(int fd) +{ + drmModeRes *resources; + bool is_kms; + + resources = drmModeGetResources(fd); + if (!resources) + return false; + + is_kms = resources->count_crtcs != 0 && + resources->count_connectors != 0 && + resources->count_encoders != 0; + + drmModeFreeResources(resources); + + return is_kms; +} + +static bool +dri2_null_try_device(_EGLDisplay *disp) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + + dri2_dpy->fd = -1; + + if (!dri2_null_device_is_kms(dri2_dpy->fd_dpy)) + return false; + +#if defined(NULL_DRI_DRIVER_NAME) + /* Skip devices not handled by NULL_DRI_DRIVER_NAME */ + { + char *driver_name = loader_get_driver_for_fd(dri2_dpy->fd_dpy); + bool skip = !driver_name || !!strcmp(driver_name, NULL_DRI_DRIVER_NAME); + + free(driver_name); + + if (skip) + return false; + } +#endif + + dri2_dpy->fd = os_dupfd_cloexec(dri2_dpy->fd_dpy); + if (dri2_dpy->fd < 0) { + _eglLog(_EGL_WARNING, "DRI2: failed to dup display FD"); + dri2_dpy->fd = dri2_dpy->fd_dpy; + } else { + int fd_old; + bool is_different_gpu; + + fd_old = dri2_dpy->fd; + dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd, + &is_different_gpu); + if (dri2_dpy->fd == fd_old) { + close (dri2_dpy->fd); + dri2_dpy->fd = dri2_dpy->fd_dpy; + } + } + + dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd); + if (!dri2_dpy->driver_name) + return false; + + if (dri2_load_driver_dri3(disp)) { + _EGLDevice *dev = _eglAddDevice(dri2_dpy->fd, false); + if (!dev) { + dlclose(dri2_dpy->driver); + _eglLog(_EGL_WARNING, "DRI2: failed to find EGLDevice"); + } else { + dri2_dpy->loader_extensions = image_loader_extensions; + dri2_dpy->own_device = 1; + disp->Device = dev; + return true; + } + } + + free(dri2_dpy->driver_name); + dri2_dpy->driver_name = NULL; + + return false; +} + +static bool +dri2_null_probe_device(_EGLDisplay *disp, unsigned minor) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + char *card_path; + + if (asprintf(&card_path, DRM_DEV_NAME, DRM_DIR_NAME, minor) < 0) + goto cleanup; + + dri2_dpy->fd_dpy = loader_open_device(card_path); + free(card_path); + if (dri2_dpy->fd_dpy < 0) + goto cleanup; + + if (dri2_null_try_device(disp)) + return true; + + close(dri2_dpy->fd_dpy); + + if (dri2_dpy->fd >= 0 && dri2_dpy->fd != dri2_dpy->fd_dpy) + close(dri2_dpy->fd); + +cleanup: + dri2_dpy->fd_dpy = -1; + dri2_dpy->fd = -1; + + return false; +} + +static bool +dri2_null_probe_devices(_EGLDisplay *disp) +{ + const char *null_drm_display = getenv("NULL_DRM_DISPLAY"); + + if (null_drm_display) { + char *endptr; + long val = strtol(null_drm_display, &endptr, 10); + + if (endptr != null_drm_display && !*endptr && + val >= 0 && val <= NULL_CARD_MINOR_MAX) { + if (dri2_null_probe_device(disp, (unsigned)val)) + return true; + } else { + _eglLog(_EGL_FATAL, "NULL_DRM_DISPLAY is invalid: %s", + null_drm_display); + } + } else { + for (unsigned i = 0; i <= NULL_CARD_MINOR_MAX; i++) { + if (dri2_null_probe_device(disp, i)) + return true; + } + } + + return false; +} + +static EGLBoolean +dri2_null_add_configs_for_formats(_EGLDisplay *disp) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + unsigned int count = 0; + + for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++) { + struct dri2_egl_config *dri2_conf; + EGLint surface_type = EGL_WINDOW_BIT; + unsigned int render_type; + int format_idx; + + if (!dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i], + __DRI_ATTRIB_RENDER_TYPE, + &render_type)) + continue; + + if (render_type & __DRI_ATTRIB_YUV_BIT) { + format_idx = yuv_format_idx_get_from_config(dri2_dpy, + dri2_dpy->driver_configs[i]); + } else { + format_idx = format_idx_get_from_config(dri2_dpy, + dri2_dpy->driver_configs[i]); + surface_type |= EGL_PBUFFER_BIT; + } + + if (format_idx == -1) + continue; + + if (!(dri2_dpy->output.formats & (1 << format_idx))) { + _eglLog(_EGL_DEBUG, "unsupported drm format 0x%04x", + dri2_null_formats[format_idx].drm_format); + continue; + } + + dri2_conf = dri2_add_config(disp, + dri2_dpy->driver_configs[i], count + 1, + surface_type, NULL, NULL, NULL); + if (dri2_conf) + count++; + } + + return count != 0; +} +static void +dri2_null_setup_swap_interval(_EGLDisplay *disp) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + const int swap_max_interval = 10; /* Arbitrary max value */ + uint64_t value; + int err; + + dri2_setup_swap_interval(disp, swap_max_interval); + + err = drmGetCap(dri2_dpy->fd_dpy, DRM_CAP_ASYNC_PAGE_FLIP, &value); + if (err || value == 0) { + + /* DRM/KMS does not support async page flip. In order to support + * swap interval 0, use front buffer rendering. + */ + _eglLog(_EGL_DEBUG, + "drm async flip not supported, use front buffer"); + } else { + + /* drm/atomic: Reject FLIP_ASYNC unconditionally + * upstream f2cbda2dba11de868759cae9c0d2bab5b8411406 + * + * Legacy DRM/KMS can use DRM_MODE_PAGE_FLIP_ASYNC, for atomic + * drivers fallback to front buffer rendering. + */ + if (dri2_dpy->atomic_enabled) + _eglLog(_EGL_DEBUG, + "async flip not supported by atomic, use front buffer"); + else + dri2_dpy->async_flip_enabled = true; + } +} + +EGLBoolean +dri2_initialize_null(_EGLDisplay *disp) +{ + struct dri2_egl_display *dri2_dpy; + bool prefer_in_formats = false; + uint64_t value; + int err; + + dri2_dpy = calloc(1, sizeof(*dri2_dpy)); + if (!dri2_dpy) + return _eglError(EGL_BAD_ALLOC, "eglInitialize"); + + disp->DriverData = (void *) dri2_dpy; + + dri2_dpy->fd_dpy = -1; + dri2_dpy->fd = -1; + + if (!dri2_null_probe_devices(disp)) { + _eglError(EGL_NOT_INITIALIZED, "failed to load driver"); + goto cleanup; + } + + /* + * Try to use atomic modesetting if available and fallback to legacy kernel + * modesetting if not. If this succeeds then universal planes will also have + * been enabled. + */ + err = drmSetClientCap(dri2_dpy->fd_dpy, DRM_CLIENT_CAP_ATOMIC, 1); + dri2_dpy->atomic_enabled = !err; + + if (!dri2_dpy->atomic_enabled) { + /* + * Enable universal planes so that we can get the pixel formats for the + * primary plane + */ + err = drmSetClientCap(dri2_dpy->fd_dpy, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); + if (err) { + _eglError(EGL_NOT_INITIALIZED, "failed to enable universal planes"); + goto cleanup; + } + + dri2_dpy->atomic_enabled = false; + } + + if (!dri2_create_screen(disp)) { + _eglError(EGL_NOT_INITIALIZED, "failed to create screen"); + goto cleanup; + } + + if (!dri2_setup_extensions(disp)) { + _eglError(EGL_NOT_INITIALIZED, "failed to find required DRI extensions"); + goto cleanup; + } + + dri2_setup_screen(disp); + dri2_null_setup_swap_interval(disp); + + if (dri2_dpy->image->base.version < NULL_IMAGE_EXTENSION_VERSION_MIN) { + _eglError(EGL_NOT_INITIALIZED, "image extension version too old"); + goto cleanup; + } + + err = drmGetCap(dri2_dpy->fd_dpy, DRM_CAP_ADDFB2_MODIFIERS, &value); + if (!err && value) { + /* in_formats could be supported by the platform, however not being + * actually enabled, i.e. in_formats init can still fail. + */ + prefer_in_formats = dri2_dpy->image->base.version >= 14 && + dri2_dpy->image->createImageWithModifiers; + } + + if (!display_output_init(dri2_dpy->fd_dpy, &dri2_dpy->output, + dri2_dpy->atomic_enabled, + prefer_in_formats, + &dri2_dpy->in_formats_enabled)) { + _eglError(EGL_NOT_INITIALIZED, "failed to create output"); + goto cleanup; + } + + if (!dri2_null_add_configs_for_formats(disp)) { + _eglError(EGL_NOT_INITIALIZED, "failed to add configs"); + goto cleanup; + } + + disp->Extensions.EXT_buffer_age = EGL_TRUE; + disp->Extensions.KHR_image_base = EGL_TRUE; + + /* Fill vtbl last to prevent accidentally calling virtual function during + * initialization. + */ + dri2_dpy->vtbl = &dri2_null_display_vtbl; + + return EGL_TRUE; + +cleanup: + dri2_display_destroy(disp); + return EGL_FALSE; +} + +void +dri2_teardown_null(struct dri2_egl_display *dri2_dpy) +{ + drmModeAtomicFree(dri2_dpy->output.atomic_state); + + if (dri2_dpy->output.mode_blob_id) + drmModeDestroyPropertyBlob(dri2_dpy->fd_dpy, dri2_dpy->output.mode_blob_id); + + if (dri2_dpy->output.plane_prop_res) { + for (unsigned i = 0; dri2_dpy->output.plane_prop_res[i]; i++) + drmModeFreeProperty(dri2_dpy->output.plane_prop_res[i]); + free(dri2_dpy->output.plane_prop_res); + } + + if (dri2_dpy->output.crtc_prop_res) { + for (unsigned i = 0; dri2_dpy->output.crtc_prop_res[i]; i++) + drmModeFreeProperty(dri2_dpy->output.crtc_prop_res[i]); + free(dri2_dpy->output.crtc_prop_res); + } + + if (dri2_dpy->output.connector_prop_res) { + for (unsigned i = 0; dri2_dpy->output.connector_prop_res[i]; i++) + drmModeFreeProperty(dri2_dpy->output.connector_prop_res[i]); + free(dri2_dpy->output.connector_prop_res); + } + + u_vector_finish(&dri2_dpy->output.modifiers); +} diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c index 93bb97c..8124697 100644 --- a/src/egl/drivers/dri2/platform_wayland.c +++ b/src/egl/drivers/dri2/platform_wayland.c @@ -44,6 +44,7 @@ #include "loader.h" #include "util/u_vector.h" #include "util/anon_file.h" +#include "util/os_file.h" #include "eglglobals.h" #include "kopper_interface.h" @@ -151,6 +152,13 @@ static const struct dri2_wl_visual { { 11, 5, 0, -1 }, { 5, 6, 5, 0 }, }, + { + "YUYV", + WL_DRM_FORMAT_YUYV, WL_SHM_FORMAT_YUYV, + __DRI_IMAGE_FORMAT_YUYV, __DRI_IMAGE_FORMAT_NONE, 32, + { -1, -1, -1, -1 }, + { 0, 0, 0, 0 }, + }, }; static int @@ -385,6 +393,9 @@ resize_callback(struct wl_egl_window *wl_win, void *data) struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); + dri2_surf->dx = wl_win->dx; + dri2_surf->dy = wl_win->dy; + if (dri2_surf->base.Width == wl_win->width && dri2_surf->base.Height == wl_win->height) return; @@ -787,6 +798,99 @@ dri2_wl_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf, return NULL; } +static _EGLSurface * +dri2_wl_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf, + const EGLint *attrib_list) +{ + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_config *dri2_conf = dri2_egl_config(conf); + struct dri2_egl_surface *dri2_surf; + int visual_idx; + const __DRIconfig *config; + + dri2_surf = calloc(1, sizeof *dri2_surf); + if (!dri2_surf) { + _eglError(EGL_BAD_ALLOC, "dri2_create_surface"); + return NULL; + } + + if (!dri2_init_surface(&dri2_surf->base, disp, EGL_PBUFFER_BIT, conf, + attrib_list, false, NULL)) + goto cleanup_surf; + + config = dri2_get_dri_config(dri2_conf, EGL_PBUFFER_BIT, + dri2_surf->base.GLColorspace); + if (!config) { + _eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration"); + goto cleanup_surf; + } + + visual_idx = dri2_wl_visual_idx_from_config(dri2_dpy, config, false); + assert(visual_idx != -1); + + if (dri2_dpy->wl_dmabuf || dri2_dpy->wl_drm) { + dri2_surf->format = dri2_wl_visuals[visual_idx].wl_drm_format; + } else { + assert(dri2_dpy->wl_shm); + dri2_surf->format = dri2_wl_visuals[visual_idx].wl_shm_format; + } + + if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf)) + goto cleanup_surf; + + return &dri2_surf->base; + + cleanup_surf: + free(dri2_surf); + + return NULL; +} + +static int +allocate_front_buffer(struct dri2_egl_display *dri2_dpy, + struct dri2_egl_surface *dri2_surf, + EGLBoolean need_name) +{ + int use_flags = need_name ? __DRI_IMAGE_USE_SHARE : 0; + int visual_idx; + unsigned int dri_image_format; + + visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format); + assert(visual_idx != -1); + dri_image_format = dri2_wl_visuals[visual_idx].dri_image_format; + + if (!dri2_surf->front) + dri2_surf->front = dri2_dpy->image->createImage(dri2_dpy->dri_screen, + dri2_surf->base.Width, + dri2_surf->base.Height, + dri_image_format, + use_flags, + NULL); + if (!dri2_surf->front) { + _eglError(EGL_BAD_ALLOC, "failed to allocate front buffer"); + return -1; + } + + return 0; +} + +static void +free_front_buffer(struct dri2_egl_display *dri2_dpy, + struct dri2_egl_surface *dri2_surf) +{ + if (dri2_surf->front) { + dri2_dpy->image->destroyImage(dri2_surf->front); + dri2_surf->front = NULL; + } +} + +static void +swrast_free_front_buffer(struct dri2_egl_surface *dri2_surf) +{ + free(dri2_surf->swrast_front); + dri2_surf->swrast_front = NULL; +} + /** * Called via eglDestroySurface(), drv->DestroySurface(). */ @@ -813,6 +917,9 @@ dri2_wl_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf) if (dri2_dpy->dri2) dri2_egl_surface_free_local_buffers(dri2_surf); + free_front_buffer(dri2_dpy, dri2_surf); + swrast_free_front_buffer(dri2_surf); + if (dri2_surf->throttle_callback) wl_callback_destroy(dri2_surf->throttle_callback); @@ -822,8 +929,10 @@ dri2_wl_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf) dri2_surf->wl_win->destroy_window_callback = NULL; } - wl_proxy_wrapper_destroy(dri2_surf->wl_surface_wrapper); - wl_proxy_wrapper_destroy(dri2_surf->wl_dpy_wrapper); + if (dri2_surf->wl_surface_wrapper) + wl_proxy_wrapper_destroy(dri2_surf->wl_surface_wrapper); + if (dri2_surf->wl_dpy_wrapper) + wl_proxy_wrapper_destroy(dri2_surf->wl_dpy_wrapper); if (dri2_surf->wl_drm_wrapper) wl_proxy_wrapper_destroy(dri2_surf->wl_drm_wrapper); if (dri2_surf->wl_dmabuf_feedback) { @@ -831,7 +940,8 @@ dri2_wl_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf) dmabuf_feedback_fini(&dri2_surf->dmabuf_feedback); dmabuf_feedback_fini(&dri2_surf->pending_dmabuf_feedback); } - wl_event_queue_destroy(dri2_surf->wl_queue); + if (dri2_surf->wl_queue) + wl_event_queue_destroy(dri2_surf->wl_queue); dri2_fini_surface(surf); free(surf); @@ -852,12 +962,22 @@ dri2_wl_swap_interval(_EGLDisplay *disp, _EGLSurface *surf, EGLint interval) } static void -dri2_wl_release_buffers(struct dri2_egl_surface *dri2_surf) +dri2_wl_release_buffers(struct dri2_egl_surface *dri2_surf, + bool release_non_current, + bool release_current) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { + if (dri2_surf->current == &dri2_surf->color_buffers[i]) { + if (!release_current) + continue; + } else { + if (!release_non_current) + continue; + } + if (dri2_surf->color_buffers[i].wl_buffer) { if (dri2_surf->color_buffers[i].locked) { dri2_surf->color_buffers[i].wl_release = true; @@ -882,6 +1002,9 @@ dri2_wl_release_buffers(struct dri2_egl_surface *dri2_surf) if (dri2_dpy->dri2) dri2_egl_surface_free_local_buffers(dri2_surf); + + if (release_current) + dri2_surf->current = NULL; } static void @@ -904,7 +1027,7 @@ create_dri_image_diff_gpu(struct dri2_egl_surface *dri2_surf, &linear_mod, 1, NULL); } -static void +static bool create_dri_image_from_dmabuf_feedback(struct dri2_egl_surface *dri2_surf, unsigned int dri_image_format, uint32_t use_flags) { @@ -917,7 +1040,7 @@ create_dri_image_from_dmabuf_feedback(struct dri2_egl_surface *dri2_surf, /* We don't have valid dma-buf feedback, so return */ if (dri2_surf->dmabuf_feedback.main_device == 0) - return; + return false; visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format); assert(visual_idx != -1); @@ -961,11 +1084,13 @@ create_dri_image_from_dmabuf_feedback(struct dri2_egl_surface *dri2_surf, modifiers, num_modifiers, NULL); if (dri2_surf->back->dri_image) - return; + return num_modifiers != 0; } + + return false; } -static void +static bool create_dri_image(struct dri2_egl_surface *dri2_surf, unsigned int dri_image_format, uint32_t use_flags) { @@ -997,10 +1122,13 @@ create_dri_image(struct dri2_egl_surface *dri2_surf, dri_image_format, dri2_dpy->is_different_gpu ? 0 : use_flags, modifiers, num_modifiers, NULL); + + return num_modifiers != 0; } static int -get_back_bo(struct dri2_egl_surface *dri2_surf) +get_back_bo(struct dri2_egl_surface *dri2_surf, bool allow_preserve, + bool preserve_current) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display); @@ -1008,6 +1136,7 @@ get_back_bo(struct dri2_egl_surface *dri2_surf) int visual_idx; unsigned int dri_image_format; unsigned int linear_dri_image_format; + bool have_modifiers = false; visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format); assert(visual_idx != -1); @@ -1067,23 +1196,46 @@ get_back_bo(struct dri2_egl_surface *dri2_surf) use_flags |= __DRI_IMAGE_USE_PROTECTED; } - if (dri2_dpy->is_different_gpu && dri2_surf->back->linear_copy == NULL) { - create_dri_image_diff_gpu(dri2_surf, linear_dri_image_format, use_flags); - if (dri2_surf->back->linear_copy == NULL) - return -1; - } - if (dri2_surf->back->dri_image == NULL) { if (dri2_surf->wl_dmabuf_feedback) - create_dri_image_from_dmabuf_feedback(dri2_surf, dri_image_format, use_flags); + have_modifiers = create_dri_image_from_dmabuf_feedback(dri2_surf, dri_image_format, use_flags); if (dri2_surf->back->dri_image == NULL) - create_dri_image(dri2_surf, dri_image_format, use_flags); + have_modifiers = create_dri_image(dri2_surf, dri_image_format, use_flags); dri2_surf->back->age = 0; } if (dri2_surf->back->dri_image == NULL) return -1; + if (dri2_dpy->is_different_gpu && !have_modifiers && + dri2_surf->back->linear_copy == NULL) { + create_dri_image_diff_gpu(dri2_surf, linear_dri_image_format, use_flags); + if (dri2_surf->back->linear_copy == NULL) + return -1; + } + + if ((allow_preserve || preserve_current) && + dri2_surf->base.SwapBehavior == EGL_BUFFER_PRESERVED && + dri2_surf->current && dri2_surf->back->age != 1) { + _EGLContext *ctx = _eglGetCurrentContext(); + struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); + + if (dri2_ctx) { + dri2_dpy->image->blitImage(dri2_ctx->dri_context, + dri2_surf->back->dri_image, + dri2_surf->current->dri_image, + 0, 0, dri2_surf->base.Width, + dri2_surf->base.Height, + 0, 0, dri2_surf->base.Width, + dri2_surf->base.Height, + __BLIT_FLAG_FLUSH); + dri2_surf->back->age = 1; + + if (!preserve_current) + dri2_surf->current = NULL; + } + } + dri2_surf->back->locked = true; return 0; @@ -1091,23 +1243,28 @@ get_back_bo(struct dri2_egl_surface *dri2_surf) static void -back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer) +bo_to_dri_buffer(struct dri2_egl_display *dri2_dpy, unsigned int attachment, + __DRIimage *image, __DRIbuffer *buffer) { - struct dri2_egl_display *dri2_dpy = - dri2_egl_display(dri2_surf->base.Resource.Display); - __DRIimage *image; - int name, pitch; - - image = dri2_surf->back->dri_image; + int name, pitch, format; dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name); dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch); + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &format); - buffer->attachment = __DRI_BUFFER_BACK_LEFT; + buffer->attachment = attachment; buffer->name = name; buffer->pitch = pitch; - buffer->cpp = 4; buffer->flags = 0; + + switch (format) { + case __DRI_IMAGE_FORMAT_RGB565: + buffer->cpp = 2; + break; + default: + buffer->cpp = 4; + break; + } } /* Value chosen empirically as a compromise between avoiding frequent @@ -1116,11 +1273,31 @@ back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer) */ #define BUFFER_TRIM_AGE_HYSTERESIS 20 -static int -update_buffers(struct dri2_egl_surface *dri2_surf) +static void +back_bo_to_dri_buffer(struct dri2_egl_display *dri2_dpy, + struct dri2_egl_surface *dri2_surf, + __DRIbuffer *buffer) { - struct dri2_egl_display *dri2_dpy = - dri2_egl_display(dri2_surf->base.Resource.Display); + bo_to_dri_buffer(dri2_dpy, __DRI_BUFFER_BACK_LEFT, + dri2_surf->back->dri_image, buffer); +} + +static void +front_bo_to_dri_buffer(struct dri2_egl_display *dri2_dpy, + struct dri2_egl_surface *dri2_surf, + __DRIbuffer *buffer) +{ + bo_to_dri_buffer(dri2_dpy, __DRI_BUFFER_FRONT_LEFT, + dri2_surf->front, buffer); +} + +static int +update_buffers(struct dri2_egl_display *dri2_dpy, + struct dri2_egl_surface *dri2_surf, + bool allow_preserve) +{ + bool preserve_current = false; + int res; if (dri2_surf->wl_win && (dri2_surf->base.Width != dri2_surf->wl_win->width || @@ -1128,17 +1305,23 @@ update_buffers(struct dri2_egl_surface *dri2_surf) dri2_surf->base.Width = dri2_surf->wl_win->width; dri2_surf->base.Height = dri2_surf->wl_win->height; - dri2_surf->dx = dri2_surf->wl_win->dx; - dri2_surf->dy = dri2_surf->wl_win->dy; } if (dri2_surf->resized || dri2_surf->received_dmabuf_feedback) { - dri2_wl_release_buffers(dri2_surf); + preserve_current = !dri2_surf->resized && + dri2_surf->base.SwapBehavior == EGL_BUFFER_PRESERVED; + + dri2_wl_release_buffers(dri2_surf, true, !preserve_current); dri2_surf->resized = false; dri2_surf->received_dmabuf_feedback = false; } - if (get_back_bo(dri2_surf) < 0) { + res = get_back_bo(dri2_surf, allow_preserve, preserve_current); + + if (preserve_current) + dri2_wl_release_buffers(dri2_surf, false, true); + + if (res < 0) { _eglError(EGL_BAD_ALLOC, "failed to allocate color buffer"); return -1; } @@ -1154,7 +1337,7 @@ update_buffers(struct dri2_egl_surface *dri2_surf) dri2_surf->color_buffers[i].age > BUFFER_TRIM_AGE_HYSTERESIS) { wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer); dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image); - if (dri2_dpy->is_different_gpu) + if (dri2_surf->color_buffers[i].linear_copy) dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy); dri2_surf->color_buffers[i].wl_buffer = NULL; dri2_surf->color_buffers[i].dri_image = NULL; @@ -1167,12 +1350,14 @@ update_buffers(struct dri2_egl_surface *dri2_surf) } static int -update_buffers_if_needed(struct dri2_egl_surface *dri2_surf) +update_buffers_if_needed(struct dri2_egl_display *dri2_dpy, + struct dri2_egl_surface *dri2_surf, + bool allow_preserve) { if (dri2_surf->back != NULL) return 0; - return update_buffers(dri2_surf); + return update_buffers(dri2_dpy, dri2_surf, allow_preserve); } static __DRIbuffer * @@ -1182,17 +1367,25 @@ dri2_wl_get_buffers_with_format(__DRIdrawable * driDrawable, int *out_count, void *loaderPrivate) { struct dri2_egl_surface *dri2_surf = loaderPrivate; + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); int i, j; - if (update_buffers_if_needed(dri2_surf) < 0) - return NULL; - for (i = 0, j = 0; i < 2 * count; i += 2, j++) { __DRIbuffer *local; switch (attachments[i]) { case __DRI_BUFFER_BACK_LEFT: - back_bo_to_dri_buffer(dri2_surf, &dri2_surf->buffers[j]); + if (update_buffers_if_needed(dri2_dpy, dri2_surf, true) < 0) + return NULL; + + back_bo_to_dri_buffer(dri2_dpy, dri2_surf, &dri2_surf->buffers[j]); + break; + case __DRI_BUFFER_FRONT_LEFT: + if (allocate_front_buffer(dri2_dpy, dri2_surf, EGL_TRUE) < 0) + return NULL; + + front_bo_to_dri_buffer(dri2_dpy, dri2_surf, &dri2_surf->buffers[j]); break; default: local = dri2_egl_surface_alloc_local_buffer(dri2_surf, attachments[i], @@ -1262,12 +1455,41 @@ image_get_buffers(__DRIdrawable *driDrawable, struct __DRIimageList *buffers) { struct dri2_egl_surface *dri2_surf = loaderPrivate; + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); - if (update_buffers_if_needed(dri2_surf) < 0) - return 0; + buffers->image_mask = 0; + buffers->front = NULL; + buffers->back = NULL; + buffers->prev = NULL; - buffers->image_mask = __DRI_IMAGE_BUFFER_BACK; - buffers->back = dri2_surf->back->dri_image; + if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) + { + bool buffer_prev = buffer_mask & __DRI_IMAGE_BUFFER_PREV; + + if (update_buffers_if_needed(dri2_dpy, dri2_surf, !buffer_prev) < 0) + return 0; + + buffers->image_mask |= __DRI_IMAGE_BUFFER_BACK; + buffers->back = dri2_surf->back->dri_image; + + if (buffer_prev && dri2_surf->current && + dri2_surf->base.SwapBehavior == EGL_BUFFER_PRESERVED) + { + buffers->image_mask |= __DRI_IMAGE_BUFFER_PREV; + buffers->prev = dri2_surf->current->dri_image; + dri2_surf->back->age = 1; + } + } + + if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) + { + if (allocate_front_buffer(dri2_dpy, dri2_surf, EGL_FALSE) < 0) + return 0; + + buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT; + buffers->front = dri2_surf->front; + } return 1; } @@ -1284,6 +1506,7 @@ dri2_wl_get_capability(void *loaderPrivate, enum dri_loader_cap cap) { switch (cap) { case DRI_LOADER_CAP_FP16: + case DRI_LOADER_CAP_YUV_SURFACE_IMG: return 1; case DRI_LOADER_CAP_RGBA_ORDERING: return 1; @@ -1292,21 +1515,32 @@ dri2_wl_get_capability(void *loaderPrivate, enum dri_loader_cap cap) } } +static int +dri2_wl_get_display_fd(void *loaderPrivate) +{ + _EGLDisplay *disp = loaderPrivate; + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + + return dri2_dpy->fd_dpy; +} + static const __DRIdri2LoaderExtension dri2_loader_extension = { - .base = { __DRI_DRI2_LOADER, 4 }, + .base = { __DRI_DRI2_LOADER, 6 }, .getBuffers = dri2_wl_get_buffers, .flushFrontBuffer = dri2_wl_flush_front_buffer, .getBuffersWithFormat = dri2_wl_get_buffers_with_format, .getCapability = dri2_wl_get_capability, + .getDisplayFD = dri2_wl_get_display_fd, }; static const __DRIimageLoaderExtension image_loader_extension = { - .base = { __DRI_IMAGE_LOADER, 2 }, + .base = { __DRI_IMAGE_LOADER, 5 }, .getBuffers = image_get_buffers, .flushFrontBuffer = dri2_wl_flush_front_buffer, .getCapability = dri2_wl_get_capability, + .getDisplayFD = dri2_wl_get_display_fd, }; static void @@ -1515,6 +1749,9 @@ dri2_wl_swap_buffers_with_damage(_EGLDisplay *disp, struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); + if (draw->Type != EGL_WINDOW_BIT) + return EGL_TRUE; + if (!dri2_surf->wl_win) return _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_swap_buffers"); @@ -1540,7 +1777,7 @@ dri2_wl_swap_buffers_with_damage(_EGLDisplay *disp, /* Make sure we have a back buffer in case we're swapping without ever * rendering. */ - if (update_buffers_if_needed(dri2_surf) < 0) + if (update_buffers_if_needed(dri2_dpy, dri2_surf, true) < 0) return _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers"); if (draw->SwapInterval > 0) { @@ -1557,7 +1794,7 @@ dri2_wl_swap_buffers_with_damage(_EGLDisplay *disp, if (!dri2_surf->current->wl_buffer) { __DRIimage *image; - if (dri2_dpy->is_different_gpu) + if (dri2_surf->current->linear_copy) image = dri2_surf->current->linear_copy; else image = dri2_surf->current->dri_image; @@ -1584,11 +1821,12 @@ dri2_wl_swap_buffers_with_damage(_EGLDisplay *disp, /* If the compositor doesn't support damage_buffer, we deliberately * ignore the damage region and post maximum damage, due to * https://bugs.freedesktop.org/78190 */ - if (!n_rects || !try_damage_buffer(dri2_surf, rects, n_rects)) + if (dri2_dpy->is_different_gpu || + !n_rects || !try_damage_buffer(dri2_surf, rects, n_rects)) wl_surface_damage(dri2_surf->wl_surface_wrapper, 0, 0, INT32_MAX, INT32_MAX); - if (dri2_dpy->is_different_gpu) { + if (dri2_surf->current->linear_copy) { _EGLContext *ctx = _eglGetCurrentContext(); struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); dri2_dpy->image->blitImage(dri2_ctx->dri_context, @@ -1597,7 +1835,7 @@ dri2_wl_swap_buffers_with_damage(_EGLDisplay *disp, 0, 0, dri2_surf->base.Width, dri2_surf->base.Height, 0, 0, dri2_surf->base.Width, - dri2_surf->base.Height, 0); + dri2_surf->base.Height, __BLIT_FLAG_FLUSH); } wl_surface_commit(dri2_surf->wl_surface_wrapper); @@ -1620,9 +1858,13 @@ dri2_wl_swap_buffers_with_damage(_EGLDisplay *disp, static EGLint dri2_wl_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surface) { + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface); - if (update_buffers_if_needed(dri2_surf) < 0) { + if (surface->Type != EGL_WINDOW_BIT) + return 0; + + if (update_buffers_if_needed(dri2_dpy, dri2_surf, true) < 0) { _eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age"); return -1; } @@ -1977,6 +2219,7 @@ static const struct dri2_egl_display_vtbl dri2_wl_display_vtbl = { .authenticate = dri2_wl_authenticate, .create_window_surface = dri2_wl_create_window_surface, .create_pixmap_surface = dri2_wl_create_pixmap_surface, + .create_pbuffer_surface = dri2_wl_create_pbuffer_surface, .destroy_surface = dri2_wl_destroy_surface, .swap_interval = dri2_wl_swap_interval, .create_image = dri2_create_image_khr, @@ -2003,11 +2246,12 @@ static const __DRIextension *image_loader_extensions[] = { }; static EGLBoolean -dri2_wl_add_configs_for_visuals(_EGLDisplay *disp) +dri2_wl_add_configs_for_visuals(_EGLDisplay *disp, bool allow_preserve) { struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); unsigned int format_count[ARRAY_SIZE(dri2_wl_visuals)] = { 0 }; unsigned int count = 0; + EGLint surface_type; bool assigned; for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++) { @@ -2019,8 +2263,16 @@ dri2_wl_add_configs_for_visuals(_EGLDisplay *disp) if (!BITSET_TEST(dri2_dpy->formats.formats_bitmap, j)) continue; + surface_type = EGL_WINDOW_BIT; + if (dri2_wl_visuals[j].wl_drm_format != WL_DRM_FORMAT_YUYV) + surface_type |= EGL_PBUFFER_BIT; + + if (allow_preserve && + dri2_dpy->image->base.version >= 9 && dri2_dpy->image->blitImage) + surface_type |= EGL_SWAP_BEHAVIOR_PRESERVED_BIT; + dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i], - count + 1, EGL_WINDOW_BIT, NULL, dri2_wl_visuals[j].rgba_shifts, dri2_wl_visuals[j].rgba_sizes); + count + 1, surface_type, NULL, dri2_wl_visuals[j].rgba_shifts, dri2_wl_visuals[j].rgba_sizes); if (dri2_conf) { if (dri2_conf->base.ConfigID == count + 1) count++; @@ -2083,12 +2335,14 @@ dri2_initialize_wayland_drm(_EGLDisplay *disp) { _EGLDevice *dev; struct dri2_egl_display *dri2_dpy; + int fd_old; dri2_dpy = calloc(1, sizeof *dri2_dpy); if (!dri2_dpy) return _eglError(EGL_BAD_ALLOC, "eglInitialize"); dri2_dpy->fd = -1; + dri2_dpy->fd_dpy = -1; disp->DriverData = (void *) dri2_dpy; if (dri2_wl_formats_init(&dri2_dpy->formats) < 0) @@ -2160,8 +2414,20 @@ dri2_initialize_wayland_drm(_EGLDisplay *disp) goto cleanup; } + fd_old = dri2_dpy->fd; + dri2_dpy->fd_dpy = os_dupfd_cloexec(dri2_dpy->fd); dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd, &dri2_dpy->is_different_gpu); + if (dri2_dpy->fd == fd_old) { + if (dri2_dpy->fd_dpy != -1) + close(dri2_dpy->fd_dpy); + + dri2_dpy->fd_dpy = dri2_dpy->fd; + } else if (dri2_dpy->fd_dpy == -1) { + _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to dup display FD"); + goto cleanup; + } + dev = _eglAddDevice(dri2_dpy->fd, false); if (!dev) { _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to find EGLDevice"); @@ -2241,7 +2507,7 @@ dri2_initialize_wayland_drm(_EGLDisplay *disp) goto cleanup; } - if (!dri2_wl_add_configs_for_visuals(disp)) { + if (!dri2_wl_add_configs_for_visuals(disp, true)) { _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to add configs"); goto cleanup; } @@ -2282,6 +2548,23 @@ dri2_wl_swrast_get_stride_for_format(int format, int w) return w * (dri2_wl_visuals[visual_idx].bpp / 8); } +static EGLBoolean +swrast_allocate_local_buffer(int format, int w, int h, void **data) +{ + int stride, size_map; + void *data_map; + + stride = dri2_wl_swrast_get_stride_for_format(format, w); + size_map = h * stride; + + data_map = malloc(size_map); + if (!data_map) + return EGL_FALSE; + + *data = data_map; + return EGL_TRUE; +} + static EGLBoolean dri2_wl_swrast_allocate_buffer(struct dri2_egl_surface *dri2_surf, int format, int w, int h, @@ -2336,7 +2619,7 @@ swrast_update_buffers(struct dri2_egl_surface *dri2_surf) dri2_surf->base.Height != dri2_surf->wl_win->height)) { if (!zink) - dri2_wl_release_buffers(dri2_surf); + dri2_wl_release_buffers(dri2_surf, true, true); dri2_surf->base.Width = dri2_surf->wl_win->width; dri2_surf->base.Height = dri2_surf->wl_win->height; @@ -2413,8 +2696,24 @@ swrast_update_buffers(struct dri2_egl_surface *dri2_surf) return 0; } +static int +swrast_allocate_front_buffer(struct dri2_egl_surface *dri2_surf) +{ + if (!dri2_surf->swrast_front) { + if (!swrast_allocate_local_buffer(dri2_surf->format, + dri2_surf->base.Width, + dri2_surf->base.Height, + &dri2_surf->swrast_front)) { + _eglError(EGL_BAD_ALLOC, "failed to allocate front buffer"); + return -1; + } + } + + return 0; +} + static void* -dri2_wl_swrast_get_frontbuffer_data(struct dri2_egl_surface *dri2_surf) +dri2_wl_swrast_get_currentbuffer_data(struct dri2_egl_surface *dri2_surf) { /* if there has been a resize: */ if (!dri2_surf->current) @@ -2484,7 +2783,9 @@ dri2_wl_swrast_get_drawable_info(__DRIdrawable * draw, { struct dri2_egl_surface *dri2_surf = loaderPrivate; - (void) swrast_update_buffers(dri2_surf); + if (dri2_surf->base.Type == EGL_WINDOW_BIT) + (void) swrast_update_buffers(dri2_surf); + *x = 0; *y = 0; *w = dri2_surf->base.Width; @@ -2503,7 +2804,11 @@ dri2_wl_swrast_get_image(__DRIdrawable * read, int dst_stride = copy_width; char *src, *dst; - src = dri2_wl_swrast_get_frontbuffer_data(dri2_surf); + if (dri2_surf->base.Type == EGL_WINDOW_BIT) + src = dri2_wl_swrast_get_currentbuffer_data(dri2_surf); + else + src = dri2_surf->swrast_front; + if (!src) { memset(data, 0, copy_width * h); return; @@ -2541,14 +2846,20 @@ dri2_wl_swrast_put_image2(__DRIdrawable * draw, int op, assert(copy_width <= stride); - (void) swrast_update_buffers(dri2_surf); - dst = dri2_wl_swrast_get_backbuffer_data(dri2_surf); + if (dri2_surf->base.Type == EGL_WINDOW_BIT) { + (void) swrast_update_buffers(dri2_surf); + dst = dri2_wl_swrast_get_backbuffer_data(dri2_surf); - /* partial copy, copy old content */ - if (copy_width < dst_stride) - dri2_wl_swrast_get_image(draw, 0, 0, - dri2_surf->base.Width, dri2_surf->base.Height, - dst, loaderPrivate); + /* partial copy, copy old content */ + if (copy_width < dst_stride) + dri2_wl_swrast_get_image(draw, 0, 0, + dri2_surf->base.Width, dri2_surf->base.Height, + dst, loaderPrivate); + } else { + (void) swrast_allocate_front_buffer(dri2_surf); + dst = dri2_surf->swrast_front; + assert(dst); + } dst += x_offset; dst += y * dst_stride; @@ -2566,7 +2877,9 @@ dri2_wl_swrast_put_image2(__DRIdrawable * draw, int op, src += stride; dst += dst_stride; } - dri2_wl_swrast_commit_backbuffer(dri2_surf); + + if (dri2_surf->base.Type == EGL_WINDOW_BIT) + dri2_wl_swrast_commit_backbuffer(dri2_surf); } static void @@ -2638,6 +2951,7 @@ static const struct dri2_egl_display_vtbl dri2_wl_swrast_display_vtbl = { .authenticate = NULL, .create_window_surface = dri2_wl_create_window_surface, .create_pixmap_surface = dri2_wl_create_pixmap_surface, + .create_pbuffer_surface = dri2_wl_create_pbuffer_surface, .destroy_surface = dri2_wl_destroy_surface, .create_image = dri2_create_image_khr, .swap_buffers = dri2_wl_swrast_swap_buffers, @@ -2690,6 +3004,7 @@ dri2_initialize_wayland_swrast(_EGLDisplay *disp) return _eglError(EGL_BAD_ALLOC, "eglInitialize"); dri2_dpy->fd = -1; + dri2_dpy->fd_dpy = -1; disp->DriverData = (void *) dri2_dpy; if (dri2_wl_formats_init(&dri2_dpy->formats) < 0) @@ -2751,7 +3066,7 @@ dri2_initialize_wayland_swrast(_EGLDisplay *disp) dri2_wl_setup_swap_interval(disp); - if (!dri2_wl_add_configs_for_visuals(disp)) { + if (!dri2_wl_add_configs_for_visuals(disp, false)) { _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to add configs"); goto cleanup; } diff --git a/src/egl/drivers/dri2/platform_x11.c b/src/egl/drivers/dri2/platform_x11.c index 15be86d..389c105 100644 --- a/src/egl/drivers/dri2/platform_x11.c +++ b/src/egl/drivers/dri2/platform_x11.c @@ -1507,6 +1507,7 @@ dri2_initialize_x11_swrast(_EGLDisplay *disp) return _eglError(EGL_BAD_ALLOC, "eglInitialize"); dri2_dpy->fd = -1; + dri2_dpy->fd_dpy = -1; if (!dri2_get_xcb_connection(disp, dri2_dpy)) goto cleanup; @@ -1596,6 +1597,7 @@ dri2_initialize_x11_dri3(_EGLDisplay *disp) return _eglError(EGL_BAD_ALLOC, "eglInitialize"); dri2_dpy->fd = -1; + dri2_dpy->fd_dpy = -1; if (!dri2_get_xcb_connection(disp, dri2_dpy)) goto cleanup; @@ -1708,6 +1710,7 @@ dri2_initialize_x11_dri2(_EGLDisplay *disp) return _eglError(EGL_BAD_ALLOC, "eglInitialize"); dri2_dpy->fd = -1; + dri2_dpy->fd_dpy = -1; if (!dri2_get_xcb_connection(disp, dri2_dpy)) goto cleanup; diff --git a/src/egl/drivers/dri2/platform_x11_dri3.c b/src/egl/drivers/dri2/platform_x11_dri3.c index c529f42..63d3dc5 100644 --- a/src/egl/drivers/dri2/platform_x11_dri3.c +++ b/src/egl/drivers/dri2/platform_x11_dri3.c @@ -32,6 +32,7 @@ #include #include "util/macros.h" +#include "util/os_file.h" #include "egl_dri2.h" #include "platform_x11_dri3.h" @@ -157,6 +158,7 @@ dri3_create_surface(_EGLDisplay *disp, EGLint type, _EGLConfig *conf, struct dri3_egl_surface *dri3_surf; const __DRIconfig *dri_config; xcb_drawable_t drawable; + bool is_incompat_gpu; dri3_surf = calloc(1, sizeof *dri3_surf); if (!dri3_surf) { @@ -164,6 +166,10 @@ dri3_create_surface(_EGLDisplay *disp, EGLint type, _EGLConfig *conf, return NULL; } + is_incompat_gpu = dri2_dpy->is_different_gpu && + !loader_dri3_has_modifiers(dri2_dpy->multibuffers_available, + dri2_dpy->image); + if (!dri2_init_surface(&dri3_surf->surf.base, disp, type, conf, attrib_list, false, native_surface)) goto cleanup_surf; @@ -189,7 +195,7 @@ dri3_create_surface(_EGLDisplay *disp, EGLint type, _EGLConfig *conf, if (loader_dri3_drawable_init(dri2_dpy->conn, drawable, egl_to_loader_dri3_drawable_type(type), dri2_dpy->dri_screen, - dri2_dpy->is_different_gpu, + is_incompat_gpu, dri2_dpy->multibuffers_available, true, dri_config, @@ -431,11 +437,21 @@ dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate) _eglLog(_EGL_WARNING, "FIXME: egl/x11 doesn't support front buffer rendering."); } +static int +dri3_get_display_fd(void *loaderPrivate) +{ + _EGLDisplay *disp = loaderPrivate; + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + + return dri2_dpy->fd_dpy; +} + const __DRIimageLoaderExtension dri3_image_loader_extension = { - .base = { __DRI_IMAGE_LOADER, 1 }, + .base = { __DRI_IMAGE_LOADER, 5 }, .getBuffers = loader_dri3_get_buffers, .flushFrontBuffer = dri3_flush_front_buffer, + .getDisplayFD = dri3_get_display_fd, }; static EGLBoolean @@ -555,6 +571,7 @@ dri3_x11_connect(struct dri2_egl_display *dri2_dpy) xcb_xfixes_query_version_cookie_t xfixes_query_cookie; xcb_generic_error_t *error; const xcb_query_extension_reply_t *extension; + int fd_old; xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri3_id); xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_present_id); @@ -634,12 +651,25 @@ dri3_x11_connect(struct dri2_egl_display *dri2_dpy) return EGL_FALSE; } + fd_old = dri2_dpy->fd; + dri2_dpy->fd_dpy = os_dupfd_cloexec(dri2_dpy->fd); dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd, &dri2_dpy->is_different_gpu); + if (dri2_dpy->fd == fd_old) { + if (dri2_dpy->fd_dpy != -1) + close(dri2_dpy->fd_dpy); + + dri2_dpy->fd_dpy = dri2_dpy->fd; + } else if (dri2_dpy->fd_dpy == -1) { + _eglLog(_EGL_WARNING, "DRI3: failed to dup display FD"); + close(dri2_dpy->fd); + return EGL_FALSE; + } dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd); if (!dri2_dpy->driver_name) { _eglLog(_EGL_WARNING, "DRI3: No driver found"); close(dri2_dpy->fd); + close(dri2_dpy->fd_dpy); return EGL_FALSE; } diff --git a/src/egl/drivers/haiku/egl_haiku.cpp b/src/egl/drivers/haiku/egl_haiku.cpp index 18c73c9..2690a82 100644 --- a/src/egl/drivers/haiku/egl_haiku.cpp +++ b/src/egl/drivers/haiku/egl_haiku.cpp @@ -297,6 +297,14 @@ haiku_make_current(_EGLDisplay *disp, _EGLSurface *dsurf, } +extern "C" +EGLint +haiku_dri2_query_context_client_version(_EGLDisplay *disp, _EGLContext *ctx) +{ + // Tell caller to use the default value. + return 0; +} + extern "C" EGLBoolean haiku_swap_buffers(_EGLDisplay *disp, _EGLSurface *surf) @@ -316,6 +324,7 @@ const _EGLDriver _eglDriver = { .CreateContext = haiku_create_context, .DestroyContext = haiku_destroy_context, .MakeCurrent = haiku_make_current, + .QueryContextClientVersion = haiku_dri2_query_context_client_version, .CreateWindowSurface = haiku_create_window_surface, .CreatePixmapSurface = haiku_create_pixmap_surface, .CreatePbufferSurface = haiku_create_pbuffer_surface, diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c index 041f35a..b5064a3 100644 --- a/src/egl/main/eglapi.c +++ b/src/egl/main/eglapi.c @@ -564,11 +564,13 @@ _eglCreateExtensionsString(_EGLDisplay *disp) _EGL_CHECK_EXTENSION(EXT_image_dma_buf_import); _EGL_CHECK_EXTENSION(EXT_image_dma_buf_import_modifiers); _EGL_CHECK_EXTENSION(EXT_protected_content); + _EGL_CHECK_EXTENSION(EXT_image_gl_colorspace); _EGL_CHECK_EXTENSION(EXT_protected_surface); _EGL_CHECK_EXTENSION(EXT_present_opaque); _EGL_CHECK_EXTENSION(EXT_surface_CTA861_3_metadata); _EGL_CHECK_EXTENSION(EXT_surface_SMPTE2086_metadata); _EGL_CHECK_EXTENSION(EXT_swap_buffers_with_damage); + _EGL_CHECK_EXTENSION(EXT_yuv_surface); _EGL_CHECK_EXTENSION(IMG_context_priority); @@ -613,6 +615,7 @@ _eglCreateExtensionsString(_EGLDisplay *disp) _EGL_CHECK_EXTENSION(WL_bind_wayland_display); _EGL_CHECK_EXTENSION(WL_create_wayland_buffer_from_image); + _EGL_CHECK_EXTENSION(IMG_cl_image); #undef _EGL_CHECK_EXTENSION } @@ -934,6 +937,7 @@ eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) { _EGLDisplay *disp = _eglLockDisplay(dpy); + _EGLContext *current_context = _eglGetCurrentContext(); _EGLContext *context = _eglLookupContext(ctx, disp); _EGLSurface *draw_surf = _eglLookupSurface(draw, disp); _EGLSurface *read_surf = _eglLookupSurface(read, disp); @@ -987,8 +991,17 @@ eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, draw_surf && !draw_surf->ProtectedContent) RETURN_EGL_ERROR(disp, EGL_BAD_ACCESS, EGL_FALSE); - egl_relax (disp, &draw_surf->Resource, &read_surf->Resource, &context->Resource) { - ret = disp->Driver->MakeCurrent(disp, draw_surf, read_surf, context); + /* As an optimisation don't do anything unless something has changed */ + if (context != current_context || + (current_context && + (draw_surf != current_context->DrawSurface || + read_surf != current_context->ReadSurface)) || + (!current_context && (draw_surf || read_surf))) { + egl_relax (disp, &draw_surf->Resource, &read_surf->Resource, &context->Resource) { + ret = disp->Driver->MakeCurrent(disp, draw_surf, read_surf, context); + } + } else { + ret = EGL_TRUE; } RETURN_EGL_EVAL(disp, ret); @@ -1051,7 +1064,10 @@ _eglCreateWindowSurfaceCommon(_EGLDisplay *disp, EGLConfig config, if (native_window == NULL) - RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); +#ifdef HAVE_NULL_PLATFORM + if (disp && disp->Platform != _EGL_PLATFORM_NULL) +#endif + RETURN_EGL_ERROR(disp, EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); if (disp && (disp->Platform == _EGL_PLATFORM_SURFACELESS || disp->Platform == _EGL_PLATFORM_DEVICE)) { diff --git a/src/egl/main/eglconfig.c b/src/egl/main/eglconfig.c index 1c8b01b..86d8285 100644 --- a/src/egl/main/eglconfig.c +++ b/src/egl/main/eglconfig.c @@ -258,6 +258,24 @@ static const struct { { EGL_COLOR_COMPONENT_TYPE_EXT, ATTRIB_TYPE_ENUM, ATTRIB_CRITERION_EXACT, EGL_COLOR_COMPONENT_TYPE_FIXED_EXT }, + { EGL_YUV_ORDER_EXT, ATTRIB_TYPE_ENUM, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_YUV_NUMBER_OF_PLANES_EXT, ATTRIB_TYPE_INTEGER, + ATTRIB_CRITERION_ATLEAST, + 0 }, + { EGL_YUV_SUBSAMPLE_EXT, ATTRIB_TYPE_ENUM, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_YUV_DEPTH_RANGE_EXT, ATTRIB_TYPE_ENUM, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_YUV_CSC_STANDARD_EXT, ATTRIB_TYPE_ENUM, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, + { EGL_YUV_PLANE_BPP_EXT, ATTRIB_TYPE_ENUM, + ATTRIB_CRITERION_EXACT, + EGL_DONT_CARE }, }; @@ -296,6 +314,28 @@ _eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching) if (val > 1 || val < 0) valid = EGL_FALSE; break; + case EGL_YUV_NUMBER_OF_PLANES_EXT: + /* From the EGL_EXT_yuv_surface spec (v9): + * + * The allowed values for EGL_YUV_NUMBER_OF_PLANES_EXT must + * be greater than zero and not more than three. + * + * However, it also says: + * + * Attribute Default Selection Sort Sort + * Criteria Order Priority + * ---------------------------- ------- --------- ----- -------- + * EGL_YUV_NUMBER_OF_PLANES_EXT 0 At least None + * + * This means that we need to allow the value 0 when doing config + * matching (where it's essentially treated as EGL_DONT_CARE). + * Furthermore, this attribute isn't applicable to non-YUV EGL + * color buffer types. Allow 0 through here and then do further + * validation later on. + */ + if (val < 0 || val > 3) + valid = EGL_FALSE; + break; default: if (val < 0) valid = EGL_FALSE; @@ -318,7 +358,43 @@ _eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching) valid = EGL_FALSE; break; case EGL_COLOR_BUFFER_TYPE: - if (val != EGL_RGB_BUFFER && val != EGL_LUMINANCE_BUFFER) + if (val != EGL_RGB_BUFFER && val != EGL_LUMINANCE_BUFFER && + val != EGL_YUV_BUFFER_EXT) + valid = EGL_FALSE; + break; + case EGL_YUV_ORDER_EXT: + if (val != EGL_NONE && + val != EGL_YUV_ORDER_YUV_EXT && val != EGL_YUV_ORDER_YVU_EXT && + val != EGL_YUV_ORDER_YUYV_EXT && val != EGL_YUV_ORDER_UYVY_EXT && + val != EGL_YUV_ORDER_YVYU_EXT && val != EGL_YUV_ORDER_VYUY_EXT && + val != EGL_YUV_ORDER_AYUV_EXT) + valid = EGL_FALSE; + break; + case EGL_YUV_SUBSAMPLE_EXT: + if (val != EGL_NONE && + val != EGL_YUV_SUBSAMPLE_4_2_0_EXT && + val != EGL_YUV_SUBSAMPLE_4_2_2_EXT && + val != EGL_YUV_SUBSAMPLE_4_4_4_EXT) + valid = EGL_FALSE; + break; + case EGL_YUV_DEPTH_RANGE_EXT: + if (val != EGL_NONE && + val != EGL_YUV_DEPTH_RANGE_LIMITED_EXT && + val != EGL_YUV_DEPTH_RANGE_FULL_EXT) + valid = EGL_FALSE; + break; + case EGL_YUV_CSC_STANDARD_EXT: + if (val != EGL_NONE && + val != EGL_YUV_CSC_STANDARD_601_EXT && + val != EGL_YUV_CSC_STANDARD_709_EXT && + val != EGL_YUV_CSC_STANDARD_2020_EXT) + valid = EGL_FALSE; + break; + case EGL_YUV_PLANE_BPP_EXT: + if (val != EGL_NONE && + val != EGL_YUV_PLANE_BPP_0_EXT && + val != EGL_YUV_PLANE_BPP_8_EXT && + val != EGL_YUV_PLANE_BPP_10_EXT) valid = EGL_FALSE; break; case EGL_COLOR_COMPONENT_TYPE_EXT: @@ -404,6 +480,11 @@ _eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching) if (conf->LuminanceSize + conf->AlphaSize != conf->BufferSize) valid = EGL_FALSE; break; + case EGL_YUV_BUFFER_EXT: + if (conf->RedSize || conf->GreenSize || conf->BlueSize || + conf->AlphaSize || conf->LuminanceSize) + valid = EGL_FALSE; + break; } if (!valid) { _eglLog(_EGL_DEBUG, "conflicting color buffer type and channel sizes"); @@ -430,6 +511,88 @@ _eglValidateConfig(const _EGLConfig *conf, EGLBoolean for_matching) return EGL_FALSE; } + /* From the EGL_EXT_yuv_surface spec (v9): + * + * SUBSAMPLE_EXT NUMBER_OF_PLANES_EXT ORDER_EXT PLANE_BPP_EXT + * ------------------- -------------------- ----------------- ------------------ + * SUBSAMPLE_4_2_0_EXT 2 or 3 ORDER_YUV_EXT or PLANE_BPP_8_EXT or + * ORDER_YVU_EXT PLANE_BPP_10_EXT + */ + if (conf->YUVSubsampleEXT == EGL_YUV_SUBSAMPLE_4_2_0_EXT) { + if ((!for_matching || conf->YUVNumberOfPlanesEXT != 0) && + conf->YUVNumberOfPlanesEXT != 2 && + conf->YUVNumberOfPlanesEXT != 3) + valid = EGL_FALSE; + if (conf->YUVOrderEXT != EGL_DONT_CARE && + conf->YUVOrderEXT != EGL_YUV_ORDER_YUV_EXT && + conf->YUVOrderEXT != EGL_YUV_ORDER_YVU_EXT) + valid = EGL_FALSE; + if (conf->YUVPlaneBPPEXT != EGL_DONT_CARE && + conf->YUVPlaneBPPEXT != EGL_YUV_PLANE_BPP_8_EXT && + conf->YUVPlaneBPPEXT != EGL_YUV_PLANE_BPP_10_EXT) + valid = EGL_FALSE; + } + /* From the EGL_EXT_yuv_surface spec (v9): + * + * SUBSAMPLE_EXT NUMBER_OF_PLANES_EXT ORDER_EXT PLANE_BPP_EXT + * ------------------- -------------------- ----------------- ------------------ + * SUBSAMPLE_4_2_2_EXT 1 ORDER_YUYV_EXT or PLANE_BPP_8_EXT or + * ORDER_YVYU_EXT or PLANE_BPP_10_EXT + * ORDER_UYVY_EXT or + * ORDER_VYUY_EXT + * + * SUBSAMPLE_4_2_2_EXT 2 or 3 ORDER_YUV_EXT or PLANE_BPP_8_EXT or + * ORDER_YVU_EXT PLANE_BPP_10_EXT + */ + else if (conf->YUVSubsampleEXT == EGL_YUV_SUBSAMPLE_4_2_2_EXT) { + if ((!for_matching || conf->YUVNumberOfPlanesEXT != 0) && + conf->YUVNumberOfPlanesEXT != 1 && + conf->YUVNumberOfPlanesEXT != 2 && + conf->YUVNumberOfPlanesEXT != 3) + valid = EGL_FALSE; + if (conf->YUVNumberOfPlanesEXT == 1) { + if (conf->YUVOrderEXT != EGL_DONT_CARE && + conf->YUVOrderEXT != EGL_YUV_ORDER_YUYV_EXT && + conf->YUVOrderEXT != EGL_YUV_ORDER_YVYU_EXT && + conf->YUVOrderEXT != EGL_YUV_ORDER_UYVY_EXT && + conf->YUVOrderEXT != EGL_YUV_ORDER_VYUY_EXT) + valid = EGL_FALSE; + } else if (conf->YUVNumberOfPlanesEXT == 2 || + conf->YUVNumberOfPlanesEXT == 3) { + if (conf->YUVOrderEXT != EGL_DONT_CARE && + conf->YUVOrderEXT != EGL_YUV_ORDER_YUV_EXT && + conf->YUVOrderEXT != EGL_YUV_ORDER_YVU_EXT) + valid = EGL_FALSE; + } + if (conf->YUVPlaneBPPEXT != EGL_DONT_CARE && + conf->YUVPlaneBPPEXT != EGL_YUV_PLANE_BPP_8_EXT && + conf->YUVPlaneBPPEXT != EGL_YUV_PLANE_BPP_10_EXT) + valid = EGL_FALSE; + } + /* From the EGL_EXT_yuv_surface spec (v9): + * + * SUBSAMPLE_EXT NUMBER_OF_PLANES_EXT ORDER_EXT PLANE_BPP_EXT + * ------------------- -------------------- ----------------- ------------------ + * SUBSAMPLE_4_4_4_EXT 1 ORDER_AYUV_EXT PLANE_BPP_8_EXT or + * PLANE_BPP_10_EXT + */ + else if (conf->YUVSubsampleEXT == EGL_YUV_SUBSAMPLE_4_4_4_EXT) { + if ((!for_matching || conf->YUVNumberOfPlanesEXT != 0) && + conf->YUVNumberOfPlanesEXT != 1) + valid = EGL_FALSE; + if (conf->YUVOrderEXT != EGL_DONT_CARE && + conf->YUVOrderEXT != EGL_YUV_ORDER_AYUV_EXT) + valid = EGL_FALSE; + if (conf->YUVPlaneBPPEXT != EGL_DONT_CARE && + conf->YUVPlaneBPPEXT != EGL_YUV_PLANE_BPP_8_EXT && + conf->YUVPlaneBPPEXT != EGL_YUV_PLANE_BPP_10_EXT) + valid = EGL_FALSE; + } + if (!valid) { + _eglLog(_EGL_DEBUG, "invalid YUV subsample/num planes/order/bpp combination"); + return EGL_FALSE; + } + return valid; } @@ -509,6 +672,28 @@ _eglIsConfigAttribValid(_EGLConfig *conf, EGLint attr) return conf->Display->Extensions.ANDROID_framebuffer_target; case EGL_RECORDABLE_ANDROID: return conf->Display->Extensions.ANDROID_recordable; + case EGL_YUV_ORDER_EXT: + case EGL_YUV_NUMBER_OF_PLANES_EXT: + case EGL_YUV_SUBSAMPLE_EXT: + case EGL_YUV_DEPTH_RANGE_EXT: + case EGL_YUV_CSC_STANDARD_EXT: + case EGL_YUV_PLANE_BPP_EXT: + return conf->Display->Extensions.EXT_yuv_surface; + default: + break; + } + + return EGL_TRUE; +} + +static inline EGLBoolean +_eglIsConfigAttribValueValid(_EGLConfig *conf, EGLint attr, EGLint val) +{ + switch (attr) { + case EGL_COLOR_BUFFER_TYPE: + if (!conf->Display->Extensions.EXT_yuv_surface && val == EGL_YUV_BUFFER_EXT) + return EGL_FALSE; + break; default: break; } @@ -543,6 +728,9 @@ _eglParseConfigAttribList(_EGLConfig *conf, _EGLDisplay *disp, if (!_eglIsConfigAttribValid(conf, attr)) return EGL_FALSE; + if (!_eglIsConfigAttribValueValid(conf, attr, val)) + return EGL_FALSE; + _eglSetConfigKey(conf, attr, val); } @@ -617,6 +805,7 @@ _eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2, /* the enum values have the desired ordering */ STATIC_ASSERT(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER); + STATIC_ASSERT(EGL_LUMINANCE_BUFFER < EGL_YUV_BUFFER_EXT); val1 = conf1->ColorBufferType - conf2->ColorBufferType; if (val1) return val1; @@ -636,16 +825,42 @@ _eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2, val1 += conf1->BlueSize; val2 += conf2->BlueSize; } + if (criteria->AlphaSize > 0) { + val1 += conf1->AlphaSize; + val2 += conf2->AlphaSize; + } } - else { + else if (conf1->ColorBufferType == EGL_LUMINANCE_BUFFER) { if (criteria->LuminanceSize > 0) { val1 += conf1->LuminanceSize; val2 += conf2->LuminanceSize; } + if (criteria->AlphaSize > 0) { + val1 += conf1->AlphaSize; + val2 += conf2->AlphaSize; + } } - if (criteria->AlphaSize > 0) { - val1 += conf1->AlphaSize; - val2 += conf2->AlphaSize; + else { + /* From the EGL_EXT_yuv_surface spec (v9): + * + * Special: by larger total number of color bits + * ... + * for YUV color buffers, this returns the integer value with + * respect to the enumeration provided for EGL_YUV_PLANE_BPP_EXT + * + * and: + * + * EGL_BUFFER_SIZE gives the total of the color component bits of + * the color buffer for EGL_RGB_BUFFER or for EGL_LUMINANCE_BUFFER. + * ... + * When EGL_COLOR_BUFFER_TYPE is of type EGL_YUV_BUFFER_EXT, + * this will reflect the enumeration provided as an integer) + * for EGL_YUV_PLANE_BPP_EXT, giving a value of 0, 8 or 10 + */ + if (criteria->BufferSize > 0) { + val1 = conf1->BufferSize; + val2 = conf2->BufferSize; + } } } else { @@ -664,6 +879,36 @@ _eglCompareConfigs(const _EGLConfig *conf1, const _EGLConfig *conf2, return (val1 - val2); } + if (conf1->YUVOrderEXT != conf2->YUVOrderEXT) + { + const EGLint yuv_order[] = { + EGL_NONE, + EGL_YUV_ORDER_YUV_EXT, + EGL_YUV_ORDER_YVU_EXT, + EGL_YUV_ORDER_YUYV_EXT, + EGL_YUV_ORDER_YVYU_EXT, + EGL_YUV_ORDER_UYVY_EXT, + EGL_YUV_ORDER_VYUY_EXT, + EGL_YUV_ORDER_AYUV_EXT, + }; + + val1 = val2 = 0; + for (i = 0; i < ARRAY_SIZE(yuv_order); i++) { + if (yuv_order[i] == conf1->YUVOrderEXT) { + val1 = i; + break; + } + } + for (i = 0; i < ARRAY_SIZE(yuv_order); i++) { + if (yuv_order[i] == conf2->YUVOrderEXT) { + val2 = i; + break; + } + } + if (val1 != val2) + return val1 - val2; + } + /* EGL_NATIVE_VISUAL_TYPE cannot be compared here */ return (compare_id) ? (conf1->ConfigID - conf2->ConfigID) : 0; diff --git a/src/egl/main/eglconfig.h b/src/egl/main/eglconfig.h index dcfb11b..0523c89 100644 --- a/src/egl/main/eglconfig.h +++ b/src/egl/main/eglconfig.h @@ -88,6 +88,12 @@ struct _egl_config EGLint FramebufferTargetAndroid; EGLint RecordableAndroid; EGLint ComponentType; + EGLint YUVOrderEXT; + EGLint YUVNumberOfPlanesEXT; + EGLint YUVSubsampleEXT; + EGLint YUVDepthRangeEXT; + EGLint YUVCSCStandardEXT; + EGLint YUVPlaneBPPEXT; }; @@ -138,6 +144,12 @@ _eglOffsetOfConfig(EGLint attr) ATTRIB_MAP(EGL_FRAMEBUFFER_TARGET_ANDROID, FramebufferTargetAndroid); ATTRIB_MAP(EGL_RECORDABLE_ANDROID, RecordableAndroid); ATTRIB_MAP(EGL_COLOR_COMPONENT_TYPE_EXT, ComponentType); + ATTRIB_MAP(EGL_YUV_ORDER_EXT, YUVOrderEXT); + ATTRIB_MAP(EGL_YUV_NUMBER_OF_PLANES_EXT, YUVNumberOfPlanesEXT); + ATTRIB_MAP(EGL_YUV_SUBSAMPLE_EXT, YUVSubsampleEXT); + ATTRIB_MAP(EGL_YUV_DEPTH_RANGE_EXT, YUVDepthRangeEXT); + ATTRIB_MAP(EGL_YUV_CSC_STANDARD_EXT, YUVCSCStandardEXT); + ATTRIB_MAP(EGL_YUV_PLANE_BPP_EXT, YUVPlaneBPPEXT); #undef ATTRIB_MAP default: return -1; diff --git a/src/egl/main/eglcontext.c b/src/egl/main/eglcontext.c index 63b65cc..51de016 100644 --- a/src/egl/main/eglcontext.c +++ b/src/egl/main/eglcontext.c @@ -35,6 +35,7 @@ #include "eglcontext.h" #include "egldisplay.h" #include "eglcurrent.h" +#include "egldriver.h" #include "eglsurface.h" #include "egllog.h" #include "util/macros.h" @@ -678,6 +679,17 @@ _eglQueryContextRenderBuffer(_EGLContext *ctx) } +static EGLint +_eglQueryContextClientVersion(_EGLContext *ctx) +{ + _EGLDisplay *disp = ctx->Resource.Display; + EGLint version; + + version = disp->Driver->QueryContextClientVersion(disp, ctx); + + return (version) ? version : ctx->ClientMajorVersion; +} + EGLBoolean _eglQueryContext(_EGLContext *c, EGLint attribute, EGLint *value) { @@ -698,7 +710,7 @@ _eglQueryContext(_EGLContext *c, EGLint attribute, EGLint *value) *value = c->Config ? c->Config->ConfigID : 0; break; case EGL_CONTEXT_CLIENT_VERSION: - *value = c->ClientMajorVersion; + *value = _eglQueryContextClientVersion(c); break; case EGL_CONTEXT_CLIENT_TYPE: *value = c->ClientAPI; diff --git a/src/egl/main/eglcurrent.h b/src/egl/main/eglcurrent.h index d813a46..5e08302 100644 --- a/src/egl/main/eglcurrent.h +++ b/src/egl/main/eglcurrent.h @@ -72,11 +72,10 @@ struct _egl_thread_info static inline EGLBoolean _eglIsApiValid(EGLenum api) { -#ifdef ANDROID - /* OpenGL is not a valid/supported API on Android */ - return api == EGL_OPENGL_ES_API; -#else +#ifdef EGL_WITH_OPENGL return (api == EGL_OPENGL_ES_API || api == EGL_OPENGL_API); +#else + return api == EGL_OPENGL_ES_API; #endif } diff --git a/src/egl/main/egldisplay.c b/src/egl/main/egldisplay.c index 39850e3..a092019 100644 --- a/src/egl/main/egldisplay.c +++ b/src/egl/main/egldisplay.c @@ -85,6 +85,7 @@ static const struct { { _EGL_PLATFORM_SURFACELESS, "surfaceless" }, { _EGL_PLATFORM_DEVICE, "device" }, { _EGL_PLATFORM_WINDOWS, "windows" }, + { _EGL_PLATFORM_NULL, "null" }, }; diff --git a/src/egl/main/egldisplay.h b/src/egl/main/egldisplay.h index 28c2b29..4b16fb5 100644 --- a/src/egl/main/egldisplay.h +++ b/src/egl/main/egldisplay.h @@ -56,6 +56,7 @@ enum _egl_platform_type { _EGL_PLATFORM_SURFACELESS, _EGL_PLATFORM_DEVICE, _EGL_PLATFORM_WINDOWS, + _EGL_PLATFORM_NULL, _EGL_NUM_PLATFORMS, _EGL_INVALID_PLATFORM = -1 @@ -111,6 +112,7 @@ struct _egl_extensions EGLBoolean EXT_create_context_robustness; EGLBoolean EXT_image_dma_buf_import; EGLBoolean EXT_image_dma_buf_import_modifiers; + EGLBoolean EXT_image_gl_colorspace; EGLBoolean EXT_pixel_format_float; EGLBoolean EXT_protected_content; EGLBoolean EXT_protected_surface; @@ -118,6 +120,7 @@ struct _egl_extensions EGLBoolean EXT_surface_CTA861_3_metadata; EGLBoolean EXT_surface_SMPTE2086_metadata; EGLBoolean EXT_swap_buffers_with_damage; + EGLBoolean EXT_yuv_surface; unsigned int IMG_context_priority; #define __EGL_CONTEXT_PRIORITY_LOW_BIT 0 @@ -157,6 +160,8 @@ struct _egl_extensions EGLBoolean WL_bind_wayland_display; EGLBoolean WL_create_wayland_buffer_from_image; + + EGLBoolean IMG_cl_image; }; struct _egl_display diff --git a/src/egl/main/egldriver.h b/src/egl/main/egldriver.h index da2281e..2f4669e 100644 --- a/src/egl/main/egldriver.h +++ b/src/egl/main/egldriver.h @@ -96,6 +96,7 @@ struct _egl_driver EGLBoolean (*MakeCurrent)(_EGLDisplay *disp, _EGLSurface *draw, _EGLSurface *read, _EGLContext *ctx); + EGLint (*QueryContextClientVersion)(_EGLDisplay *disp, _EGLContext *ctx); /* surface funcs */ _EGLSurface *(*CreateWindowSurface)(_EGLDisplay *disp, _EGLConfig *config, diff --git a/src/egl/main/eglimage.c b/src/egl/main/eglimage.c index 997855f..1011b66 100644 --- a/src/egl/main/eglimage.c +++ b/src/egl/main/eglimage.c @@ -46,6 +46,18 @@ _eglParseKHRImageAttribs(_EGLImageAttribs *attrs, _EGLDisplay *disp, attrs->ImagePreserved = val; break; + case EGL_GL_COLORSPACE_KHR: + if (!disp->Extensions.EXT_image_gl_colorspace) + return EGL_BAD_PARAMETER; + + if (val != EGL_GL_COLORSPACE_SRGB_KHR && + val != EGL_GL_COLORSPACE_LINEAR_KHR && + val != EGL_GL_COLORSPACE_DEFAULT_EXT) + return EGL_BAD_PARAMETER; + + attrs->GLColorspace = val; + break; + case EGL_GL_TEXTURE_LEVEL_KHR: if (!disp->Extensions.KHR_gl_texture_2D_image) return EGL_BAD_PARAMETER; @@ -286,6 +298,8 @@ _eglParseImageAttribList(_EGLImageAttribs *attrs, _EGLDisplay *disp, memset(attrs, 0, sizeof(*attrs)); + attrs->GLColorspace = EGL_GL_COLORSPACE_DEFAULT_EXT; + if (!attrib_list) return EGL_TRUE; diff --git a/src/egl/main/eglimage.h b/src/egl/main/eglimage.h index 02ad3b8..003955d 100644 --- a/src/egl/main/eglimage.h +++ b/src/egl/main/eglimage.h @@ -80,6 +80,9 @@ struct _egl_image_attribs /* EGL_EXT_protected_content || EGL_EXT_protected_surface */ EGLBoolean ProtectedContent; + + /* EGL_EXT_image_gl_colorspace */ + EGLint GLColorspace; }; /** diff --git a/src/egl/meson.build b/src/egl/meson.build index a7c6471..88514d7 100644 --- a/src/egl/meson.build +++ b/src/egl/meson.build @@ -152,6 +152,16 @@ elif with_platform_windows incs_for_egl += [inc_wgl, inc_gallium, inc_gallium_aux] link_for_egl += libgallium_wgl endif +if with_platform_null + if null_dri_driver_name != '' + c_args_for_egl += [ + '-DNULL_DRI_DRIVER_NAME="@0@"'.format(null_dri_driver_name), + ] + endif + files_egl += files('drivers/dri2/platform_null.c') + incs_for_egl += [inc_loader] + deps_for_egl += dep_libdrm +endif if cc.has_function('mincore') c_args_for_egl += '-DHAVE_MINCORE' diff --git a/src/egl/wayland/wayland-drm/meson.build b/src/egl/wayland/wayland-drm/meson.build index b4782a0..f291ef9 100644 --- a/src/egl/wayland/wayland-drm/meson.build +++ b/src/egl/wayland/wayland-drm/meson.build @@ -49,6 +49,21 @@ libwayland_drm = static_library( build_by_default : false, ) +install_data('wayland-drm.xml') + +pkg.generate( + filebase : 'wayland-drm', + name : 'Mesa Wayland Protocols', + description : 'Mesa Wayland protocol files', + version : meson.project_version(), + variables : [ + 'datarootdir=${prefix}/' + get_option('datadir'), + 'pkgdatadir=${pc_sysrootdir}${datarootdir}/' + meson.project_name(), + ], + install_dir : '@0@/@1@/pkgconfig'.format(get_option('prefix'), + get_option('datadir')), +) + # linux-dmabuf isn't part of wayland-drm, but this happens to be the only # place which is a) guaranteed to be built when building either or both # of EGL and Vulkan WSI, and b) guaranteed to be included before both, diff --git a/src/egl/wayland/wayland-drm/wayland-drm.pc.in b/src/egl/wayland/wayland-drm/wayland-drm.pc.in new file mode 100644 index 0000000..d08ccda --- /dev/null +++ b/src/egl/wayland/wayland-drm/wayland-drm.pc.in @@ -0,0 +1,7 @@ +prefix=@prefix@ +datarootdir=@datarootdir@ +pkgdatadir=${pc_sysrootdir}@datadir@/@PACKAGE@ + +Name: @PACKAGE_NAME@ Wayland Protocols +Description: @PACKAGE_NAME@ Wayland protocol files +Version: @PACKAGE_VERSION@ \ No newline at end of file diff --git a/src/gallium/auxiliary/draw/draw_pipe_aaline.c b/src/gallium/auxiliary/draw/draw_pipe_aaline.c index 7dac407..d2bc475 100644 --- a/src/gallium/auxiliary/draw/draw_pipe_aaline.c +++ b/src/gallium/auxiliary/draw/draw_pipe_aaline.c @@ -107,6 +107,7 @@ struct aa_transform_context { uint64_t tempsUsed; /**< bitmask */ int colorOutput; /**< which output is the primary color */ int maxInput, maxGeneric; /**< max input index found */ + int numImm; /**< number of immediate regsters */ int colorTemp, aaTemp; /**< temp registers */ }; @@ -147,6 +148,18 @@ aa_transform_decl(struct tgsi_transform_context *ctx, ctx->emit_declaration(ctx, decl); } +/** + * TGSI immediate declaration transform callback. + */ +static void +aa_immediate(struct tgsi_transform_context *ctx, + struct tgsi_full_immediate *imm) +{ + struct aa_transform_context *aactx = (struct aa_transform_context *)ctx; + + ctx->emit_immediate(ctx, imm); + aactx->numImm++; +} /** * Find the lowest zero bit, or -1 if bitfield is all ones. @@ -182,6 +195,9 @@ aa_transform_prolog(struct tgsi_transform_context *ctx) /* declare new temp regs */ tgsi_transform_temp_decl(ctx, aactx->aaTemp); tgsi_transform_temp_decl(ctx, aactx->colorTemp); + + /* declare new immediate reg */ + tgsi_transform_immediate_decl(ctx, 2.0, -1.0, 0.0, 0.25); } @@ -215,6 +231,26 @@ aa_transform_epilog(struct tgsi_transform_context *ctx) inst.Src[1].Register.Negate = true; ctx->emit_instruction(ctx, &inst); + /* linelength * 2 - 1 */ + tgsi_transform_op3_swz_inst(ctx, TGSI_OPCODE_MAD, + TGSI_FILE_TEMPORARY, aactx->aaTemp, + TGSI_WRITEMASK_Y, + TGSI_FILE_INPUT, aactx->maxInput + 1, + TGSI_SWIZZLE_W, false, + TGSI_FILE_IMMEDIATE, aactx->numImm, + TGSI_SWIZZLE_X, + TGSI_FILE_IMMEDIATE, aactx->numImm, + TGSI_SWIZZLE_Y); + + /* MIN height alpha */ + tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_MIN, + TGSI_FILE_TEMPORARY, aactx->aaTemp, + TGSI_WRITEMASK_Z, + TGSI_FILE_TEMPORARY, aactx->aaTemp, + TGSI_SWIZZLE_Z, + TGSI_FILE_TEMPORARY, aactx->aaTemp, + TGSI_SWIZZLE_Y, false); + /* MUL width / height alpha */ tgsi_transform_op2_swz_inst(ctx, TGSI_OPCODE_MUL, TGSI_FILE_TEMPORARY, aactx->aaTemp, @@ -292,6 +328,7 @@ generate_aaline_fs(struct aaline_stage *aaline) transform.base.epilog = aa_transform_epilog; transform.base.transform_instruction = aa_transform_inst; transform.base.transform_declaration = aa_transform_decl; + transform.base.transform_immediate = aa_immediate; aaline_fs.tokens = tgsi_transform_shader(orig_fs->tokens, newLen, &transform.base); if (!aaline_fs.tokens) @@ -324,7 +361,7 @@ generate_aaline_fs_nir(struct aaline_stage *aaline) if (!aaline_fs.ir.nir) return FALSE; - nir_lower_aaline_fs(aaline_fs.ir.nir, &aaline->fs->generic_attrib); + nir_lower_aaline_fs(aaline_fs.ir.nir, &aaline->fs->generic_attrib, NULL, NULL); aaline->fs->aaline_fs = aaline->driver_create_fs_state(pipe, &aaline_fs); if (aaline->fs->aaline_fs == NULL) return FALSE; @@ -383,36 +420,13 @@ aaline_line(struct draw_stage *stage, struct prim_header *header) float *pos, *tex; float dx = header->v[1]->data[posPos][0] - header->v[0]->data[posPos][0]; float dy = header->v[1]->data[posPos][1] - header->v[0]->data[posPos][1]; - float a = atan2f(dy, dx); - float c_a = cosf(a), s_a = sinf(a); - float half_length; + float length = sqrtf(dx * dx + dy * dy); + float c_a = dx / length, s_a = dy / length; + float half_length = 0.5 * length; float t_l, t_w; uint i; - half_length = 0.5f * sqrtf(dx * dx + dy * dy); - - if (half_length < 0.5f) { - /* - * The logic we use for "normal" sized segments is incorrect - * for very short segments (basically because we only have - * one value to interpolate, not a distance to each endpoint). - * Therefore, we calculate half_length differently, so that for - * original line length (near) 0, we get alpha 0 - otherwise - * max alpha would still be 0.5. This also prevents us from - * artifacts due to degenerated lines (the endpoints being - * identical, which would still receive anywhere from alpha - * 0-0.5 otherwise) (at least the pstipple stage may generate - * such lines due to float inaccuracies if line length is very - * close to a integer). - * Might not be fully accurate neither (because the "strength" of - * the line is going to be determined by how close to the pixel - * center those 1 or 2 fragments are) but it's probably the best - * we can do. - */ - half_length = 2.0f * half_length; - } else { - half_length = half_length + 0.5f; - } + half_length = half_length + 0.5f; t_w = half_width; t_l = 0.5f; diff --git a/src/gallium/auxiliary/nir/nir_draw_helpers.c b/src/gallium/auxiliary/nir/nir_draw_helpers.c index daa1fcb..0ebc1ef 100644 --- a/src/gallium/auxiliary/nir/nir_draw_helpers.c +++ b/src/gallium/auxiliary/nir/nir_draw_helpers.c @@ -147,71 +147,94 @@ nir_lower_pstipple_fs(struct nir_shader *shader, } typedef struct { - nir_builder b; - nir_shader *shader; nir_variable *line_width_input; + nir_variable *stipple_counter; + nir_variable *stipple_pattern; } lower_aaline; -static void -nir_lower_aaline_block(nir_block *block, - lower_aaline *state) +static bool +lower_aaline_instr(nir_builder *b, nir_instr *instr, void *data) { - nir_builder *b = &state->b; - nir_foreach_instr(instr, block) { - if (instr->type != nir_instr_type_intrinsic) - continue; + lower_aaline *state = data; - nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); - if (intrin->intrinsic != nir_intrinsic_store_deref) - continue; + if (instr->type != nir_instr_type_intrinsic) + return false; - nir_variable *var = nir_intrinsic_get_var(intrin, 0); - if (var->data.mode != nir_var_shader_out) - continue; - if (var->data.location < FRAG_RESULT_DATA0 && var->data.location != FRAG_RESULT_COLOR) - continue; + nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); + if (intrin->intrinsic != nir_intrinsic_store_deref) + return false; - nir_ssa_def *out_input = intrin->src[1].ssa; - b->cursor = nir_before_instr(instr); - nir_ssa_def *lw = nir_load_var(b, state->line_width_input); - nir_ssa_def *tmp = nir_fsat(b, nir_fadd(b, nir_channel(b, lw, 1), - nir_fneg(b, nir_fabs(b, nir_channel(b, lw, 0))))); - nir_ssa_def *tmp1 = nir_fsat(b, nir_fadd(b, nir_channel(b, lw, 3), - nir_fneg(b, nir_fabs(b, nir_channel(b, lw, 2))))); + nir_variable *var = nir_intrinsic_get_var(intrin, 0); + if (var->data.mode != nir_var_shader_out) + return false; + if (var->data.location < FRAG_RESULT_DATA0 && var->data.location != FRAG_RESULT_COLOR) + return false; - tmp = nir_fmul(b, tmp, tmp1); - tmp = nir_fmul(b, nir_channel(b, out_input, 3), tmp); + nir_ssa_def *out_input = intrin->src[1].ssa; + b->cursor = nir_before_instr(instr); + nir_ssa_def *lw = nir_load_var(b, state->line_width_input); + nir_ssa_def *len = nir_channel(b, lw, 3); + len = nir_fadd_imm(b, nir_fmul_imm(b, len, 2.0), -1.0); + nir_ssa_def *tmp = nir_fsat(b, nir_fadd(b, nir_channels(b, lw, 0xa), + nir_fneg(b, nir_fabs(b, nir_channels(b, lw, 0x5))))); - nir_ssa_def *out = nir_vec4(b, nir_channel(b, out_input, 0), - nir_channel(b, out_input, 1), - nir_channel(b, out_input, 2), - tmp); - nir_instr_rewrite_src(instr, &intrin->src[1], nir_src_for_ssa(out)); + nir_ssa_def *max = len; + if (state->stipple_counter) { + assert(state->stipple_pattern); + + nir_ssa_def *counter = nir_load_var(b, state->stipple_counter); + nir_ssa_def *pattern = nir_load_var(b, state->stipple_pattern); + nir_ssa_def *factor = nir_i2f32(b, nir_ishr_imm(b, pattern, 16)); + pattern = nir_iand_imm(b, pattern, 0xffff); + + nir_ssa_def *stipple_pos = nir_vec2(b, nir_fadd_imm(b, counter, -0.5), + nir_fadd_imm(b, counter, 0.5)); + + stipple_pos = nir_frem(b, nir_fdiv(b, stipple_pos, factor), + nir_imm_float(b, 16.0)); + + nir_ssa_def *p = nir_f2i32(b, stipple_pos); + nir_ssa_def *one = nir_imm_float(b, 1.0); + + // float t = 1.0 - min((1.0 - fract(stipple_pos.x)) * factor, 1.0); + nir_ssa_def *t = nir_ffract(b, nir_channel(b, stipple_pos, 0)); + t = nir_fsub(b, one, + nir_fmin(b, nir_fmul(b, factor, + nir_fsub(b, one, t)), one)); + + // vec2 a = vec2((uvec2(pattern) >> p) & uvec2(1u)); + nir_ssa_def *a = nir_i2f32(b, + nir_iand(b, nir_ishr(b, nir_vec2(b, pattern, pattern), p), + nir_imm_ivec2(b, 1, 1))); + + // float cov = mix(a.x, a.y, t); + nir_ssa_def *cov = nir_flrp(b, nir_channel(b, a, 0), nir_channel(b, a, 1), t); + + max = nir_fmin(b, len, cov); } -} + tmp = nir_fmul(b, nir_channel(b, tmp, 0), + nir_fmin(b, nir_channel(b, tmp, 1), max)); + tmp = nir_fmul(b, nir_channel(b, out_input, 3), tmp); -static void -nir_lower_aaline_impl(nir_function_impl *impl, - lower_aaline *state) -{ - nir_builder *b = &state->b; - - nir_builder_init(b, impl); - - nir_foreach_block(block, impl) { - nir_lower_aaline_block(block, state); - } + nir_ssa_def *out = nir_vec4(b, nir_channel(b, out_input, 0), + nir_channel(b, out_input, 1), + nir_channel(b, out_input, 2), + tmp); + nir_instr_rewrite_src(instr, &intrin->src[1], nir_src_for_ssa(out)); + return true; } void -nir_lower_aaline_fs(struct nir_shader *shader, int *varying) +nir_lower_aaline_fs(struct nir_shader *shader, int *varying, + nir_variable *stipple_counter, + nir_variable *stipple_pattern) { lower_aaline state = { - .shader = shader, + .stipple_counter = stipple_counter, + .stipple_pattern = stipple_pattern, }; - if (shader->info.stage != MESA_SHADER_FRAGMENT) - return; + assert(shader->info.stage == MESA_SHADER_FRAGMENT); int highest_location = -1, highest_drv_location = -1; nir_foreach_shader_in_variable(var, shader) { @@ -234,11 +257,8 @@ nir_lower_aaline_fs(struct nir_shader *shader, int *varying) *varying = tgsi_get_generic_gl_varying_index(line_width->data.location, true); state.line_width_input = line_width; - nir_foreach_function(function, shader) { - if (function->impl) { - nir_lower_aaline_impl(function->impl, &state); - } - } + nir_shader_instructions_pass(shader, lower_aaline_instr, + nir_metadata_dominance, &state); } typedef struct { diff --git a/src/gallium/auxiliary/nir/nir_draw_helpers.h b/src/gallium/auxiliary/nir/nir_draw_helpers.h index 4262c45..114fc8d 100644 --- a/src/gallium/auxiliary/nir/nir_draw_helpers.h +++ b/src/gallium/auxiliary/nir/nir_draw_helpers.h @@ -38,7 +38,9 @@ nir_lower_pstipple_fs(struct nir_shader *shader, bool fs_pos_is_sysval); void -nir_lower_aaline_fs(struct nir_shader *shader, int *varying); +nir_lower_aaline_fs(struct nir_shader *shader, int *varying, + nir_variable *stipple_counter, + nir_variable *stipple_pattern); void nir_lower_aapoint_fs(struct nir_shader *shader, int *varying); diff --git a/src/gallium/auxiliary/util/u_transfer_helper.c b/src/gallium/auxiliary/util/u_transfer_helper.c index 73e4f1b..82ffa64 100644 --- a/src/gallium/auxiliary/util/u_transfer_helper.c +++ b/src/gallium/auxiliary/util/u_transfer_helper.c @@ -39,8 +39,13 @@ struct u_transfer_helper { bool interleave_in_place; }; -static inline bool need_interleave_path(struct u_transfer_helper *helper, - enum pipe_format format) +/* If we need to take the path for PIPE_MAP_DEPTH/STENCIL_ONLY on the parent + * depth/stencil resource an interleaving those to/from a staging buffer. The + * other path for z/s interleave is when separate z and s resources are + * created at resource create time. + */ +static inline bool needs_in_place_zs_interleave(struct u_transfer_helper *helper, + enum pipe_format format) { if (!helper->interleave_in_place) return false; @@ -68,6 +73,9 @@ static inline bool handle_transfer(struct pipe_resource *prsc) if (helper->msaa_map && (prsc->nr_samples > 1)) return true; + if (needs_in_place_zs_interleave(helper, prsc->format)) + return true; + return false; } @@ -263,10 +271,9 @@ u_transfer_helper_transfer_map(struct pipe_context *pctx, enum pipe_format format = prsc->format; unsigned width = box->width; unsigned height = box->height; + bool in_place_zs_interleave = needs_in_place_zs_interleave(helper, format); - if (need_interleave_path(helper, format)) - return u_transfer_helper_deinterleave_transfer_map(pctx, prsc, level, usage, box, pptrans); - else if (!handle_transfer(prsc)) + if (!handle_transfer(prsc)) return helper->vtbl->transfer_map(pctx, prsc, level, usage, box, pptrans); if (helper->msaa_map && (prsc->nr_samples > 1)) @@ -290,15 +297,22 @@ u_transfer_helper_transfer_map(struct pipe_context *pctx, if (!trans->staging) goto fail; - trans->ptr = helper->vtbl->transfer_map(pctx, prsc, level, usage, box, - &trans->trans); + trans->ptr = helper->vtbl->transfer_map(pctx, prsc, level, + usage | (in_place_zs_interleave ? PIPE_MAP_DEPTH_ONLY : 0), + box, &trans->trans); if (!trans->ptr) goto fail; if (util_format_is_depth_and_stencil(prsc->format)) { - struct pipe_resource *stencil = helper->vtbl->get_stencil(prsc); + struct pipe_resource *stencil; + + if (in_place_zs_interleave) + stencil = prsc; + else + stencil = helper->vtbl->get_stencil(prsc); trans->ptr2 = helper->vtbl->transfer_map(pctx, stencil, level, - usage, box, &trans->trans2); + usage | (in_place_zs_interleave ? PIPE_MAP_STENCIL_ONLY : 0), + box, &trans->trans2); if (needs_pack(usage)) { switch (prsc->format) { @@ -315,27 +329,53 @@ u_transfer_helper_transfer_map(struct pipe_context *pctx, width, height); break; case PIPE_FORMAT_Z24_UNORM_S8_UINT: - if (helper->z24_in_z32f) { - util_format_z24_unorm_s8_uint_pack_z_float(trans->staging, - ptrans->stride, - trans->ptr, - trans->trans->stride, - width, height); - util_format_z24_unorm_s8_uint_pack_s_8uint(trans->staging, - ptrans->stride, - trans->ptr2, - trans->trans2->stride, - width, height); + if (in_place_zs_interleave) { + if (helper->z24_in_z32f) { + util_format_z24_unorm_s8_uint_pack_separate_z32(trans->staging, + ptrans->stride, + trans->ptr, + trans->trans->stride, + trans->ptr2, + trans->trans2->stride, + width, height); + } else { + util_format_z24_unorm_s8_uint_pack_separate(trans->staging, + ptrans->stride, + trans->ptr, + trans->trans->stride, + trans->ptr2, + trans->trans2->stride, + width, height); + } } else { - util_format_z24_unorm_s8_uint_pack_separate(trans->staging, - ptrans->stride, - trans->ptr, - trans->trans->stride, - trans->ptr2, - trans->trans2->stride, - width, height); + if (helper->z24_in_z32f) { + util_format_z24_unorm_s8_uint_pack_z_float(trans->staging, + ptrans->stride, + trans->ptr, + trans->trans->stride, + width, height); + util_format_z24_unorm_s8_uint_pack_s_8uint(trans->staging, + ptrans->stride, + trans->ptr2, + trans->trans2->stride, + width, height); + } else { + util_format_z24_unorm_s8_uint_pack_separate(trans->staging, + ptrans->stride, + trans->ptr, + trans->trans->stride, + trans->ptr2, + trans->trans2->stride, + width, height); + } } break; + case PIPE_FORMAT_Z24X8_UNORM: + assert(helper->z24_in_z32f); + util_format_z24x8_unorm_pack_z_float(trans->staging, ptrans->stride, + trans->ptr, trans->trans->stride, + width, height); + break; default: unreachable("Unexpected format"); } @@ -495,21 +535,12 @@ u_transfer_helper_transfer_flush_region(struct pipe_context *pctx, } } -static void -u_transfer_helper_deinterleave_transfer_unmap(struct pipe_context *pctx, - struct pipe_transfer *ptrans); - void u_transfer_helper_transfer_unmap(struct pipe_context *pctx, struct pipe_transfer *ptrans) { struct u_transfer_helper *helper = pctx->screen->transfer_helper; - if (need_interleave_path(helper, ptrans->resource->format)) { - u_transfer_helper_deinterleave_transfer_unmap(pctx, ptrans); - return; - } - if (handle_transfer(ptrans->resource)) { struct u_transfer *trans = u_transfer(ptrans); @@ -563,144 +594,3 @@ u_transfer_helper_destroy(struct u_transfer_helper *helper) { free(helper); } - - -/* these two functions 'deinterleave' are meant to be used without the corresponding - * resource_create/destroy hooks, as they perform the interleaving on-the-fly - * - * drivers should expect to be passed the same buffer repeatedly with the format changed - * to indicate which component is being mapped - */ -static void * -u_transfer_helper_deinterleave_transfer_map(struct pipe_context *pctx, - struct pipe_resource *prsc, - unsigned level, unsigned usage, - const struct pipe_box *box, - struct pipe_transfer **pptrans) -{ - struct u_transfer_helper *helper = pctx->screen->transfer_helper; - struct u_transfer *trans; - struct pipe_transfer *ptrans; - enum pipe_format format = prsc->format; - unsigned width = box->width; - unsigned height = box->height; - - if (!need_interleave_path(helper, format)) - return helper->vtbl->transfer_map(pctx, prsc, level, usage, box, pptrans); - - assert(box->depth == 1); - - trans = calloc(1, sizeof(*trans)); - if (!trans) - return NULL; - - ptrans = &trans->base; - pipe_resource_reference(&ptrans->resource, prsc); - ptrans->level = level; - ptrans->usage = usage; - ptrans->box = *box; - ptrans->stride = util_format_get_stride(format, box->width); - ptrans->layer_stride = ptrans->stride * box->height; - - bool has_stencil = util_format_is_depth_and_stencil(format); - - trans->staging = malloc(ptrans->layer_stride); - if (!trans->staging) - goto fail; - - trans->ptr = helper->vtbl->transfer_map(pctx, prsc, level, usage | PIPE_MAP_DEPTH_ONLY, box, - &trans->trans); - if (!trans->ptr) - goto fail; - - trans->ptr2 = NULL; - if (has_stencil) - trans->ptr2 = helper->vtbl->transfer_map(pctx, prsc, level, - usage | PIPE_MAP_STENCIL_ONLY, box, &trans->trans2); - if (needs_pack(usage)) { - switch (prsc->format) { - case PIPE_FORMAT_Z32_FLOAT_S8X24_UINT: - util_format_z32_float_s8x24_uint_pack_z_float(trans->staging, - ptrans->stride, - trans->ptr, - trans->trans->stride, - width, height); - util_format_z32_float_s8x24_uint_pack_s_8uint(trans->staging, - ptrans->stride, - trans->ptr2, - trans->trans2->stride, - width, height); - break; - case PIPE_FORMAT_Z24_UNORM_S8_UINT: - if (helper->z24_in_z32f) { - util_format_z24_unorm_s8_uint_pack_separate_z32(trans->staging, - ptrans->stride, - trans->ptr, - trans->trans->stride, - trans->ptr2, - trans->trans2->stride, - width, height); - } else { - util_format_z24_unorm_s8_uint_pack_separate(trans->staging, - ptrans->stride, - trans->ptr, - trans->trans->stride, - trans->ptr2, - trans->trans2->stride, - width, height); - } - break; - case PIPE_FORMAT_Z24X8_UNORM: - assert(helper->z24_in_z32f); - util_format_z24x8_unorm_pack_z_float(trans->staging, ptrans->stride, - trans->ptr, trans->trans->stride, - width, height); - break; - default: - unreachable("Unexpected format"); - } - } - - *pptrans = ptrans; - return trans->staging; - -fail: - if (trans->trans) - helper->vtbl->transfer_unmap(pctx, trans->trans); - if (trans->trans2) - helper->vtbl->transfer_unmap(pctx, trans->trans2); - pipe_resource_reference(&ptrans->resource, NULL); - free(trans->staging); - free(trans); - return NULL; -} - -static void -u_transfer_helper_deinterleave_transfer_unmap(struct pipe_context *pctx, - struct pipe_transfer *ptrans) -{ - struct u_transfer_helper *helper = pctx->screen->transfer_helper; - enum pipe_format format = ptrans->resource->format; - - if (!need_interleave_path(helper, format)) { - helper->vtbl->transfer_unmap(pctx, ptrans); - return; - } - - struct u_transfer *trans = (struct u_transfer *)ptrans; - - if (!(ptrans->usage & PIPE_MAP_FLUSH_EXPLICIT)) { - struct pipe_box box; - u_box_2d(0, 0, ptrans->box.width, ptrans->box.height, &box); - flush_region(pctx, ptrans, &box); - } - - helper->vtbl->transfer_unmap(pctx, trans->trans); - if (trans->trans2) - helper->vtbl->transfer_unmap(pctx, trans->trans2); - - pipe_resource_reference(&ptrans->resource, NULL); - - free(trans->staging); - free(trans); -} diff --git a/src/gallium/drivers/llvmpipe/ci/traces-llvmpipe.yml b/src/gallium/drivers/llvmpipe/ci/traces-llvmpipe.yml index 32fe5e4..2ff2689 100644 --- a/src/gallium/drivers/llvmpipe/ci/traces-llvmpipe.yml +++ b/src/gallium/drivers/llvmpipe/ci/traces-llvmpipe.yml @@ -72,7 +72,7 @@ traces: checksum: de5452f4cbc0100d8ecb51459e47cd99 bgfx/29-debugdraw.rdc: gl-vmware-llvmpipe: - checksum: 164e5226af26b6552506542a45bc6bf5 + checksum: 015201fe000d6a323b0f7d3f218d3e47 bgfx/31-rsm.rdc: gl-vmware-llvmpipe: checksum: b59d323511488d5c098ebfa9b434c2dc @@ -126,7 +126,7 @@ traces: checksum: a55dd3d87a86b3b47121ff67861028c3 jvgs/jvgs-d27fb67-v2.trace: gl-vmware-llvmpipe: - checksum: b8c21bf76e667735d1640b215f456531 + checksum: 43b89627364b4cabbab84931aef4ce5e pathfinder/demo-v2.trace: gl-vmware-llvmpipe: checksum: a053c56658bc830249bc94317a3b3ea8 diff --git a/src/gallium/drivers/pvr/meson.build b/src/gallium/drivers/pvr/meson.build new file mode 100644 index 0000000..4f3e200 --- /dev/null +++ b/src/gallium/drivers/pvr/meson.build @@ -0,0 +1,23 @@ +# Copyright (c) Imagination Technologies Ltd. + +# 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 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. + +driver_pvr = declare_dependency( + compile_args : '-DGALLIUM_PVR' +) diff --git a/src/gallium/drivers/pvr_alias/meson.build b/src/gallium/drivers/pvr_alias/meson.build new file mode 100644 index 0000000..128efd7 --- /dev/null +++ b/src/gallium/drivers/pvr_alias/meson.build @@ -0,0 +1,23 @@ +# Copyright (c) Imagination Technologies Ltd. + +# 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 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. + +driver_pvr_alias = declare_dependency( + compile_args: '-DGALLIUM_PVR_ALIAS=@0@'.format(gallium_pvr_alias) +) diff --git a/src/gallium/drivers/zink/VP_ZINK_requirements.json b/src/gallium/drivers/zink/VP_ZINK_requirements.json index f42f4c8..ab41389 100644 --- a/src/gallium/drivers/zink/VP_ZINK_requirements.json +++ b/src/gallium/drivers/zink/VP_ZINK_requirements.json @@ -33,12 +33,6 @@ }, "VkPhysicalDeviceLineRasterizationFeaturesEXT": { "rectangularLines": true, - "bresenhamLines": true - } - }, - "properties": { - "VkPhysicalDeviceProperties": { - } } }, @@ -59,6 +53,22 @@ } } }, + "gl21_baseline_line_bresenham": { + "features": { + "VkPhysicalDeviceLineRasterizationFeaturesEXT": { + "bresenhamLines": true + } + } + }, + "gl21_baseline_line_non_strict": { + "properties": { + "VkPhysicalDeviceProperties": { + "limits": { + "strictLines": false + } + } + } + }, "gl21_optional": { "extensions": { "VK_KHR_external_memory": 1 @@ -105,7 +115,6 @@ }, "features": { "VkPhysicalDeviceFeatures": { - "occlusionQueryPrecise": true, "dualSrcBlend": true } } @@ -190,6 +199,33 @@ } } }, + "gl43_baseline_rb2": { + "extensions": { + "VK_EXT_robustness2": 1 + }, + "features": { + "VkPhysicalDeviceRobustness2FeaturesEXT": { + "robustImageAccess2": true + } + } + }, + "gl43_baseline_rb_image_vk13": { + "features": { + "VkPhysicalDeviceVulkan13Features": { + "robustImageAccess": true + } + } + }, + "gl43_baseline_rb_image_ext": { + "extensions": { + "VK_EXT_image_robustness": 1 + }, + "features": { + "VkPhysicalDeviceImageRobustnessFeaturesEXT": { + "robustImageAccess": true + } + } + }, "gl43_baseline": { "features": { "VkPhysicalDeviceFeatures": { @@ -298,7 +334,6 @@ "features": { "VkPhysicalDeviceFeatures": { "samplerAnisotropy": true, - "pipelineStatisticsQuery": true, "depthBiasClamp": true } } @@ -551,7 +586,8 @@ "capabilities": [ "vulkan10requirements", "gl21_baseline", - [ "gl21_baseline_vk10", "gl21_baseline_vk12" ] + [ "gl21_baseline_vk10", "gl21_baseline_vk12" ], + [ "gl21_baseline_line_bresenham", "gl21_baseline_line_non_strict" ] ] }, "VP_ZINK_gl30_baseline": { @@ -563,6 +599,7 @@ "vulkan10requirements", "gl21_baseline", [ "gl21_baseline_vk10", "gl21_baseline_vk12" ], + [ "gl21_baseline_line_bresenham", "gl21_baseline_line_non_strict" ], "gl30_baseline" ] }, @@ -575,6 +612,7 @@ "vulkan10requirements", "gl21_baseline", [ "gl21_baseline_vk10", "gl21_baseline_vk12" ], + [ "gl21_baseline_line_bresenham", "gl21_baseline_line_non_strict" ], "gl30_baseline", "gl31_baseline" ] @@ -588,6 +626,7 @@ "vulkan10requirements", "gl21_baseline", [ "gl21_baseline_vk10", "gl21_baseline_vk12" ], + [ "gl21_baseline_line_bresenham", "gl21_baseline_line_non_strict" ], "gl30_baseline", "gl31_baseline", "gl32_baseline" @@ -602,6 +641,7 @@ "vulkan10requirements", "gl21_baseline", [ "gl21_baseline_vk10", "gl21_baseline_vk12" ], + [ "gl21_baseline_line_bresenham", "gl21_baseline_line_non_strict" ], "gl30_baseline", "gl31_baseline", "gl32_baseline", @@ -617,6 +657,7 @@ "vulkan10requirements", "gl21_baseline", [ "gl21_baseline_vk10", "gl21_baseline_vk12" ], + [ "gl21_baseline_line_bresenham", "gl21_baseline_line_non_strict" ], "gl30_baseline", "gl31_baseline", "gl32_baseline", @@ -633,6 +674,7 @@ "vulkan10requirements", "gl21_baseline", [ "gl21_baseline_vk10", "gl21_baseline_vk12" ], + [ "gl21_baseline_line_bresenham", "gl21_baseline_line_non_strict" ], "gl30_baseline", "gl31_baseline", "gl32_baseline", @@ -650,6 +692,7 @@ "vulkan10requirements", "gl21_baseline", [ "gl21_baseline_vk10", "gl21_baseline_vk12" ], + [ "gl21_baseline_line_bresenham", "gl21_baseline_line_non_strict" ], "gl30_baseline", "gl31_baseline", "gl32_baseline", @@ -669,6 +712,7 @@ "vulkan10requirements", "gl21_baseline", [ "gl21_baseline_vk10", "gl21_baseline_vk12" ], + [ "gl21_baseline_line_bresenham", "gl21_baseline_line_non_strict" ], "gl30_baseline", "gl31_baseline", "gl32_baseline", @@ -677,7 +721,8 @@ "gl41_baseline", "gl42_baseline", [ "gl42_baseline_vk10", "gl42_baseline_vk12" ], - "gl43_baseline" + "gl43_baseline", + [ "gl43_baseline_rb2", "gl43_baseline_rb_image_vk13", "gl43_baseline_rb_image_ext" ] ] }, "VP_ZINK_gl44_baseline": { @@ -689,6 +734,7 @@ "vulkan10requirements", "gl21_baseline", [ "gl21_baseline_vk10", "gl21_baseline_vk12" ], + [ "gl21_baseline_line_bresenham", "gl21_baseline_line_non_strict" ], "gl30_baseline", "gl31_baseline", "gl32_baseline", @@ -698,6 +744,7 @@ "gl42_baseline", [ "gl42_baseline_vk10", "gl42_baseline_vk12" ], "gl43_baseline", + [ "gl43_baseline_rb2", "gl43_baseline_rb_image_vk13", "gl43_baseline_rb_image_ext" ], "gl44_baseline" ] }, @@ -710,6 +757,7 @@ "vulkan10requirements", "gl21_baseline", [ "gl21_baseline_vk10", "gl21_baseline_vk12" ], + [ "gl21_baseline_line_bresenham", "gl21_baseline_line_non_strict" ], "gl30_baseline", "gl31_baseline", "gl32_baseline", @@ -719,6 +767,7 @@ "gl42_baseline", [ "gl42_baseline_vk10", "gl42_baseline_vk12" ], "gl43_baseline", + [ "gl43_baseline_rb2", "gl43_baseline_rb_image_vk13", "gl43_baseline_rb_image_ext" ], "gl44_baseline", "gl45_baseline" ] @@ -732,6 +781,7 @@ "vulkan10requirements", "gl21_baseline", [ "gl21_baseline_vk10", "gl21_baseline_vk12" ], + [ "gl21_baseline_line_bresenham", "gl21_baseline_line_non_strict" ], "gl30_baseline", "gl31_baseline", "gl32_baseline", @@ -741,6 +791,7 @@ "gl42_baseline", [ "gl42_baseline_vk10", "gl42_baseline_vk12" ], "gl43_baseline", + [ "gl43_baseline_rb2", "gl43_baseline_rb_image_vk13", "gl43_baseline_rb_image_ext" ], "gl44_baseline", "gl45_baseline", "gl46_baseline" @@ -755,6 +806,7 @@ "vulkan10requirements", "gl21_baseline", [ "gl21_baseline_vk10", "gl21_baseline_vk12" ], + [ "gl21_baseline_line_bresenham", "gl21_baseline_line_non_strict" ], "gl30_baseline", "gl31_baseline", "gl32_baseline", @@ -764,6 +816,7 @@ "gl42_baseline", [ "gl42_baseline_vk10", "gl42_baseline_vk12" ], "gl43_baseline", + [ "gl43_baseline_rb2", "gl43_baseline_rb_image_vk13", "gl43_baseline_rb_image_ext" ], "gl44_baseline", "gl45_baseline", "gl46_baseline", diff --git a/src/gallium/drivers/zink/ci/zink-anv-tgl-fails.txt b/src/gallium/drivers/zink/ci/zink-anv-tgl-fails.txt index e69de29..36ff7cb 100644 --- a/src/gallium/drivers/zink/ci/zink-anv-tgl-fails.txt +++ b/src/gallium/drivers/zink/ci/zink-anv-tgl-fails.txt @@ -0,0 +1,813 @@ +dEQP-GLES31.functional.layout_binding.ubo.fragment_binding_array,Fail +dEQP-GLES31.functional.layout_binding.ubo.fragment_binding_max_array,Fail +dEQP-GLES31.functional.layout_binding.ubo.fragment_binding_multiple,Fail +dEQP-GLES31.functional.layout_binding.ubo.vertex_binding_array,Fail +dEQP-GLES31.functional.layout_binding.ubo.vertex_binding_max_array,Fail +dEQP-GLES31.functional.layout_binding.ubo.vertex_binding_multiple,Fail + +# CTS bug: https://gitlab.khronos.org/Tracker/vk-gl-cts/-/issues/4200 +KHR-GLES31.core.compute_shader.max,Fail + +# "Invalid result. Region (0x0). Expected: 0 got 1" +KHR-GLES31.core.viewport_array.dynamic_viewport_index,Fail + +# "Fail, buffer content is not well preserved when age > 0 (Fail)" +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_clear_clear_even_clear_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_clear_clear_even_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_clear_clear_even_none,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_clear_clear_even_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_clear_even_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_clear_even_none,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_clear_render_even_clear_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_clear_render_even_clear_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_clear_render_even_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_clear_render_even_none,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_clear_render_even_render_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_clear_render_even_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_render_clear_even_clear_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_render_clear_even_clear_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_render_clear_even_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_render_clear_even_none,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_render_clear_even_render_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_render_clear_even_render_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_render_clear_even_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_render_even_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_render_even_none,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_render_even_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_render_render_even_clear_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_render_render_even_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_render_render_even_none,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_render_render_even_render_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.no_resize.odd_render_render_even_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_clear_clear_even_clear_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_clear_clear_even_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_clear_clear_even_none,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_clear_clear_even_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_clear_even_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_clear_even_none,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_clear_render_even_clear_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_clear_render_even_clear_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_clear_render_even_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_clear_render_even_none,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_clear_render_even_render_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_clear_render_even_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_render_clear_even_clear_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_render_clear_even_clear_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_render_clear_even_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_render_clear_even_none,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_render_clear_even_render_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_render_clear_even_render_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_render_clear_even_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_render_even_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_render_even_none,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_render_even_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_render_render_even_clear_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_render_render_even_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_render_render_even_none,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_render_render_even_render_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_after_swap.odd_render_render_even_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_clear_clear_even_clear_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_clear_clear_even_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_clear_clear_even_none,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_clear_clear_even_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_clear_even_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_clear_even_none,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_clear_render_even_clear_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_clear_render_even_clear_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_clear_render_even_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_clear_render_even_none,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_clear_render_even_render_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_clear_render_even_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_render_clear_even_clear_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_render_clear_even_clear_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_render_clear_even_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_render_clear_even_none,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_render_clear_even_render_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_render_clear_even_render_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_render_clear_even_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_render_even_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_render_even_none,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_render_even_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_render_render_even_clear_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_render_render_even_clear,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_render_render_even_none,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_render_render_even_render_render,Fail +dEQP-EGL.functional.buffer_age.no_preserve.resize_before_swap.odd_render_render_even_render,Fail + +dEQP-EGL.functional.query_context.get_current_context.rgba8888_window,Crash + +# Around the time of running these tests there are some warnings from the kernel in dma_resv.c, and at least +# some failures look like not waiting for rendering to complete. +wayland-dEQP-EGL.functional.color_clears.multi_context.gles1_gles2_gles3.rgb565_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_context.gles1_gles2_gles3.rgb888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_context.gles1_gles2_gles3.rgba8888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_context.gles1_gles2.rgb565_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_context.gles1_gles2.rgb888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_context.gles1_gles2.rgba8888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_context.gles1.rgb565_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_context.gles1.rgb888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_context.gles1.rgba8888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_context.gles2.rgb565_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_context.gles2.rgb888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_context.gles2.rgba8888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_context.gles3.rgb565_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_context.gles3.rgb888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_context.gles3.rgba8888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_thread.gles1_gles2_gles3.rgb565_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_thread.gles1_gles2_gles3.rgb888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_thread.gles1_gles2_gles3.rgba8888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_thread.gles1_gles2.rgb565_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_thread.gles1_gles2.rgb888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_thread.gles1_gles2.rgba8888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_thread.gles1.rgb565_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_thread.gles1.rgb888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_thread.gles1.rgba8888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_thread.gles2.rgb565_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_thread.gles2.rgb888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_thread.gles2.rgba8888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_thread.gles3.rgb565_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_thread.gles3.rgb888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.multi_thread.gles3.rgba8888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.single_context.gles1.rgb565_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.single_context.gles1.rgb888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.single_context.gles1.rgba8888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.single_context.gles2.rgb565_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.single_context.gles2.rgb888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.single_context.gles2.rgba8888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.single_context.gles3.rgb565_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.single_context.gles3.rgb888_pbuffer,Fail +wayland-dEQP-EGL.functional.color_clears.single_context.gles3.rgba8888_pbuffer,Fail +wayland-dEQP-EGL.functional.negative_api.create_pixmap_surface,Fail +wayland-dEQP-EGL.functional.render.multi_context.gles2_gles3.rgb565_pbuffer,Fail +wayland-dEQP-EGL.functional.render.multi_context.gles2_gles3.rgb888_pbuffer,Fail +wayland-dEQP-EGL.functional.render.multi_context.gles2_gles3.rgba8888_pbuffer,Fail +wayland-dEQP-EGL.functional.render.multi_context.gles2.rgb565_pbuffer,Fail +wayland-dEQP-EGL.functional.render.multi_context.gles2.rgb888_pbuffer,Fail +wayland-dEQP-EGL.functional.render.multi_context.gles2.rgba8888_pbuffer,Fail +wayland-dEQP-EGL.functional.render.multi_context.gles3.rgb565_pbuffer,Fail +wayland-dEQP-EGL.functional.render.multi_context.gles3.rgb888_pbuffer,Fail +wayland-dEQP-EGL.functional.render.multi_context.gles3.rgba8888_pbuffer,Fail +wayland-dEQP-EGL.functional.render.multi_thread.gles2_gles3.rgb565_pbuffer,Fail +wayland-dEQP-EGL.functional.render.multi_thread.gles2_gles3.rgb888_pbuffer,Fail +wayland-dEQP-EGL.functional.render.multi_thread.gles2_gles3.rgba8888_pbuffer,Fail +wayland-dEQP-EGL.functional.render.multi_thread.gles2.rgb565_pbuffer,Fail +wayland-dEQP-EGL.functional.render.multi_thread.gles2.rgb888_pbuffer,Fail +wayland-dEQP-EGL.functional.render.multi_thread.gles2.rgba8888_pbuffer,Fail +wayland-dEQP-EGL.functional.render.multi_thread.gles3.rgb565_pbuffer,Fail +wayland-dEQP-EGL.functional.render.multi_thread.gles3.rgb888_pbuffer,Fail +wayland-dEQP-EGL.functional.render.multi_thread.gles3.rgba8888_pbuffer,Fail +wayland-dEQP-EGL.functional.render.single_context.gles2.rgb565_pbuffer,Fail +wayland-dEQP-EGL.functional.render.single_context.gles2.rgb888_pbuffer,Fail +wayland-dEQP-EGL.functional.render.single_context.gles2.rgba8888_pbuffer,Fail +wayland-dEQP-EGL.functional.render.single_context.gles3.rgb565_pbuffer,Fail +wayland-dEQP-EGL.functional.render.single_context.gles3.rgb888_pbuffer,Fail +wayland-dEQP-EGL.functional.render.single_context.gles3.rgba8888_pbuffer,Fail + +565-nozs-dEQP-GLES3.functional.color_clear.complex_rgb,Fail + +spec@egl_chromium_sync_control@conformance@eglGetSyncValuesCHROMIUM_ust_test,Fail +spec@egl_chromium_sync_control@conformance@eglGetSyncValuesCHROMIUM_msc_and_sbc_test,Fail +spec@egl_chromium_sync_control@conformance,Fail + +# "GLX_MESA_copy_sub_buffer found in both client and server extension strings, but missing from unified string." +glx@extension string sanity,Fail + +glx@glx_arb_create_context_es2_profile@invalid opengl es version,Fail +glx@glx_arb_create_context_no_error@no error,Fail +glx@glx_arb_create_context_robustness@invalid reset notification strategy,Fail + +# "Could not create initial indirect-rendering context." +glx@glx_ext_import_context@free context,Fail +glx@glx_ext_import_context@get context id,Fail + +glx@glx_ext_import_context@get current display,Fail +glx@glx_ext_import_context@import context- multi process,Fail +glx@glx_ext_import_context@import context- single process,Fail +glx@glx_ext_import_context@imported context has same context id,Fail +glx@glx_ext_import_context@make current- multi process,Fail +glx@glx_ext_import_context@make current- single process,Fail +glx@glx_ext_import_context@query context info,Fail + +# See also the EGL buffer age failures +glx@glx-buffer-age,Fail +glx@glx-buffer-age vblank_mode=0,Fail + +glx@glx-make-current,Crash +glx@glx-multi-window-single-context,Crash +glx@glx-swap-copy,Fail +glx@glx-swap-pixmap-bad,Fail +glx@glx-tfp,Crash + +# errors like: +# X Error of failed request: BadWindow (invalid Window parameter) +# ../src/gallium/drivers/zink/zink_resource.c:1215: resource_create: Assertion `res->obj->dt' failed. +glx@glx-visuals-depth,Crash + +# ../src/gallium/drivers/zink/zink_kopper.c:859: zink_kopper_update: Assertion `pres->bind & PIPE_BIND_DISPLAY_TARGET' failed. +glx@glx-visuals-depth -pixmap,Crash + +glx@glx-visuals-stencil -pixmap,Crash +glx@glx-visuals-stencil,Crash + +shaders@glsl-fs-pointcoord,Fail + +shaders@point-vertex-id divisor,Fail +shaders@point-vertex-id gl_instanceid divisor,Fail +shaders@point-vertex-id gl_instanceid,Fail +shaders@point-vertex-id gl_vertexid divisor,Fail +shaders@point-vertex-id gl_vertexid gl_instanceid divisor,Fail +shaders@point-vertex-id gl_vertexid gl_instanceid,Fail +shaders@point-vertex-id gl_vertexid,Fail + +spec@!opengl 1.0@gl-1.0-edgeflag-quads,Fail +spec@!opengl 1.0@gl-1.0-edgeflag,Fail + +spec@!opengl 1.0@gl-1.0-no-op-paths,Fail + +spec@!opengl 1.0@gl-1.0-spot-light,Fail + +spec@!opengl 1.0@gl-1.0-swapbuffers-behavior,Fail + +spec@!opengl 1.1@depthstencil-default_fb-blit samples=16,Fail +spec@!opengl 1.1@depthstencil-default_fb-blit samples=2,Fail +spec@!opengl 1.1@depthstencil-default_fb-blit samples=6,Fail +spec@!opengl 1.1@depthstencil-default_fb-blit samples=8,Fail + +spec@!opengl 1.1@line-aa-width,Fail +spec@!opengl 1.1@line-flat-clip-color,Fail + +spec@!opengl 1.1@polygon-mode-facing,Fail +spec@!opengl 1.1@polygon-mode-offset,Fail +spec@!opengl 1.1@polygon-mode-offset@config 0: Expected blue pixel in center,Fail +spec@!opengl 1.1@polygon-mode-offset@config 1: Expected blue pixel in center,Fail +spec@!opengl 1.1@polygon-mode-offset@config 2: Expected blue pixel in center,Fail +spec@!opengl 1.1@polygon-mode-offset@config 2: Expected white pixel on right edge,Fail +spec@!opengl 1.1@polygon-mode-offset@config 2: Expected white pixel on top edge,Fail +spec@!opengl 1.1@polygon-mode-offset@config 5: Expected blue pixel in center,Fail +spec@!opengl 1.1@polygon-mode-offset@config 6: Expected blue pixel in center,Fail +spec@!opengl 1.1@polygon-mode-offset@config 6: Expected white pixel on right edge,Fail +spec@!opengl 1.1@polygon-mode-offset@config 6: Expected white pixel on top edge,Fail + +# Frontend issue across multiple drivers. +spec@!opengl 1.0@rasterpos,Fail +spec@!opengl 1.0@rasterpos@glsl_vs_gs_linked,Fail +spec@!opengl 1.0@rasterpos@glsl_vs_tes_linked,Fail + +spec@!opengl 1.1@linestipple@Line strip,Fail +spec@!opengl 1.1@linestipple@Line loop,Fail +spec@!opengl 1.1@linestipple@Factor 2x,Fail +spec@!opengl 1.1@linestipple@Factor 3x,Fail +spec@!opengl 1.1@linestipple,Fail + +# polygon-mode: glPolygonMode(front=GL_LINE, back=GL_FILL), glCullMode(GL_NONE/GL_FALSE/GL_NO_ERROR) failed +# At position 0, found prim GL_FILL instead of GL_LINE +# polygon-mode: glPolygonMode(front=GL_POINT, back=GL_FILL), glCullMode(GL_NONE/GL_FALSE/GL_NO_ERROR) failed +# At position 1, found prim GL_POINT instead of GL_FILL +# (and more) +spec@!opengl 1.1@polygon-mode,Fail + +spec@!opengl 2.0@gl-2.0-edgeflag-immediate,Fail +spec@!opengl 2.0@gl-2.0-edgeflag,Fail + +spec@!opengl 2.0@vs-point_size-zero,Fail + +spec@!opengl 2.1@pbo,Fail +spec@!opengl 2.1@pbo@test_polygon_stip,Fail + +spec@!opengl 2.1@polygon-stipple-fs,Fail + +spec@!opengl 3.0@clearbuffer-depth-cs-probe,Fail + +spec@!opengl 3.2@gl-3.2-adj-prims cull-back pv-first,Fail +spec@!opengl 3.2@gl-3.2-adj-prims cull-front pv-first,Fail +spec@!opengl 3.2@gl-3.2-adj-prims line cull-back pv-first,Fail +spec@!opengl 3.2@gl-3.2-adj-prims line cull-front pv-first,Fail +spec@!opengl 3.2@gl-3.2-adj-prims pv-first,Fail + +spec@!opengl es 2.0@glsl-fs-pointcoord,Fail + +spec@arb_arrays_of_arrays@execution@image_store@basic-imagestore-mixed-const-non-const-uniform-index,Fail +spec@arb_arrays_of_arrays@execution@image_store@basic-imagestore-mixed-const-non-const-uniform-index2,Fail +spec@arb_arrays_of_arrays@execution@image_store@basic-imagestore-non-const-uniform-index,Fail + +spec@arb_framebuffer_object@fbo-blit-scaled-linear,Fail + +spec@arb_framebuffer_object@fbo-gl_pointcoord,Fail + +spec@arb_gl_spirv@execution@xfb@vs_block_array,Fail + +spec@arb_gpu_shader_fp64@execution@arb_gpu_shader_fp64-tf-separate,Fail +spec@arb_gpu_shader_fp64@execution@glsl-fs-loop-unroll-mul-fp64,Fail +spec@arb_gpu_shader_fp64@uniform_buffers@fs-ubo-load.indirect.3,Fail + +spec@arb_point_sprite@arb_point_sprite-checkerboard,Fail +spec@arb_point_sprite@arb_point_sprite-mipmap,Fail + +spec@arb_program_interface_query@arb_program_interface_query-getprogramresourceindex,Fail +spec@arb_program_interface_query@arb_program_interface_query-getprogramresourceindex@'vs_input2[1][0]' on GL_PROGRAM_INPUT,Fail + +spec@arb_sample_locations@test,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 0- Y: 0- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 0- Y: 0- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 0- Y: 1- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 0- Y: 1- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 0- Y: 2- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 0- Y: 2- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 0- Y: 3- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 0- Y: 3- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 0- Y: 4- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 0- Y: 4- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 0- Y: 5- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 0- Y: 5- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 0- Y: 6- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 0- Y: 6- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 1- Y: 0- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 1- Y: 0- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 1- Y: 1- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 1- Y: 1- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 1- Y: 2- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 1- Y: 2- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 1- Y: 3- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 1- Y: 3- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 1- Y: 4- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 1- Y: 4- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 1- Y: 5- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 1- Y: 5- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 1- Y: 6- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 1- Y: 6- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 2- Y: 0- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 2- Y: 0- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 2- Y: 1- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 2- Y: 1- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 2- Y: 2- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 2- Y: 2- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 2- Y: 3- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 2- Y: 3- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 2- Y: 4- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 2- Y: 4- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 2- Y: 5- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 2- Y: 5- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 2- Y: 6- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 2- Y: 6- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 3- Y: 0- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 3- Y: 0- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 3- Y: 1- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 3- Y: 1- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 3- Y: 2- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 3- Y: 2- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 3- Y: 3- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 3- Y: 3- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 3- Y: 4- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 3- Y: 4- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 3- Y: 5- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 3- Y: 5- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 3- Y: 6- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 1- X: 3- Y: 6- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 0- Y: 0- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 0- Y: 0- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 0- Y: 1- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 0- Y: 1- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 0- Y: 2- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 0- Y: 2- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 0- Y: 3- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 0- Y: 3- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 0- Y: 4- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 0- Y: 4- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 0- Y: 5- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 0- Y: 5- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 0- Y: 6- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 0- Y: 6- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 1- Y: 0- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 1- Y: 0- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 1- Y: 1- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 1- Y: 1- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 1- Y: 2- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 1- Y: 2- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 1- Y: 3- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 1- Y: 3- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 1- Y: 4- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 1- Y: 4- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 1- Y: 5- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 1- Y: 5- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 1- Y: 6- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 1- Y: 6- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 2- Y: 0- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 2- Y: 0- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 2- Y: 1- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 2- Y: 1- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 2- Y: 2- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 2- Y: 2- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 2- Y: 3- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 2- Y: 3- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 2- Y: 4- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 2- Y: 4- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 2- Y: 5- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 2- Y: 5- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 2- Y: 6- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 2- Y: 6- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 3- Y: 0- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 3- Y: 0- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 3- Y: 1- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 3- Y: 1- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 3- Y: 2- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 3- Y: 2- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 3- Y: 3- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 3- Y: 3- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 3- Y: 4- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 3- Y: 4- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 3- Y: 5- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 3- Y: 5- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 3- Y: 6- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 16- X: 3- Y: 6- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 0- Y: 0- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 0- Y: 0- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 0- Y: 1- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 0- Y: 1- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 0- Y: 2- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 0- Y: 2- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 0- Y: 3- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 0- Y: 3- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 0- Y: 4- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 0- Y: 4- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 0- Y: 5- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 0- Y: 5- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 0- Y: 6- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 0- Y: 6- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 1- Y: 0- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 1- Y: 0- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 1- Y: 1- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 1- Y: 1- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 1- Y: 2- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 1- Y: 2- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 1- Y: 3- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 1- Y: 3- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 1- Y: 4- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 1- Y: 4- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 1- Y: 5- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 1- Y: 5- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 1- Y: 6- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 1- Y: 6- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 2- Y: 0- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 2- Y: 0- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 2- Y: 1- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 2- Y: 1- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 2- Y: 2- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 2- Y: 2- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 2- Y: 3- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 2- Y: 3- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 2- Y: 4- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 2- Y: 4- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 2- Y: 5- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 2- Y: 5- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 2- Y: 6- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 2- Y: 6- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 3- Y: 0- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 3- Y: 0- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 3- Y: 1- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 3- Y: 1- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 3- Y: 2- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 3- Y: 2- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 3- Y: 3- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 3- Y: 3- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 3- Y: 4- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 3- Y: 4- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 3- Y: 5- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 3- Y: 5- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 3- Y: 6- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 2- X: 3- Y: 6- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 0- Y: 0- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 0- Y: 0- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 0- Y: 1- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 0- Y: 1- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 0- Y: 2- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 0- Y: 2- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 0- Y: 3- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 0- Y: 3- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 0- Y: 4- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 0- Y: 4- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 0- Y: 5- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 0- Y: 5- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 0- Y: 6- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 0- Y: 6- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 1- Y: 0- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 1- Y: 0- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 1- Y: 1- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 1- Y: 1- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 1- Y: 2- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 1- Y: 2- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 1- Y: 3- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 1- Y: 3- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 1- Y: 4- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 1- Y: 4- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 1- Y: 5- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 1- Y: 5- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 1- Y: 6- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 1- Y: 6- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 2- Y: 0- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 2- Y: 0- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 2- Y: 1- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 2- Y: 1- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 2- Y: 2- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 2- Y: 2- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 2- Y: 3- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 2- Y: 3- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 2- Y: 4- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 2- Y: 4- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 2- Y: 5- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 2- Y: 5- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 2- Y: 6- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 2- Y: 6- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 3- Y: 0- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 3- Y: 0- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 3- Y: 1- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 3- Y: 1- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 3- Y: 2- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 3- Y: 2- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 3- Y: 3- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 3- Y: 3- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 3- Y: 4- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 3- Y: 4- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 3- Y: 5- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 3- Y: 5- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 3- Y: 6- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 4- X: 3- Y: 6- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 0- Y: 0- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 0- Y: 0- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 0- Y: 1- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 0- Y: 1- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 0- Y: 2- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 0- Y: 2- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 0- Y: 3- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 0- Y: 3- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 0- Y: 4- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 0- Y: 4- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 0- Y: 5- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 0- Y: 5- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 0- Y: 6- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 0- Y: 6- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 1- Y: 0- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 1- Y: 0- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 1- Y: 1- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 1- Y: 1- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 1- Y: 2- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 1- Y: 2- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 1- Y: 3- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 1- Y: 3- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 1- Y: 4- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 1- Y: 4- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 1- Y: 5- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 1- Y: 5- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 1- Y: 6- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 1- Y: 6- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 2- Y: 0- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 2- Y: 0- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 2- Y: 1- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 2- Y: 1- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 2- Y: 2- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 2- Y: 2- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 2- Y: 3- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 2- Y: 3- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 2- Y: 4- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 2- Y: 4- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 2- Y: 5- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 2- Y: 5- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 2- Y: 6- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 2- Y: 6- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 3- Y: 0- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 3- Y: 0- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 3- Y: 1- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 3- Y: 1- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 3- Y: 2- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 3- Y: 2- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 3- Y: 3- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 3- Y: 3- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 3- Y: 4- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 3- Y: 4- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 3- Y: 5- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 3- Y: 5- Grid: true,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 3- Y: 6- Grid: false,Fail +spec@arb_sample_locations@test@MSAA: 8- X: 3- Y: 6- Grid: true,Fail +spec@arb_sample_shading@samplemask 16 all,Fail +spec@arb_sample_shading@samplemask 16 all@0.062500 mask_in_one,Fail +spec@arb_sample_shading@samplemask 16 all@0.125000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 16 all@0.250000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 16 all@0.500000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 16 all@1.000000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 16 all@noms mask_in_one,Fail +spec@arb_sample_shading@samplemask 16 all@noms partition,Fail +spec@arb_sample_shading@samplemask 16 all@sample mask_in_one,Fail +spec@arb_sample_shading@samplemask 16,Fail +spec@arb_sample_shading@samplemask 16@0.062500 mask_in_one,Fail +spec@arb_sample_shading@samplemask 16@0.125000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 16@0.250000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 16@0.500000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 16@1.000000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 16@noms mask_in_one,Fail +spec@arb_sample_shading@samplemask 16@noms partition,Fail +spec@arb_sample_shading@samplemask 16@sample mask_in_one,Fail +spec@arb_sample_shading@samplemask 2 all,Fail +spec@arb_sample_shading@samplemask 2 all@0.500000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 2 all@1.000000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 2 all@noms mask_in_one,Fail +spec@arb_sample_shading@samplemask 2 all@noms partition,Fail +spec@arb_sample_shading@samplemask 2 all@sample mask_in_one,Fail +spec@arb_sample_shading@samplemask 2,Fail +spec@arb_sample_shading@samplemask 2@0.500000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 2@1.000000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 2@noms mask_in_one,Fail +spec@arb_sample_shading@samplemask 2@noms partition,Fail +spec@arb_sample_shading@samplemask 2@sample mask_in_one,Fail +spec@arb_sample_shading@samplemask 4 all,Fail +spec@arb_sample_shading@samplemask 4 all@0.250000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 4 all@0.500000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 4 all@1.000000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 4 all@noms mask_in_one,Fail +spec@arb_sample_shading@samplemask 4 all@noms partition,Fail +spec@arb_sample_shading@samplemask 4 all@sample mask_in_one,Fail +spec@arb_sample_shading@samplemask 4,Fail +spec@arb_sample_shading@samplemask 4@0.250000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 4@0.500000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 4@1.000000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 4@noms mask_in_one,Fail +spec@arb_sample_shading@samplemask 4@noms partition,Fail +spec@arb_sample_shading@samplemask 4@sample mask_in_one,Fail +spec@arb_sample_shading@samplemask 6 all,Fail +spec@arb_sample_shading@samplemask 6 all@0.125000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 6 all@0.250000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 6 all@0.500000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 6 all@1.000000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 6 all@noms mask_in_one,Fail +spec@arb_sample_shading@samplemask 6 all@noms partition,Fail +spec@arb_sample_shading@samplemask 6 all@sample mask_in_one,Fail +spec@arb_sample_shading@samplemask 6,Fail +spec@arb_sample_shading@samplemask 6@0.125000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 6@0.250000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 6@0.500000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 6@1.000000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 6@noms mask_in_one,Fail +spec@arb_sample_shading@samplemask 6@noms partition,Fail +spec@arb_sample_shading@samplemask 6@sample mask_in_one,Fail +spec@arb_sample_shading@samplemask 8 all,Fail +spec@arb_sample_shading@samplemask 8 all@0.125000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 8 all@0.250000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 8 all@0.500000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 8 all@1.000000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 8 all@noms mask_in_one,Fail +spec@arb_sample_shading@samplemask 8 all@noms partition,Fail +spec@arb_sample_shading@samplemask 8 all@sample mask_in_one,Fail +spec@arb_sample_shading@samplemask 8,Fail +spec@arb_sample_shading@samplemask 8@0.125000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 8@0.250000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 8@0.500000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 8@1.000000 mask_in_one,Fail +spec@arb_sample_shading@samplemask 8@noms mask_in_one,Fail +spec@arb_sample_shading@samplemask 8@noms partition,Fail +spec@arb_sample_shading@samplemask 8@sample mask_in_one,Fail + +spec@arb_shader_image_load_store@early-z,Fail +spec@arb_shader_image_load_store@early-z@occlusion query test/early-z pass,Fail +spec@arb_shader_image_load_store@host-mem-barrier,Fail +spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/one bit barrier test/16x16,Fail +spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/one bit barrier test/4x4,Fail +spec@arb_shader_image_load_store@host-mem-barrier@Transform feedback/WaW/one bit barrier test/64x64,Fail + +spec@arb_tessellation_shader@execution@variable-indexing@tcs-patch-vec4-swiz-index-wr,Fail + +# "../src/gallium/drivers/zink/zink_compiler.c:2071: assign_producer_var_io: Assertion `*reserved < MAX_VARYING' failed." +spec@arb_tessellation_shader@execution@variable-indexing@tes-both-input-array-float-index-rd,Crash +spec@arb_tessellation_shader@execution@variable-indexing@tes-both-input-array-vec2-index-rd,Crash +spec@arb_tessellation_shader@execution@variable-indexing@tes-both-input-array-vec3-index-rd,Crash +spec@arb_tessellation_shader@execution@variable-indexing@tes-both-input-array-vec4-index-rd,Crash + +# "arb_texture_buffer_object-formats: ../src/gallium/drivers/zink/zink_context.c:807: create_bvci: Assertion `bvci.format' failed." +spec@arb_texture_buffer_object@formats (vs- arb),Crash + +spec@arb_texture_buffer_object@formats (fs- arb),Crash +spec@arb_texture_buffer_object@formats (fs- arb)@GL_ALPHA16,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_ALPHA16F_ARB,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_ALPHA16I_EXT,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_ALPHA16UI_EXT,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_ALPHA32F_ARB,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_ALPHA32I_EXT,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_ALPHA32UI_EXT,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_ALPHA8,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_ALPHA8I_EXT,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_ALPHA8UI_EXT,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_LUMINANCE_ALPHA16F_ARB,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_LUMINANCE_ALPHA16I_EXT,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_LUMINANCE_ALPHA16UI_EXT,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_LUMINANCE_ALPHA32F_ARB,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_LUMINANCE_ALPHA32I_EXT,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_LUMINANCE_ALPHA32UI_EXT,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_LUMINANCE_ALPHA8I_EXT,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_LUMINANCE_ALPHA8UI_EXT,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_LUMINANCE16_ALPHA16,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_LUMINANCE16,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_LUMINANCE16F_ARB,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_LUMINANCE16I_EXT,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_LUMINANCE16UI_EXT,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_LUMINANCE32F_ARB,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_LUMINANCE32I_EXT,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_LUMINANCE32UI_EXT,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_LUMINANCE8_ALPHA8,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_LUMINANCE8,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_LUMINANCE8I_EXT,Fail +spec@arb_texture_buffer_object@formats (fs- arb)@GL_LUMINANCE8UI_EXT,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_ALPHA16,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_ALPHA16F_ARB,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_ALPHA16I_EXT,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_ALPHA16UI_EXT,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_ALPHA32F_ARB,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_ALPHA32I_EXT,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_ALPHA32UI_EXT,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_ALPHA8,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_ALPHA8I_EXT,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_ALPHA8UI_EXT,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_LUMINANCE_ALPHA16F_ARB,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_LUMINANCE_ALPHA16I_EXT,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_LUMINANCE_ALPHA16UI_EXT,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_LUMINANCE_ALPHA32F_ARB,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_LUMINANCE_ALPHA32I_EXT,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_LUMINANCE_ALPHA32UI_EXT,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_LUMINANCE_ALPHA8I_EXT,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_LUMINANCE_ALPHA8UI_EXT,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_LUMINANCE16_ALPHA16,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_LUMINANCE16,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_LUMINANCE16F_ARB,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_LUMINANCE16I_EXT,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_LUMINANCE16UI_EXT,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_LUMINANCE32F_ARB,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_LUMINANCE32I_EXT,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_LUMINANCE32UI_EXT,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_LUMINANCE8_ALPHA8,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_LUMINANCE8,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_LUMINANCE8I_EXT,Fail +spec@arb_texture_buffer_object@formats (vs- arb)@GL_LUMINANCE8UI_EXT,Fail + +spec@arb_texture_cube_map@copyteximage cube samples=16,Fail +spec@arb_texture_cube_map@copyteximage cube samples=2,Fail +spec@arb_texture_cube_map@copyteximage cube samples=4,Fail +spec@arb_texture_cube_map@copyteximage cube samples=6,Fail +spec@arb_texture_cube_map@copyteximage cube samples=8,Fail + +spec@egl 1.4@eglterminate then unbind context,Fail + +spec@egl_khr_gl_image@egl_khr_gl_renderbuffer_image-clear-shared-image gl_depth_component24,Fail + +spec@egl_khr_surfaceless_context@viewport,Fail + +spec@egl_mesa_configless_context@basic,Fail + +# Fails across most drivers, but it's a silly test. +spec@ext_framebuffer_blit@fbo-blit-check-limits,Fail + +spec@ext_framebuffer_multisample@blit-mismatched-formats,Fail +spec@ext_framebuffer_multisample@clip-and-scissor-blit 16 msaa,Fail +spec@ext_framebuffer_multisample@enable-flag,Fail +spec@ext_framebuffer_multisample@interpolation 16 centroid-deriv-disabled,Fail +spec@ext_framebuffer_multisample@interpolation 16 centroid-disabled,Fail +spec@ext_framebuffer_multisample@interpolation 16 non-centroid-deriv-disabled,Fail +spec@ext_framebuffer_multisample@interpolation 16 non-centroid-disabled,Fail +spec@ext_framebuffer_multisample@interpolation 2 centroid-deriv-disabled,Fail +spec@ext_framebuffer_multisample@interpolation 2 centroid-disabled,Fail +spec@ext_framebuffer_multisample@interpolation 2 non-centroid-deriv-disabled,Fail +spec@ext_framebuffer_multisample@interpolation 2 non-centroid-disabled,Fail +spec@ext_framebuffer_multisample@interpolation 4 centroid-deriv-disabled,Fail +spec@ext_framebuffer_multisample@interpolation 4 centroid-disabled,Fail +spec@ext_framebuffer_multisample@interpolation 4 non-centroid-deriv-disabled,Fail +spec@ext_framebuffer_multisample@interpolation 4 non-centroid-disabled,Fail +spec@ext_framebuffer_multisample@interpolation 6 centroid-deriv-disabled,Fail +spec@ext_framebuffer_multisample@interpolation 6 centroid-disabled,Fail +spec@ext_framebuffer_multisample@interpolation 6 non-centroid-deriv-disabled,Fail +spec@ext_framebuffer_multisample@interpolation 6 non-centroid-disabled,Fail +spec@ext_framebuffer_multisample@interpolation 8 centroid-deriv-disabled,Fail +spec@ext_framebuffer_multisample@interpolation 8 centroid-disabled,Fail +spec@ext_framebuffer_multisample@interpolation 8 non-centroid-deriv-disabled,Fail +spec@ext_framebuffer_multisample@interpolation 8 non-centroid-disabled,Fail + +spec@ext_packed_float@query-rgba-signed-components,Fail + +spec@ext_texture_array@copyteximage 1d_array samples=16,Fail +spec@ext_texture_array@copyteximage 1d_array samples=2,Fail +spec@ext_texture_array@copyteximage 1d_array samples=4,Fail +spec@ext_texture_array@copyteximage 1d_array samples=6,Fail +spec@ext_texture_array@copyteximage 1d_array samples=8,Fail +spec@ext_texture_array@copyteximage 2d_array samples=16,Fail +spec@ext_texture_array@copyteximage 2d_array samples=2,Fail +spec@ext_texture_array@copyteximage 2d_array samples=4,Fail +spec@ext_texture_array@copyteximage 2d_array samples=6,Fail +spec@ext_texture_array@copyteximage 2d_array samples=8,Fail + +spec@ext_transform_feedback@tessellation triangle_fan flat_first,Fail + +spec@glsl-1.50@execution@primitive-id-no-gs-quad-strip,Fail +spec@glsl-1.50@execution@primitive-id-no-gs-quads,Fail + +spec@khr_texture_compression_astc@miptree-gl srgb-fp,Fail +spec@khr_texture_compression_astc@miptree-gl srgb-fp@sRGB decode full precision,Fail +spec@khr_texture_compression_astc@miptree-gles srgb-fp,Fail +spec@khr_texture_compression_astc@miptree-gles srgb-fp@sRGB decode full precision,Fail +spec@khr_texture_compression_astc@sliced-3d-miptree-gl srgb-fp,Fail +spec@khr_texture_compression_astc@sliced-3d-miptree-gl srgb-fp@sRGB decode full precision,Fail +spec@khr_texture_compression_astc@sliced-3d-miptree-gles srgb-fp,Fail +spec@khr_texture_compression_astc@sliced-3d-miptree-gles srgb-fp@sRGB decode full precision,Fail diff --git a/src/gallium/drivers/zink/ci/zink-lvp-fails.txt b/src/gallium/drivers/zink/ci/zink-lvp-fails.txt index 54d5bbc..c1aa22b 100644 --- a/src/gallium/drivers/zink/ci/zink-lvp-fails.txt +++ b/src/gallium/drivers/zink/ci/zink-lvp-fails.txt @@ -85,13 +85,11 @@ spec@!opengl 1.1@polygon-mode-offset@config 6: Expected blue pixel in center,Fai spec@!opengl 1.1@polygon-mode-offset@config 6: Expected white pixel on right edge,Fail spec@!opengl 1.1@polygon-mode-offset@config 6: Expected white pixel on top edge,Fail spec@!opengl 1.2@copyteximage 3d,Fail -spec@!opengl 2.0@depth-tex-modes-glsl,Fail spec@!opengl 2.0@gl-2.0-edgeflag,Fail spec@!opengl 2.0@gl-2.0-edgeflag-immediate,Fail spec@!opengl 2.1@pbo,Fail spec@!opengl 2.1@pbo@test_polygon_stip,Fail spec@!opengl 2.1@polygon-stipple-fs,Fail -spec@arb_depth_texture@depth-tex-modes,Fail spec@arb_gpu_shader_fp64@execution@arb_gpu_shader_fp64-tf-separate,Fail spec@arb_pipeline_statistics_query@arb_pipeline_statistics_query-frag,Fail spec@arb_point_sprite@arb_point_sprite-checkerboard,Fail @@ -154,7 +152,6 @@ spec@ext_framebuffer_multisample@interpolation 4 centroid-edges,Fail spec@ext_framebuffer_multisample@interpolation 4 non-centroid-deriv-disabled,Fail spec@ext_framebuffer_multisample@interpolation 4 non-centroid-disabled,Fail spec@ext_packed_float@query-rgba-signed-components,Fail -spec@ext_texture_swizzle@depth_texture_mode_and_swizzle,Fail spec@intel_performance_query@intel_performance_query-issue_2235,Fail spec@khr_texture_compression_astc@miptree-gl srgb-fp,Fail @@ -185,12 +182,6 @@ spec@!opengl 1.0@rasterpos@glsl_vs_tes_linked,Fail spec@arb_arrays_of_arrays@execution@image_store@basic-imagestore-mixed-const-non-const-uniform-index,Fail spec@arb_arrays_of_arrays@execution@image_store@basic-imagestore-mixed-const-non-const-uniform-index2,Fail spec@arb_arrays_of_arrays@execution@image_store@basic-imagestore-non-const-uniform-index,Fail -spec@arb_fragment_program_shadow@tex-shadow1d,Fail -spec@arb_fragment_program_shadow@tex-shadow2d,Fail -spec@arb_fragment_program_shadow@tex-shadow2drect,Fail -spec@arb_fragment_program_shadow@txp-shadow1d,Fail -spec@arb_fragment_program_shadow@txp-shadow2d,Fail -spec@arb_fragment_program_shadow@txp-shadow2drect,Fail spec@arb_gl_spirv@execution@xfb@vs_block_array,Fail spec@arb_gpu_shader_fp64@execution@conversion@frag-conversion-explicit-dmat2-mat2,Fail spec@arb_gpu_shader_fp64@execution@conversion@frag-conversion-explicit-dmat2x3-mat2x3,Fail @@ -232,48 +223,7 @@ spec@arb_gpu_shader_fp64@execution@conversion@vert-conversion-explicit-dvec2-vec spec@arb_gpu_shader_fp64@execution@conversion@vert-conversion-explicit-dvec3-vec3,Fail spec@arb_gpu_shader_fp64@execution@conversion@vert-conversion-explicit-dvec4-vec4,Fail spec@arb_shader_storage_buffer_object@execution@ssbo-atomiccompswap-int,Fail -spec@arb_shader_texture_lod@execution@glsl-fs-shadow2dgradarb-01,Fail -spec@arb_shader_texture_lod@execution@glsl-fs-shadow2dgradarb-03,Fail -spec@arb_shader_texture_lod@execution@glsl-fs-shadow2dgradarb-07,Fail -spec@arb_shader_texture_lod@execution@glsl-fs-shadow2dgradarb-08,Fail -spec@arb_shader_texture_lod@execution@glsl-fs-shadow2dgradarb-cumulative,Fail spec@arb_tessellation_shader@execution@gs-primitiveid-instanced,Fail -spec@arb_texture_rectangle@glsl-fs-shadow2drect,Fail -spec@arb_texture_rectangle@glsl-fs-shadow2drect-01,Fail -spec@arb_texture_rectangle@glsl-fs-shadow2drect-03,Fail -spec@arb_texture_rectangle@glsl-fs-shadow2drect-07,Fail -spec@arb_texture_rectangle@glsl-fs-shadow2drect-08,Fail -spec@arb_texture_rectangle@glsl-fs-shadow2drectproj,Fail -spec@arb_texture_rg@execution@fs-shadow2d-red-01,Fail -spec@arb_texture_rg@execution@fs-shadow2d-red-02,Fail -spec@arb_texture_rg@execution@fs-shadow2d-red-03,Fail -spec@ext_texture_array@glsl-fs-shadow1darray,Fail -spec@ext_texture_array@glsl-fs-shadow1darray-01,Fail -spec@ext_texture_array@glsl-fs-shadow1darray-03,Fail -spec@ext_texture_array@glsl-fs-shadow1darray-07,Fail -spec@ext_texture_array@glsl-fs-shadow1darray-08,Fail -spec@ext_texture_array@glsl-fs-shadow1darray-bias,Fail -spec@ext_texture_array@glsl-fs-shadow2darray,Fail -spec@ext_texture_array@glsl-fs-shadow2darray-01,Fail -spec@ext_texture_array@glsl-fs-shadow2darray-03,Fail -spec@ext_texture_array@glsl-fs-shadow2darray-07,Fail -spec@ext_texture_array@glsl-fs-shadow2darray-08,Fail -spec@glsl-1.10@execution@samplers@glsl-fs-shadow1d,Fail -spec@glsl-1.10@execution@samplers@glsl-fs-shadow1d-01,Fail -spec@glsl-1.10@execution@samplers@glsl-fs-shadow1d-03,Fail -spec@glsl-1.10@execution@samplers@glsl-fs-shadow1d-07,Fail -spec@glsl-1.10@execution@samplers@glsl-fs-shadow1d-08,Fail -spec@glsl-1.10@execution@samplers@glsl-fs-shadow1d-bias,Fail -spec@glsl-1.10@execution@samplers@glsl-fs-shadow1dproj,Fail -spec@glsl-1.10@execution@samplers@glsl-fs-shadow1dproj-bias,Fail -spec@glsl-1.10@execution@samplers@glsl-fs-shadow2d,Fail -spec@glsl-1.10@execution@samplers@glsl-fs-shadow2d-01,Fail -spec@glsl-1.10@execution@samplers@glsl-fs-shadow2d-03,Fail -spec@glsl-1.10@execution@samplers@glsl-fs-shadow2d-07,Fail -spec@glsl-1.10@execution@samplers@glsl-fs-shadow2d-08,Fail -spec@glsl-1.10@execution@samplers@glsl-fs-shadow2d-bias,Fail -spec@glsl-1.10@execution@samplers@glsl-fs-shadow2dproj,Fail -spec@glsl-1.10@execution@samplers@glsl-fs-shadow2dproj-bias,Fail spec@glsl-1.50@execution@primitive-id-no-gs-quad-strip,Fail spec@glsl-1.50@execution@primitive-id-no-gs-quads,Fail spec@glsl-4.00@execution@conversion@frag-conversion-explicit-dmat2-mat2,Fail diff --git a/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c b/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c index 5166eb9..a3e68b6 100644 --- a/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c +++ b/src/gallium/drivers/zink/nir_to_spirv/nir_to_spirv.c @@ -779,6 +779,25 @@ emit_output(struct ntv_context *ctx, struct nir_variable *var) ctx->entry_ifaces[ctx->num_entry_ifaces++] = var_id; } +static void +emit_shader_temp(struct ntv_context *ctx, struct nir_variable *var) +{ + SpvId var_type = get_glsl_type(ctx, var->type); + + SpvId pointer_type = spirv_builder_type_pointer(&ctx->builder, + SpvStorageClassPrivate, + var_type); + SpvId var_id = spirv_builder_emit_var(&ctx->builder, pointer_type, + SpvStorageClassPrivate); + if (var->name) + spirv_builder_emit_name(&ctx->builder, var_id, var->name); + + _mesa_hash_table_insert(ctx->vars, var, (void *)(intptr_t)var_id); + + assert(ctx->num_entry_ifaces < ARRAY_SIZE(ctx->entry_ifaces)); + ctx->entry_ifaces[ctx->num_entry_ifaces++] = var_id; +} + static void emit_temp(struct ntv_context *ctx, struct nir_variable *var) { @@ -3286,7 +3305,7 @@ emit_intrinsic(struct ntv_context *ctx, nir_intrinsic_instr *intr) emit_load_uint_input(ctx, intr, &ctx->sample_mask_in_var, "gl_SampleMaskIn", SpvBuiltInSampleMask); break; - case nir_intrinsic_emit_vertex_with_counter: + case nir_intrinsic_emit_vertex: /* geometry shader emits copied xfb outputs just prior to EmitVertex(), * since that's the end of the shader */ @@ -3297,11 +3316,7 @@ emit_intrinsic(struct ntv_context *ctx, nir_intrinsic_instr *intr) ctx->nir->info.stage == MESA_SHADER_GEOMETRY && util_bitcount(ctx->nir->info.gs.active_stream_mask) > 1); break; - case nir_intrinsic_set_vertex_and_primitive_count: - /* do nothing */ - break; - - case nir_intrinsic_end_primitive_with_counter: + case nir_intrinsic_end_primitive: spirv_builder_end_primitive(&ctx->builder, nir_intrinsic_stream_id(intr), ctx->nir->info.stage == MESA_SHADER_GEOMETRY && util_bitcount(ctx->nir->info.gs.active_stream_mask) > 1); break; @@ -3831,26 +3846,22 @@ emit_tex(struct ntv_context *ctx, nir_tex_instr *tex) return; } SpvId actual_dest_type; - if (dref && tex->op != nir_texop_tg4) - actual_dest_type = spirv_builder_type_float(&ctx->builder, 32); - else { - unsigned num_components = nir_dest_num_components(tex->dest); - switch (nir_alu_type_get_base_type(tex->dest_type)) { - case nir_type_int: - actual_dest_type = get_ivec_type(ctx, 32, num_components); - break; + unsigned num_components = nir_dest_num_components(tex->dest); + switch (nir_alu_type_get_base_type(tex->dest_type)) { + case nir_type_int: + actual_dest_type = get_ivec_type(ctx, 32, num_components); + break; - case nir_type_uint: - actual_dest_type = get_uvec_type(ctx, 32, num_components); - break; + case nir_type_uint: + actual_dest_type = get_uvec_type(ctx, 32, num_components); + break; - case nir_type_float: - actual_dest_type = get_fvec_type(ctx, 32, num_components); - break; + case nir_type_float: + actual_dest_type = get_fvec_type(ctx, 32, num_components); + break; - default: - unreachable("unexpected nir_alu_type"); - } + default: + unreachable("unexpected nir_alu_type"); } SpvId result; @@ -4741,6 +4752,9 @@ nir_to_spirv(struct nir_shader *s, const struct zink_shader_info *sinfo, uint32_ ctx.regs[reg->index] = var; } + nir_foreach_variable_with_modes(var, s, nir_var_shader_temp) + emit_shader_temp(&ctx, var); + nir_foreach_function_temp_variable(var, entry) emit_temp(&ctx, var); diff --git a/src/gallium/drivers/zink/zink_batch.c b/src/gallium/drivers/zink/zink_batch.c index 7063463..dd0d8e7 100644 --- a/src/gallium/drivers/zink/zink_batch.c +++ b/src/gallium/drivers/zink/zink_batch.c @@ -29,8 +29,8 @@ reset_obj(struct zink_screen *screen, struct zink_batch_state *bs, struct zink_r /* if no batch usage exists after removing the usage from 'bs', this resource is considered fully idle */ if (!zink_resource_object_usage_unset(obj, bs)) { /* the resource is idle, so reset all access/reordering info */ - obj->unordered_read = false; - obj->unordered_write = false; + obj->unordered_read = true; + obj->unordered_write = true; obj->access = 0; obj->access_stage = 0; /* also prune dead view objects */ @@ -139,14 +139,15 @@ zink_reset_batch_state(struct zink_context *ctx, struct zink_batch_state *bs) util_dynarray_clear(&bs->wait_semaphore_stages); bs->present = VK_NULL_HANDLE; - /* semaphores are not destroyed here; - * destroying semaphores triggers ioctls, so defer deletion to the submit thread to avoid blocking - */ - memcpy(&bs->unref_semaphores, &bs->acquires, sizeof(struct util_dynarray)); - util_dynarray_init(&bs->acquires, NULL); - while (util_dynarray_contains(&bs->wait_semaphores, VkSemaphore)) - util_dynarray_append(&bs->unref_semaphores, VkSemaphore, util_dynarray_pop(&bs->wait_semaphores, VkSemaphore)); - util_dynarray_init(&bs->wait_semaphores, NULL); + /* check the arrays first to avoid locking unnecessarily */ + if (util_dynarray_contains(&bs->acquires, VkSemaphore) || util_dynarray_contains(&bs->wait_semaphores, VkSemaphore)) { + simple_mtx_lock(&screen->semaphores_lock); + util_dynarray_append_dynarray(&screen->semaphores, &bs->acquires); + util_dynarray_clear(&bs->acquires); + util_dynarray_append_dynarray(&screen->semaphores, &bs->wait_semaphores); + util_dynarray_clear(&bs->wait_semaphores); + simple_mtx_unlock(&screen->semaphores_lock); + } bs->swapchain = NULL; /* only reset submitted here so that tc fence desync can pick up the 'completed' flag @@ -198,8 +199,6 @@ unref_resources(struct zink_screen *screen, struct zink_batch_state *bs) /* this is typically where resource objects get destroyed */ zink_resource_object_reference(screen, &obj, NULL); } - while (util_dynarray_contains(&bs->unref_semaphores, VkSemaphore)) - VKSCR(DestroySemaphore)(screen->dev, util_dynarray_pop(&bs->unref_semaphores, VkSemaphore), NULL); } /* utility for resetting a batch state; called on context destruction */ @@ -269,7 +268,6 @@ zink_batch_state_destroy(struct zink_screen *screen, struct zink_batch_state *bs util_dynarray_fini(&bs->bindless_releases[0]); util_dynarray_fini(&bs->bindless_releases[1]); util_dynarray_fini(&bs->acquires); - util_dynarray_fini(&bs->unref_semaphores); util_dynarray_fini(&bs->acquire_flags); zink_batch_descriptor_deinit(screen, bs); ralloc_free(bs); @@ -326,7 +324,6 @@ create_batch_state(struct zink_context *ctx) util_dynarray_init(&bs->persistent_resources, NULL); util_dynarray_init(&bs->unref_resources, NULL); util_dynarray_init(&bs->acquires, NULL); - util_dynarray_init(&bs->unref_semaphores, NULL); util_dynarray_init(&bs->acquire_flags, NULL); util_dynarray_init(&bs->bindless_releases[0], NULL); util_dynarray_init(&bs->bindless_releases[1], NULL); diff --git a/src/gallium/drivers/zink/zink_bo.c b/src/gallium/drivers/zink/zink_bo.c index 011d1b8..d5152ce 100644 --- a/src/gallium/drivers/zink/zink_bo.c +++ b/src/gallium/drivers/zink/zink_bo.c @@ -721,23 +721,10 @@ zink_bo_unmap(struct zink_screen *screen, struct zink_bo *bo) } } -static VkSemaphore -get_semaphore(struct zink_screen *screen) -{ - VkSemaphoreCreateInfo sci = { - VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, - NULL, - 0 - }; - VkSemaphore sem; - VkResult ret = VKSCR(CreateSemaphore)(screen->dev, &sci, NULL, &sem); - return ret == VK_SUCCESS ? sem : VK_NULL_HANDLE; -} - static VkSemaphore buffer_commit_single(struct zink_screen *screen, struct zink_resource *res, struct zink_bo *bo, uint32_t bo_offset, uint32_t offset, uint32_t size, bool commit, VkSemaphore wait) { - VkSemaphore sem = get_semaphore(screen); + VkSemaphore sem = zink_create_semaphore(screen); VkBindSparseInfo sparse = {0}; sparse.sType = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO; sparse.bufferBindCount = res->obj->storage_buffer ? 2 : 1; @@ -886,7 +873,7 @@ out: static VkSemaphore texture_commit_single(struct zink_screen *screen, struct zink_resource *res, VkSparseImageMemoryBind *ibind, unsigned num_binds, bool commit, VkSemaphore wait) { - VkSemaphore sem = get_semaphore(screen); + VkSemaphore sem = zink_create_semaphore(screen); VkBindSparseInfo sparse = {0}; sparse.sType = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO; sparse.imageBindCount = 1; @@ -911,7 +898,7 @@ texture_commit_single(struct zink_screen *screen, struct zink_resource *res, VkS static VkSemaphore texture_commit_miptail(struct zink_screen *screen, struct zink_resource *res, struct zink_bo *bo, uint32_t bo_offset, uint32_t offset, bool commit, VkSemaphore wait) { - VkSemaphore sem = get_semaphore(screen); + VkSemaphore sem = zink_create_semaphore(screen); VkBindSparseInfo sparse = {0}; sparse.sType = VK_STRUCTURE_TYPE_BIND_SPARSE_INFO; sparse.imageOpaqueBindCount = 1; @@ -969,9 +956,9 @@ zink_bo_commit(struct zink_screen *screen, struct zink_resource *res, unsigned l unsigned nheight = DIV_ROUND_UP(box->height, gheight); unsigned ndepth = DIV_ROUND_UP(box->depth, gdepth); VkExtent3D lastBlockExtent = { - (box->width % gwidth) ? box->width % gwidth : gwidth, - (box->height % gheight) ? box->height % gheight : gheight, - (box->depth % gdepth) ? box->depth % gdepth : gdepth + (box->width % gwidth) ? box->width % gwidth : gwidth, + (box->height % gheight) ? box->height % gheight : gheight, + (box->depth % gdepth) ? box->depth % gdepth : gdepth }; #define NUM_BATCHED_BINDS 50 VkSparseImageMemoryBind ibind[NUM_BATCHED_BINDS]; diff --git a/src/gallium/drivers/zink/zink_compiler.c b/src/gallium/drivers/zink/zink_compiler.c index 3deaed0..7ce8eda 100644 --- a/src/gallium/drivers/zink/zink_compiler.c +++ b/src/gallium/drivers/zink/zink_compiler.c @@ -31,7 +31,9 @@ #include "pipe/p_state.h" #include "nir.h" +#include "nir/nir_draw_helpers.h" #include "compiler/nir/nir_builder.h" +#include "compiler/nir/nir_builtin_builder.h" #include "nir/tgsi_to_nir.h" #include "tgsi/tgsi_dump.h" @@ -64,6 +66,9 @@ fields[member_idx].offset = offsetof(struct zink_gfx_push_constant, field); PUSHCONST_MEMBER(ZINK_GFX_PUSHCONST_FRAMEBUFFER_IS_LAYERED, framebuffer_is_layered); PUSHCONST_MEMBER(ZINK_GFX_PUSHCONST_DEFAULT_INNER_LEVEL, default_inner_level); PUSHCONST_MEMBER(ZINK_GFX_PUSHCONST_DEFAULT_OUTER_LEVEL, default_outer_level); + PUSHCONST_MEMBER(ZINK_GFX_PUSHCONST_LINE_STIPPLE_PATTERN, line_stipple_pattern); + PUSHCONST_MEMBER(ZINK_GFX_PUSHCONST_VIEWPORT_SCALE, viewport_scale); + PUSHCONST_MEMBER(ZINK_GFX_PUSHCONST_LINE_WIDTH, line_width); pushconst = nir_variable_create(nir, nir_var_mem_push_const, glsl_struct_type(fields, ZINK_GFX_PUSHCONST_MAX, "struct", false), @@ -270,6 +275,575 @@ lower_drawid(nir_shader *shader) return nir_shader_instructions_pass(shader, lower_drawid_instr, nir_metadata_dominance, NULL); } +struct lower_gl_point_state { + nir_variable *gl_pos_out; + nir_variable *gl_point_size; +}; + +static bool +lower_gl_point_gs_instr(nir_builder *b, nir_instr *instr, void *data) +{ + struct lower_gl_point_state *state = data; + nir_ssa_def *vp_scale, *pos; + + if (instr->type != nir_instr_type_intrinsic) + return false; + + nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); + if (intrin->intrinsic != nir_intrinsic_emit_vertex_with_counter && + intrin->intrinsic != nir_intrinsic_emit_vertex) + return false; + + if (nir_intrinsic_stream_id(intrin) != 0) + return false; + + if (intrin->intrinsic == nir_intrinsic_end_primitive_with_counter || + intrin->intrinsic == nir_intrinsic_end_primitive) { + nir_instr_remove(&intrin->instr); + return true; + } + + b->cursor = nir_before_instr(instr); + + // viewport-map endpoints + nir_ssa_def *vp_const_pos = nir_imm_int(b, ZINK_GFX_PUSHCONST_VIEWPORT_SCALE); + vp_scale = nir_load_push_constant(b, 2, 32, vp_const_pos, .base = 1, .range = 2); + + // Load point info values + nir_ssa_def *point_size = nir_load_var(b, state->gl_point_size); + nir_ssa_def *point_pos = nir_load_var(b, state->gl_pos_out); + + // w_delta = gl_point_size / width_viewport_size_scale * gl_Position.w + nir_ssa_def *w_delta = nir_fdiv(b, point_size, nir_channel(b, vp_scale, 0)); + w_delta = nir_fmul(b, w_delta, nir_channel(b, point_pos, 3)); + // halt_w_delta = w_delta / 2 + nir_ssa_def *half_w_delta = nir_fmul(b, w_delta, nir_imm_float(b, 0.5)); + + // h_delta = gl_point_size / height_viewport_size_scale * gl_Position.w + nir_ssa_def *h_delta = nir_fdiv(b, point_size, nir_channel(b, vp_scale, 1)); + h_delta = nir_fmul(b, h_delta, nir_channel(b, point_pos, 3)); + // halt_h_delta = h_delta / 2 + nir_ssa_def *half_h_delta = nir_fmul(b, h_delta, nir_imm_float(b, 0.5)); + + nir_ssa_def *point_dir[4][2] = { + { nir_imm_float(b, -1), nir_imm_float(b, -1) }, + { nir_imm_float(b, -1), nir_imm_float(b, 1) }, + { nir_imm_float(b, 1), nir_imm_float(b, -1) }, + { nir_imm_float(b, 1), nir_imm_float(b, 1) } + }; + + nir_ssa_def *point_pos_x = nir_channel(b, point_pos, 0); + nir_ssa_def *point_pos_y = nir_channel(b, point_pos, 1); + + for (size_t i = 0; i < 4; i++) { + pos = nir_vec4(b, + nir_ffma(b, half_w_delta, point_dir[i][0], point_pos_x), + nir_ffma(b, half_h_delta, point_dir[i][1], point_pos_y), + nir_channel(b, point_pos, 2), + nir_channel(b, point_pos, 3)); + + nir_store_var(b, state->gl_pos_out, pos, 0xf); + + nir_emit_vertex(b); + } + + nir_end_primitive(b); + + nir_instr_remove(&intrin->instr); + + return true; +} + +static bool +lower_gl_point_gs(nir_shader *shader) +{ + struct lower_gl_point_state state; + nir_builder b; + + shader->info.gs.output_primitive = SHADER_PRIM_TRIANGLE_STRIP; + shader->info.gs.vertices_out *= 4; + + // Gets the gl_Position in and out + state.gl_pos_out = + nir_find_variable_with_location(shader, nir_var_shader_out, + VARYING_SLOT_POS); + state.gl_point_size = + nir_find_variable_with_location(shader, nir_var_shader_out, + VARYING_SLOT_PSIZ); + + // if position in or gl_PointSize aren't written, we have nothing to do + if (!state.gl_pos_out || !state.gl_point_size) + return false; + + nir_function_impl *entry = nir_shader_get_entrypoint(shader); + nir_builder_init(&b, entry); + b.cursor = nir_before_cf_list(&entry->body); + + return nir_shader_instructions_pass(shader, lower_gl_point_gs_instr, + nir_metadata_dominance, &state); +} + +struct lower_line_stipple_state { + nir_variable *pos_out; + nir_variable *stipple_out; + nir_variable *prev_pos; + nir_variable *pos_counter; + nir_variable *stipple_counter; +}; + +static nir_ssa_def * +viewport_map(nir_builder *b, nir_ssa_def *vert, + nir_ssa_def *scale) +{ + nir_ssa_def *w_recip = nir_frcp(b, nir_channel(b, vert, 3)); + nir_ssa_def *ndc_point = nir_fmul(b, nir_channels(b, vert, 0x3), + w_recip); + return nir_fmul(b, ndc_point, scale); +} + +static bool +lower_line_stipple_gs_instr(nir_builder *b, nir_instr *instr, void *data) +{ + struct lower_line_stipple_state *state = data; + if (instr->type != nir_instr_type_intrinsic) + return false; + + nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); + if (intrin->intrinsic != nir_intrinsic_emit_vertex_with_counter && + intrin->intrinsic != nir_intrinsic_emit_vertex) + return false; + + b->cursor = nir_before_instr(instr); + + nir_push_if(b, nir_ine_imm(b, nir_load_var(b, state->pos_counter), 0)); + // viewport-map endpoints + nir_ssa_def *vp_scale = nir_load_push_constant(b, 2, 32, + nir_imm_int(b, ZINK_GFX_PUSHCONST_VIEWPORT_SCALE), + .base = 1, + .range = 2); + nir_ssa_def *prev = nir_load_var(b, state->prev_pos); + nir_ssa_def *curr = nir_load_var(b, state->pos_out); + prev = viewport_map(b, prev, vp_scale); + curr = viewport_map(b, curr, vp_scale); + + // calculate length of line + nir_ssa_def *len = nir_fast_distance(b, prev, curr); + // update stipple_counter + nir_store_var(b, state->stipple_counter, + nir_fadd(b, nir_load_var(b, state->stipple_counter), + len), 1); + nir_pop_if(b, NULL); + // emit stipple out + nir_copy_var(b, state->stipple_out, state->stipple_counter); + nir_copy_var(b, state->prev_pos, state->pos_out); + + // update prev_pos and pos_counter for next vertex + b->cursor = nir_after_instr(instr); + nir_store_var(b, state->pos_counter, + nir_iadd_imm(b, nir_load_var(b, state->pos_counter), + 1), 1); + + return true; +} + +static bool +lower_line_stipple_gs(nir_shader *shader) +{ + nir_builder b; + struct lower_line_stipple_state state; + + state.pos_out = + nir_find_variable_with_location(shader, nir_var_shader_out, + VARYING_SLOT_POS); + + // if position isn't written, we have nothing to do + if (!state.pos_out) + return false; + + state.stipple_out = nir_variable_create(shader, nir_var_shader_out, + glsl_float_type(), + "__stipple"); + state.stipple_out->data.interpolation = INTERP_MODE_NOPERSPECTIVE; + state.stipple_out->data.driver_location = shader->num_outputs++; + state.stipple_out->data.location = MAX2(util_last_bit64(shader->info.outputs_written), VARYING_SLOT_VAR0); + shader->info.outputs_written |= BITFIELD64_BIT(state.stipple_out->data.location); + + // create temp variables + state.prev_pos = nir_variable_create(shader, nir_var_shader_temp, + glsl_vec4_type(), + "__prev_pos"); + state.pos_counter = nir_variable_create(shader, nir_var_shader_temp, + glsl_uint_type(), + "__pos_counter"); + state.stipple_counter = nir_variable_create(shader, nir_var_shader_temp, + glsl_float_type(), + "__stipple_counter"); + + // initialize pos_counter and stipple_counter + nir_function_impl *entry = nir_shader_get_entrypoint(shader); + nir_builder_init(&b, entry); + b.cursor = nir_before_cf_list(&entry->body); + nir_store_var(&b, state.pos_counter, nir_imm_int(&b, 0), 1); + nir_store_var(&b, state.stipple_counter, nir_imm_float(&b, 0), 1); + + return nir_shader_instructions_pass(shader, lower_line_stipple_gs_instr, + nir_metadata_dominance, &state); +} + +static bool +lower_line_stipple_fs(nir_shader *shader) +{ + nir_builder b; + nir_function_impl *entry = nir_shader_get_entrypoint(shader); + nir_builder_init(&b, entry); + + // create stipple counter + nir_variable *stipple = nir_variable_create(shader, nir_var_shader_in, + glsl_float_type(), + "__stipple"); + stipple->data.interpolation = INTERP_MODE_NOPERSPECTIVE; + stipple->data.driver_location = shader->num_inputs++; + stipple->data.location = MAX2(util_last_bit64(shader->info.inputs_read), VARYING_SLOT_VAR0); + shader->info.inputs_read |= BITFIELD64_BIT(stipple->data.location); + + nir_variable *sample_mask_out = + nir_find_variable_with_location(shader, nir_var_shader_out, + FRAG_RESULT_SAMPLE_MASK); + if (!sample_mask_out) { + sample_mask_out = nir_variable_create(shader, nir_var_shader_out, + glsl_uint_type(), "sample_mask"); + sample_mask_out->data.driver_location = shader->num_outputs++; + sample_mask_out->data.location = FRAG_RESULT_SAMPLE_MASK; + } + + b.cursor = nir_after_cf_list(&entry->body); + + nir_ssa_def *pattern = nir_load_push_constant(&b, 1, 32, + nir_imm_int(&b, ZINK_GFX_PUSHCONST_LINE_STIPPLE_PATTERN), + .base = 1); + nir_ssa_def *factor = nir_i2f32(&b, nir_ishr_imm(&b, pattern, 16)); + pattern = nir_iand_imm(&b, pattern, 0xffff); + + nir_ssa_def *sample_mask_in = nir_load_sample_mask_in(&b); + nir_variable *v = nir_local_variable_create(entry, glsl_uint_type(), NULL); + nir_variable *sample_mask = nir_local_variable_create(entry, glsl_uint_type(), NULL); + nir_store_var(&b, v, sample_mask_in, 1); + nir_store_var(&b, sample_mask, sample_mask_in, 1); + nir_push_loop(&b); + { + nir_ssa_def *value = nir_load_var(&b, v); + nir_ssa_def *index = nir_ufind_msb(&b, value); + nir_ssa_def *index_mask = nir_ishl(&b, nir_imm_int(&b, 1), index); + nir_ssa_def *new_value = nir_ixor(&b, value, index_mask); + nir_store_var(&b, v, new_value, 1); + nir_push_if(&b, nir_ieq_imm(&b, value, 0)); + nir_jump(&b, nir_jump_break); + nir_pop_if(&b, NULL); + + nir_ssa_def *stipple_pos = + nir_interp_deref_at_sample(&b, 1, 32, + &nir_build_deref_var(&b, stipple)->dest.ssa, index); + stipple_pos = nir_fmod(&b, nir_fdiv(&b, stipple_pos, factor), + nir_imm_float(&b, 16.0)); + stipple_pos = nir_f2i32(&b, stipple_pos); + nir_ssa_def *bit = + nir_iand_imm(&b, nir_ishr(&b, pattern, stipple_pos), 1); + nir_push_if(&b, nir_ieq_imm(&b, bit, 0)); + { + nir_ssa_def *value = nir_load_var(&b, sample_mask); + value = nir_ixor(&b, value, index_mask); + nir_store_var(&b, sample_mask, value, 1); + } + nir_pop_if(&b, NULL); + } + nir_pop_loop(&b, NULL); + nir_store_var(&b, sample_mask_out, nir_load_var(&b, sample_mask), 1); + + return true; +} + +struct lower_line_smooth_state { + nir_variable *pos_out; + nir_variable *line_coord_out; + nir_variable *prev_pos; + nir_variable *pos_counter; + nir_variable *prev_varyings[VARYING_SLOT_MAX], + *varyings[VARYING_SLOT_MAX]; +}; + +static bool +lower_line_smooth_gs_store(nir_builder *b, + nir_intrinsic_instr *intrin, + struct lower_line_smooth_state *state) +{ + b->cursor = nir_before_instr(&intrin->instr); + nir_deref_instr *deref = nir_src_as_deref(intrin->src[0]); + if (nir_deref_mode_is(deref, nir_var_shader_out)) { + nir_variable *var = nir_deref_instr_get_variable(deref); + + // we take care of position elsewhere + gl_varying_slot location = var->data.location; + if (location != VARYING_SLOT_POS) { + assert(state->varyings[location]); + assert(intrin->src[1].is_ssa); + nir_store_var(b, state->varyings[location], + intrin->src[1].ssa, + nir_intrinsic_write_mask(intrin)); + nir_instr_remove(&intrin->instr); + return true; + } + } + + return false; +} + +static bool +lower_line_smooth_gs_emit_vertex(nir_builder *b, + nir_intrinsic_instr *intrin, + struct lower_line_smooth_state *state) +{ + b->cursor = nir_before_instr(&intrin->instr); + + nir_push_if(b, nir_ine_imm(b, nir_load_var(b, state->pos_counter), 0)); + nir_ssa_def *vp_scale = nir_load_push_constant(b, 2, 32, + nir_imm_int(b, ZINK_GFX_PUSHCONST_VIEWPORT_SCALE), + .base = 1, + .range = 2); + nir_ssa_def *prev = nir_load_var(b, state->prev_pos); + nir_ssa_def *curr = nir_load_var(b, state->pos_out); + nir_ssa_def *prev_vp = viewport_map(b, prev, vp_scale); + nir_ssa_def *curr_vp = viewport_map(b, curr, vp_scale); + + nir_ssa_def *width = nir_load_push_constant(b, 1, 32, + nir_imm_int(b, ZINK_GFX_PUSHCONST_LINE_WIDTH), + .base = 1); + nir_ssa_def *half_width = nir_fadd_imm(b, nir_fmul_imm(b, width, 0.5), 0.5); + + const unsigned yx[2] = { 1, 0 }; + nir_ssa_def *vec = nir_fsub(b, curr_vp, prev_vp); + nir_ssa_def *len = nir_fast_length(b, vec); + nir_ssa_def *dir = nir_normalize(b, vec); + nir_ssa_def *half_length = nir_fmul_imm(b, len, 0.5); + half_length = nir_fadd_imm(b, half_length, 0.5); + + nir_ssa_def *vp_scale_rcp = nir_frcp(b, vp_scale); + nir_ssa_def *tangent = + nir_fmul(b, + nir_fmul(b, + nir_swizzle(b, dir, yx, 2), + nir_imm_vec2(b, 1.0, -1.0)), + vp_scale_rcp); + tangent = nir_fmul(b, tangent, half_width); + tangent = nir_pad_vector_imm_int(b, tangent, 0, 4); + dir = nir_fmul_imm(b, nir_fmul(b, dir, vp_scale_rcp), 0.5); + + nir_ssa_def *line_offets[8] = { + nir_fadd(b, tangent, nir_fneg(b, dir)), + nir_fadd(b, nir_fneg(b, tangent), nir_fneg(b, dir)), + tangent, + nir_fneg(b, tangent), + tangent, + nir_fneg(b, tangent), + nir_fadd(b, tangent, dir), + nir_fadd(b, nir_fneg(b, tangent), dir), + }; + nir_ssa_def *line_coord = + nir_vec4(b, half_width, half_width, half_length, half_length); + nir_ssa_def *line_coords[8] = { + nir_fmul(b, line_coord, nir_imm_vec4(b, -1, 1, -1, 1)), + nir_fmul(b, line_coord, nir_imm_vec4(b, 1, 1, -1, 1)), + nir_fmul(b, line_coord, nir_imm_vec4(b, -1, 1, 0, 1)), + nir_fmul(b, line_coord, nir_imm_vec4(b, 1, 1, 0, 1)), + nir_fmul(b, line_coord, nir_imm_vec4(b, -1, 1, 0, 1)), + nir_fmul(b, line_coord, nir_imm_vec4(b, 1, 1, 0, 1)), + nir_fmul(b, line_coord, nir_imm_vec4(b, -1, 1, 1, 1)), + nir_fmul(b, line_coord, nir_imm_vec4(b, 1, 1, 1, 1)), + }; + + /* emit first end-cap, and start line */ + for (int i = 0; i < 4; ++i) { + nir_foreach_variable_with_modes(var, b->shader, nir_var_shader_out) { + gl_varying_slot location = var->data.location; + if (state->prev_varyings[location]) + nir_copy_var(b, var, state->prev_varyings[location]); + } + nir_store_var(b, state->pos_out, + nir_fadd(b, prev, nir_fmul(b, line_offets[i], + nir_channel(b, prev, 3))), 0xf); + nir_store_var(b, state->line_coord_out, line_coords[i], 0xf); + nir_emit_vertex(b); + } + + /* finish line and emit last end-cap */ + for (int i = 4; i < 8; ++i) { + nir_foreach_variable_with_modes(var, b->shader, nir_var_shader_out) { + gl_varying_slot location = var->data.location; + if (state->varyings[location]) + nir_copy_var(b, var, state->varyings[location]); + } + nir_store_var(b, state->pos_out, + nir_fadd(b, curr, nir_fmul(b, line_offets[i], + nir_channel(b, curr, 3))), 0xf); + nir_store_var(b, state->line_coord_out, line_coords[i], 0xf); + nir_emit_vertex(b); + } + nir_end_primitive(b); + + nir_pop_if(b, NULL); + + nir_copy_var(b, state->prev_pos, state->pos_out); + nir_foreach_variable_with_modes(var, b->shader, nir_var_shader_out) { + gl_varying_slot location = var->data.location; + if (state->varyings[location]) + nir_copy_var(b, state->prev_varyings[location], state->varyings[location]); + } + + // update prev_pos and pos_counter for next vertex + b->cursor = nir_after_instr(&intrin->instr); + nir_store_var(b, state->pos_counter, + nir_iadd_imm(b, nir_load_var(b, state->pos_counter), + 1), 1); + + nir_instr_remove(&intrin->instr); + return true; +} + +static bool +lower_line_smooth_gs_end_primitive(nir_builder *b, + nir_intrinsic_instr *intrin, + struct lower_line_smooth_state *state) +{ + b->cursor = nir_before_instr(&intrin->instr); + + // reset line counter + nir_store_var(b, state->pos_counter, nir_imm_int(b, 0), 1); + + nir_instr_remove(&intrin->instr); + return true; +} + +static bool +lower_line_smooth_gs_instr(nir_builder *b, nir_instr *instr, void *data) +{ + if (instr->type != nir_instr_type_intrinsic) + return false; + + struct lower_line_smooth_state *state = data; + nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr); + + switch (intrin->intrinsic) { + case nir_intrinsic_store_deref: + return lower_line_smooth_gs_store(b, intrin, state); + case nir_intrinsic_copy_deref: + unreachable("should be lowered"); + case nir_intrinsic_emit_vertex_with_counter: + case nir_intrinsic_emit_vertex: + return lower_line_smooth_gs_emit_vertex(b, intrin, state); + case nir_intrinsic_end_primitive: + case nir_intrinsic_end_primitive_with_counter: + return lower_line_smooth_gs_end_primitive(b, intrin, state); + default: + return false; + } +} + +static bool +lower_line_smooth_gs(nir_shader *shader) +{ + nir_builder b; + struct lower_line_smooth_state state; + + memset(state.varyings, 0, sizeof(state.varyings)); + memset(state.prev_varyings, 0, sizeof(state.prev_varyings)); + nir_foreach_variable_with_modes(var, shader, nir_var_shader_out) { + gl_varying_slot location = var->data.location; + if (location == VARYING_SLOT_POS) + continue; + + char name[100]; + snprintf(name, sizeof(name), "__tmp_%d", location); + state.varyings[location] = + nir_variable_create(shader, nir_var_shader_temp, + var->type, name); + + snprintf(name, sizeof(name), "__tmp_prev_%d", location); + state.prev_varyings[location] = + nir_variable_create(shader, nir_var_shader_temp, + var->type, name); + } + + state.pos_out = + nir_find_variable_with_location(shader, nir_var_shader_out, + VARYING_SLOT_POS); + + // if position isn't written, we have nothing to do + if (!state.pos_out) + return false; + + state.line_coord_out = + nir_variable_create(shader, nir_var_shader_out, glsl_vec4_type(), + "__line_coord"); + state.line_coord_out->data.interpolation = INTERP_MODE_NOPERSPECTIVE; + state.line_coord_out->data.driver_location = shader->num_outputs++; + state.line_coord_out->data.location = MAX2(util_last_bit64(shader->info.outputs_written), VARYING_SLOT_VAR0); + shader->info.outputs_written |= BITFIELD64_BIT(state.line_coord_out->data.location); + + // create temp variables + state.prev_pos = nir_variable_create(shader, nir_var_shader_temp, + glsl_vec4_type(), + "__prev_pos"); + state.pos_counter = nir_variable_create(shader, nir_var_shader_temp, + glsl_uint_type(), + "__pos_counter"); + + // initialize pos_counter + nir_function_impl *entry = nir_shader_get_entrypoint(shader); + nir_builder_init(&b, entry); + b.cursor = nir_before_cf_list(&entry->body); + nir_store_var(&b, state.pos_counter, nir_imm_int(&b, 0), 1); + + shader->info.gs.vertices_out = 8 * shader->info.gs.vertices_out; + shader->info.gs.output_primitive = SHADER_PRIM_TRIANGLE_STRIP; + + return nir_shader_instructions_pass(shader, lower_line_smooth_gs_instr, + nir_metadata_dominance, &state); +} + +static bool +lower_line_smooth_fs(nir_shader *shader, bool lower_stipple) +{ + int dummy; + nir_builder b; + + nir_variable *stipple_counter = NULL, *stipple_pattern = NULL; + if (lower_stipple) { + stipple_counter = nir_variable_create(shader, nir_var_shader_in, + glsl_float_type(), + "__stipple"); + stipple_counter->data.interpolation = INTERP_MODE_NOPERSPECTIVE; + stipple_counter->data.driver_location = shader->num_inputs++; + stipple_counter->data.location = + MAX2(util_last_bit64(shader->info.inputs_read), VARYING_SLOT_VAR0); + shader->info.inputs_read |= BITFIELD64_BIT(stipple_counter->data.location); + + stipple_pattern = nir_variable_create(shader, nir_var_shader_temp, + glsl_uint_type(), + "stipple_pattern"); + + // initialize stipple_pattern + nir_function_impl *entry = nir_shader_get_entrypoint(shader); + nir_builder_init(&b, entry); + b.cursor = nir_before_cf_list(&entry->body); + nir_ssa_def *pattern = nir_load_push_constant(&b, 1, 32, + nir_imm_int(&b, ZINK_GFX_PUSHCONST_LINE_STIPPLE_PATTERN), + .base = 1); + nir_store_var(&b, stipple_pattern, pattern, 1); + } + + nir_lower_aaline_fs(shader, &dummy, stipple_counter, stipple_pattern); + return true; +} + static bool lower_dual_blend(nir_shader *shader) { @@ -663,6 +1237,80 @@ lower_fbfetch(nir_shader *shader, nir_variable **fbfetch, bool ms) return nir_shader_instructions_pass(shader, lower_fbfetch_instr, nir_metadata_dominance, (void*)ms); } +/* + * Add a check for out of bounds LOD for every texel fetch op + * It boils down to: + * - if (lod < query_levels(tex)) + * - res = txf(tex) + * - else + * - res = (0, 0, 0, 1) + */ +static bool +lower_txf_lod_robustness_instr(nir_builder *b, nir_instr *in, void *data) +{ + if (in->type != nir_instr_type_tex) + return false; + nir_tex_instr *txf = nir_instr_as_tex(in); + if (txf->op != nir_texop_txf) + return false; + + b->cursor = nir_before_instr(in); + int lod_idx = nir_tex_instr_src_index(txf, nir_tex_src_lod); + assert(lod_idx >= 0); + nir_src lod_src = txf->src[lod_idx].src; + if (nir_src_is_const(lod_src) && nir_src_as_const_value(lod_src)->u32 == 0) + return false; + + assert(lod_src.is_ssa); + nir_ssa_def *lod = lod_src.ssa; + + int offset_idx = nir_tex_instr_src_index(txf, nir_tex_src_texture_offset); + int handle_idx = nir_tex_instr_src_index(txf, nir_tex_src_texture_handle); + nir_tex_instr *levels = nir_tex_instr_create(b->shader, + !!(offset_idx >= 0) + !!(handle_idx >= 0)); + levels->op = nir_texop_query_levels; + levels->texture_index = txf->texture_index; + levels->dest_type = nir_type_int | lod->bit_size; + if (offset_idx >= 0) { + levels->src[0].src_type = nir_tex_src_texture_offset; + nir_src_copy(&levels->src[0].src, &txf->src[offset_idx].src, &levels->instr); + } + if (handle_idx >= 0) { + levels->src[!!(offset_idx >= 0)].src_type = nir_tex_src_texture_handle; + nir_src_copy(&levels->src[!!(offset_idx >= 0)].src, &txf->src[handle_idx].src, &levels->instr); + } + nir_ssa_dest_init(&levels->instr, &levels->dest, + nir_tex_instr_dest_size(levels), 32, NULL); + nir_builder_instr_insert(b, &levels->instr); + + nir_if *lod_oob_if = nir_push_if(b, nir_ilt(b, lod, &levels->dest.ssa)); + nir_tex_instr *new_txf = nir_instr_as_tex(nir_instr_clone(b->shader, in)); + nir_builder_instr_insert(b, &new_txf->instr); + + nir_if *lod_oob_else = nir_push_else(b, lod_oob_if); + nir_const_value oob_values[4] = {0}; + unsigned bit_size = nir_alu_type_get_type_size(txf->dest_type); + oob_values[3] = (txf->dest_type & nir_type_float) ? + nir_const_value_for_float(1.0, bit_size) : nir_const_value_for_uint(1, bit_size); + nir_ssa_def *oob_val = nir_build_imm(b, nir_tex_instr_dest_size(txf), bit_size, oob_values); + + nir_pop_if(b, lod_oob_else); + nir_ssa_def *robust_txf = nir_if_phi(b, &new_txf->dest.ssa, oob_val); + + nir_ssa_def_rewrite_uses(&txf->dest.ssa, robust_txf); + nir_instr_remove_v(in); + return true; +} + +/* This pass is used to workaround the lack of out of bounds LOD robustness + * for texel fetch ops in VK_EXT_image_robustness. + */ +static bool +lower_txf_lod_robustness(nir_shader *shader) +{ + return nir_shader_instructions_pass(shader, lower_txf_lod_robustness_instr, nir_metadata_none, NULL); +} + /* check for a genuine gl_PointSize output vs one from nir_lower_point_size_mov */ static bool check_psiz(struct nir_shader *s) @@ -1429,7 +2077,8 @@ clamp_layer_output_instr(nir_builder *b, nir_instr *instr, void *data) switch (instr->type) { case nir_instr_type_intrinsic: { nir_intrinsic_instr *intr = nir_instr_as_intrinsic(instr); - if (intr->intrinsic != nir_intrinsic_emit_vertex_with_counter) + if (intr->intrinsic != nir_intrinsic_emit_vertex_with_counter && + intr->intrinsic != nir_intrinsic_emit_vertex) return false; b->cursor = nir_before_instr(instr); clamp_layer_output_emit(b, state); @@ -2205,6 +2854,7 @@ prune_io(nir_shader *nir) if (!find_var_deref(nir, var)) var->data.mode = nir_var_shader_temp; } + NIR_PASS_V(nir, nir_remove_dead_variables, nir_var_shader_temp, NULL); } static bool @@ -2233,8 +2883,173 @@ invert_point_coord(nir_shader *nir) return nir_shader_instructions_pass(nir, invert_point_coord_instr, nir_metadata_dominance, NULL); } +static void +flag_shadow_tex(nir_variable *var, struct zink_shader *zs) +{ + /* unconvert from zink_binding() */ + uint32_t sampler_id = var->data.binding - (PIPE_MAX_SAMPLERS * MESA_SHADER_FRAGMENT); + assert(sampler_id < 32); //bitfield size for tracking + zs->fs.legacy_shadow_mask |= BITFIELD_BIT(sampler_id); +} + +static nir_ssa_def * +rewrite_tex_dest(nir_builder *b, nir_tex_instr *tex, nir_variable *var, void *data) +{ + assert(var); + const struct glsl_type *type = glsl_without_array(var->type); + enum glsl_base_type ret_type = glsl_get_sampler_result_type(type); + bool is_int = glsl_base_type_is_integer(ret_type); + unsigned bit_size = glsl_base_type_get_bit_size(ret_type); + unsigned dest_size = nir_dest_bit_size(tex->dest); + b->cursor = nir_after_instr(&tex->instr); + unsigned num_components = nir_dest_num_components(tex->dest); + bool rewrite_depth = tex->is_shadow && num_components > 1 && tex->op != nir_texop_tg4 && !tex->is_sparse; + if (bit_size == dest_size && !rewrite_depth) + return NULL; + nir_ssa_def *dest = &tex->dest.ssa; + if (rewrite_depth && data) { + if (b->shader->info.stage == MESA_SHADER_FRAGMENT) + flag_shadow_tex(var, data); + else + mesa_loge("unhandled old-style shadow sampler in non-fragment stage!"); + return NULL; + } + if (bit_size != dest_size) { + tex->dest.ssa.bit_size = bit_size; + tex->dest_type = nir_get_nir_type_for_glsl_base_type(ret_type); + + if (is_int) { + if (glsl_unsigned_base_type_of(ret_type) == ret_type) + dest = nir_u2uN(b, &tex->dest.ssa, dest_size); + else + dest = nir_i2iN(b, &tex->dest.ssa, dest_size); + } else { + dest = nir_f2fN(b, &tex->dest.ssa, dest_size); + } + if (rewrite_depth) + return dest; + nir_ssa_def_rewrite_uses_after(&tex->dest.ssa, dest, dest->parent_instr); + } else if (rewrite_depth) { + return dest; + } + return dest; +} + +struct lower_zs_swizzle_state { + bool shadow_only; + unsigned base_sampler_id; + const struct zink_zs_swizzle_key *swizzle; +}; + +static bool +lower_zs_swizzle_tex_instr(nir_builder *b, nir_instr *instr, void *data) +{ + struct lower_zs_swizzle_state *state = data; + const struct zink_zs_swizzle_key *swizzle_key = state->swizzle; + assert(state->shadow_only || swizzle_key); + if (instr->type != nir_instr_type_tex) + return false; + nir_tex_instr *tex = nir_instr_as_tex(instr); + if (tex->op == nir_texop_txs || tex->op == nir_texop_lod || + (!tex->is_shadow && state->shadow_only) || tex->is_new_style_shadow) + return false; + if (tex->is_shadow && tex->op == nir_texop_tg4) + /* Will not even try to emulate the shadow comparison */ + return false; + int handle = nir_tex_instr_src_index(tex, nir_tex_src_texture_handle); + nir_variable *var = NULL; + if (handle != -1) + /* gtfo bindless depth texture mode */ + return false; + nir_foreach_variable_with_modes(img, b->shader, nir_var_uniform) { + if (glsl_type_is_sampler(glsl_without_array(img->type))) { + unsigned size = glsl_type_is_array(img->type) ? glsl_get_aoa_size(img->type) : 1; + if (tex->texture_index >= img->data.driver_location && + tex->texture_index < img->data.driver_location + size) { + var = img; + break; + } + } + } + assert(var); + uint32_t sampler_id = var->data.binding - state->base_sampler_id; + const struct glsl_type *type = glsl_without_array(var->type); + enum glsl_base_type ret_type = glsl_get_sampler_result_type(type); + bool is_int = glsl_base_type_is_integer(ret_type); + unsigned num_components = nir_dest_num_components(tex->dest); + if (tex->is_shadow) + tex->is_new_style_shadow = true; + nir_ssa_def *dest = rewrite_tex_dest(b, tex, var, NULL); + assert(dest || !state->shadow_only); + if (!dest && !(swizzle_key->mask & BITFIELD_BIT(sampler_id))) + return false; + else if (!dest) + dest = &tex->dest.ssa; + else + tex->dest.ssa.num_components = 1; + if (swizzle_key && (swizzle_key->mask & BITFIELD_BIT(sampler_id))) { + /* these require manual swizzles */ + if (tex->op == nir_texop_tg4) { + assert(!tex->is_shadow); + nir_ssa_def *swizzle; + switch (swizzle_key->swizzle[sampler_id].s[tex->component]) { + case PIPE_SWIZZLE_0: + swizzle = nir_imm_zero(b, 4, nir_dest_bit_size(tex->dest)); + break; + case PIPE_SWIZZLE_1: + if (is_int) + swizzle = nir_imm_intN_t(b, 4, nir_dest_bit_size(tex->dest)); + else + swizzle = nir_imm_floatN_t(b, 4, nir_dest_bit_size(tex->dest)); + break; + default: + if (!tex->component) + return false; + tex->component = 0; + return true; + } + nir_ssa_def_rewrite_uses_after(dest, swizzle, swizzle->parent_instr); + return true; + } + nir_ssa_def *vec[4]; + for (unsigned i = 0; i < ARRAY_SIZE(vec); i++) { + switch (swizzle_key->swizzle[sampler_id].s[i]) { + case PIPE_SWIZZLE_0: + vec[i] = nir_imm_zero(b, 1, nir_dest_bit_size(tex->dest)); + break; + case PIPE_SWIZZLE_1: + if (is_int) + vec[i] = nir_imm_intN_t(b, 1, nir_dest_bit_size(tex->dest)); + else + vec[i] = nir_imm_floatN_t(b, 1, nir_dest_bit_size(tex->dest)); + break; + default: + vec[i] = dest->num_components == 1 ? dest : nir_channel(b, dest, i); + break; + } + } + nir_ssa_def *swizzle = nir_vec(b, vec, num_components); + nir_ssa_def_rewrite_uses_after(dest, swizzle, swizzle->parent_instr); + } else { + assert(tex->is_shadow); + nir_ssa_def *vec[4] = {dest, dest, dest, dest}; + nir_ssa_def *splat = nir_vec(b, vec, num_components); + nir_ssa_def_rewrite_uses_after(dest, splat, splat->parent_instr); + } + return true; +} + +static bool +lower_zs_swizzle_tex(nir_shader *nir, const void *swizzle, bool shadow_only) +{ + unsigned base_sampler_id = gl_shader_stage_is_compute(nir->info.stage) ? 0 : PIPE_MAX_SAMPLERS * nir->info.stage; + struct lower_zs_swizzle_state state = {shadow_only, base_sampler_id, swizzle}; + return nir_shader_instructions_pass(nir, lower_zs_swizzle_tex_instr, nir_metadata_dominance | nir_metadata_block_index, (void*)&state); +} + VkShaderModule -zink_shader_compile(struct zink_screen *screen, struct zink_shader *zs, nir_shader *base_nir, const struct zink_shader_key *key) +zink_shader_compile(struct zink_screen *screen, struct zink_shader *zs, + nir_shader *base_nir, const struct zink_shader_key *key, const void *extra_data) { VkShaderModule mod = VK_NULL_HANDLE; struct zink_shader_info *sinfo = &zs->sinfo; @@ -2253,9 +3068,10 @@ zink_shader_compile(struct zink_screen *screen, struct zink_shader *zs, nir_shad } /* TODO: use a separate mem ctx here for ralloc */ - switch (zs->nir->info.stage) { - case MESA_SHADER_VERTEX: { - if (!screen->optimal_keys) { + + if (!screen->optimal_keys) { + switch (zs->nir->info.stage) { + case MESA_SHADER_VERTEX: { uint32_t decomposed_attrs = 0, decomposed_attrs_without_w = 0; const struct zink_vs_key *vs_key = zink_vs_key(key); switch (vs_key->size) { @@ -2275,25 +3091,63 @@ zink_shader_compile(struct zink_screen *screen, struct zink_shader *zs, nir_shad } if (decomposed_attrs || decomposed_attrs_without_w) NIR_PASS_V(nir, decompose_attribs, decomposed_attrs, decomposed_attrs_without_w); + break; + } + + case MESA_SHADER_GEOMETRY: + if (zink_gs_key(key)->lower_line_stipple) { + NIR_PASS_V(nir, lower_line_stipple_gs); + NIR_PASS_V(nir, nir_lower_var_copies); + need_optimize = true; + } + + if (zink_gs_key(key)->lower_line_smooth) { + NIR_PASS_V(nir, lower_line_smooth_gs); + NIR_PASS_V(nir, nir_lower_var_copies); + need_optimize = true; + } + + if (zink_gs_key(key)->lower_gl_point) { + NIR_PASS_V(nir, lower_gl_point_gs); + need_optimize = true; + } + break; + + default: + break; } - FALLTHROUGH; } + + switch (zs->nir->info.stage) { + case MESA_SHADER_VERTEX: case MESA_SHADER_TESS_EVAL: case MESA_SHADER_GEOMETRY: if (zink_vs_key_base(key)->last_vertex_stage) { if (zs->sinfo.have_xfb) sinfo->last_vertex = true; - if (!zink_vs_key_base(key)->clip_halfz && screen->driver_workarounds.depth_clip_control_missing) { + if (!zink_vs_key_base(key)->clip_halfz && !screen->info.have_EXT_depth_clip_control) { NIR_PASS_V(nir, nir_lower_clip_halfz); } if (zink_vs_key_base(key)->push_drawid) { NIR_PASS_V(nir, lower_drawid); } } + if (zink_vs_key_base(key)->robust_access) + NIR_PASS(need_optimize, nir, lower_txf_lod_robustness); break; case MESA_SHADER_FRAGMENT: - if (!zink_fs_key(key)->samples && + if (zink_fs_key(key)->lower_line_smooth) { + NIR_PASS_V(nir, lower_line_smooth_fs, + zink_fs_key(key)->lower_line_stipple); + need_optimize = true; + } else if (zink_fs_key(key)->lower_line_stipple) + NIR_PASS_V(nir, lower_line_stipple_fs); + + if (zink_fs_key(key)->robust_access) + NIR_PASS(need_optimize, nir, lower_txf_lod_robustness); + + if (!zink_fs_key_base(key)->samples && nir->info.outputs_written & BITFIELD64_BIT(FRAG_RESULT_SAMPLE_MASK)) { /* VK will always use gl_SampleMask[] values even if sample count is 0, * so we need to skip this write here to mimic GL's behavior of ignoring it @@ -2306,22 +3160,24 @@ zink_shader_compile(struct zink_screen *screen, struct zink_shader *zs, nir_shad NIR_PASS_V(nir, nir_remove_dead_variables, nir_var_shader_temp, NULL); need_optimize = true; } - if (zink_fs_key(key)->force_dual_color_blend && nir->info.outputs_written & BITFIELD64_BIT(FRAG_RESULT_DATA1)) { + if (zink_fs_key_base(key)->force_dual_color_blend && nir->info.outputs_written & BITFIELD64_BIT(FRAG_RESULT_DATA1)) { NIR_PASS_V(nir, lower_dual_blend); } - if (zink_fs_key(key)->coord_replace_bits) - NIR_PASS_V(nir, nir_lower_texcoord_replace, zink_fs_key(key)->coord_replace_bits, false, false); - if (zink_fs_key(key)->point_coord_yinvert) + if (zink_fs_key_base(key)->coord_replace_bits) + NIR_PASS_V(nir, nir_lower_texcoord_replace, zink_fs_key_base(key)->coord_replace_bits, false, false); + if (zink_fs_key_base(key)->point_coord_yinvert) NIR_PASS_V(nir, invert_point_coord); - if (zink_fs_key(key)->force_persample_interp || zink_fs_key(key)->fbfetch_ms) { + if (zink_fs_key_base(key)->force_persample_interp || zink_fs_key_base(key)->fbfetch_ms) { nir_foreach_shader_in_variable(var, nir) var->data.sample = true; nir->info.fs.uses_sample_qualifier = true; nir->info.fs.uses_sample_shading = true; } + if (zs->fs.legacy_shadow_mask && !key->base.needs_zs_shader_swizzle) + NIR_PASS(need_optimize, nir, lower_zs_swizzle_tex, zink_fs_key_base(key)->shadow_needs_shader_swizzle ? extra_data : NULL, true); if (nir->info.fs.uses_fbfetch_output) { nir_variable *fbfetch = NULL; - NIR_PASS_V(nir, lower_fbfetch, &fbfetch, zink_fs_key(key)->fbfetch_ms); + NIR_PASS_V(nir, lower_fbfetch, &fbfetch, zink_fs_key_base(key)->fbfetch_ms); /* old variable must be deleted to avoid spirv errors */ fbfetch->data.mode = nir_var_shader_temp; nir_fixup_deref_modes(nir); @@ -2338,8 +3194,16 @@ zink_shader_compile(struct zink_screen *screen, struct zink_shader *zs, nir_shad need_optimize = true; } break; + case MESA_SHADER_COMPUTE: + if (zink_cs_key(key)->robust_access) + NIR_PASS(need_optimize, nir, lower_txf_lod_robustness); + break; default: break; } + if (key->base.needs_zs_shader_swizzle) { + assert(extra_data); + NIR_PASS(need_optimize, nir, lower_zs_swizzle_tex, extra_data, false); + } if (key->base.nonseamless_cube_mask) { NIR_PASS_V(nir, zink_lower_cubemap_to_array, key->base.nonseamless_cube_mask); need_optimize = true; @@ -2374,7 +3238,7 @@ zink_shader_compile(struct zink_screen *screen, struct zink_shader *zs, nir_shad ralloc_free(nir); /* TODO: determine if there's any reason to cache spirv output? */ - if (zs->nir->info.stage == MESA_SHADER_TESS_CTRL && zs->tcs.is_generated) + if (zs->nir->info.stage == MESA_SHADER_TESS_CTRL && zs->non_fs.is_generated) zs->spirv = spirv; else ralloc_free(spirv); @@ -3084,55 +3948,13 @@ match_tex_dests_instr(nir_builder *b, nir_instr *in, void *data) } } } - assert(var); - const struct glsl_type *type = glsl_without_array(var->type); - enum glsl_base_type ret_type = glsl_get_sampler_result_type(type); - bool is_int = glsl_base_type_is_integer(ret_type); - unsigned bit_size = glsl_base_type_get_bit_size(ret_type); - unsigned dest_size = nir_dest_bit_size(tex->dest); - b->cursor = nir_after_instr(in); - unsigned num_components = nir_dest_num_components(tex->dest); - bool rewrite_depth = tex->is_shadow && num_components > 1 && tex->op != nir_texop_tg4 && !tex->is_sparse; - if (bit_size == dest_size && !rewrite_depth) - return false; - nir_ssa_def *dest = &tex->dest.ssa; - if (bit_size != dest_size) { - tex->dest.ssa.bit_size = bit_size; - tex->dest_type = nir_get_nir_type_for_glsl_base_type(ret_type); - if (rewrite_depth) { - assert(!tex->is_new_style_shadow); - tex->dest.ssa.num_components = 1; - tex->is_new_style_shadow = true; - } - - if (is_int) { - if (glsl_unsigned_base_type_of(ret_type) == ret_type) - dest = nir_u2uN(b, &tex->dest.ssa, dest_size); - else - dest = nir_i2iN(b, &tex->dest.ssa, dest_size); - } else { - dest = nir_f2fN(b, &tex->dest.ssa, dest_size); - } - if (rewrite_depth) { - nir_ssa_def *vec[4] = {dest, dest, dest, dest}; - dest = nir_vec(b, vec, num_components); - } - nir_ssa_def_rewrite_uses_after(&tex->dest.ssa, dest, dest->parent_instr); - } else if (rewrite_depth) { - assert(!tex->is_new_style_shadow); - tex->dest.ssa.num_components = 1; - tex->is_new_style_shadow = true; - nir_ssa_def *vec[4] = {dest, dest, dest, dest}; - nir_ssa_def *splat = nir_vec(b, vec, num_components); - nir_ssa_def_rewrite_uses_after(dest, splat, splat->parent_instr); - } - return true; + return !!rewrite_tex_dest(b, tex, var, data); } static bool -match_tex_dests(nir_shader *shader) +match_tex_dests(nir_shader *shader, struct zink_shader *zs) { - return nir_shader_instructions_pass(shader, match_tex_dests_instr, nir_metadata_dominance, NULL); + return nir_shader_instructions_pass(shader, match_tex_dests_instr, nir_metadata_dominance, zs); } static bool @@ -3394,7 +4216,7 @@ struct zink_shader * zink_shader_create(struct zink_screen *screen, struct nir_shader *nir, const struct pipe_stream_output_info *so_info) { - struct zink_shader *ret = CALLOC_STRUCT(zink_shader); + struct zink_shader *ret = rzalloc(NULL, struct zink_shader); bool have_psiz = false; ret->sinfo.have_vulkan_memory_model = screen->info.have_KHR_vulkan_memory_model; @@ -3586,7 +4408,7 @@ zink_shader_create(struct zink_screen *screen, struct nir_shader *nir, if (!screen->info.feats.features.shaderInt64 || !screen->info.feats.features.shaderFloat64) NIR_PASS_V(nir, lower_64bit_vars, screen->info.feats.features.shaderInt64); if (nir->info.stage != MESA_SHADER_KERNEL) - NIR_PASS_V(nir, match_tex_dests); + NIR_PASS_V(nir, match_tex_dests, ret); ret->nir = nir; nir_foreach_shader_out_variable(var, nir) @@ -3637,8 +4459,6 @@ zink_shader_finalize(struct pipe_screen *pscreen, void *nirptr) if (!screen->info.feats.features.shaderImageGatherExtended) tex_opts.lower_tg4_offsets = true; NIR_PASS_V(nir, nir_lower_tex, &tex_opts); - if (nir->info.stage == MESA_SHADER_GEOMETRY) - NIR_PASS_V(nir, nir_lower_gs_intrinsics, nir_lower_gs_intrinsics_per_stream); optimize_nir(nir, NULL); nir_shader_gather_info(nir, nir_shader_get_entrypoint(nir)); if (screen->driconf.inline_uniforms) @@ -3656,10 +4476,10 @@ zink_shader_free(struct zink_screen *screen, struct zink_shader *shader) gl_shader_stage stage = shader->nir->info.stage; assert(stage < ZINK_GFX_SHADER_COUNT); if (!prog->base.removed && prog->stages_present == prog->stages_remaining && - (stage != MESA_SHADER_TESS_CTRL || !shader->tcs.is_generated)) { + (stage == MESA_SHADER_FRAGMENT || !shader->non_fs.is_generated)) { unsigned stages_present = prog->stages_present; if (prog->shaders[MESA_SHADER_TESS_CTRL] && - prog->shaders[MESA_SHADER_TESS_CTRL]->tcs.is_generated) + prog->shaders[MESA_SHADER_TESS_CTRL]->non_fs.is_generated) stages_present &= ~BITFIELD_BIT(MESA_SHADER_TESS_CTRL); unsigned idx = zink_program_cache_stages(stages_present); struct hash_table *ht = &prog->ctx->program_cache[idx]; @@ -3671,25 +4491,33 @@ zink_shader_free(struct zink_screen *screen, struct zink_shader *shader) simple_mtx_unlock(&prog->ctx->program_lock[idx]); util_queue_fence_wait(&prog->base.cache_fence); } - if (stage != MESA_SHADER_TESS_CTRL || !shader->tcs.is_generated) { + if (stage == MESA_SHADER_FRAGMENT || !shader->non_fs.is_generated) { prog->shaders[stage] = NULL; prog->stages_remaining &= ~BITFIELD_BIT(stage); } /* only remove generated tcs during parent tes destruction */ - if (stage == MESA_SHADER_TESS_EVAL && shader->tes.generated) + if (stage == MESA_SHADER_TESS_EVAL && shader->non_fs.generated_tcs) prog->shaders[MESA_SHADER_TESS_CTRL] = NULL; + if (stage != MESA_SHADER_FRAGMENT && shader->non_fs.generated_gs) + prog->shaders[MESA_SHADER_GEOMETRY] = NULL; zink_gfx_program_reference(screen, &prog, NULL); } if (shader->nir->info.stage == MESA_SHADER_TESS_EVAL && - shader->tes.generated) { + shader->non_fs.generated_tcs) { /* automatically destroy generated tcs shaders when tes is destroyed */ - zink_shader_free(screen, shader->tes.generated); - shader->tes.generated = NULL; + zink_shader_free(screen, shader->non_fs.generated_tcs); + shader->non_fs.generated_tcs = NULL; + } + if (shader->nir->info.stage != MESA_SHADER_FRAGMENT && + shader->non_fs.generated_gs) { + /* automatically destroy generated gs shaders when owner is destroyed */ + zink_shader_free(screen, shader->non_fs.generated_gs); + shader->non_fs.generated_gs = NULL; } _mesa_set_destroy(shader->programs, NULL); ralloc_free(shader->nir); ralloc_free(shader->spirv); - FREE(shader); + ralloc_free(shader); } @@ -3726,7 +4554,7 @@ void main() struct zink_shader * zink_shader_tcs_create(struct zink_screen *screen, struct zink_shader *vs, unsigned vertices_per_patch) { - struct zink_shader *ret = CALLOC_STRUCT(zink_shader); + struct zink_shader *ret = rzalloc(NULL, struct zink_shader); ret->hash = _mesa_hash_pointer(ret); ret->programs = _mesa_pointer_set_create(NULL); simple_mtx_init(&ret->lock, mtx_plain); @@ -3803,7 +4631,7 @@ zink_shader_tcs_create(struct zink_screen *screen, struct zink_shader *vs, unsig NIR_PASS_V(nir, nir_convert_from_ssa, true); ret->nir = nir; - ret->tcs.is_generated = true; + ret->non_fs.is_generated = true; return ret; } diff --git a/src/gallium/drivers/zink/zink_compiler.h b/src/gallium/drivers/zink/zink_compiler.h index 1572aa3..a1c894d 100644 --- a/src/gallium/drivers/zink/zink_compiler.h +++ b/src/gallium/drivers/zink/zink_compiler.h @@ -59,8 +59,9 @@ void zink_screen_init_compiler(struct zink_screen *screen); void zink_compiler_assign_io(struct zink_screen *screen, nir_shader *producer, nir_shader *consumer); +/* pass very large shader key data with extra_data */ VkShaderModule -zink_shader_compile(struct zink_screen *screen, struct zink_shader *zs, nir_shader *nir, const struct zink_shader_key *key); +zink_shader_compile(struct zink_screen *screen, struct zink_shader *zs, nir_shader *nir, const struct zink_shader_key *key, const void *extra_data); VkShaderModule zink_shader_spirv_compile(struct zink_screen *screen, struct zink_shader *zs, struct spirv_shader *spirv); struct zink_shader * diff --git a/src/gallium/drivers/zink/zink_context.c b/src/gallium/drivers/zink/zink_context.c index 7c8cec2..6326c21 100644 --- a/src/gallium/drivers/zink/zink_context.c +++ b/src/gallium/drivers/zink/zink_context.c @@ -521,9 +521,15 @@ get_imageview_for_binding(struct zink_context *ctx, gl_shader_stage stage, enum if (!sampler_view || !sampler_view->base.texture) return NULL; /* if this is a non-seamless cube sampler, return the cube array view */ - return (ctx->di.emulate_nonseamless[stage] & ctx->di.cubes[stage] & BITFIELD_BIT(idx)) ? - sampler_view->cube_array : - sampler_view->image_view; + if (ctx->di.emulate_nonseamless[stage] & ctx->di.cubes[stage] & BITFIELD_BIT(idx)) + return sampler_view->cube_array; + bool needs_zs_shader_swizzle = (ctx->di.zs_swizzle[stage].mask & BITFIELD_BIT(idx)) && + zink_screen(ctx->base.screen)->driver_workarounds.needs_zs_shader_swizzle; + bool needs_shadow_shader_swizzle = (stage == MESA_SHADER_FRAGMENT) && ctx->gfx_stages[MESA_SHADER_FRAGMENT] && + (ctx->di.zs_swizzle[MESA_SHADER_FRAGMENT].mask & ctx->gfx_stages[MESA_SHADER_FRAGMENT]->fs.legacy_shadow_mask & BITFIELD_BIT(idx)); + if (sampler_view->zs_view && (needs_zs_shader_swizzle || needs_shadow_shader_swizzle)) + return sampler_view->zs_view; + return sampler_view->image_view; } case ZINK_DESCRIPTOR_TYPE_IMAGE: { struct zink_image_view *image_view = &ctx->image_views[stage][idx]; @@ -644,6 +650,13 @@ update_descriptor_state_sampler(struct zink_context *ctx, gl_shader_stage shader return res; } +void +zink_update_shadow_samplerviews(struct zink_context *ctx, unsigned mask) +{ + u_foreach_bit(slot, mask) + update_descriptor_state_sampler(ctx, MESA_SHADER_FRAGMENT, slot, ctx->di.descriptor_res[ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW][MESA_SHADER_FRAGMENT][slot]); +} + ALWAYS_INLINE static struct zink_resource * update_descriptor_state_image(struct zink_context *ctx, gl_shader_stage shader, unsigned slot, struct zink_resource *res) { @@ -964,25 +977,27 @@ zink_create_sampler_view(struct pipe_context *pctx, struct pipe_resource *pres, ivci = create_ivci(screen, res, &templ, state->target); ivci.subresourceRange.levelCount = state->u.tex.last_level - state->u.tex.first_level + 1; ivci.subresourceRange.aspectMask = sampler_aspect_from_format(state->format); + bool shadow_needs_shader_swizzle = false; /* samplers for stencil aspects of packed formats need to always use stencil swizzle */ if (ivci.subresourceRange.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) { - if (sampler_view->base.swizzle_r == PIPE_SWIZZLE_0 && - sampler_view->base.swizzle_g == PIPE_SWIZZLE_0 && - sampler_view->base.swizzle_b == PIPE_SWIZZLE_0 && - sampler_view->base.swizzle_a == PIPE_SWIZZLE_X) { - /* - * When the state tracker asks for 000x swizzles, this is depth mode GL_ALPHA, - * however with the single dref fetch this will fail, so just spam all the channels. - */ - ivci.components.r = VK_COMPONENT_SWIZZLE_R; - ivci.components.g = VK_COMPONENT_SWIZZLE_R; - ivci.components.b = VK_COMPONENT_SWIZZLE_R; - ivci.components.a = VK_COMPONENT_SWIZZLE_R; - } else { - ivci.components.r = zink_component_mapping(clamp_zs_swizzle(sampler_view->base.swizzle_r)); - ivci.components.g = zink_component_mapping(clamp_zs_swizzle(sampler_view->base.swizzle_g)); - ivci.components.b = zink_component_mapping(clamp_zs_swizzle(sampler_view->base.swizzle_b)); - ivci.components.a = zink_component_mapping(clamp_zs_swizzle(sampler_view->base.swizzle_a)); + ivci.components.r = zink_component_mapping(clamp_zs_swizzle(sampler_view->base.swizzle_r)); + ivci.components.g = zink_component_mapping(clamp_zs_swizzle(sampler_view->base.swizzle_g)); + ivci.components.b = zink_component_mapping(clamp_zs_swizzle(sampler_view->base.swizzle_b)); + ivci.components.a = zink_component_mapping(clamp_zs_swizzle(sampler_view->base.swizzle_a)); + if (ivci.subresourceRange.aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT || + zink_screen(ctx->base.screen)->driver_workarounds.needs_zs_shader_swizzle) { + VkComponentSwizzle *swizzle = (VkComponentSwizzle*)&ivci.components; + for (unsigned i = 0; i < 4; i++) { + /* these require shader rewrites to correctly emulate */ + if (swizzle[i] == VK_COMPONENT_SWIZZLE_ONE || + (swizzle[i] == VK_COMPONENT_SWIZZLE_ZERO && ivci.subresourceRange.aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT)) + shadow_needs_shader_swizzle = true; + } + /* this is the data that will be used in shader rewrites */ + sampler_view->swizzle.s[0] = clamp_zs_swizzle(sampler_view->base.swizzle_r); + sampler_view->swizzle.s[1] = clamp_zs_swizzle(sampler_view->base.swizzle_g); + sampler_view->swizzle.s[2] = clamp_zs_swizzle(sampler_view->base.swizzle_b); + sampler_view->swizzle.s[3] = clamp_zs_swizzle(sampler_view->base.swizzle_a); } } else { enum pipe_swizzle swizzle[4] = { @@ -1039,6 +1054,15 @@ zink_create_sampler_view(struct pipe_context *pctx, struct pipe_resource *pres, if (!screen->info.have_EXT_non_seamless_cube_map && viewtype_is_cube(&sampler_view->image_view->ivci)) { ivci.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; sampler_view->cube_array = (struct zink_surface*)zink_get_surface(ctx, pres, &templ, &ivci); + } else if (shadow_needs_shader_swizzle) { + /* there is only one component, and real swizzling can't be done here, + * so ensure the shader gets the sampled data + */ + ivci.components.r = VK_COMPONENT_SWIZZLE_R; + ivci.components.g = VK_COMPONENT_SWIZZLE_R; + ivci.components.b = VK_COMPONENT_SWIZZLE_R; + ivci.components.a = VK_COMPONENT_SWIZZLE_R; + sampler_view->zs_view = (struct zink_surface*)zink_get_surface(ctx, pres, &templ, &ivci); } err = !sampler_view->image_view; } else { @@ -1084,6 +1108,7 @@ zink_sampler_view_destroy(struct pipe_context *pctx, else { zink_surface_reference(zink_screen(pctx->screen), &view->image_view, NULL); zink_surface_reference(zink_screen(pctx->screen), &view->cube_array, NULL); + zink_surface_reference(zink_screen(pctx->screen), &view->zs_view, NULL); } pipe_resource_reference(&pview->texture, NULL); FREE_CL(view); @@ -1809,6 +1834,8 @@ unbind_samplerview(struct zink_context *ctx, gl_shader_stage stage, unsigned slo unbind_descriptor_stage(res, stage); unbind_descriptor_reads(res, stage); } + assert(slot < 32); + ctx->di.zs_swizzle[stage].mask &= ~BITFIELD_BIT(slot); } static void @@ -1824,9 +1851,11 @@ zink_set_sampler_views(struct pipe_context *pctx, unsigned i; const uint32_t mask = BITFIELD_RANGE(start_slot, num_views); + uint32_t shadow_mask = ctx->di.zs_swizzle[shader_type].mask; ctx->di.cubes[shader_type] &= ~mask; bool update = false; + bool shadow_update = false; for (i = 0; i < num_views; ++i) { struct pipe_sampler_view *pview = views ? views[i] : NULL; struct zink_sampler_view *a = zink_sampler_view(ctx->sampler_views[shader_type][start_slot + i]); @@ -1860,27 +1889,38 @@ zink_set_sampler_views(struct pipe_context *pctx, res->gfx_barrier); zink_batch_resource_usage_set(&ctx->batch, res, false, true); } else if (!res->obj->is_buffer) { - if (res->base.b.format != b->image_view->base.format) - /* mutable not set by default */ - zink_resource_object_init_mutable(ctx, res); - if (res->obj != b->image_view->obj) { - struct pipe_surface *psurf = &b->image_view->base; - VkImageView iv = b->image_view->image_view; - zink_rebind_surface(ctx, &psurf); - b->image_view = zink_surface(psurf); - update |= iv != b->image_view->image_view; - } else if (a != b) - update = true; - if (shader_type == MESA_SHADER_COMPUTE) - flush_pending_clears(ctx, res); - if (b->cube_array) { - ctx->di.cubes[shader_type] |= BITFIELD_BIT(start_slot + i); - } - check_for_layout_update(ctx, res, shader_type == MESA_SHADER_COMPUTE); - if (!a) - update = true; - zink_batch_resource_usage_set(&ctx->batch, res, false, false); - res->obj->unordered_write = false; + if (res->base.b.format != b->image_view->base.format) + /* mutable not set by default */ + zink_resource_object_init_mutable(ctx, res); + if (res->obj != b->image_view->obj) { + struct pipe_surface *psurf = &b->image_view->base; + VkImageView iv = b->image_view->image_view; + zink_rebind_surface(ctx, &psurf); + b->image_view = zink_surface(psurf); + update |= iv != b->image_view->image_view; + } else if (a != b) + update = true; + if (shader_type == MESA_SHADER_COMPUTE) + flush_pending_clears(ctx, res); + if (b->cube_array) { + ctx->di.cubes[shader_type] |= BITFIELD_BIT(start_slot + i); + } + check_for_layout_update(ctx, res, shader_type == MESA_SHADER_COMPUTE); + if (!a) + update = true; + zink_batch_resource_usage_set(&ctx->batch, res, false, false); + res->obj->unordered_write = false; + if (b->zs_view) { + assert(start_slot + i < 32); //bitfield size + ctx->di.zs_swizzle[shader_type].mask |= BITFIELD_BIT(start_slot + i); + /* this is already gonna be slow, so don't bother trying to micro-optimize */ + shadow_update |= memcmp(&ctx->di.zs_swizzle[shader_type].swizzle[start_slot + i], + &b->swizzle, sizeof(struct zink_zs_swizzle)); + memcpy(&ctx->di.zs_swizzle[shader_type].swizzle[start_slot + i], &b->swizzle, sizeof(struct zink_zs_swizzle)); + } else { + assert(start_slot + i < 32); //bitfield size + ctx->di.zs_swizzle[shader_type].mask &= ~BITFIELD_BIT(start_slot + i); + } } res->sampler_binds[shader_type] |= BITFIELD_BIT(start_slot + i); res->obj->unordered_read = false; @@ -1910,6 +1950,8 @@ zink_set_sampler_views(struct pipe_context *pctx, zink_context_invalidate_descriptor_state(ctx, shader_type, ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW, start_slot, num_views); if (!screen->info.have_EXT_non_seamless_cube_map) update_nonseamless_shader_key(ctx, shader_type); + shadow_update |= shadow_mask != ctx->di.zs_swizzle[shader_type].mask; + zink_set_zs_needs_shader_swizzle_key(ctx, shader_type, shadow_update); } } @@ -2243,8 +2285,8 @@ zink_update_fbfetch(struct zink_context *ctx) ctx->di.fbfetch.imageView = zink_csurface(ctx->fb_state.cbufs[0])->image_view; bool fbfetch_ms = ctx->fb_state.cbufs[0]->texture->nr_samples > 1; - if (zink_get_fs_key(ctx)->fbfetch_ms != fbfetch_ms) - zink_set_fs_key(ctx)->fbfetch_ms = fbfetch_ms; + if (zink_get_fs_base_key(ctx)->fbfetch_ms != fbfetch_ms) + zink_set_fs_base_key(ctx)->fbfetch_ms = fbfetch_ms; } ctx->di.fbfetch.imageLayout = VK_IMAGE_LAYOUT_GENERAL; if (changed) { @@ -2301,7 +2343,9 @@ begin_rendering(struct zink_context *ctx) unsigned clear_buffers = 0; ctx->gfx_pipeline_state.render_pass = NULL; zink_update_vk_sample_locations(ctx); - zink_render_update_swapchain(ctx); + bool has_swapchain = zink_render_update_swapchain(ctx); + if (has_swapchain) + zink_render_fixup_swapchain(ctx); bool has_depth = false; bool has_stencil = false; bool changed_layout = false; @@ -2450,6 +2494,14 @@ begin_rendering(struct zink_context *ctx) return 0; ctx->dynamic_fb.attachments[i].imageView = iv; } + if (has_swapchain) { + struct zink_resource *res = zink_resource(ctx->fb_state.cbufs[0]->texture); + zink_render_fixup_swapchain(ctx); + assert(ctx->dynamic_fb.info.renderArea.extent.width <= res->base.b.width0); + assert(ctx->dynamic_fb.info.renderArea.extent.height <= res->base.b.height0); + assert(ctx->fb_state.width <= res->base.b.width0); + assert(ctx->fb_state.height <= res->base.b.height0); + } if (ctx->fb_state.zsbuf && zsbuf_used) { struct zink_surface *surf = zink_csurface(ctx->fb_state.zsbuf); VkImageView iv = zink_prep_fb_attachment(ctx, surf, ctx->fb_state.nr_cbufs); @@ -2458,6 +2510,8 @@ begin_rendering(struct zink_context *ctx) ctx->dynamic_fb.attachments[PIPE_MAX_COLOR_BUFS+1].imageView = iv; ctx->dynamic_fb.attachments[PIPE_MAX_COLOR_BUFS+1].imageLayout = zink_resource(surf->base.texture)->layout; } + assert(ctx->fb_state.width >= ctx->dynamic_fb.info.renderArea.extent.width); + assert(ctx->fb_state.height >= ctx->dynamic_fb.info.renderArea.extent.height); ctx->gfx_pipeline_state.dirty |= rp_changed; ctx->gfx_pipeline_state.rp_state = rp_state; @@ -2918,6 +2972,22 @@ zink_set_color_write_enables(struct zink_context *ctx) } } +static void +check_framebuffer_surface_mutable(struct pipe_context *pctx, struct pipe_surface *psurf) +{ + struct zink_context *ctx = zink_context(pctx); + struct zink_ctx_surface *csurf = (struct zink_ctx_surface *)psurf; + if (!csurf->needs_mutable) + return; + zink_resource_object_init_mutable(ctx, zink_resource(psurf->texture)); + struct pipe_surface *psurf2 = pctx->create_surface(pctx, psurf->texture, psurf); + pipe_resource_reference(&psurf2->texture, NULL); + struct zink_ctx_surface *csurf2 = (struct zink_ctx_surface *)psurf2; + zink_surface_reference(zink_screen(pctx->screen), &csurf->surf, csurf2->surf); + pctx->surface_destroy(pctx, psurf2); + csurf->needs_mutable = false; +} + static void zink_set_framebuffer_state(struct pipe_context *pctx, const struct pipe_framebuffer_state *state) @@ -2941,7 +3011,7 @@ zink_set_framebuffer_state(struct pipe_context *pctx, struct zink_surface *b = zink_csurface(state->cbufs[i]); if (a == b) continue; - if (memcmp(&a->base.u.tex, &b->base.u.tex, sizeof(b->base.u.tex)) || + if (!a || !b || memcmp(&a->base.u.tex, &b->base.u.tex, sizeof(b->base.u.tex)) || a->base.texture != b->base.texture) flush_clears = true; else if (a->base.format != b->base.format) @@ -3004,6 +3074,7 @@ zink_set_framebuffer_state(struct pipe_context *pctx, if (!samples) samples = MAX3(transient ? transient->base.nr_samples : 1, psurf->texture->nr_samples, 1); struct zink_resource *res = zink_resource(psurf->texture); + check_framebuffer_surface_mutable(pctx, psurf); if (zink_csurface(psurf)->info.layerCount > layers) ctx->fb_layer_mismatch |= BITFIELD_BIT(i); if (res->modifiers) { @@ -3033,6 +3104,7 @@ zink_set_framebuffer_state(struct pipe_context *pctx, if (ctx->fb_state.zsbuf) { struct pipe_surface *psurf = ctx->fb_state.zsbuf; struct zink_surface *transient = zink_transient_surface(psurf); + check_framebuffer_surface_mutable(pctx, psurf); if (transient) ctx->transient_attachments |= BITFIELD_BIT(PIPE_MAX_COLOR_BUFS); if (!samples) @@ -4356,7 +4428,8 @@ zink_copy_image_buffer(struct zink_context *ctx, struct zink_resource *dst, stru int aspect = 1 << u_bit_scan(&aspects); region.imageSubresource.aspectMask = aspect; - /* this may or may not work with multisampled depth/stencil buffers depending on the driver implementation: + /* MSAA transfers should have already been handled by U_TRANSFER_HELPER_MSAA_MAP, since + * there's no way to resolve using this interface: * * srcImage must have a sample count equal to VK_SAMPLE_COUNT_1_BIT * - vkCmdCopyImageToBuffer spec @@ -4364,6 +4437,7 @@ zink_copy_image_buffer(struct zink_context *ctx, struct zink_resource *dst, stru * dstImage must have a sample count equal to VK_SAMPLE_COUNT_1_BIT * - vkCmdCopyBufferToImage spec */ + assert(img->base.b.nr_samples <= 1); if (buf2img) VKCTX(CmdCopyBufferToImage)(cmdbuf, buf->obj->buffer, img->obj->image, img->layout, 1, ®ion); else @@ -4509,32 +4583,33 @@ zink_resource_commit(struct pipe_context *pctx, struct pipe_resource *pres, unsi static void rebind_image(struct zink_context *ctx, struct zink_resource *res) { - zink_rebind_framebuffer(ctx, res); - if (!zink_resource_has_binds(res)) - return; - for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { - if (res->sampler_binds[i]) { - for (unsigned j = 0; j < ctx->di.num_sampler_views[i]; j++) { - struct zink_sampler_view *sv = zink_sampler_view(ctx->sampler_views[i][j]); - if (sv && sv->base.texture == &res->base.b) { - struct pipe_surface *psurf = &sv->image_view->base; - zink_rebind_surface(ctx, &psurf); - sv->image_view = zink_surface(psurf); - zink_context_invalidate_descriptor_state(ctx, i, ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW, j, 1); - update_descriptor_state_sampler(ctx, i, j, res); - } - } - } - if (!res->image_bind_count[i == MESA_SHADER_COMPUTE]) - continue; - for (unsigned j = 0; j < ctx->di.num_images[i]; j++) { - if (zink_resource(ctx->image_views[i][j].base.resource) == res) { - zink_context_invalidate_descriptor_state(ctx, i, ZINK_DESCRIPTOR_TYPE_IMAGE, j, 1); - update_descriptor_state_image(ctx, i, j, res); - _mesa_set_add(ctx->need_barriers[i == MESA_SHADER_COMPUTE], res); - } - } - } + if (res->fb_binds) + zink_rebind_framebuffer(ctx, res); + if (!zink_resource_has_binds(res)) + return; + for (unsigned i = 0; i < MESA_SHADER_STAGES; i++) { + if (res->sampler_binds[i]) { + for (unsigned j = 0; j < ctx->di.num_sampler_views[i]; j++) { + struct zink_sampler_view *sv = zink_sampler_view(ctx->sampler_views[i][j]); + if (sv && sv->base.texture == &res->base.b) { + struct pipe_surface *psurf = &sv->image_view->base; + zink_rebind_surface(ctx, &psurf); + sv->image_view = zink_surface(psurf); + zink_context_invalidate_descriptor_state(ctx, i, ZINK_DESCRIPTOR_TYPE_SAMPLER_VIEW, j, 1); + update_descriptor_state_sampler(ctx, i, j, res); + } + } + } + if (!res->image_bind_count[i == MESA_SHADER_COMPUTE]) + continue; + for (unsigned j = 0; j < ctx->di.num_images[i]; j++) { + if (zink_resource(ctx->image_views[i][j].base.resource) == res) { + zink_context_invalidate_descriptor_state(ctx, i, ZINK_DESCRIPTOR_TYPE_IMAGE, j, 1); + update_descriptor_state_image(ctx, i, j, res); + _mesa_set_add(ctx->need_barriers[i == MESA_SHADER_COMPUTE], res); + } + } + } } bool @@ -4728,6 +4803,7 @@ zink_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags) struct zink_context *ctx = rzalloc(NULL, struct zink_context); bool is_copy_only = (flags & ZINK_CONTEXT_COPY_ONLY) > 0; bool is_compute_only = (flags & PIPE_CONTEXT_COMPUTE_ONLY) > 0; + bool is_robust = (flags & PIPE_CONTEXT_ROBUST_BUFFER_ACCESS) > 0; if (!ctx) goto fail; @@ -4843,8 +4919,19 @@ zink_context_create(struct pipe_screen *pscreen, void *priv, unsigned flags) ctx->gfx_pipeline_state.shader_keys.key[MESA_SHADER_VERTEX].size = sizeof(struct zink_vs_key_base); ctx->gfx_pipeline_state.shader_keys.key[MESA_SHADER_TESS_EVAL].size = sizeof(struct zink_vs_key_base); ctx->gfx_pipeline_state.shader_keys.key[MESA_SHADER_TESS_CTRL].size = sizeof(struct zink_tcs_key); - ctx->gfx_pipeline_state.shader_keys.key[MESA_SHADER_GEOMETRY].size = sizeof(struct zink_vs_key_base); + ctx->gfx_pipeline_state.shader_keys.key[MESA_SHADER_GEOMETRY].size = sizeof(struct zink_gs_key); ctx->gfx_pipeline_state.shader_keys.key[MESA_SHADER_FRAGMENT].size = sizeof(struct zink_fs_key); + + /* this condition must be updated if new fields are added to zink_cs_key */ + if (screen->driver_workarounds.lower_robustImageAccess2) + ctx->compute_pipeline_state.key.size = sizeof(struct zink_cs_key); + + if (is_robust && screen->driver_workarounds.lower_robustImageAccess2) { + ctx->compute_pipeline_state.key.key.cs.robust_access = true; + for (gl_shader_stage pstage = MESA_SHADER_VERTEX; pstage < MESA_SHADER_FRAGMENT; pstage++) + ctx->gfx_pipeline_state.shader_keys.key[pstage].key.vs_base.robust_access = true; + ctx->gfx_pipeline_state.shader_keys.key[MESA_SHADER_FRAGMENT].key.fs.robust_access = true; + } } _mesa_hash_table_init(&ctx->framebuffer_cache, ctx, hash_framebuffer_imageless, equals_framebuffer_imageless); if (!zink_init_render_pass(ctx)) diff --git a/src/gallium/drivers/zink/zink_context.h b/src/gallium/drivers/zink/zink_context.h index 3fd64a8..e20980a 100644 --- a/src/gallium/drivers/zink/zink_context.h +++ b/src/gallium/drivers/zink/zink_context.h @@ -211,6 +211,9 @@ zink_component_mapping(enum pipe_swizzle swizzle) } } +void +zink_update_shadow_samplerviews(struct zink_context *ctx, unsigned mask); + enum pipe_swizzle zink_clamp_void_swizzle(const struct util_format_description *desc, enum pipe_swizzle swizzle); diff --git a/src/gallium/drivers/zink/zink_descriptors.c b/src/gallium/drivers/zink/zink_descriptors.c index f8c8467..d6285ec 100644 --- a/src/gallium/drivers/zink/zink_descriptors.c +++ b/src/gallium/drivers/zink/zink_descriptors.c @@ -1042,15 +1042,9 @@ consolidate_pool_alloc(struct zink_screen *screen, struct zink_descriptor_pool_m if (!mpool->overflowed_pools[mpool->overflow_idx].size) return; - unsigned old_size = mpool->overflowed_pools[!mpool->overflow_idx].size; - if (util_dynarray_resize(&mpool->overflowed_pools[!mpool->overflow_idx], struct zink_descriptor_pool*, sizes[0] + sizes[1])) { - /* attempt to consolidate all the overflow into one array to maximize reuse */ - uint8_t *src = mpool->overflowed_pools[mpool->overflow_idx].data; - uint8_t *dst = mpool->overflowed_pools[!mpool->overflow_idx].data; - dst += old_size; - memcpy(dst, src, mpool->overflowed_pools[mpool->overflow_idx].size); - util_dynarray_clear(&mpool->overflowed_pools[mpool->overflow_idx]); - } + /* attempt to consolidate all the overflow into one array to maximize reuse */ + util_dynarray_append_dynarray(&mpool->overflowed_pools[!mpool->overflow_idx], &mpool->overflowed_pools[mpool->overflow_idx]); + util_dynarray_clear(&mpool->overflowed_pools[mpool->overflow_idx]); } /* called when a batch state is reset, i.e., just before a batch state becomes the current state */ diff --git a/src/gallium/drivers/zink/zink_device_info.py b/src/gallium/drivers/zink/zink_device_info.py index 86f3c8c..2847a16 100644 --- a/src/gallium/drivers/zink/zink_device_info.py +++ b/src/gallium/drivers/zink/zink_device_info.py @@ -60,39 +60,54 @@ import sys # - guard: adds a #if defined(`extension_name`)/#endif guard around the code generated for this Extension. EXTENSIONS = [ Extension("VK_KHR_maintenance1", - required=True), + required=True), Extension("VK_KHR_maintenance2"), Extension("VK_KHR_maintenance3"), - Extension("VK_KHR_maintenance4", alias="maint4", features=True), + Extension("VK_KHR_maintenance4", + alias="maint4", + features=True), Extension("VK_KHR_external_memory"), Extension("VK_KHR_external_memory_fd"), Extension("VK_KHR_vulkan_memory_model"), - Extension("VK_KHR_pipeline_executable_properties", alias="pipestats", features=True), + Extension("VK_KHR_pipeline_executable_properties", + alias="pipestats", + features=True), Extension("VK_KHR_external_semaphore_fd"), - Extension("VK_KHR_create_renderpass2", required=True), + Extension("VK_KHR_create_renderpass2", + required=True), Extension("VK_KHR_synchronization2", alias="sync2", features=True), Extension("VK_KHR_external_memory_win32"), Extension("VK_KHR_external_semaphore_win32"), Extension("VK_EXT_external_memory_dma_buf"), - Extension("VK_KHR_buffer_device_address", alias="bda", features=True), + Extension("VK_KHR_buffer_device_address", + alias="bda", + features=True), Extension("VK_EXT_queue_family_foreign"), Extension("VK_KHR_swapchain_mutable_format"), Extension("VK_EXT_provoking_vertex", - alias="pv", - features=True, - properties=True, - conditions=["$feats.provokingVertexLast"]), + alias="pv", + features=True, + properties=True, + conditions=["$feats.provokingVertexLast"]), Extension("VK_EXT_shader_viewport_index_layer"), Extension("VK_KHR_get_memory_requirements2"), Extension("VK_EXT_post_depth_coverage"), - Extension("VK_EXT_depth_clip_control", alias="clip_control", features=True), - Extension("VK_EXT_depth_clamp_zero_one", alias="clamp_01", features=True), + Extension("VK_EXT_depth_clip_control", + alias="clip_control", + features=True), + Extension("VK_EXT_depth_clamp_zero_one", + alias="clamp_01", + features=True), Extension("VK_EXT_shader_subgroup_ballot"), Extension("VK_EXT_shader_subgroup_vote"), - Extension("VK_EXT_shader_atomic_float", alias="atomic_float", features=True), - Extension("VK_KHR_shader_atomic_int64", alias="atomic_int", features=True), + Extension("VK_EXT_shader_atomic_float", + alias="atomic_float", + features=True), + Extension("VK_KHR_shader_atomic_int64", + alias="atomic_int", + features=True), Extension("VK_KHR_8bit_storage", alias="storage_8bit", features=True, @@ -105,56 +120,59 @@ EXTENSIONS = [ alias="view2d", features=True), Extension("VK_KHR_driver_properties", - alias="driver", - properties=True), + alias="driver", + properties=True), Extension("VK_EXT_memory_budget"), Extension("VK_KHR_draw_indirect_count"), Extension("VK_EXT_attachment_feedback_loop_layout", alias="feedback_loop", features=True), Extension("VK_EXT_fragment_shader_interlock", - alias="interlock", - features=True, - conditions=["$feats.fragmentShaderSampleInterlock", "$feats.fragmentShaderPixelInterlock"]), + alias="interlock", + features=True, + conditions=["$feats.fragmentShaderSampleInterlock", "$feats.fragmentShaderPixelInterlock"]), Extension("VK_EXT_sample_locations", - alias="sample_locations", - properties=True), + alias="sample_locations", + properties=True), Extension("VK_EXT_conservative_rasterization", - alias="cons_raster", - properties=True, - conditions=["$props.fullyCoveredFragmentShaderInputVariable"]), + alias="cons_raster", + properties=True, + conditions=["$props.fullyCoveredFragmentShaderInputVariable"]), Extension("VK_KHR_shader_draw_parameters"), Extension("VK_KHR_sampler_mirror_clamp_to_edge"), Extension("VK_EXT_conditional_rendering", - alias="cond_render", - features=True, - conditions=["$feats.conditionalRendering"]), + alias="cond_render", + features=True, + conditions=["$feats.conditionalRendering"]), Extension("VK_EXT_transform_feedback", - alias="tf", - properties=True, - features=True, - conditions=["$feats.transformFeedback"]), + alias="tf", + properties=True, + features=True, + conditions=["$feats.transformFeedback"]), Extension("VK_EXT_index_type_uint8", - alias="index_uint8", - features=True, - conditions=["$feats.indexTypeUint8"]), + alias="index_uint8", + features=True, + conditions=["$feats.indexTypeUint8"]), Extension("VK_KHR_image_format_list"), Extension("VK_KHR_sampler_ycbcr_conversion"), Extension("VK_KHR_imageless_framebuffer", - alias="imgless", - features=True, - required=True), + alias="imgless", + features=True, + required=True), Extension("VK_EXT_robustness2", - alias="rb2", - properties=True, - features=True, - conditions=["$feats.nullDescriptor"]), + alias="rb2", + properties=True, + features=True, + conditions=["$feats.nullDescriptor"]), + Extension("VK_EXT_image_robustness", + alias="rb_image", + features=True), Extension("VK_EXT_image_drm_format_modifier"), Extension("VK_EXT_vertex_attribute_divisor", - alias="vdiv", - properties=True, - features=True, - conditions=["$feats.vertexAttributeInstanceRateDivisor"]), + alias="vdiv", + properties=True, + features=True, + conditions=["$feats.vertexAttributeInstanceRateDivisor"]), Extension("VK_EXT_calibrated_timestamps"), Extension("VK_NV_linear_color_attachment", alias="linear_color", @@ -163,60 +181,64 @@ EXTENSIONS = [ alias="dynamic_render", features=True), Extension("VK_KHR_shader_clock", - alias="shader_clock", - features=True, - conditions=["$feats.shaderSubgroupClock"]), + alias="shader_clock", + features=True, + conditions=["$feats.shaderSubgroupClock"]), Extension("VK_EXT_sampler_filter_minmax", - alias="reduction", - properties=True, - conditions=["$props.filterMinmaxSingleComponentFormats"]), + alias="reduction", + properties=True, + conditions=["$props.filterMinmaxSingleComponentFormats"]), Extension("VK_EXT_custom_border_color", - alias="border_color", - properties=True, - features=True, - conditions=["$feats.customBorderColors"]), + alias="border_color", + properties=True, + features=True, + conditions=["$feats.customBorderColors"]), Extension("VK_EXT_non_seamless_cube_map", - alias="nonseamless", - features=True), + alias="nonseamless", + features=True), Extension("VK_EXT_border_color_swizzle", - alias="border_swizzle", - features=True), + alias="border_swizzle", + features=True), Extension("VK_EXT_blend_operation_advanced", - alias="blend", - properties=True, - # TODO: we can probably support non-premul here with some work? - conditions=["$props.advancedBlendNonPremultipliedSrcColor", "$props.advancedBlendNonPremultipliedDstColor"]), + alias="blend", + properties=True, + # TODO: we can probably support non-premul here with some work? + conditions=["$props.advancedBlendNonPremultipliedSrcColor", "$props.advancedBlendNonPremultipliedDstColor"]), Extension("VK_EXT_extended_dynamic_state", - alias="dynamic_state", - features=True, - conditions=["$feats.extendedDynamicState"]), + alias="dynamic_state", + features=True, + conditions=["$feats.extendedDynamicState"]), Extension("VK_EXT_extended_dynamic_state2", - alias="dynamic_state2", - features=True, - conditions=["$feats.extendedDynamicState2"]), + alias="dynamic_state2", + features=True, + conditions=["$feats.extendedDynamicState2"]), Extension("VK_EXT_extended_dynamic_state3", - alias="dynamic_state3", - properties=True, - features=True), + alias="dynamic_state3", + properties=True, + features=True), Extension("VK_EXT_pipeline_creation_cache_control", - alias="pipeline_cache_control", - features=True, - conditions=["$feats.pipelineCreationCacheControl"]), + alias="pipeline_cache_control", + features=True, + conditions=["$feats.pipelineCreationCacheControl"]), Extension("VK_EXT_shader_stencil_export", - alias="stencil_export"), + alias="stencil_export"), Extension("VK_KHR_portability_subset", - alias="portability_subset", - features=True, - guard=True), - Extension("VK_KHR_timeline_semaphore", alias="timeline", features=True), - Extension("VK_EXT_color_write_enable", alias="cwrite", features=True), + alias="portability_subset", + features=True, + guard=True), + Extension("VK_KHR_timeline_semaphore", + alias="timeline", + features=True), + Extension("VK_EXT_color_write_enable", + alias="cwrite", + features=True), Extension("VK_EXT_4444_formats", - alias="format_4444", - features=True), + alias="format_4444", + features=True), Extension("VK_EXT_scalar_block_layout", - alias="scalar_block_layout", - features=True, - conditions=["$feats.scalarBlockLayout"]), + alias="scalar_block_layout", + features=True, + conditions=["$feats.scalarBlockLayout"]), Extension("VK_KHR_swapchain"), Extension("VK_EXT_rasterization_order_attachment_access", alias="rast_order_access", @@ -227,48 +249,48 @@ EXTENSIONS = [ features=True), Extension("VK_EXT_multi_draw", alias="multidraw", - features=True, - properties=True, - conditions=["$feats.multiDraw"]), + features=True, + properties=True, + conditions=["$feats.multiDraw"]), Extension("VK_EXT_primitives_generated_query", alias="primgen", - features=True), + features=True), Extension("VK_KHR_pipeline_library"), Extension("VK_EXT_graphics_pipeline_library", alias="gpl", - features=True, - properties=True), + features=True, + properties=True), Extension("VK_KHR_push_descriptor", - alias="push", - properties=True), + alias="push", + properties=True), Extension("VK_KHR_descriptor_update_template", - alias="template", required=True), + alias="template", required=True), Extension("VK_EXT_line_rasterization", - alias="line_rast", - properties=True, - features=True), + alias="line_rast", + properties=True, + features=True), Extension("VK_EXT_vertex_input_dynamic_state", - alias="vertex_input", - features=True, - conditions=["$feats.vertexInputDynamicState"]), + alias="vertex_input", + features=True, + conditions=["$feats.vertexInputDynamicState"]), Extension("VK_EXT_primitive_topology_list_restart", - alias="list_restart", - features=True, - conditions=["$feats.primitiveTopologyListRestart"]), + alias="list_restart", + features=True, + conditions=["$feats.primitiveTopologyListRestart"]), Extension("VK_KHR_dedicated_allocation", - alias="dedicated"), + alias="dedicated"), Extension("VK_EXT_descriptor_indexing", - alias="desc_indexing", - features=True, - properties=True, - conditions=["$feats.descriptorBindingPartiallyBound"]), + alias="desc_indexing", + features=True, + properties=True, + conditions=["$feats.descriptorBindingPartiallyBound"]), Extension("VK_EXT_depth_clip_enable", - alias="depth_clip_enable", - features=True), + alias="depth_clip_enable", + features=True), Extension("VK_EXT_shader_demote_to_helper_invocation", - alias="demote", - features=True, - conditions=["$feats.shaderDemoteToHelperInvocation"]), + alias="demote", + features=True, + conditions=["$feats.shaderDemoteToHelperInvocation"]), ] # constructor: Versions(device_version(major, minor, patch), struct_version(major, minor)) diff --git a/src/gallium/drivers/zink/zink_draw.cpp b/src/gallium/drivers/zink/zink_draw.cpp index 2188407..d8c24e7 100644 --- a/src/gallium/drivers/zink/zink_draw.cpp +++ b/src/gallium/drivers/zink/zink_draw.cpp @@ -525,6 +525,7 @@ zink_draw(struct pipe_context *pctx, zink_set_last_vertex_key(ctx)->push_drawid = drawid_broken; bool rast_prim_changed = false; + bool lines_changed = false; bool rast_state_changed = ctx->rast_state_changed; if (mode_changed || ctx->gfx_pipeline_state.modules_changed || rast_state_changed) { @@ -534,6 +535,10 @@ zink_draw(struct pipe_context *pctx, (ctx->gfx_pipeline_state.rast_prim == PIPE_PRIM_POINTS) != (rast_prim == PIPE_PRIM_POINTS); + lines_changed = + (ctx->gfx_pipeline_state.rast_prim == PIPE_PRIM_LINES) != + (rast_prim == PIPE_PRIM_LINES); + ctx->gfx_pipeline_state.rast_prim = rast_prim; rast_prim_changed = true; @@ -543,6 +548,10 @@ zink_draw(struct pipe_context *pctx, } ctx->gfx_pipeline_state.gfx_prim_mode = mode; + if (!screen->optimal_keys && + (lines_changed || rast_state_changed || ctx->gfx_pipeline_state.modules_changed)) + zink_set_primitive_emulation_keys(ctx); + if (index_size) { const VkIndexType index_type[3] = { VK_INDEX_TYPE_UINT8_EXT, @@ -670,7 +679,7 @@ zink_draw(struct pipe_context *pctx, VKCTX(CmdSetCullModeEXT)(batch->state->cmdbuf, ctx->gfx_pipeline_state.dyn_state1.cull_mode); } if ((BATCH_CHANGED || rast_state_changed) && - (DYNAMIC_STATE >= ZINK_DYNAMIC_STATE3 || (screen->info.have_EXT_line_rasterization && rast_state->base.line_stipple_enable))) + (DYNAMIC_STATE >= ZINK_DYNAMIC_STATE3 || (!screen->driver_workarounds.no_linestipple && rast_state->base.line_stipple_enable))) VKCTX(CmdSetLineStippleEXT)(batch->state->cmdbuf, rast_state->base.line_stipple_factor, rast_state->base.line_stipple_pattern); if ((BATCH_CHANGED || rast_state_changed) && DYNAMIC_STATE >= ZINK_DYNAMIC_STATE3) { @@ -695,9 +704,11 @@ zink_draw(struct pipe_context *pctx, VKCTX(CmdSetAlphaToCoverageEnableEXT)(batch->state->cmdbuf, ctx->gfx_pipeline_state.blend_state->alpha_to_coverage); if (screen->info.feats.features.alphaToOne) VKCTX(CmdSetAlphaToOneEnableEXT)(batch->state->cmdbuf, ctx->gfx_pipeline_state.blend_state->alpha_to_one); - VKCTX(CmdSetColorBlendEnableEXT)(batch->state->cmdbuf, 0, ctx->fb_state.nr_cbufs, ctx->gfx_pipeline_state.blend_state->ds3.enables); - VKCTX(CmdSetColorWriteMaskEXT)(batch->state->cmdbuf, 0, ctx->fb_state.nr_cbufs, ctx->gfx_pipeline_state.blend_state->ds3.wrmask); - VKCTX(CmdSetColorBlendEquationEXT)(batch->state->cmdbuf, 0, ctx->fb_state.nr_cbufs, ctx->gfx_pipeline_state.blend_state->ds3.eq); + if (ctx->fb_state.nr_cbufs) { + VKCTX(CmdSetColorBlendEnableEXT)(batch->state->cmdbuf, 0, ctx->fb_state.nr_cbufs, ctx->gfx_pipeline_state.blend_state->ds3.enables); + VKCTX(CmdSetColorWriteMaskEXT)(batch->state->cmdbuf, 0, ctx->fb_state.nr_cbufs, ctx->gfx_pipeline_state.blend_state->ds3.wrmask); + VKCTX(CmdSetColorBlendEquationEXT)(batch->state->cmdbuf, 0, ctx->fb_state.nr_cbufs, ctx->gfx_pipeline_state.blend_state->ds3.eq); + } VKCTX(CmdSetLogicOpEnableEXT)(batch->state->cmdbuf, ctx->gfx_pipeline_state.blend_state->logicop_enable); VKCTX(CmdSetLogicOpEXT)(batch->state->cmdbuf, ctx->gfx_pipeline_state.blend_state->logicop_func); } @@ -787,12 +798,52 @@ zink_draw(struct pipe_context *pctx, &draw_mode_is_indexed); } if (ctx->curr_program->shaders[MESA_SHADER_TESS_CTRL] && - ctx->curr_program->shaders[MESA_SHADER_TESS_CTRL]->tcs.is_generated) { + ctx->curr_program->shaders[MESA_SHADER_TESS_CTRL]->non_fs.is_generated) { VKCTX(CmdPushConstants)(batch->state->cmdbuf, ctx->curr_program->base.layout, VK_SHADER_STAGE_ALL_GRAPHICS, offsetof(struct zink_gfx_push_constant, default_inner_level), sizeof(float) * 6, &ctx->tess_levels[0]); } + if (!screen->optimal_keys) { + if (zink_get_fs_key(ctx)->lower_line_stipple || + zink_get_gs_key(ctx)->lower_gl_point || + zink_get_fs_key(ctx)->lower_line_smooth) { + + assert(zink_get_gs_key(ctx)->lower_line_stipple == + zink_get_fs_key(ctx)->lower_line_stipple); + + assert(zink_get_gs_key(ctx)->lower_line_smooth == + zink_get_fs_key(ctx)->lower_line_smooth); + + float viewport_scale[2] = { + ctx->vp_state.viewport_states[0].scale[0], + ctx->vp_state.viewport_states[0].scale[1] + }; + VKCTX(CmdPushConstants)(batch->state->cmdbuf, + ctx->curr_program->base.layout, + VK_SHADER_STAGE_ALL_GRAPHICS, + offsetof(struct zink_gfx_push_constant, viewport_scale), + sizeof(float) * 2, &viewport_scale); + + uint32_t stipple = ctx->rast_state->base.line_stipple_pattern; + stipple |= ctx->rast_state->base.line_stipple_factor << 16; + VKCTX(CmdPushConstants)(batch->state->cmdbuf, + ctx->curr_program->base.layout, + VK_SHADER_STAGE_ALL_GRAPHICS, + offsetof(struct zink_gfx_push_constant, line_stipple_pattern), + sizeof(uint32_t), &stipple); + + if (ctx->gfx_pipeline_state.shader_keys.key[MESA_SHADER_FRAGMENT].key.fs.lower_line_smooth) { + float line_width = ctx->rast_state->base.line_width; + VKCTX(CmdPushConstants)(batch->state->cmdbuf, + ctx->curr_program->base.layout, + VK_SHADER_STAGE_ALL_GRAPHICS, + offsetof(struct zink_gfx_push_constant, line_width), + sizeof(uint32_t), &line_width); + } + } + } + if (have_streamout) { for (unsigned i = 0; i < ctx->num_so_targets; i++) { struct zink_so_target *t = zink_so_target(ctx->so_targets[i]); diff --git a/src/gallium/drivers/zink/zink_kopper.c b/src/gallium/drivers/zink/zink_kopper.c index a67b756..819d72e 100644 --- a/src/gallium/drivers/zink/zink_kopper.c +++ b/src/gallium/drivers/zink/zink_kopper.c @@ -493,17 +493,12 @@ kopper_acquire(struct zink_screen *screen, struct zink_resource *res, uint64_t t p_atomic_read_relaxed(&cdt->swapchain->num_acquires) >= cdt->swapchain->max_acquires) { util_queue_fence_wait(&cdt->present_fence); } - VkSemaphoreCreateInfo sci = { - VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, - NULL, - 0 - }; VkResult ret; if (!acquire) { - ret = VKSCR(CreateSemaphore)(screen->dev, &sci, NULL, &acquire); + acquire = zink_create_semaphore(screen); assert(acquire); - if (ret != VK_SUCCESS) - return ret; + if (!acquire) + return VK_ERROR_OUT_OF_HOST_MEMORY; } ret = VKSCR(AcquireNextImageKHR)(screen->dev, cdt->swapchain->swapchain, timeout, acquire, VK_NULL_HANDLE, &res->obj->dt_idx); if (ret != VK_SUCCESS && ret != VK_SUBOPTIMAL_KHR) { @@ -611,14 +606,9 @@ zink_kopper_present(struct zink_screen *screen, struct zink_resource *res) { assert(res->obj->dt); assert(!res->obj->present); - VkSemaphoreCreateInfo sci = { - VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, - NULL, - 0 - }; assert(zink_kopper_acquired(res->obj->dt, res->obj->dt_idx)); - VkResult ret = VKSCR(CreateSemaphore)(screen->dev, &sci, NULL, &res->obj->present); - return zink_screen_handle_vkresult(screen, ret) ? res->obj->present : VK_NULL_HANDLE; + res->obj->present = zink_create_semaphore(screen); + return res->obj->present; } struct kopper_present_info { @@ -730,6 +720,11 @@ zink_kopper_present_queue(struct zink_screen *screen, struct zink_resource *res) struct kopper_displaytarget *cdt = res->obj->dt; assert(zink_kopper_acquired(res->obj->dt, res->obj->dt_idx)); assert(res->obj->present); + + /* always try to prune if the current swapchain has seen presents */ + if (cdt->swapchain->last_present != UINT32_MAX) + prune_old_swapchains(screen, cdt, false); + struct kopper_present_info *cpi = malloc(sizeof(struct kopper_present_info)); cpi->sem = res->obj->present; cpi->res = res; diff --git a/src/gallium/drivers/zink/zink_pipeline.c b/src/gallium/drivers/zink/zink_pipeline.c index 12869a7..d31188c 100644 --- a/src/gallium/drivers/zink/zink_pipeline.c +++ b/src/gallium/drivers/zink/zink_pipeline.c @@ -148,7 +148,7 @@ zink_create_gfx_pipeline(struct zink_screen *screen, viewport_state.pViewports = NULL; viewport_state.scissorCount = screen->info.have_EXT_extended_dynamic_state ? 0 : state->dyn_state1.num_viewports; viewport_state.pScissors = NULL; - if (!screen->driver_workarounds.depth_clip_control_missing && !hw_rast_state->clip_halfz) + if (screen->info.have_EXT_depth_clip_control && !hw_rast_state->clip_halfz) viewport_state.pNext = &clip; VkPipelineRasterizationStateCreateInfo rast_state = {0}; @@ -270,7 +270,8 @@ zink_create_gfx_pipeline(struct zink_screen *screen, assert(state->rast_prim != PIPE_PRIM_MAX); VkPipelineRasterizationLineStateCreateInfoEXT rast_line_state; - if (screen->info.have_EXT_line_rasterization) { + if (screen->info.have_EXT_line_rasterization && + !state->shader_keys.key[MESA_SHADER_FRAGMENT].key.fs.lower_line_smooth) { rast_line_state.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT; rast_line_state.pNext = rast_state.pNext; rast_line_state.stippledLineEnable = VK_FALSE; @@ -294,7 +295,18 @@ zink_create_gfx_pipeline(struct zink_screen *screen, mode_idx += hw_rast_state->line_stipple_enable * 3; if (*(feat + mode_idx)) rast_line_state.lineRasterizationMode = hw_rast_state->line_mode; - else + else if (hw_rast_state->line_stipple_enable && + screen->driver_workarounds.no_linestipple) { + /* drop line stipple, we can emulate it */ + mode_idx -= hw_rast_state->line_stipple_enable * 3; + if (*(feat + mode_idx)) + rast_line_state.lineRasterizationMode = hw_rast_state->line_mode; + /* non-strictLine default lines are either parallelogram or bresenham which while not in GL spec, + * in practice end up being within the two-pixel exception in the GL spec. + */ + else if ((mode_idx != 1) || screen->info.props.limits.strictLines) + warn_missing_feature(warned[mode_idx], features[hw_rast_state->line_mode][0]); + } else if ((mode_idx != 1) || screen->info.props.limits.strictLines) warn_missing_feature(warned[mode_idx], features[hw_rast_state->line_mode][hw_rast_state->line_stipple_enable]); } @@ -681,7 +693,7 @@ zink_create_gfx_pipeline_library(struct zink_screen *screen, struct zink_gfx_pro dynamicStateEnables[state_count++] = VK_DYNAMIC_STATE_LINE_RASTERIZATION_MODE_EXT; if (screen->info.dynamic_state3_feats.extendedDynamicState3LineStippleEnable) dynamicStateEnables[state_count++] = VK_DYNAMIC_STATE_LINE_STIPPLE_ENABLE_EXT; - if (screen->info.have_EXT_line_rasterization) + if (!screen->driver_workarounds.no_linestipple) dynamicStateEnables[state_count++] = VK_DYNAMIC_STATE_LINE_STIPPLE_EXT; assert(state_count < ARRAY_SIZE(dynamicStateEnables)); diff --git a/src/gallium/drivers/zink/zink_program.c b/src/gallium/drivers/zink/zink_program.c index 9534815..c0b9739 100644 --- a/src/gallium/drivers/zink/zink_program.c +++ b/src/gallium/drivers/zink/zink_program.c @@ -38,6 +38,7 @@ #include "util/u_memory.h" #include "util/u_prim.h" #include "nir_serialize.h" +#include "nir/nir_draw_helpers.h" /* for pipeline cache */ #define XXH_INLINE_ALL @@ -58,7 +59,8 @@ debug_describe_zink_compute_program(char *buf, const struct zink_compute_program ALWAYS_INLINE static bool shader_key_matches_tcs_nongenerated(const struct zink_shader_module *zm, const struct zink_shader_key *key, unsigned num_uniforms) { - if (zm->num_uniforms != num_uniforms || zm->has_nonseamless != !!key->base.nonseamless_cube_mask) + if (zm->num_uniforms != num_uniforms || zm->has_nonseamless != !!key->base.nonseamless_cube_mask || + zm->needs_zs_shader_swizzle != key->base.needs_zs_shader_swizzle) return false; const uint32_t nonseamless_size = zm->has_nonseamless ? sizeof(uint32_t) : 0; return (!nonseamless_size || !memcmp(zm->key + zm->key_size, &key->base.nonseamless_cube_mask, nonseamless_size)) && @@ -84,6 +86,8 @@ shader_key_matches(const struct zink_shader_module *zm, (nonseamless_size && memcmp(zm->key + zm->key_size, &key->base.nonseamless_cube_mask, nonseamless_size))) return false; } + if (zm->needs_zs_shader_swizzle != key->base.needs_zs_shader_swizzle) + return false; return !memcmp(zm->key, key, zm->key_size); } @@ -129,17 +133,21 @@ create_shader_module_for_stage(struct zink_context *ctx, struct zink_screen *scr struct zink_shader_module *zm; const struct zink_shader_key *key = &state->shader_keys.key[stage]; /* non-generated tcs won't use the shader key */ - const bool is_nongenerated_tcs = stage == MESA_SHADER_TESS_CTRL && !zs->tcs.is_generated; - zm = malloc(sizeof(struct zink_shader_module) + key->size + (!has_nonseamless ? nonseamless_size : 0) + inline_size * sizeof(uint32_t)); + const bool is_nongenerated_tcs = stage == MESA_SHADER_TESS_CTRL && !zs->non_fs.is_generated; + const bool shadow_needs_shader_swizzle = key->base.needs_zs_shader_swizzle || + (stage == MESA_SHADER_FRAGMENT && key->key.fs.base.shadow_needs_shader_swizzle); + zm = malloc(sizeof(struct zink_shader_module) + key->size + + (!has_nonseamless ? nonseamless_size : 0) + inline_size * sizeof(uint32_t) + + (shadow_needs_shader_swizzle ? sizeof(struct zink_zs_swizzle_key) : 0)); if (!zm) { return NULL; } unsigned patch_vertices = state->shader_keys.key[MESA_SHADER_TESS_CTRL ].key.tcs.patch_vertices; - if (stage == MESA_SHADER_TESS_CTRL && zs->tcs.is_generated && zs->spirv) { + if (stage == MESA_SHADER_TESS_CTRL && zs->non_fs.is_generated && zs->spirv) { assert(ctx); //TODO async mod = zink_shader_tcs_compile(screen, zs, patch_vertices); } else { - mod = zink_shader_compile(screen, zs, prog->nir[stage], key); + mod = zink_shader_compile(screen, zs, prog->nir[stage], key, &ctx->di.zs_swizzle[stage]); } if (!mod) { FREE(zm); @@ -158,14 +166,19 @@ create_shader_module_for_stage(struct zink_context *ctx, struct zink_screen *scr /* nonseamless mask gets added to base key if it exists */ memcpy(zm->key + key->size, &key->base.nonseamless_cube_mask, nonseamless_size); } + zm->needs_zs_shader_swizzle = shadow_needs_shader_swizzle; zm->has_nonseamless = has_nonseamless ? 0 : !!nonseamless_size; if (inline_size) memcpy(zm->key + key->size + nonseamless_size, key->base.inlined_uniform_values, inline_size * sizeof(uint32_t)); - if (stage == MESA_SHADER_TESS_CTRL && zs->tcs.is_generated) + if (stage == MESA_SHADER_TESS_CTRL && zs->non_fs.is_generated) zm->hash = patch_vertices; else zm->hash = shader_module_hash(zm); - zm->default_variant = !inline_size && !util_dynarray_contains(&prog->shader_cache[stage][0][0], void*); + if (unlikely(shadow_needs_shader_swizzle)) { + memcpy(zm->key + key->size + nonseamless_size + inline_size * sizeof(uint32_t), &ctx->di.zs_swizzle[stage], sizeof(struct zink_zs_swizzle_key)); + zm->hash ^= _mesa_hash_data(&ctx->di.zs_swizzle[stage], sizeof(struct zink_zs_swizzle_key)); + } + zm->default_variant = !shadow_needs_shader_swizzle && !inline_size && !util_dynarray_contains(&prog->shader_cache[stage][0][0], void*); if (inline_size) prog->inlined_variant_count[stage]++; util_dynarray_append(&prog->shader_cache[stage][has_nonseamless ? 0 : !!nonseamless_size][!!inline_size], void*, zm); @@ -183,7 +196,9 @@ get_shader_module_for_stage(struct zink_context *ctx, struct zink_screen *screen { const struct zink_shader_key *key = &state->shader_keys.key[stage]; /* non-generated tcs won't use the shader key */ - const bool is_nongenerated_tcs = stage == MESA_SHADER_TESS_CTRL && !zs->tcs.is_generated; + const bool is_nongenerated_tcs = stage == MESA_SHADER_TESS_CTRL && !zs->non_fs.is_generated; + const bool shadow_needs_shader_swizzle = unlikely(key->base.needs_zs_shader_swizzle) || + (stage == MESA_SHADER_FRAGMENT && unlikely(key->key.fs.base.shadow_needs_shader_swizzle)); struct util_dynarray *shader_cache = &prog->shader_cache[stage][!has_nonseamless ? !!nonseamless_size : 0][has_inline ? !!inline_size : 0]; unsigned count = util_dynarray_num_elements(shader_cache, struct zink_shader_module *); @@ -198,6 +213,12 @@ get_shader_module_for_stage(struct zink_context *ctx, struct zink_screen *screen continue; if (!shader_key_matches(iter, key, inline_size, has_inline, has_nonseamless)) continue; + if (unlikely(shadow_needs_shader_swizzle)) { + /* shadow swizzle data needs a manual compare since it's so fat */ + if (memcmp(iter->key + iter->key_size + nonseamless_size + iter->num_uniforms * sizeof(uint32_t), + &ctx->di.zs_swizzle[stage], sizeof(struct zink_zs_swizzle_key))) + continue; + } } if (i > 0) { struct zink_shader_module *zero = pzm[0]; @@ -220,26 +241,28 @@ create_shader_module_for_stage_optimal(struct zink_context *ctx, struct zink_scr struct zink_shader_module *zm; uint16_t *key; unsigned mask = stage == MESA_SHADER_FRAGMENT ? BITFIELD_MASK(16) : BITFIELD_MASK(8); + bool shadow_needs_shader_swizzle = false; if (zs == prog->last_vertex_stage) { key = (uint16_t*)&state->shader_keys_optimal.key.vs_base; } else if (stage == MESA_SHADER_FRAGMENT) { key = (uint16_t*)&state->shader_keys_optimal.key.fs; - } else if (stage == MESA_SHADER_TESS_CTRL && zs->tcs.is_generated) { + shadow_needs_shader_swizzle = ctx ? ctx->gfx_pipeline_state.shader_keys_optimal.key.fs.shadow_needs_shader_swizzle : false; + } else if (stage == MESA_SHADER_TESS_CTRL && zs->non_fs.is_generated) { key = (uint16_t*)&state->shader_keys_optimal.key.tcs; } else { key = NULL; } size_t key_size = sizeof(uint16_t); - zm = calloc(1, sizeof(struct zink_shader_module) + (key ? key_size : 0)); + zm = calloc(1, sizeof(struct zink_shader_module) + (key ? key_size : 0) + (unlikely(shadow_needs_shader_swizzle) ? sizeof(struct zink_zs_swizzle_key) : 0)); if (!zm) { return NULL; } - if (stage == MESA_SHADER_TESS_CTRL && zs->tcs.is_generated && zs->spirv) { + if (stage == MESA_SHADER_TESS_CTRL && zs->non_fs.is_generated && zs->spirv) { assert(ctx); //TODO async struct zink_tcs_key *tcs = (struct zink_tcs_key*)key; mod = zink_shader_tcs_compile(screen, zs, tcs->patch_vertices); } else { - mod = zink_shader_compile(screen, zs, prog->nir[stage], (struct zink_shader_key*)key); + mod = zink_shader_compile(screen, zs, prog->nir[stage], (struct zink_shader_key*)key, shadow_needs_shader_swizzle ? &ctx->di.zs_swizzle[stage] : NULL); } if (!mod) { FREE(zm); @@ -247,12 +270,14 @@ create_shader_module_for_stage_optimal(struct zink_context *ctx, struct zink_scr } zm->shader = mod; /* non-generated tcs won't use the shader key */ - const bool is_nongenerated_tcs = stage == MESA_SHADER_TESS_CTRL && !zs->tcs.is_generated; + const bool is_nongenerated_tcs = stage == MESA_SHADER_TESS_CTRL && !zs->non_fs.is_generated; if (key && !is_nongenerated_tcs) { zm->key_size = key_size; uint16_t *data = (uint16_t*)zm->key; /* sanitize actual key bits */ *data = (*key) & mask; + if (unlikely(shadow_needs_shader_swizzle)) + memcpy(&data[1], &ctx->di.zs_swizzle[stage], sizeof(struct zink_zs_swizzle_key)); } zm->default_variant = !util_dynarray_contains(&prog->shader_cache[stage][0][0], void*); util_dynarray_append(&prog->shader_cache[stage][0][0], void*, zm); @@ -266,14 +291,16 @@ get_shader_module_for_stage_optimal(struct zink_context *ctx, struct zink_screen struct zink_gfx_pipeline_state *state) { /* non-generated tcs won't use the shader key */ - const bool is_nongenerated_tcs = stage == MESA_SHADER_TESS_CTRL && !zs->tcs.is_generated; + const bool is_nongenerated_tcs = stage == MESA_SHADER_TESS_CTRL && !zs->non_fs.is_generated; + bool shadow_needs_shader_swizzle = false; uint16_t *key; unsigned mask = stage == MESA_SHADER_FRAGMENT ? BITFIELD_MASK(16) : BITFIELD_MASK(8); if (zs == prog->last_vertex_stage) { key = (uint16_t*)&ctx->gfx_pipeline_state.shader_keys_optimal.key.vs_base; } else if (stage == MESA_SHADER_FRAGMENT) { key = (uint16_t*)&ctx->gfx_pipeline_state.shader_keys_optimal.key.fs; - } else if (stage == MESA_SHADER_TESS_CTRL && zs->tcs.is_generated) { + shadow_needs_shader_swizzle = ctx->gfx_pipeline_state.shader_keys_optimal.key.fs.shadow_needs_shader_swizzle; + } else if (stage == MESA_SHADER_TESS_CTRL && zs->non_fs.is_generated) { key = (uint16_t*)&ctx->gfx_pipeline_state.shader_keys_optimal.key.tcs; } else { key = NULL; @@ -290,6 +317,11 @@ get_shader_module_for_stage_optimal(struct zink_context *ctx, struct zink_screen /* no key is bigger than uint16_t */ if (memcmp(iter->key, &val, sizeof(uint16_t))) continue; + if (unlikely(shadow_needs_shader_swizzle)) { + /* shadow swizzle data needs a manual compare since it's so fat */ + if (memcmp(iter->key + sizeof(uint16_t), &ctx->di.zs_swizzle[stage], sizeof(struct zink_zs_swizzle_key))) + continue; + } } if (i > 0) { struct zink_shader_module *zero = pzm[0]; @@ -370,31 +402,6 @@ update_gfx_shader_modules(struct zink_context *ctx, } } -ALWAYS_INLINE static void -update_gfx_shader_modules_optimal(struct zink_context *ctx, - struct zink_screen *screen, - struct zink_gfx_program *prog, uint32_t mask, - struct zink_gfx_pipeline_state *state) -{ - assert(prog->modules[MESA_SHADER_VERTEX]); - for (unsigned i = 0; i < MESA_SHADER_COMPUTE; i++) { - if (!(mask & BITFIELD_BIT(i))) - continue; - - assert(prog->shaders[i]); - - struct zink_shader_module *zm = get_shader_module_for_stage_optimal(ctx, screen, prog->shaders[i], prog, i, state); - if (!zm) - zm = create_shader_module_for_stage_optimal(ctx, screen, prog->shaders[i], prog, i, state); - if (prog->modules[i] == zm->shader) - continue; - state->modules_changed = true; - prog->modules[i] = zm->shader; - } - - prog->last_variant_hash = state->shader_keys_optimal.key.val; -} - static void generate_gfx_program_modules(struct zink_context *ctx, struct zink_screen *screen, struct zink_gfx_program *prog, struct zink_gfx_pipeline_state *state) { @@ -453,7 +460,8 @@ generate_gfx_program_modules_optimal(struct zink_context *ctx, struct zink_scree static uint32_t hash_pipeline_lib_generated_tcs(const void *key) { - return 1; + const struct zink_gfx_library_key *gkey = key; + return gkey->optimal_key; } @@ -623,7 +631,7 @@ zink_gfx_program_update(struct zink_context *ctx) ctx->dirty_gfx_stages = 0; } -ALWAYS_INLINE static void +ALWAYS_INLINE static bool update_gfx_shader_module_optimal(struct zink_context *ctx, struct zink_gfx_program *prog, gl_shader_stage pstage) { struct zink_screen *screen = zink_screen(ctx->base.screen); @@ -632,7 +640,10 @@ update_gfx_shader_module_optimal(struct zink_context *ctx, struct zink_gfx_progr struct zink_shader_module *zm = get_shader_module_for_stage_optimal(ctx, screen, prog->shaders[pstage], prog, pstage, &ctx->gfx_pipeline_state); if (!zm) zm = create_shader_module_for_stage_optimal(ctx, screen, prog->shaders[pstage], prog, pstage, &ctx->gfx_pipeline_state); + + bool changed = prog->modules[pstage] != zm->shader; prog->modules[pstage] = zm->shader; + return changed; } static void @@ -640,17 +651,24 @@ update_gfx_program_optimal(struct zink_context *ctx, struct zink_gfx_program *pr { const union zink_shader_key_optimal *optimal_key = (union zink_shader_key_optimal*)&prog->last_variant_hash; if (ctx->gfx_pipeline_state.shader_keys_optimal.key.vs_bits != optimal_key->vs_bits) { - update_gfx_shader_module_optimal(ctx, prog, ctx->last_vertex_stage->nir->info.stage); - ctx->gfx_pipeline_state.modules_changed = true; + bool changed = update_gfx_shader_module_optimal(ctx, prog, ctx->last_vertex_stage->nir->info.stage); + ctx->gfx_pipeline_state.modules_changed |= changed; } - if (ctx->gfx_pipeline_state.shader_keys_optimal.key.fs_bits != optimal_key->fs_bits) { - update_gfx_shader_module_optimal(ctx, prog, MESA_SHADER_FRAGMENT); - ctx->gfx_pipeline_state.modules_changed = true; + const bool shadow_needs_shader_swizzle = optimal_key->fs.shadow_needs_shader_swizzle && (ctx->dirty_gfx_stages & BITFIELD_BIT(MESA_SHADER_FRAGMENT)); + if (ctx->gfx_pipeline_state.shader_keys_optimal.key.fs_bits != optimal_key->fs_bits || + /* always recheck shadow swizzles since they aren't directly part of the key */ + unlikely(shadow_needs_shader_swizzle)) { + bool changed = update_gfx_shader_module_optimal(ctx, prog, MESA_SHADER_FRAGMENT); + ctx->gfx_pipeline_state.modules_changed |= changed; + if (unlikely(shadow_needs_shader_swizzle)) { + struct zink_shader_module **pzm = prog->shader_cache[MESA_SHADER_FRAGMENT][0][0].data; + ctx->gfx_pipeline_state.shadow = (struct zink_zs_swizzle_key*)pzm[0]->key + sizeof(uint16_t); + } } - if (prog->shaders[MESA_SHADER_TESS_CTRL] && prog->shaders[MESA_SHADER_TESS_CTRL]->tcs.is_generated && + if (prog->shaders[MESA_SHADER_TESS_CTRL] && prog->shaders[MESA_SHADER_TESS_CTRL]->non_fs.is_generated && ctx->gfx_pipeline_state.shader_keys_optimal.key.tcs_bits != optimal_key->tcs_bits) { - update_gfx_shader_module_optimal(ctx, prog, MESA_SHADER_TESS_CTRL); - ctx->gfx_pipeline_state.modules_changed = true; + bool changed = update_gfx_shader_module_optimal(ctx, prog, MESA_SHADER_TESS_CTRL); + ctx->gfx_pipeline_state.modules_changed |= changed; } prog->last_variant_hash = ctx->gfx_pipeline_state.shader_keys_optimal.key.val; } @@ -725,8 +743,10 @@ update_cs_shader_module(struct zink_context *ctx, struct zink_compute_program *c struct zink_shader *zs = comp->shader; VkShaderModule mod; struct zink_shader_module *zm = NULL; - unsigned inline_size = 0, nonseamless_size = 0; + unsigned inline_size = 0, nonseamless_size = 0, zs_swizzle_size = 0; struct zink_shader_key *key = &ctx->compute_pipeline_state.key; + ASSERTED bool check_robustness = screen->driver_workarounds.lower_robustImageAccess2 && (ctx->flags & PIPE_CONTEXT_ROBUST_BUFFER_ACCESS); + assert(zink_cs_key(key)->robust_access == check_robustness); if (ctx && zs->nir->info.num_inlinable_uniforms && ctx->inlinable_uniforms_valid_mask & BITFIELD64_BIT(MESA_SHADER_COMPUTE)) { @@ -737,8 +757,10 @@ update_cs_shader_module(struct zink_context *ctx, struct zink_compute_program *c } if (key->base.nonseamless_cube_mask) nonseamless_size = sizeof(uint32_t); + if (key->base.needs_zs_shader_swizzle) + zs_swizzle_size = sizeof(struct zink_zs_swizzle_key); - if (inline_size || nonseamless_size) { + if (inline_size || nonseamless_size || zink_cs_key(key)->robust_access || zs_swizzle_size) { struct util_dynarray *shader_cache = &comp->shader_cache[!!nonseamless_size]; unsigned count = util_dynarray_num_elements(shader_cache, struct zink_shader_module *); struct zink_shader_module **pzm = shader_cache->data; @@ -748,6 +770,12 @@ update_cs_shader_module(struct zink_context *ctx, struct zink_compute_program *c screen->driconf.inline_uniforms, screen->info.have_EXT_non_seamless_cube_map)) continue; + if (unlikely(zs_swizzle_size)) { + /* zs swizzle data needs a manual compare since it's so fat */ + if (memcmp(iter->key + iter->key_size + nonseamless_size + inline_size * sizeof(uint32_t), + &ctx->di.zs_swizzle[MESA_SHADER_COMPUTE], zs_swizzle_size)) + continue; + } if (i > 0) { struct zink_shader_module *zero = pzm[0]; pzm[0] = iter; @@ -760,31 +788,36 @@ update_cs_shader_module(struct zink_context *ctx, struct zink_compute_program *c } if (!zm) { - zm = malloc(sizeof(struct zink_shader_module) + nonseamless_size + inline_size * sizeof(uint32_t)); + zm = malloc(sizeof(struct zink_shader_module) + nonseamless_size + inline_size * sizeof(uint32_t) + zs_swizzle_size); if (!zm) { return; } - mod = zink_shader_compile(screen, zs, comp->shader->nir, key); + mod = zink_shader_compile(screen, zs, comp->shader->nir, key, zs_swizzle_size ? &ctx->di.zs_swizzle[MESA_SHADER_COMPUTE] : NULL); if (!mod) { FREE(zm); return; } zm->shader = mod; zm->num_uniforms = inline_size; - zm->key_size = 0; + zm->key_size = key->size; + memcpy(zm->key, key, key->size); zm->has_nonseamless = !!nonseamless_size; - assert(nonseamless_size || inline_size); + zm->needs_zs_shader_swizzle = !!zs_swizzle_size; + assert(nonseamless_size || inline_size || zink_cs_key(key)->robust_access || zs_swizzle_size); if (nonseamless_size) - memcpy(zm->key, &key->base.nonseamless_cube_mask, nonseamless_size); + memcpy(zm->key + zm->key_size, &key->base.nonseamless_cube_mask, nonseamless_size); if (inline_size) - memcpy(zm->key + nonseamless_size, key->base.inlined_uniform_values, inline_size * sizeof(uint32_t)); + memcpy(zm->key + zm->key_size + nonseamless_size, key->base.inlined_uniform_values, inline_size * sizeof(uint32_t)); + if (zs_swizzle_size) + memcpy(zm->key + zm->key_size + nonseamless_size + inline_size * sizeof(uint32_t), &ctx->di.zs_swizzle[MESA_SHADER_COMPUTE], zs_swizzle_size); + zm->hash = shader_module_hash(zm); zm->default_variant = false; if (inline_size) comp->inlined_variant_count++; /* this is otherwise the default variant, which is stored as comp->module */ - if (zm->num_uniforms || nonseamless_size) + if (zm->num_uniforms || nonseamless_size || zink_cs_key(key)->robust_access || zs_swizzle_size) util_dynarray_append(&comp->shader_cache[!!nonseamless_size], void*, zm); } if (comp->curr == zm) @@ -886,10 +919,10 @@ zink_create_gfx_program(struct zink_context *ctx, prog->ctx = ctx; for (int i = 0; i < ZINK_GFX_SHADER_COUNT; ++i) { - util_dynarray_init(&prog->shader_cache[i][0][0], NULL); - util_dynarray_init(&prog->shader_cache[i][0][1], NULL); - util_dynarray_init(&prog->shader_cache[i][1][0], NULL); - util_dynarray_init(&prog->shader_cache[i][1][1], NULL); + util_dynarray_init(&prog->shader_cache[i][0][0], prog); + util_dynarray_init(&prog->shader_cache[i][0][1], prog); + util_dynarray_init(&prog->shader_cache[i][1][0], prog); + util_dynarray_init(&prog->shader_cache[i][1][1], prog); if (stages[i]) { prog->shaders[i] = stages[i]; prog->stages_present |= BITFIELD_BIT(i); @@ -897,7 +930,7 @@ zink_create_gfx_program(struct zink_context *ctx, } bool generated_tcs = false; if (stages[MESA_SHADER_TESS_EVAL] && !stages[MESA_SHADER_TESS_CTRL]) { - prog->shaders[MESA_SHADER_TESS_EVAL]->tes.generated = + prog->shaders[MESA_SHADER_TESS_EVAL]->non_fs.generated_tcs = prog->shaders[MESA_SHADER_TESS_CTRL] = zink_shader_tcs_create(screen, stages[MESA_SHADER_VERTEX], vertices_per_patch); prog->stages_present |= BITFIELD_BIT(MESA_SHADER_TESS_CTRL); @@ -1009,10 +1042,10 @@ precompile_compute_job(void *data, void *gdata, int thread_index) comp->shader = zink_shader_create(screen, comp->nir, NULL); comp->curr = comp->module = CALLOC_STRUCT(zink_shader_module); assert(comp->module); - comp->module->shader = zink_shader_compile(screen, comp->shader, comp->shader->nir, NULL); + comp->module->shader = zink_shader_compile(screen, comp->shader, comp->shader->nir, NULL, NULL); assert(comp->module->shader); - util_dynarray_init(&comp->shader_cache[0], NULL); - util_dynarray_init(&comp->shader_cache[1], NULL); + util_dynarray_init(&comp->shader_cache[0], comp); + util_dynarray_init(&comp->shader_cache[1], comp); struct blob blob = {0}; blob_init(&blob); @@ -1045,7 +1078,9 @@ create_compute_program(struct zink_context *ctx, nir_shader *nir) comp->use_local_size = !(nir->info.workgroup_size[0] || nir->info.workgroup_size[1] || nir->info.workgroup_size[2]); - comp->base.can_precompile = !comp->use_local_size && (screen->info.have_EXT_non_seamless_cube_map || !zink_shader_has_cubes(nir)); + comp->base.can_precompile = !comp->use_local_size && + (screen->info.have_EXT_non_seamless_cube_map || !zink_shader_has_cubes(nir)) && + (screen->info.rb2_feats.robustImageAccess2 || !(ctx->flags & PIPE_CONTEXT_ROBUST_BUFFER_ACCESS)); _mesa_hash_table_init(&comp->pipelines, comp, NULL, comp->use_local_size ? equals_compute_pipeline_state_local_size : equals_compute_pipeline_state); @@ -1226,8 +1261,13 @@ zink_destroy_compute_program(struct zink_screen *screen, { deinit_program(screen, &comp->base); - if (comp->shader) - _mesa_set_remove_key(comp->shader->programs, comp); + assert(comp->shader); + assert(!comp->shader->spirv); + + _mesa_set_destroy(comp->shader->programs, NULL); + ralloc_free(comp->shader->nir); + ralloc_free(comp->shader); + destroy_shader_cache(screen, &comp->shader_cache[0]); destroy_shader_cache(screen, &comp->shader_cache[1]); @@ -1306,7 +1346,7 @@ zink_get_compute_pipeline(struct zink_screen *screen, return state->pipeline; } -ALWAYS_INLINE static void +static void bind_gfx_stage(struct zink_context *ctx, gl_shader_stage stage, struct zink_shader *shader) { if (shader && shader->nir->info.num_inlinable_uniforms) @@ -1314,8 +1354,18 @@ bind_gfx_stage(struct zink_context *ctx, gl_shader_stage stage, struct zink_shad else ctx->shader_has_inlinable_uniforms_mask &= ~(1 << stage); - if (ctx->gfx_stages[stage]) + if (ctx->gfx_stages[stage]) { ctx->gfx_hash ^= ctx->gfx_stages[stage]->hash; + + /* unbind the generated GS */ + if (stage != MESA_SHADER_FRAGMENT && + ctx->gfx_stages[stage]->non_fs.generated_gs && + ctx->gfx_stages[MESA_SHADER_GEOMETRY] == + ctx->gfx_stages[stage]->non_fs.generated_gs) { + assert(stage != MESA_SHADER_GEOMETRY); /* let's not keep recursing! */ + bind_gfx_stage(ctx, MESA_SHADER_GEOMETRY, NULL); + } + } ctx->gfx_stages[stage] = shader; ctx->gfx_dirty = ctx->gfx_stages[MESA_SHADER_FRAGMENT] && ctx->gfx_stages[MESA_SHADER_VERTEX]; ctx->gfx_pipeline_state.modules_changed = true; @@ -1460,9 +1510,9 @@ zink_update_fs_key_samples(struct zink_context *ctx) return; nir_shader *nir = ctx->gfx_stages[MESA_SHADER_FRAGMENT]->nir; if (nir->info.outputs_written & (1 << FRAG_RESULT_SAMPLE_MASK)) { - bool samples = zink_get_fs_key(ctx)->samples; + bool samples = zink_get_fs_base_key(ctx)->samples; if (samples != (ctx->fb_state.samples > 1)) - zink_set_fs_key(ctx)->samples = ctx->fb_state.samples > 1; + zink_set_fs_base_key(ctx)->samples = ctx->fb_state.samples > 1; } } @@ -1473,6 +1523,7 @@ zink_bind_fs_state(struct pipe_context *pctx, struct zink_context *ctx = zink_context(pctx); if (!cso && !ctx->gfx_stages[MESA_SHADER_FRAGMENT]) return; + unsigned shadow_mask = ctx->gfx_stages[MESA_SHADER_FRAGMENT] ? ctx->gfx_stages[MESA_SHADER_FRAGMENT]->fs.legacy_shadow_mask : 0; bind_gfx_stage(ctx, MESA_SHADER_FRAGMENT, cso); ctx->fbfetch_outputs = 0; if (cso) { @@ -1489,6 +1540,10 @@ zink_bind_fs_state(struct pipe_context *pctx, ctx->gfx_pipeline_state.dirty = true; ctx->gfx_pipeline_state.rast_attachment_order = nir->info.fs.uses_fbfetch_output; } + zink_set_zs_needs_shader_swizzle_key(ctx, MESA_SHADER_FRAGMENT, false); + if (shadow_mask != ctx->gfx_stages[MESA_SHADER_FRAGMENT]->fs.legacy_shadow_mask && + !zink_screen(pctx->screen)->driver_workarounds.needs_zs_shader_swizzle) + zink_update_shadow_samplerviews(ctx, shadow_mask | ctx->gfx_stages[MESA_SHADER_FRAGMENT]->fs.legacy_shadow_mask); } zink_update_fbfetch(ctx); } @@ -1521,7 +1576,7 @@ zink_bind_tes_state(struct pipe_context *pctx, if (!!ctx->gfx_stages[MESA_SHADER_TESS_EVAL] != !!cso) { if (!cso) { /* if unsetting a TESS that uses a generated TCS, ensure the TCS is unset */ - if (ctx->gfx_stages[MESA_SHADER_TESS_EVAL]->tes.generated) + if (ctx->gfx_stages[MESA_SHADER_TESS_EVAL]->non_fs.generated_tcs) ctx->gfx_stages[MESA_SHADER_TESS_CTRL] = NULL; } } @@ -1851,3 +1906,59 @@ zink_driver_thread_add_job(struct pipe_screen *pscreen, void *data, struct zink_screen *screen = zink_screen(pscreen); util_queue_add_job(&screen->cache_get_thread, data, fence, execute, cleanup, job_size); } + +void +zink_set_primitive_emulation_keys(struct zink_context *ctx) +{ + struct zink_screen *screen = zink_screen(ctx->base.screen); + bool lower_line_stipple = ctx->gfx_pipeline_state.rast_prim == PIPE_PRIM_LINES && + screen->driver_workarounds.no_linestipple && + ctx->rast_state->base.line_stipple_enable && + !ctx->num_so_targets; + + if (zink_get_fs_key(ctx)->lower_line_stipple != lower_line_stipple) { + assert(zink_get_gs_key(ctx)->lower_line_stipple == + zink_get_fs_key(ctx)->lower_line_stipple); + zink_set_fs_key(ctx)->lower_line_stipple = lower_line_stipple; + zink_set_gs_key(ctx)->lower_line_stipple = lower_line_stipple; + } + + bool lower_line_smooth = screen->driver_workarounds.no_linesmooth && + ctx->rast_state->base.line_smooth && + !ctx->num_so_targets; + + if (zink_get_fs_key(ctx)->lower_line_smooth != lower_line_smooth) { + assert(zink_get_gs_key(ctx)->lower_line_smooth == + zink_get_fs_key(ctx)->lower_line_smooth); + zink_set_fs_key(ctx)->lower_line_smooth = lower_line_smooth; + zink_set_gs_key(ctx)->lower_line_smooth = lower_line_smooth; + } + + if (lower_line_stipple || lower_line_smooth || + zink_get_gs_key(ctx)->lower_gl_point) { + enum pipe_shader_type prev_vertex_stage = + ctx->gfx_stages[MESA_SHADER_TESS_EVAL] ? + MESA_SHADER_TESS_EVAL : MESA_SHADER_VERTEX; + + if (!ctx->gfx_stages[MESA_SHADER_GEOMETRY]) { + assert(!screen->optimal_keys); + + if (!ctx->gfx_stages[prev_vertex_stage]->non_fs.generated_gs) { + nir_shader *nir = nir_create_passthrough_gs( + &screen->nir_options, + ctx->gfx_stages[prev_vertex_stage]->nir, + (lower_line_stipple || lower_line_smooth) ? SHADER_PRIM_LINE_STRIP : SHADER_PRIM_POINTS, + (lower_line_stipple || lower_line_smooth) ? 2 : 1); + + struct zink_shader *shader = zink_shader_create(screen, nir, NULL); + ctx->gfx_stages[prev_vertex_stage]->non_fs.generated_gs = shader; + shader->non_fs.is_generated = true; + } + + bind_gfx_stage(ctx, MESA_SHADER_GEOMETRY, + ctx->gfx_stages[prev_vertex_stage]->non_fs.generated_gs); + } + } else if (ctx->gfx_stages[MESA_SHADER_GEOMETRY] && + ctx->gfx_stages[MESA_SHADER_GEOMETRY]->non_fs.is_generated) + bind_gfx_stage(ctx, MESA_SHADER_GEOMETRY, NULL); +} diff --git a/src/gallium/drivers/zink/zink_program.h b/src/gallium/drivers/zink/zink_program.h index 1265845..d33bbd1 100644 --- a/src/gallium/drivers/zink/zink_program.h +++ b/src/gallium/drivers/zink/zink_program.h @@ -240,21 +240,50 @@ zink_program_has_descriptors(const struct zink_program *pg) return pg->num_dsl > 0; } -static inline struct zink_fs_key * -zink_set_fs_key(struct zink_context *ctx) +static inline struct zink_fs_key_base * +zink_set_fs_base_key(struct zink_context *ctx) { ctx->dirty_gfx_stages |= BITFIELD_BIT(MESA_SHADER_FRAGMENT); return zink_screen(ctx->base.screen)->optimal_keys ? &ctx->gfx_pipeline_state.shader_keys_optimal.key.fs : - &ctx->gfx_pipeline_state.shader_keys.key[MESA_SHADER_FRAGMENT].key.fs; + &ctx->gfx_pipeline_state.shader_keys.key[MESA_SHADER_FRAGMENT].key.fs.base; +} + +static inline const struct zink_fs_key_base * +zink_get_fs_base_key(struct zink_context *ctx) +{ + return zink_screen(ctx->base.screen)->optimal_keys ? + &ctx->gfx_pipeline_state.shader_keys_optimal.key.fs : + &ctx->gfx_pipeline_state.shader_keys.key[MESA_SHADER_FRAGMENT].key.fs.base; +} + +static inline struct zink_fs_key * +zink_set_fs_key(struct zink_context *ctx) +{ + assert(!zink_screen(ctx->base.screen)->optimal_keys); + ctx->dirty_gfx_stages |= BITFIELD_BIT(MESA_SHADER_FRAGMENT); + return &ctx->gfx_pipeline_state.shader_keys.key[MESA_SHADER_FRAGMENT].key.fs; } static inline const struct zink_fs_key * zink_get_fs_key(struct zink_context *ctx) { - return zink_screen(ctx->base.screen)->optimal_keys ? - &ctx->gfx_pipeline_state.shader_keys_optimal.key.fs : - &ctx->gfx_pipeline_state.shader_keys.key[MESA_SHADER_FRAGMENT].key.fs; + assert(!zink_screen(ctx->base.screen)->optimal_keys); + return &ctx->gfx_pipeline_state.shader_keys.key[MESA_SHADER_FRAGMENT].key.fs; +} + +static inline struct zink_gs_key * +zink_set_gs_key(struct zink_context *ctx) +{ + ctx->dirty_gfx_stages |= BITFIELD_BIT(MESA_SHADER_GEOMETRY); + assert(!zink_screen(ctx->base.screen)->optimal_keys); + return &ctx->gfx_pipeline_state.shader_keys.key[MESA_SHADER_GEOMETRY].key.gs; +} + +static inline const struct zink_gs_key * +zink_get_gs_key(struct zink_context *ctx) +{ + return &ctx->gfx_pipeline_state.shader_keys.key[MESA_SHADER_GEOMETRY].key.gs; } static inline bool @@ -316,16 +345,19 @@ zink_get_last_vertex_key(struct zink_context *ctx) static inline void zink_set_fs_point_coord_key(struct zink_context *ctx) { - const struct zink_fs_key *fs = zink_get_fs_key(ctx); + const struct zink_fs_key_base *fs = zink_get_fs_base_key(ctx); bool disable = ctx->gfx_pipeline_state.rast_prim != PIPE_PRIM_POINTS; uint8_t coord_replace_bits = disable ? 0 : ctx->rast_state->base.sprite_coord_enable; bool point_coord_yinvert = disable ? false : !!ctx->rast_state->base.sprite_coord_mode; if (fs->coord_replace_bits != coord_replace_bits || fs->point_coord_yinvert != point_coord_yinvert) { - zink_set_fs_key(ctx)->coord_replace_bits = coord_replace_bits; - zink_set_fs_key(ctx)->point_coord_yinvert = point_coord_yinvert; + zink_set_fs_base_key(ctx)->coord_replace_bits = coord_replace_bits; + zink_set_fs_base_key(ctx)->point_coord_yinvert = point_coord_yinvert; } } +void +zink_set_primitive_emulation_keys(struct zink_context *ctx); + static inline const struct zink_shader_key_base * zink_get_shader_key_base(struct zink_context *ctx, gl_shader_stage pstage) { @@ -341,6 +373,24 @@ zink_set_shader_key_base(struct zink_context *ctx, gl_shader_stage pstage) return &ctx->gfx_pipeline_state.shader_keys.key[pstage].base; } +static inline void +zink_set_zs_needs_shader_swizzle_key(struct zink_context *ctx, gl_shader_stage pstage, bool swizzle_update) +{ + if (!zink_screen(ctx->base.screen)->driver_workarounds.needs_zs_shader_swizzle) { + if (pstage != MESA_SHADER_FRAGMENT) + return; + const struct zink_fs_key_base *fs = zink_get_fs_base_key(ctx); + bool enable = ctx->gfx_stages[MESA_SHADER_FRAGMENT] && (ctx->gfx_stages[MESA_SHADER_FRAGMENT]->fs.legacy_shadow_mask & ctx->di.zs_swizzle[pstage].mask) > 0; + if (enable != fs->shadow_needs_shader_swizzle || (enable && swizzle_update)) + zink_set_fs_base_key(ctx)->shadow_needs_shader_swizzle = enable; + return; + } + bool enable = !!ctx->di.zs_swizzle[pstage].mask; + const struct zink_shader_key_base *key = zink_get_shader_key_base(ctx, pstage); + if (enable != key->needs_zs_shader_swizzle || (enable && swizzle_update)) + zink_set_shader_key_base(ctx, pstage)->needs_zs_shader_swizzle = enable; +} + bool zink_set_rasterizer_discard(struct zink_context *ctx, bool disable); void diff --git a/src/gallium/drivers/zink/zink_program_state.hpp b/src/gallium/drivers/zink/zink_program_state.hpp index d1832f4..0e78e9e 100644 --- a/src/gallium/drivers/zink/zink_program_state.hpp +++ b/src/gallium/drivers/zink/zink_program_state.hpp @@ -226,7 +226,10 @@ zink_get_gfx_pipeline(struct zink_context *ctx, const int rp_idx = state->render_pass ? 1 : 0; /* shortcut for reusing previous pipeline across program changes */ if (DYNAMIC_STATE == ZINK_DYNAMIC_VERTEX_INPUT || DYNAMIC_STATE == ZINK_DYNAMIC_VERTEX_INPUT2) { - if (prog->last_finalized_hash[rp_idx][idx] == state->final_hash && !prog->inline_variants && likely(prog->last_pipeline[rp_idx][idx])) { + if (prog->last_finalized_hash[rp_idx][idx] == state->final_hash && + !prog->inline_variants && likely(prog->last_pipeline[rp_idx][idx]) && + /* this data is too big to compare in the fast-path */ + likely(!prog->shaders[MESA_SHADER_FRAGMENT]->fs.legacy_shadow_mask)) { state->pipeline = prog->last_pipeline[rp_idx][idx]->pipeline; return state->pipeline; } @@ -251,9 +254,11 @@ zink_get_gfx_pipeline(struct zink_context *ctx, if (HAVE_LIB && /* TODO: if there's ever a dynamic render extension with input attachments */ !ctx->gfx_pipeline_state.render_pass && + /* this is just terrible */ + !zink_get_fs_base_key(ctx)->shadow_needs_shader_swizzle && /* TODO: is sample shading even possible to handle with GPL? */ !ctx->gfx_stages[MESA_SHADER_FRAGMENT]->nir->info.fs.uses_sample_shading && - !zink_get_fs_key(ctx)->fbfetch_ms && + !zink_get_fs_base_key(ctx)->fbfetch_ms && !ctx->gfx_pipeline_state.force_persample_interp && !ctx->gfx_pipeline_state.min_samples) { /* this is the graphics pipeline library path: find/construct all partial pipelines */ @@ -357,6 +362,10 @@ equals_gfx_pipeline_state(const void *a, const void *b) if (STAGE_MASK & STAGE_MASK_OPTIMAL) { if (sa->optimal_key != sb->optimal_key) return false; + if (STAGE_MASK & STAGE_MASK_OPTIMAL_SHADOW) { + if (sa->shadow != sb->shadow) + return false; + } } else { if (STAGE_MASK & BITFIELD_BIT(MESA_SHADER_TESS_CTRL)) { if (sa->modules[MESA_SHADER_TESS_CTRL] != sb->modules[MESA_SHADER_TESS_CTRL]) @@ -382,10 +391,13 @@ equals_gfx_pipeline_state(const void *a, const void *b) /* below is a bunch of code to pick the right equals_gfx_pipeline_state template for runtime */ template static equals_gfx_pipeline_state_func -get_optimal_gfx_pipeline_stage_eq_func(bool optimal_keys) +get_optimal_gfx_pipeline_stage_eq_func(bool optimal_keys, bool shadow_needs_shader_swizzle) { - if (optimal_keys) + if (optimal_keys) { + if (shadow_needs_shader_swizzle) + return equals_gfx_pipeline_state; return equals_gfx_pipeline_state; + } return equals_gfx_pipeline_state; } @@ -393,39 +405,40 @@ template static equals_gfx_pipeline_state_func get_gfx_pipeline_stage_eq_func(struct zink_gfx_program *prog, bool optimal_keys) { + bool shadow_needs_shader_swizzle = prog->shaders[MESA_SHADER_FRAGMENT]->fs.legacy_shadow_mask > 0; unsigned vertex_stages = prog->stages_present & BITFIELD_MASK(MESA_SHADER_FRAGMENT); if (vertex_stages & BITFIELD_BIT(MESA_SHADER_TESS_CTRL)) { - if (prog->shaders[MESA_SHADER_TESS_CTRL]->tcs.is_generated) + if (prog->shaders[MESA_SHADER_TESS_CTRL]->non_fs.is_generated) vertex_stages &= ~BITFIELD_BIT(MESA_SHADER_TESS_CTRL); } if (vertex_stages & BITFIELD_BIT(MESA_SHADER_TESS_CTRL)) { if (vertex_stages == BITFIELD_MASK(MESA_SHADER_FRAGMENT)) /* all stages */ return get_optimal_gfx_pipeline_stage_eq_func(optimal_keys); + BITFIELD_MASK(MESA_SHADER_COMPUTE)>(optimal_keys, shadow_needs_shader_swizzle); if (vertex_stages == BITFIELD_MASK(MESA_SHADER_GEOMETRY)) /* tess only: includes generated tcs too */ return get_optimal_gfx_pipeline_stage_eq_func(optimal_keys); + BITFIELD_MASK(MESA_SHADER_COMPUTE) & ~BITFIELD_BIT(MESA_SHADER_GEOMETRY)>(optimal_keys, shadow_needs_shader_swizzle); if (vertex_stages == (BITFIELD_BIT(MESA_SHADER_VERTEX) | BITFIELD_BIT(MESA_SHADER_GEOMETRY))) /* geom only */ return get_optimal_gfx_pipeline_stage_eq_func(optimal_keys); + BITFIELD_BIT(MESA_SHADER_VERTEX) | BITFIELD_BIT(MESA_SHADER_FRAGMENT) | BITFIELD_BIT(MESA_SHADER_GEOMETRY)>(optimal_keys, shadow_needs_shader_swizzle); } if (vertex_stages == (BITFIELD_MASK(MESA_SHADER_FRAGMENT) & ~BITFIELD_BIT(MESA_SHADER_TESS_CTRL))) /* all stages but tcs */ return get_optimal_gfx_pipeline_stage_eq_func(optimal_keys); + BITFIELD_MASK(MESA_SHADER_COMPUTE) & ~BITFIELD_BIT(MESA_SHADER_TESS_CTRL)>(optimal_keys, shadow_needs_shader_swizzle); if (vertex_stages == (BITFIELD_MASK(MESA_SHADER_GEOMETRY) & ~BITFIELD_BIT(MESA_SHADER_TESS_CTRL))) /* tess only: generated tcs */ return get_optimal_gfx_pipeline_stage_eq_func(optimal_keys); + BITFIELD_MASK(MESA_SHADER_COMPUTE) & ~(BITFIELD_BIT(MESA_SHADER_GEOMETRY) | BITFIELD_BIT(MESA_SHADER_TESS_CTRL))>(optimal_keys, shadow_needs_shader_swizzle); if (vertex_stages == (BITFIELD_BIT(MESA_SHADER_VERTEX) | BITFIELD_BIT(MESA_SHADER_GEOMETRY))) /* geom only */ return get_optimal_gfx_pipeline_stage_eq_func(optimal_keys); + BITFIELD_BIT(MESA_SHADER_VERTEX) | BITFIELD_BIT(MESA_SHADER_FRAGMENT) | BITFIELD_BIT(MESA_SHADER_GEOMETRY)>(optimal_keys, shadow_needs_shader_swizzle); return get_optimal_gfx_pipeline_stage_eq_func(optimal_keys); + BITFIELD_BIT(MESA_SHADER_VERTEX) | BITFIELD_BIT(MESA_SHADER_FRAGMENT)>(optimal_keys, shadow_needs_shader_swizzle); } equals_gfx_pipeline_state_func diff --git a/src/gallium/drivers/zink/zink_render_pass.c b/src/gallium/drivers/zink/zink_render_pass.c index ac13442..2bcb2b8 100644 --- a/src/gallium/drivers/zink/zink_render_pass.c +++ b/src/gallium/drivers/zink/zink_render_pass.c @@ -366,7 +366,8 @@ zink_init_zs_attachment(struct zink_context *ctx, struct zink_rt_attrib *rt) needs_write_z |= transient || rt->clear_color || (zink_fb_clear_enabled(ctx, PIPE_MAX_COLOR_BUFS) && (zink_fb_clear_element(fb_clear, 0)->zs.bits & PIPE_CLEAR_DEPTH)); - bool needs_write_s = rt->clear_stencil || (outputs_written & BITFIELD64_BIT(FRAG_RESULT_STENCIL)) || + bool needs_write_s = (ctx->dsa_state && (util_writes_stencil(&ctx->dsa_state->base.stencil[0]) || util_writes_stencil(&ctx->dsa_state->base.stencil[1]))) || + rt->clear_stencil || (outputs_written & BITFIELD64_BIT(FRAG_RESULT_STENCIL)) || (zink_fb_clear_enabled(ctx, PIPE_MAX_COLOR_BUFS) && (zink_fb_clear_element(fb_clear, 0)->zs.bits & PIPE_CLEAR_STENCIL)); rt->needs_write = needs_write_z | needs_write_s; rt->invalid = !zsbuf->valid; @@ -589,7 +590,9 @@ setup_framebuffer(struct zink_context *ctx) ctx->rp_loadop_changed = false; ctx->rp_layout_changed = false; ctx->rp_changed = false; - zink_render_update_swapchain(ctx); + + if (zink_render_update_swapchain(ctx)) + zink_render_fixup_swapchain(ctx); if (!ctx->fb_changed) return; @@ -814,6 +817,25 @@ zink_init_render_pass(struct zink_context *ctx) } void +zink_render_fixup_swapchain(struct zink_context *ctx) +{ + if ((ctx->swapchain_size.width || ctx->swapchain_size.height)) { + unsigned old_w = ctx->fb_state.width; + unsigned old_h = ctx->fb_state.height; + ctx->fb_state.width = ctx->swapchain_size.width; + ctx->fb_state.height = ctx->swapchain_size.height; + ctx->dynamic_fb.info.renderArea.extent.width = MIN2(ctx->dynamic_fb.info.renderArea.extent.width, ctx->fb_state.width); + ctx->dynamic_fb.info.renderArea.extent.height = MIN2(ctx->dynamic_fb.info.renderArea.extent.height, ctx->fb_state.height); + zink_kopper_fixup_depth_buffer(ctx); + if (ctx->fb_state.width != old_w || ctx->fb_state.height != old_h) + ctx->scissor_changed = true; + if (ctx->framebuffer) + zink_update_framebuffer_state(ctx); + ctx->swapchain_size.width = ctx->swapchain_size.height = 0; + } +} + +bool zink_render_update_swapchain(struct zink_context *ctx) { bool has_swapchain = false; @@ -827,16 +849,5 @@ zink_render_update_swapchain(struct zink_context *ctx) zink_surface_swapchain_update(ctx, zink_csurface(ctx->fb_state.cbufs[i])); } } - if (has_swapchain && (ctx->swapchain_size.width || ctx->swapchain_size.height)) { - unsigned old_w = ctx->fb_state.width; - unsigned old_h = ctx->fb_state.height; - ctx->fb_state.width = ctx->swapchain_size.width; - ctx->fb_state.height = ctx->swapchain_size.height; - zink_kopper_fixup_depth_buffer(ctx); - if (ctx->fb_state.width != old_w || ctx->fb_state.height != old_h) - ctx->scissor_changed = true; - if (ctx->framebuffer) - zink_update_framebuffer_state(ctx); - ctx->swapchain_size.width = ctx->swapchain_size.height = 0; - } + return has_swapchain; } diff --git a/src/gallium/drivers/zink/zink_render_pass.h b/src/gallium/drivers/zink/zink_render_pass.h index d3d74e2..3d5bd41 100644 --- a/src/gallium/drivers/zink/zink_render_pass.h +++ b/src/gallium/drivers/zink/zink_render_pass.h @@ -47,9 +47,11 @@ VkImageLayout zink_tc_renderpass_info_parse(struct zink_context *ctx, const struct tc_renderpass_info *info, unsigned idx, VkPipelineStageFlags *pipeline, VkAccessFlags *access); bool zink_init_render_pass(struct zink_context *ctx); -void +bool zink_render_update_swapchain(struct zink_context *ctx); void +zink_render_fixup_swapchain(struct zink_context *ctx); +void zink_init_zs_attachment(struct zink_context *ctx, struct zink_rt_attrib *rt); void zink_init_color_attachment(struct zink_context *ctx, unsigned i, struct zink_rt_attrib *rt); diff --git a/src/gallium/drivers/zink/zink_resource.c b/src/gallium/drivers/zink/zink_resource.c index df5123c..9b54427 100644 --- a/src/gallium/drivers/zink/zink_resource.c +++ b/src/gallium/drivers/zink/zink_resource.c @@ -105,6 +105,7 @@ zink_destroy_resource_object(struct zink_screen *screen, struct zink_resource_ob while (util_dynarray_contains(&obj->views, VkImageView)) VKSCR(DestroyImageView)(screen->dev, util_dynarray_pop(&obj->views, VkImageView), NULL); } + util_dynarray_fini(&obj->views); if (obj->is_buffer) { VKSCR(DestroyBuffer)(screen->dev, obj->buffer, NULL); VKSCR(DestroyBuffer)(screen->dev, obj->storage_buffer, NULL); @@ -460,6 +461,10 @@ create_ici(struct zink_screen *screen, VkImageCreateInfo *ici, const struct pipe ici->usage = 0; ici->queueFamilyIndexCount = 0; + /* assume we're going to be doing some CompressedTexSubImage */ + if (util_format_is_compressed(templ->format) && (ici->flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT)) + ici->flags |= VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT; + if (templ->flags & PIPE_RESOURCE_FLAG_SPARSE) ici->flags |= VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT; @@ -590,6 +595,8 @@ resource_object_create(struct zink_screen *screen, const struct pipe_resource *t return NULL; simple_mtx_init(&obj->view_lock, mtx_plain); util_dynarray_init(&obj->views, NULL); + obj->unordered_read = true; + obj->unordered_write = true; obj->last_dt_idx = obj->dt_idx = UINT32_MAX; //TODO: unionize VkMemoryRequirements reqs = {0}; @@ -2348,6 +2355,7 @@ zink_screen_resource_init(struct pipe_screen *pscreen) pscreen->transfer_helper = u_transfer_helper_create(&transfer_vtbl, U_TRANSFER_HELPER_SEPARATE_Z32S8 | U_TRANSFER_HELPER_SEPARATE_STENCIL | U_TRANSFER_HELPER_INTERLEAVE_IN_PLACE | + U_TRANSFER_HELPER_MSAA_MAP | (!screen->have_D24_UNORM_S8_UINT ? U_TRANSFER_HELPER_Z24_IN_Z32F : 0)); if (screen->info.have_KHR_external_memory_fd || screen->info.have_KHR_external_memory_win32) { diff --git a/src/gallium/drivers/zink/zink_screen.c b/src/gallium/drivers/zink/zink_screen.c index 3427b68..a7b720a 100644 --- a/src/gallium/drivers/zink/zink_screen.c +++ b/src/gallium/drivers/zink/zink_screen.c @@ -89,17 +89,6 @@ uint32_t zink_debug; -static const struct debug_named_value -zink_descriptor_options[] = { - { "auto", ZINK_DESCRIPTOR_MODE_AUTO, "Automatically detect best mode" }, - { "lazy", ZINK_DESCRIPTOR_MODE_LAZY, "Don't cache, do least amount of updates" }, - DEBUG_NAMED_VALUE_END -}; - -DEBUG_GET_ONCE_FLAGS_OPTION(zink_descriptor_mode, "ZINK_DESCRIPTORS", zink_descriptor_options, ZINK_DESCRIPTOR_MODE_AUTO) - -enum zink_descriptor_mode zink_descriptor_mode; - static const char * zink_get_vendor(struct pipe_screen *pscreen) { @@ -523,6 +512,9 @@ zink_get_param(struct pipe_screen *pscreen, enum pipe_cap param) case PIPE_CAP_NATIVE_FENCE_FD: return screen->instance_info.have_KHR_external_semaphore_capabilities && screen->info.have_KHR_external_semaphore_fd; + case PIPE_CAP_SURFACE_REINTERPRET_BLOCKS: + return screen->info.have_vulkan11 || screen->info.have_KHR_maintenance2; + case PIPE_CAP_ALLOW_MAPPED_BUFFERS_DURING_EXECUTION: case PIPE_CAP_MAP_UNSYNCHRONIZED_THREAD_SAFE: case PIPE_CAP_SHAREABLE_SHADERS: @@ -587,7 +579,8 @@ zink_get_param(struct pipe_screen *pscreen, enum pipe_cap param) return screen->info.feats.features.pipelineStatisticsQuery; case PIPE_CAP_ROBUST_BUFFER_ACCESS_BEHAVIOR: - return screen->info.feats.features.robustBufferAccess; + return screen->info.feats.features.robustBufferAccess && + (screen->info.rb2_feats.robustImageAccess2 || screen->driver_workarounds.lower_robustImageAccess2); case PIPE_CAP_MULTI_DRAW_INDIRECT: return screen->info.feats.features.multiDrawIndirect; @@ -1426,6 +1419,10 @@ zink_destroy_screen(struct pipe_screen *pscreen) if (screen->threaded) util_queue_destroy(&screen->flush_queue); + simple_mtx_destroy(&screen->semaphores_lock); + while (util_dynarray_contains(&screen->semaphores, VkSemaphore)) + VKSCR(DestroySemaphore)(screen->dev, util_dynarray_pop(&screen->semaphores, VkSemaphore), NULL); + simple_mtx_destroy(&screen->queue_lock); VKSCR(DestroyDevice)(screen->dev, NULL); VKSCR(DestroyInstance)(screen->instance, NULL); @@ -2308,6 +2305,7 @@ init_driver_workarounds(struct zink_screen *screen) case VK_DRIVER_ID_MESA_V3DV: case VK_DRIVER_ID_MESA_PANVK: case VK_DRIVER_ID_MESA_VENUS: + case VK_DRIVER_ID_IMAGINATION_PROPRIETARY: screen->driver_workarounds.implicit_sync = false; break; default: @@ -2346,7 +2344,6 @@ init_driver_workarounds(struct zink_screen *screen) screen->info.gpl_props.graphicsPipelineLibraryFastLinking || screen->is_cpu); screen->driver_workarounds.broken_l4a4 = screen->info.driver_props.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY; - screen->driver_workarounds.depth_clip_control_missing = !screen->info.have_EXT_depth_clip_control; if (screen->info.driver_props.driverID == VK_DRIVER_ID_AMD_PROPRIETARY) /* this completely breaks xfb somehow */ screen->info.have_EXT_extended_dynamic_state2 = false; @@ -2354,6 +2351,37 @@ init_driver_workarounds(struct zink_screen *screen) /* performance */ screen->info.border_color_feats.customBorderColorWithoutFormat = VK_FALSE; } + + if ((!screen->info.have_EXT_line_rasterization || + !screen->info.line_rast_feats.stippledBresenhamLines) && + screen->info.feats.features.geometryShader && + screen->info.feats.features.sampleRateShading) { + /* we're using stippledBresenhamLines as a proxy for all of these, to + * avoid accidentally changing behavior on VK-drivers where we don't + * want to add emulation. + */ + screen->driver_workarounds.no_linestipple = true; + } + + if (screen->info.driver_props.driverID == + VK_DRIVER_ID_IMAGINATION_PROPRIETARY) { + assert(screen->info.feats.features.geometryShader); + screen->driver_workarounds.no_linesmooth = true; + } + + /* This is a workarround for the lack of + * gl_PointSize + glPolygonMode(..., GL_LINE), in the imagination + * proprietary driver. + */ + switch (screen->info.driver_props.driverID) { + case VK_DRIVER_ID_IMAGINATION_PROPRIETARY: + screen->driver_workarounds.no_hw_gl_point = true; + break; + default: + screen->driver_workarounds.no_hw_gl_point = false; + break; + } + if (screen->info.driver_props.driverID == VK_DRIVER_ID_AMD_OPEN_SOURCE || screen->info.driver_props.driverID == VK_DRIVER_ID_AMD_PROPRIETARY || screen->info.driver_props.driverID == VK_DRIVER_ID_NVIDIA_PROPRIETARY || @@ -2402,6 +2430,23 @@ init_driver_workarounds(struct zink_screen *screen) screen->driver_workarounds.needs_sanitised_layer = false; break; } + /* these drivers will produce undefined results when using swizzle 1 with combined z/s textures + * TODO: use a future device property when available + */ + switch (screen->info.driver_props.driverID) { + case VK_DRIVER_ID_IMAGINATION_PROPRIETARY: + screen->driver_workarounds.needs_zs_shader_swizzle = true; + break; + default: + screen->driver_workarounds.needs_zs_shader_swizzle = false; + break; + } + + /* When robust contexts are advertised but robustImageAccess2 is not available */ + screen->driver_workarounds.lower_robustImageAccess2 = + !screen->info.rb2_feats.robustImageAccess2 && + screen->info.feats.features.robustBufferAccess && + screen->info.rb_image_feats.robustImageAccess; /* once more testing has been done, use the #if 0 block */ if (zink_debug & ZINK_DEBUG_RP) @@ -2435,6 +2480,27 @@ zink_get_disk_shader_cache(struct pipe_screen *_screen) return screen->disk_cache; } +VkSemaphore +zink_create_semaphore(struct zink_screen *screen) +{ + VkSemaphoreCreateInfo sci = { + VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, + NULL, + 0 + }; + VkSemaphore sem = VK_NULL_HANDLE; + if (util_dynarray_contains(&screen->semaphores, VkSemaphore)) { + simple_mtx_lock(&screen->semaphores_lock); + if (util_dynarray_contains(&screen->semaphores, VkSemaphore)) + sem = util_dynarray_pop(&screen->semaphores, VkSemaphore); + simple_mtx_unlock(&screen->semaphores_lock); + } + if (sem) + return sem; + VkResult ret = VKSCR(CreateSemaphore)(screen->dev, &sci, NULL, &sem); + return ret == VK_SUCCESS ? sem : VK_NULL_HANDLE; +} + static struct zink_screen * zink_internal_create_screen(const struct pipe_screen_config *config) { @@ -2451,7 +2517,6 @@ zink_internal_create_screen(const struct pipe_screen_config *config) screen->abort_on_hang = debug_get_bool_option("ZINK_HANG_ABORT", false); zink_debug = debug_get_option_zink_debug(); - zink_descriptor_mode = debug_get_option_zink_descriptor_mode(); screen->loader_lib = util_dl_open(VK_LIBNAME); if (!screen->loader_lib) @@ -2560,9 +2625,6 @@ zink_internal_create_screen(const struct pipe_screen_config *config) screen->desc_set_id[ZINK_DESCRIPTOR_TYPE_IMAGE] = 4; screen->desc_set_id[ZINK_DESCRIPTOR_BINDLESS] = 5; } - if (zink_descriptor_mode == ZINK_DESCRIPTOR_MODE_AUTO) { - zink_descriptor_mode = ZINK_DESCRIPTOR_MODE_LAZY; - } if (screen->info.have_EXT_calibrated_timestamps && !check_have_device_time(screen)) goto fail; @@ -2697,6 +2759,9 @@ zink_internal_create_screen(const struct pipe_screen_config *config) util_idalloc_mt_init_tc(&screen->buffer_ids); + simple_mtx_init(&screen->semaphores_lock, mtx_plain); + util_dynarray_init(&screen->semaphores, screen); + util_vertex_state_cache_init(&screen->vertex_state_cache, zink_create_vertex_state, zink_vertex_state_destroy); screen->base.create_vertex_state = zink_cache_create_vertex_state; @@ -2725,7 +2790,14 @@ zink_internal_create_screen(const struct pipe_screen_config *config) goto fail; } - screen->optimal_keys = !screen->need_decompose_attrs && screen->info.have_EXT_non_seamless_cube_map && !screen->driconf.inline_uniforms; + screen->optimal_keys = !screen->need_decompose_attrs && + screen->info.have_EXT_non_seamless_cube_map && + !screen->driconf.inline_uniforms && + !screen->driver_workarounds.no_linestipple && + !screen->driver_workarounds.no_linesmooth && + !screen->driver_workarounds.no_hw_gl_point && + !screen->driver_workarounds.lower_robustImageAccess2 && + !screen->driver_workarounds.needs_zs_shader_swizzle; if (!screen->optimal_keys) screen->info.have_EXT_graphics_pipeline_library = false; diff --git a/src/gallium/drivers/zink/zink_screen.h b/src/gallium/drivers/zink/zink_screen.h index e678eb4..1eed13c 100644 --- a/src/gallium/drivers/zink/zink_screen.h +++ b/src/gallium/drivers/zink/zink_screen.h @@ -96,6 +96,9 @@ zink_screen_handle_vkresult(struct zink_screen *screen, VkResult ret) return success; } +VkSemaphore +zink_create_semaphore(struct zink_screen *screen); + VkFormat zink_get_format(struct zink_screen *screen, enum pipe_format format); diff --git a/src/gallium/drivers/zink/zink_shader_keys.h b/src/gallium/drivers/zink/zink_shader_keys.h index fab6fb4..865c036 100644 --- a/src/gallium/drivers/zink/zink_shader_keys.h +++ b/src/gallium/drivers/zink/zink_shader_keys.h @@ -32,7 +32,8 @@ struct zink_vs_key_base { bool last_vertex_stage : 1; bool clip_halfz : 1; bool push_drawid : 1; - uint8_t pad : 5; + bool robust_access : 1; + uint8_t pad : 4; }; struct zink_vs_key { @@ -56,21 +57,59 @@ struct zink_vs_key { unsigned size; }; -struct zink_fs_key { +struct zink_gs_key { + struct zink_vs_key_base base; + uint8_t pad; + bool lower_line_stipple : 1; + bool lower_line_smooth : 1; + bool lower_gl_point : 1; + // not hashed + unsigned size; +}; + +struct zink_zs_swizzle { + uint8_t s[4]; +}; + +struct zink_zs_swizzle_key { + uint32_t mask; + struct zink_zs_swizzle swizzle[32]; +}; + +struct zink_fs_key_base { bool point_coord_yinvert : 1; bool samples : 1; bool force_dual_color_blend : 1; bool force_persample_interp : 1; bool fbfetch_ms : 1; - uint8_t pad : 3; + bool shadow_needs_shader_swizzle : 1; //append zink_zs_swizzle_key after the key data + uint8_t pad : 2; uint8_t coord_replace_bits; }; +struct zink_fs_key { + struct zink_fs_key_base base; + /* non-optimal bits after this point */ + bool lower_line_stipple : 1; + bool lower_line_smooth : 1; + bool robust_access : 1; + uint16_t pad2 : 13; +}; + struct zink_tcs_key { uint8_t patch_vertices; }; +/* when adding a new field, make sure + * ctx->compute_pipeline_state.key.size is set in zink_context_create. + */ +struct zink_cs_key { + bool robust_access : 1; + uint32_t pad : 31; +}; + struct zink_shader_key_base { + bool needs_zs_shader_swizzle; uint32_t nonseamless_cube_mask; uint32_t inlined_uniform_values[MAX_INLINABLE_UNIFORMS]; }; @@ -82,11 +121,14 @@ struct zink_shader_key_base { */ struct zink_shader_key { union { - /* reuse vs key for now with tes/gs since we only use clip_halfz */ + /* reuse vs key for now with tes since we only use clip_halfz */ struct zink_vs_key vs; struct zink_vs_key_base vs_base; struct zink_tcs_key tcs; + struct zink_gs_key gs; struct zink_fs_key fs; + struct zink_fs_key_base fs_base; + struct zink_cs_key cs; } key; struct zink_shader_key_base base; unsigned inline_uniforms:1; @@ -97,7 +139,7 @@ union zink_shader_key_optimal { struct { struct zink_vs_key_base vs_base; struct zink_tcs_key tcs; - struct zink_fs_key fs; + struct zink_fs_key_base fs; }; struct { uint8_t vs_bits; @@ -120,6 +162,13 @@ zink_shader_key_optimal_no_tcs(uint32_t key) } #define ZINK_SHADER_KEY_OPTIMAL_IS_DEFAULT(key) (zink_shader_key_optimal_no_tcs(key) == ZINK_SHADER_KEY_OPTIMAL_DEFAULT) +static inline const struct zink_fs_key_base * +zink_fs_key_base(const struct zink_shader_key *key) +{ + assert(key); + return &key->key.fs.base; +} + static inline const struct zink_fs_key * zink_fs_key(const struct zink_shader_key *key) { @@ -140,6 +189,13 @@ zink_vs_key(const struct zink_shader_key *key) return &key->key.vs; } +static inline const struct zink_gs_key * +zink_gs_key(const struct zink_shader_key *key) +{ + assert(key); + return &key->key.gs; +} + static inline const struct zink_tcs_key * zink_tcs_key(const struct zink_shader_key *key) { @@ -147,6 +203,11 @@ zink_tcs_key(const struct zink_shader_key *key) return &key->key.tcs; } - +static inline const struct zink_cs_key * +zink_cs_key(const struct zink_shader_key *key) +{ + assert(key); + return &key->key.cs; +} #endif diff --git a/src/gallium/drivers/zink/zink_state.c b/src/gallium/drivers/zink/zink_state.c index c38a06e..17df1cd 100644 --- a/src/gallium/drivers/zink/zink_state.c +++ b/src/gallium/drivers/zink/zink_state.c @@ -411,8 +411,8 @@ zink_bind_blend_state(struct pipe_context *pctx, void *cso) state->dirty |= !zink_screen(pctx->screen)->have_full_ds3; bool force_dual_color_blend = zink_screen(pctx->screen)->driconf.dual_color_blend_by_location && blend && blend->dual_src_blend && state->blend_state->attachments[0].blendEnable; - if (force_dual_color_blend != zink_get_fs_key(ctx)->force_dual_color_blend) - zink_set_fs_key(ctx)->force_dual_color_blend = force_dual_color_blend; + if (force_dual_color_blend != zink_get_fs_base_key(ctx)->force_dual_color_blend) + zink_set_fs_base_key(ctx)->force_dual_color_blend = force_dual_color_blend; ctx->blend_state_changed = true; } } @@ -510,7 +510,7 @@ zink_bind_depth_stencil_alpha_state(struct pipe_context *pctx, void *cso) { struct zink_context *ctx = zink_context(pctx); - bool prev_zwrite = ctx->dsa_state ? ctx->dsa_state->hw_state.depth_write : false; + bool prev_zswrite = ctx->dsa_state ? ctx->dsa_state->hw_state.depth_write || ctx->dsa_state->hw_state.stencil_test : false; ctx->dsa_state = cso; if (cso) { @@ -521,7 +521,8 @@ zink_bind_depth_stencil_alpha_state(struct pipe_context *pctx, void *cso) ctx->dsa_state_changed = true; } } - if (prev_zwrite != (ctx->dsa_state ? ctx->dsa_state->hw_state.depth_write : false)) { + bool zs_write = ctx->dsa_state ? ctx->dsa_state->hw_state.depth_write || ctx->dsa_state->hw_state.stencil_test : false; + if (prev_zswrite != zs_write) { /* flag renderpass for re-check on next draw */ ctx->rp_layout_changed = true; } @@ -564,7 +565,10 @@ zink_create_rasterizer_state(struct pipe_context *pctx, state->base = *rs_state; state->base.line_stipple_factor++; - state->hw_state.line_stipple_enable = rs_state->line_stipple_enable; + + state->hw_state.line_stipple_enable = + rs_state->line_stipple_enable && + !screen->driver_workarounds.no_linestipple; assert(rs_state->depth_clip_far == rs_state->depth_clip_near); state->hw_state.depth_clip = rs_state->depth_clip_near; @@ -575,8 +579,15 @@ zink_create_rasterizer_state(struct pipe_context *pctx, assert(rs_state->fill_front <= PIPE_POLYGON_MODE_POINT); if (rs_state->fill_back != rs_state->fill_front) debug_printf("BUG: vulkan doesn't support different front and back fill modes\n"); - state->hw_state.polygon_mode = rs_state->fill_front; // same values - state->cull_mode = rs_state->cull_face; // same bits + + if (rs_state->fill_front == PIPE_POLYGON_MODE_POINT && + screen->driver_workarounds.no_hw_gl_point) { + state->hw_state.polygon_mode = VK_POLYGON_MODE_FILL; + state->cull_mode = VK_CULL_MODE_NONE; + } else { + state->hw_state.polygon_mode = rs_state->fill_front; // same values + state->cull_mode = rs_state->cull_face; // same bits + } state->front_face = rs_state->front_ccw ? VK_FRONT_FACE_COUNTER_CLOCKWISE : @@ -584,7 +595,8 @@ zink_create_rasterizer_state(struct pipe_context *pctx, state->hw_state.line_mode = VK_LINE_RASTERIZATION_MODE_DEFAULT_EXT; if (rs_state->line_rectangular) { - if (rs_state->line_smooth) + if (rs_state->line_smooth && + !screen->driver_workarounds.no_linesmooth) state->hw_state.line_mode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT; else state->hw_state.line_mode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT; @@ -638,7 +650,7 @@ zink_bind_rasterizer_state(struct pipe_context *pctx, void *cso) ctx->rast_state_changed = true; if (clip_halfz != ctx->rast_state->base.clip_halfz) { - if (!screen->driver_workarounds.depth_clip_control_missing) + if (screen->info.have_EXT_depth_clip_control) ctx->gfx_pipeline_state.dirty = true; else zink_set_last_vertex_key(ctx)->clip_halfz = ctx->rast_state->base.clip_halfz; @@ -648,6 +660,11 @@ zink_bind_rasterizer_state(struct pipe_context *pctx, void *cso) if (fabs(ctx->rast_state->base.line_width - line_width) > FLT_EPSILON) ctx->line_width_changed = true; + bool lower_gl_point = screen->driver_workarounds.no_hw_gl_point; + lower_gl_point &= ctx->rast_state->base.fill_front == PIPE_POLYGON_MODE_POINT; + if (zink_get_gs_key(ctx)->lower_gl_point != lower_gl_point) + zink_set_gs_key(ctx)->lower_gl_point = lower_gl_point; + if (ctx->gfx_pipeline_state.dyn_state1.front_face != ctx->rast_state->front_face) { ctx->gfx_pipeline_state.dyn_state1.front_face = ctx->rast_state->front_face; ctx->gfx_pipeline_state.dirty |= !zink_screen(pctx->screen)->info.have_EXT_extended_dynamic_state; @@ -667,7 +684,7 @@ zink_bind_rasterizer_state(struct pipe_context *pctx, void *cso) ctx->scissor_changed = true; if (ctx->rast_state->base.force_persample_interp != force_persample_interp) { - zink_set_fs_key(ctx)->force_persample_interp = ctx->rast_state->base.force_persample_interp; + zink_set_fs_base_key(ctx)->force_persample_interp = ctx->rast_state->base.force_persample_interp; ctx->gfx_pipeline_state.dirty = true; } ctx->gfx_pipeline_state.force_persample_interp = ctx->rast_state->base.force_persample_interp; diff --git a/src/gallium/drivers/zink/zink_surface.c b/src/gallium/drivers/zink/zink_surface.c index d0afa8e..9b4c86e 100644 --- a/src/gallium/drivers/zink/zink_surface.c +++ b/src/gallium/drivers/zink/zink_surface.c @@ -125,6 +125,22 @@ init_surface_info(struct zink_surface *surface, struct zink_resource *res, VkIma } } +static void +init_pipe_surface_info(struct pipe_context *pctx, struct pipe_surface *psurf, const struct pipe_surface *templ, const struct pipe_resource *pres) +{ + unsigned int level = templ->u.tex.level; + psurf->context = pctx; + psurf->format = templ->format; + psurf->width = u_minify(pres->width0, level); + assert(psurf->width); + psurf->height = u_minify(pres->height0, level); + assert(psurf->height); + psurf->nr_samples = templ->nr_samples; + psurf->u.tex.level = level; + psurf->u.tex.first_layer = templ->u.tex.first_layer; + psurf->u.tex.last_layer = templ->u.tex.last_layer; +} + static struct zink_surface * create_surface(struct pipe_context *pctx, struct pipe_resource *pres, @@ -134,7 +150,6 @@ create_surface(struct pipe_context *pctx, { struct zink_screen *screen = zink_screen(pctx->screen); struct zink_resource *res = zink_resource(pres); - unsigned int level = templ->u.tex.level; struct zink_surface *surface = CALLOC_STRUCT(zink_surface); if (!surface) @@ -163,16 +178,7 @@ create_surface(struct pipe_context *pctx, pipe_resource_reference(&surface->base.texture, pres); pipe_reference_init(&surface->base.reference, 1); - surface->base.context = pctx; - surface->base.format = templ->format; - surface->base.width = u_minify(pres->width0, level); - assert(surface->base.width); - surface->base.height = u_minify(pres->height0, level); - assert(surface->base.height); - surface->base.nr_samples = templ->nr_samples; - surface->base.u.tex.level = level; - surface->base.u.tex.first_layer = templ->u.tex.first_layer; - surface->base.u.tex.last_layer = templ->u.tex.last_layer; + init_pipe_surface_info(pctx, &surface->base, templ, pres); surface->obj = zink_resource(pres)->obj; init_surface_info(surface, res, ivci); @@ -247,7 +253,7 @@ zink_get_surface(struct zink_context *ctx, /* wrap a surface for use as a framebuffer attachment */ static struct pipe_surface * -wrap_surface(struct pipe_context *pctx, struct pipe_surface *psurf) +wrap_surface(struct pipe_context *pctx, const struct pipe_surface *psurf) { struct zink_ctx_surface *csurf = CALLOC_STRUCT(zink_ctx_surface); csurf->base = *psurf; @@ -266,10 +272,26 @@ zink_create_surface(struct pipe_context *pctx, { struct zink_resource *res = zink_resource(pres); bool is_array = templ->u.tex.last_layer != templ->u.tex.first_layer; + bool needs_mutable = false; enum pipe_texture_target target_2d[] = {PIPE_TEXTURE_2D, PIPE_TEXTURE_2D_ARRAY}; - if (!res->obj->dt && pres->format != templ->format) + if (!res->obj->dt && pres->format != templ->format) { /* mutable not set by default */ + needs_mutable = !(res->base.b.bind & ZINK_BIND_MUTABLE); + /* + VUID-VkImageViewCreateInfo-image-07072 + If image was created with the VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT flag and + format is a non-compressed format, the levelCount and layerCount members of + subresourceRange must both be 1 + */ + if (needs_mutable && util_format_is_compressed(pres->format) && templ->u.tex.first_layer != templ->u.tex.last_layer) + return NULL; + } + + if (!zink_screen(pctx->screen)->threaded && needs_mutable) { + /* this is fine without tc */ + needs_mutable = false; zink_resource_object_init_mutable(zink_context(pctx), res); + } if (!zink_get_format(zink_screen(pctx->screen), templ->format)) return NULL; @@ -285,12 +307,19 @@ zink_create_surface(struct pipe_context *pctx, surface->is_swapchain = true; psurf = &surface->base; } - } else + } else if (!needs_mutable) { psurf = zink_get_surface(zink_context(pctx), pres, templ, &ivci); - if (!psurf) + } + if (!psurf && !needs_mutable) return NULL; - struct zink_ctx_surface *csurf = (struct zink_ctx_surface*)wrap_surface(pctx, psurf); + struct zink_ctx_surface *csurf = (struct zink_ctx_surface*)wrap_surface(pctx, needs_mutable ? templ : psurf); + csurf->needs_mutable = needs_mutable; + if (needs_mutable) { + csurf->surf = NULL; + pipe_resource_reference(&csurf->base.texture, pres); + init_pipe_surface_info(pctx, &csurf->base, templ, pres); + } /* TODO: use VK_EXT_multisampled_render_to_single_sampled and skip this entirely */ if (templ->nr_samples) { @@ -352,6 +381,9 @@ zink_surface_destroy(struct pipe_context *pctx, struct pipe_surface *psurface) { struct zink_ctx_surface *csurf = (struct zink_ctx_surface *)psurface; + if (csurf->needs_mutable) + /* this has an extra resource ref */ + pipe_resource_reference(&csurf->base.texture, NULL); zink_surface_reference(zink_screen(pctx->screen), &csurf->surf, NULL); pipe_surface_release(pctx, (struct pipe_surface**)&csurf->transient); FREE(csurf); diff --git a/src/gallium/drivers/zink/zink_types.h b/src/gallium/drivers/zink/zink_types.h index b05ad12..77afb1f 100644 --- a/src/gallium/drivers/zink/zink_types.h +++ b/src/gallium/drivers/zink/zink_types.h @@ -147,11 +147,6 @@ enum zink_descriptor_type { ZINK_DESCRIPTOR_NON_BINDLESS_TYPES = ZINK_DESCRIPTOR_BASE_TYPES + 1, /**< for struct sizing */ }; -enum zink_descriptor_mode { - ZINK_DESCRIPTOR_MODE_AUTO, - ZINK_DESCRIPTOR_MODE_LAZY, -}; - /* indexing for descriptor template management */ enum zink_descriptor_size_index { ZDS_INDEX_UBO, @@ -507,7 +502,6 @@ struct zink_batch_state { struct zink_resource *swapchain; struct util_dynarray acquires; struct util_dynarray acquire_flags; - struct util_dynarray unref_semaphores; struct util_queue_fence flush_completed; @@ -689,14 +683,13 @@ struct zink_shader { union { struct { - struct zink_shader *generated; // a generated shader that this shader "owns" - } tes; - - struct { + struct zink_shader *generated_tcs; // a generated shader that this shader "owns"; only valid in the tes stage + struct zink_shader *generated_gs; // a generated shader that this shader "owns" bool is_generated; // if this is a driver-created shader (e.g., tcs) - } tcs; + } non_fs; struct { + uint32_t legacy_shadow_mask; //is_new_style_shadow is false for these nir_variable *fbfetch; //for fs output } fs; }; @@ -763,6 +756,7 @@ struct zink_gfx_pipeline_state { uint32_t vertex_buffers_enabled_mask; uint32_t vertex_strides[PIPE_MAX_ATTRIBS]; struct zink_vertex_elements_hw_state *element_state; + struct zink_zs_swizzle_key *shadow; bool sample_locations_enabled; enum pipe_prim_type shader_rast_prim, rast_prim; /* reduced type or max for unknown */ union { @@ -810,6 +804,9 @@ struct zink_gfx_push_constant { unsigned framebuffer_is_layered; float default_inner_level[2]; float default_outer_level[4]; + uint32_t line_stipple_pattern; + float viewport_scale[2]; + float line_width; }; /* The order of the enums MUST match the order of the zink_gfx_push_constant @@ -821,6 +818,9 @@ enum zink_gfx_push_constant_member { ZINK_GFX_PUSHCONST_FRAMEBUFFER_IS_LAYERED, ZINK_GFX_PUSHCONST_DEFAULT_INNER_LEVEL, ZINK_GFX_PUSHCONST_DEFAULT_OUTER_LEVEL, + ZINK_GFX_PUSHCONST_LINE_STIPPLE_PATTERN, + ZINK_GFX_PUSHCONST_VIEWPORT_SCALE, + ZINK_GFX_PUSHCONST_LINE_WIDTH, ZINK_GFX_PUSHCONST_MAX }; @@ -833,9 +833,10 @@ struct zink_shader_module { uint32_t hash; bool default_variant; bool has_nonseamless; + bool needs_zs_shader_swizzle; uint8_t num_uniforms; uint8_t key_size; - uint8_t key[0]; /* | key | uniforms | */ + uint8_t key[0]; /* | key | uniforms | zs shader swizzle | */ }; struct zink_program { @@ -860,6 +861,7 @@ struct zink_program { }; #define STAGE_MASK_OPTIMAL (1<<16) +#define STAGE_MASK_OPTIMAL_SHADOW (1<<17) typedef bool (*equals_gfx_pipeline_state_func)(const void *a, const void *b); struct zink_gfx_library_key { @@ -1185,6 +1187,9 @@ struct zink_screen { struct util_queue flush_queue; struct zink_context *copy_context; + simple_mtx_t semaphores_lock; + struct util_dynarray semaphores; + unsigned buffer_rebind_counter; unsigned image_rebind_counter; unsigned robust_ctx_count; @@ -1278,12 +1283,16 @@ struct zink_screen { struct { bool broken_l4a4; - bool depth_clip_control_missing; bool implicit_sync; bool always_feedback_loop; bool always_feedback_loop_zs; bool needs_sanitised_layer; bool track_renderpasses; + bool no_linestipple; + bool no_linesmooth; + bool no_hw_gl_point; + bool lower_robustImageAccess2; + bool needs_zs_shader_swizzle; unsigned z16_unscaled_bias; unsigned z24_unscaled_bias; } driver_workarounds; @@ -1339,6 +1348,7 @@ struct zink_ctx_surface { /* TODO: use VK_EXT_multisampled_render_to_single_sampled */ struct zink_ctx_surface *transient; //for use with EXT_multisample_render_to_texture bool transient_init; //whether the transient surface has data + bool needs_mutable; }; /* use this cast for framebuffer surfaces */ @@ -1409,6 +1419,8 @@ struct zink_sampler_view { struct zink_buffer_view *buffer_view; }; struct zink_surface *cube_array; + struct zink_surface *zs_view; + struct zink_zs_swizzle swizzle; }; struct zink_image_view { @@ -1645,6 +1657,9 @@ struct zink_context { VkDescriptorImageInfo fbfetch; + /* the current state of the zs swizzle data */ + struct zink_zs_swizzle_key zs_swizzle[MESA_SHADER_STAGES]; + struct zink_resource *descriptor_res[ZINK_DESCRIPTOR_BASE_TYPES][MESA_SHADER_STAGES][PIPE_MAX_SAMPLERS]; struct { diff --git a/src/gallium/frontends/dri/dri2.c b/src/gallium/frontends/dri/dri2.c index 2e5adf3..eca2986 100644 --- a/src/gallium/frontends/dri/dri2.c +++ b/src/gallium/frontends/dri/dri2.c @@ -2344,7 +2344,7 @@ dri_swrast_kms_init_screen(__DRIscreen * sPriv) if (!configs) goto destroy_screen; - screen->can_share_buffer = false; + screen->can_share_buffer = true; screen->auto_fake_front = dri_with_format(sPriv); screen->lookup_egl_image = dri2_lookup_egl_image; @@ -2399,8 +2399,12 @@ dri2_create_buffer(__DRIscreen * sPriv, const struct __DriverAPIRec galliumdrm_driver_api = { .InitScreen = dri2_init_screen, .DestroyScreen = dri_destroy_screen, + .CreateContext = dri_create_context, + .DestroyContext = dri_destroy_context, .CreateBuffer = dri2_create_buffer, .DestroyBuffer = dri_destroy_buffer, + .MakeCurrent = dri_make_current, + .UnbindContext = dri_unbind_context, .AllocateBuffer = dri2_allocate_buffer, .ReleaseBuffer = dri2_release_buffer, @@ -2421,8 +2425,12 @@ static const struct __DRIDriverVtableExtensionRec galliumdrm_vtable = { const struct __DriverAPIRec dri_swrast_kms_driver_api = { .InitScreen = dri_swrast_kms_init_screen, .DestroyScreen = dri_destroy_screen, + .CreateContext = dri_create_context, + .DestroyContext = dri_destroy_context, .CreateBuffer = dri2_create_buffer, .DestroyBuffer = dri_destroy_buffer, + .MakeCurrent = dri_make_current, + .UnbindContext = dri_unbind_context, .AllocateBuffer = dri2_allocate_buffer, .ReleaseBuffer = dri2_release_buffer, diff --git a/src/gallium/frontends/dri/dri_query_renderer.c b/src/gallium/frontends/dri/dri_query_renderer.c index b63192f..0813a16 100644 --- a/src/gallium/frontends/dri/dri_query_renderer.c +++ b/src/gallium/frontends/dri/dri_query_renderer.c @@ -23,7 +23,7 @@ * \returns * Zero if a recognized value of \c param is supplied, -1 otherwise. */ -static int +int driQueryRendererIntegerCommon(__DRIscreen *psp, int param, unsigned int *value) { switch (param) { diff --git a/src/gallium/frontends/dri/dri_query_renderer.h b/src/gallium/frontends/dri/dri_query_renderer.h index 59b3ff8..a9461fd 100644 --- a/src/gallium/frontends/dri/dri_query_renderer.h +++ b/src/gallium/frontends/dri/dri_query_renderer.h @@ -3,6 +3,9 @@ #include "dri_util.h" +int +driQueryRendererIntegerCommon(__DRIscreen *psp, int param, unsigned int *value); + extern const __DRI2rendererQueryExtension dri2RendererQueryExtension; diff --git a/src/gallium/frontends/dri/dri_screen.c b/src/gallium/frontends/dri/dri_screen.c index e3be46a..d4a61ce 100644 --- a/src/gallium/frontends/dri/dri_screen.c +++ b/src/gallium/frontends/dri/dri_screen.c @@ -137,19 +137,35 @@ dri_loader_get_cap(struct dri_screen *screen, enum dri_loader_cap cap) * This forces 32-bit color to have 24-bit depth, and * 16-bit color to have 16-bit depth. * + * \param yuv_depth_range YUV pixel depth range. For non-YUV pixel formats this + * should be \c __DRI_ATTRIB_YUV_DEPTH_RANGE_NONE. + * Otherwise valid values are + * \c __DRI_ATTRIB_YUV_DEPTH_RANGE_LIMITED_BIT and + * \c __DRI_ATTRIB_YUV_DEPTH_RANGE_FULL_BIT. See the + * EGL_EXT_yuv_surface extension spec for more details. + * \param yuv_csc_standard YUV color conversion standard. For non-YUV pixel + * formats this should be + * \c __DRI_ATTRIB_YUV_CSC_STANDARD_NONE. Otherwise + * valid values are + * \c __DRI_ATTRIB_YUV_CSC_STANDARD_601_BIT, + * \c __DRI_ATTRIB_YUV_CSC_STANDARD_709_BIT and + * \c __DRI_ATTRIB_YUV_CSC_STANDARD_2020_BIT. See the + * EGL_EXT_yuv_surface extension spec for more details. + * * \returns * Pointer to any array of pointers to the \c __DRIconfig structures created * for the specified formats. If there is an error, \c NULL is returned. * Currently the only cause of failure is a bad parameter (i.e., unsupported * \c format). */ -static __DRIconfig ** +__DRIconfig ** driCreateConfigs(mesa_format format, const uint8_t * depth_bits, const uint8_t * stencil_bits, unsigned num_depth_stencil_bits, const GLenum * db_modes, unsigned num_db_modes, const uint8_t * msaa_samples, unsigned num_msaa_modes, - GLboolean enable_accum, GLboolean color_depth_match) + GLboolean enable_accum, GLboolean color_depth_match, + GLint yuv_depth_range, GLint yuv_csc_standard) { static const struct { uint32_t masks[4]; @@ -188,6 +204,9 @@ driCreateConfigs(mesa_format format, /* MESA_FORMAT_RGBA_FLOAT16 */ {{ 0, 0, 0, 0}, { 0, 16, 32, 48 }}, + /* Mesa YUV formats */ + {{ 0, 0, 0, 0 }, + { -1, -1, -1, -1}}, }; const uint32_t * masks; @@ -201,6 +220,11 @@ driCreateConfigs(mesa_format format, int green_bits; int blue_bits; int alpha_bits; + int yuv_order = __DRI_ATTRIB_YUV_ORDER_NONE; + int yuv_num_planes = 0; + int yuv_subsample = __DRI_ATTRIB_YUV_SUBSAMPLE_NONE; + int yuv_plane_bpp = __DRI_ATTRIB_YUV_PLANE_BPP_NONE; + bool is_yuv = false; bool is_srgb; bool is_float; @@ -253,6 +277,78 @@ driCreateConfigs(mesa_format format, masks = format_table[8].masks; shifts = format_table[8].shifts; break; + case MESA_FORMAT_YCBCR: + masks = format_table[11].masks; + shifts = format_table[11].shifts; + is_yuv = true; /* FIXME: This should come from formats_info.py */ + yuv_order = __DRI_ATTRIB_YUV_ORDER_YUYV_BIT; + yuv_num_planes = 1; + yuv_subsample = __DRI_ATTRIB_YUV_SUBSAMPLE_4_2_2_BIT; + yuv_plane_bpp = __DRI_ATTRIB_YUV_PLANE_BPP_8_BIT; + break; + case MESA_FORMAT_YUV420_2PLANE: + masks = format_table[11].masks; + shifts = format_table[11].shifts; + is_yuv = true; /* FIXME: This should come from formats_info.py */ + yuv_order = __DRI_ATTRIB_YUV_ORDER_YUV_BIT; + yuv_num_planes = 2; + yuv_subsample = __DRI_ATTRIB_YUV_SUBSAMPLE_4_2_0_BIT; + yuv_plane_bpp = __DRI_ATTRIB_YUV_PLANE_BPP_8_BIT; + break; + case MESA_FORMAT_YVU420_2PLANE: + masks = format_table[11].masks; + shifts = format_table[11].shifts; + is_yuv = true; /* FIXME: This should come from formats_info.py */ + yuv_order = __DRI_ATTRIB_YUV_ORDER_YVU_BIT; + yuv_num_planes = 2; + yuv_subsample = __DRI_ATTRIB_YUV_SUBSAMPLE_4_2_0_BIT; + yuv_plane_bpp = __DRI_ATTRIB_YUV_PLANE_BPP_8_BIT; + break; + case MESA_FORMAT_YUV420_3PLANE: + masks = format_table[11].masks; + shifts = format_table[11].shifts; + is_yuv = true; /* FIXME: This should come from formats_info.py */ + yuv_order = __DRI_ATTRIB_YUV_ORDER_YUV_BIT; + yuv_num_planes = 3; + yuv_subsample = __DRI_ATTRIB_YUV_SUBSAMPLE_4_2_0_BIT; + yuv_plane_bpp = __DRI_ATTRIB_YUV_PLANE_BPP_8_BIT; + break; + case MESA_FORMAT_YVU420_3PLANE: + masks = format_table[11].masks; + shifts = format_table[11].shifts; + is_yuv = true; /* FIXME: This should come from formats_info.py */ + yuv_order = __DRI_ATTRIB_YUV_ORDER_YVU_BIT; + yuv_num_planes = 3; + yuv_subsample = __DRI_ATTRIB_YUV_SUBSAMPLE_4_2_0_BIT; + yuv_plane_bpp = __DRI_ATTRIB_YUV_PLANE_BPP_8_BIT; + break; + case MESA_FORMAT_YCBCR_REV: + masks = format_table[11].masks; + shifts = format_table[11].shifts; + is_yuv = true; /* FIXME: This should come from formats_info.py */ + yuv_order = __DRI_ATTRIB_YUV_ORDER_UYVY_BIT; + yuv_num_planes = 1; + yuv_subsample = __DRI_ATTRIB_YUV_SUBSAMPLE_4_2_2_BIT; + yuv_plane_bpp = __DRI_ATTRIB_YUV_PLANE_BPP_8_BIT; + break; + case MESA_FORMAT_VYUY: + masks = format_table[11].masks; + shifts = format_table[11].shifts; + is_yuv = true; /* FIXME: This should come from formats_info.py */ + yuv_order = __DRI_ATTRIB_YUV_ORDER_VYUY_BIT; + yuv_num_planes = 1; + yuv_subsample = __DRI_ATTRIB_YUV_SUBSAMPLE_4_2_2_BIT; + yuv_plane_bpp = __DRI_ATTRIB_YUV_PLANE_BPP_8_BIT; + break; + case MESA_FORMAT_YVYU: + masks = format_table[11].masks; + shifts = format_table[11].shifts; + is_yuv = true; /* FIXME: This should come from formats_info.py */ + yuv_order = __DRI_ATTRIB_YUV_ORDER_YVYU_BIT; + yuv_num_planes = 1; + yuv_subsample = __DRI_ATTRIB_YUV_SUBSAMPLE_4_2_2_BIT; + yuv_plane_bpp = __DRI_ATTRIB_YUV_PLANE_BPP_8_BIT; + break; default: fprintf(stderr, "[%s:%u] Unknown framebuffer type %s (%d).\n", __func__, __LINE__, @@ -308,7 +404,11 @@ driCreateConfigs(mesa_format format, modes->greenShift = shifts[1]; modes->blueShift = shifts[2]; modes->alphaShift = shifts[3]; - modes->rgbBits = modes->redBits + modes->greenBits + + if (is_yuv) + modes->rgbBits = 8; + else + modes->rgbBits = modes->redBits + modes->greenBits + modes->blueBits + modes->alphaBits; modes->accumRedBits = 16 * j; @@ -319,6 +419,8 @@ driCreateConfigs(mesa_format format, modes->stencilBits = stencil_bits[k]; modes->depthBits = depth_bits[k]; + modes->rgbMode = !is_yuv; + if (db_modes[i] == __DRI_ATTRIB_SWAP_NONE) { modes->doubleBufferMode = GL_FALSE; modes->swapMethod = __DRI_ATTRIB_SWAP_UNDEFINED; @@ -331,6 +433,13 @@ driCreateConfigs(mesa_format format, modes->samples = msaa_samples[h]; modes->sRGBCapable = is_srgb; + + modes->YUVOrder = yuv_order; + modes->YUVNumberOfPlanes = yuv_num_planes; + modes->YUVSubsample = yuv_subsample; + modes->YUVDepthRange = yuv_depth_range; + modes->YUVCSCStandard = yuv_csc_standard; + modes->YUVPlaneBPP = yuv_plane_bpp; } } } @@ -340,7 +449,7 @@ driCreateConfigs(mesa_format format, return configs; } -static __DRIconfig ** +__DRIconfig ** driConcatConfigs(__DRIconfig **a, __DRIconfig **b) { __DRIconfig **all; @@ -556,7 +665,9 @@ dri_fill_in_modes(struct dri_screen *screen) depth_buffer_factor, back_buffer_modes, ARRAY_SIZE(back_buffer_modes), msaa_modes, 1, - GL_TRUE, !mixed_color_depth); + GL_TRUE, !mixed_color_depth, + __DRI_ATTRIB_YUV_DEPTH_RANGE_NONE, + __DRI_ATTRIB_YUV_CSC_STANDARD_NONE); configs = driConcatConfigs(configs, new_configs); /* Multi-sample configs without an accumulation buffer. */ @@ -566,7 +677,9 @@ dri_fill_in_modes(struct dri_screen *screen) depth_buffer_factor, back_buffer_modes, ARRAY_SIZE(back_buffer_modes), msaa_modes+1, num_msaa_modes-1, - GL_FALSE, !mixed_color_depth); + GL_FALSE, !mixed_color_depth, + __DRI_ATTRIB_YUV_DEPTH_RANGE_NONE, + __DRI_ATTRIB_YUV_CSC_STANDARD_NONE); configs = driConcatConfigs(configs, new_configs); } } diff --git a/src/gallium/frontends/dri/dri_screen.h b/src/gallium/frontends/dri/dri_screen.h index 0e3bb59..7b168e4 100644 --- a/src/gallium/frontends/dri/dri_screen.h +++ b/src/gallium/frontends/dri/dri_screen.h @@ -169,6 +169,18 @@ dri_destroy_screen_helper(struct dri_screen * screen); void dri_destroy_screen(__DRIscreen * sPriv); +__DRIconfig ** +driCreateConfigs(mesa_format format, + const uint8_t * depth_bits, const uint8_t * stencil_bits, + unsigned num_depth_stencil_bits, + const GLenum * db_modes, unsigned num_db_modes, + const uint8_t * msaa_samples, unsigned num_msaa_modes, + GLboolean enable_accum, GLboolean color_depth_match, + GLint yuv_depth_range, GLint yuv_csc_standard); + +__DRIconfig ** +driConcatConfigs(__DRIconfig **a, __DRIconfig **b); + extern const struct __DriverAPIRec dri_swrast_kms_driver_api; extern const __DRIextension *dri_swrast_kms_driver_extensions[]; extern const struct __DriverAPIRec galliumdrm_driver_api; @@ -179,6 +191,8 @@ extern const struct __DriverAPIRec galliumvk_driver_api; extern const __DRIextension *galliumvk_driver_extensions[]; extern const __DRIconfigOptionsExtension gallium_config_options; +extern const struct __DriverAPIRec pvr_driver_api; +extern const __DRIextension *pvr_driver_extensions[]; #endif /* vim: set sw=3 ts=8 sts=3 expandtab: */ diff --git a/src/gallium/frontends/dri/dri_util.c b/src/gallium/frontends/dri/dri_util.c index ed10245..ca2655e 100644 --- a/src/gallium/frontends/dri/dri_util.c +++ b/src/gallium/frontends/dri/dri_util.c @@ -41,7 +41,6 @@ #include #include "dri_util.h" -#include "dri_context.h" #include "dri_screen.h" #include "util/u_endian.h" #include "util/driconf.h" @@ -49,6 +48,7 @@ #include "main/version.h" #include "main/debug_output.h" #include "main/errors.h" +#include "util/bitscan.h" driOptionDescription __dri2ConfigOptions[] = { DRI_CONF_SECTION_DEBUG @@ -196,6 +196,18 @@ swkmsCreateNewScreen(int scrn, int fd, driver_configs, data); } +#if defined(GALLIUM_PVR) +static __DRIscreen * +pvrCreateNewScreen(int scrn, int fd, + const __DRIextension **extensions, + const __DRIconfig ***driver_configs, void *data) +{ + return driCreateNewScreen2(scrn, fd, extensions, + pvr_driver_extensions, + driver_configs, data); +} +#endif + /** swrast driver createNewScreen entrypoint. */ static __DRIscreen * driSWRastCreateNewScreen(int scrn, const __DRIextension **extensions, @@ -290,7 +302,11 @@ driGetConfigAttribIndex(const __DRIconfig *config, SIMPLE_CASE(__DRI_ATTRIB_SAMPLES, samples); case __DRI_ATTRIB_RENDER_TYPE: /* no support for color index mode */ - *value = __DRI_ATTRIB_RGBA_BIT; + if (config->modes.rgbMode) + *value = __DRI_ATTRIB_RGBA_BIT; + else + *value = __DRI_ATTRIB_YUV_BIT; + if (config->modes.floatMode) *value |= __DRI_ATTRIB_FLOAT_BIT; break; @@ -322,9 +338,9 @@ driGetConfigAttribIndex(const __DRIconfig *config, SIMPLE_CASE(__DRI_ATTRIB_GREEN_MASK, greenMask); SIMPLE_CASE(__DRI_ATTRIB_BLUE_MASK, blueMask); SIMPLE_CASE(__DRI_ATTRIB_ALPHA_MASK, alphaMask); - case __DRI_ATTRIB_MAX_PBUFFER_WIDTH: - case __DRI_ATTRIB_MAX_PBUFFER_HEIGHT: - case __DRI_ATTRIB_MAX_PBUFFER_PIXELS: + SIMPLE_CASE(__DRI_ATTRIB_MAX_PBUFFER_WIDTH, maxPbufferWidth); + SIMPLE_CASE(__DRI_ATTRIB_MAX_PBUFFER_HEIGHT, maxPbufferHeight); + SIMPLE_CASE(__DRI_ATTRIB_MAX_PBUFFER_PIXELS, maxPbufferPixels); case __DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH: case __DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT: case __DRI_ATTRIB_VISUAL_SELECT_GROUP: @@ -358,6 +374,12 @@ driGetConfigAttribIndex(const __DRIconfig *config, SIMPLE_CASE(__DRI_ATTRIB_GREEN_SHIFT, greenShift); SIMPLE_CASE(__DRI_ATTRIB_BLUE_SHIFT, blueShift); SIMPLE_CASE(__DRI_ATTRIB_ALPHA_SHIFT, alphaShift); + SIMPLE_CASE(__DRI_ATTRIB_YUV_ORDER, YUVOrder); + SIMPLE_CASE(__DRI_ATTRIB_YUV_NUMBER_OF_PLANES, YUVNumberOfPlanes); + SIMPLE_CASE(__DRI_ATTRIB_YUV_SUBSAMPLE, YUVSubsample); + SIMPLE_CASE(__DRI_ATTRIB_YUV_DEPTH_RANGE, YUVDepthRange); + SIMPLE_CASE(__DRI_ATTRIB_YUV_CSC_STANDARD, YUVCSCStandard); + SIMPLE_CASE(__DRI_ATTRIB_YUV_PLANE_BPP, YUVPlaneBPP); default: /* XXX log an error or smth */ return GL_FALSE; @@ -478,7 +500,11 @@ driCreateContextAttribs(__DRIscreen *screen, int api, mesa_api = API_OPENGLES; break; case __DRI_API_GLES2: + ctx_config.major_version = 2; + mesa_api = API_OPENGLES2; + break; case __DRI_API_GLES3: + ctx_config.major_version = 3; mesa_api = API_OPENGLES2; break; case __DRI_API_OPENGL_CORE: @@ -639,8 +665,8 @@ driCreateContextAttribs(__DRIscreen *screen, int api, context->driDrawablePriv = NULL; context->driReadablePriv = NULL; - if (!dri_create_context(mesa_api, modes, context, &ctx_config, error, - shareCtx)) { + if (!screen->driver->CreateContext(mesa_api, modes, context, + &ctx_config, error, shareCtx)) { free(context); return NULL; } @@ -664,7 +690,14 @@ static __DRIcontext * driCreateNewContext(__DRIscreen *screen, const __DRIconfig *config, __DRIcontext *shared, void *data) { - return driCreateNewContextForAPI(screen, __DRI_API_OPENGL, + int apifs; + + apifs = ffs(screen->api_mask); + + if (!apifs) + return NULL; + + return driCreateNewContextForAPI(screen, apifs - 1, config, shared, data); } @@ -679,7 +712,7 @@ static void driDestroyContext(__DRIcontext *pcp) { if (pcp) { - dri_destroy_context(pcp); + pcp->driScreenPriv->driver->DestroyContext(pcp); free(pcp); } } @@ -732,7 +765,7 @@ static int driBindContext(__DRIcontext *pcp, dri_get_drawable(prp); } - return dri_make_current(pcp, pdp, prp); + return pcp->driScreenPriv->driver->MakeCurrent(pcp, pdp, prp); } /** @@ -765,10 +798,10 @@ static int driUnbindContext(__DRIcontext *pcp) return GL_FALSE; /* - ** Call dri_unbind_context before checking for valid drawables + ** Call UnbindContext before checking for valid drawables ** to handle surfaceless contexts properly. */ - dri_unbind_context(pcp); + pcp->driScreenPriv->driver->UnbindContext(pcp); pdp = pcp->driDrawablePriv; prp = pcp->driReadablePriv; @@ -1002,6 +1035,21 @@ const __DRIdri2Extension swkmsDRI2Extension = { .createNewScreen2 = driCreateNewScreen2, }; +#if defined(GALLIUM_PVR) +const __DRIdri2Extension pvrDRI2Extension = { + .base = { __DRI_DRI2, 4 }, + + .createNewScreen = pvrCreateNewScreen, + .createNewDrawable = driCreateNewDrawable, + .createNewContext = driCreateNewContext, + .getAPIMask = driGetAPIMask, + .createNewContextForAPI = driCreateNewContextForAPI, + .allocateBuffer = dri2AllocateBuffer, + .releaseBuffer = dri2ReleaseBuffer, + .createContextAttribs = driCreateContextAttribs, + .createNewScreen2 = driCreateNewScreen2, +}; +#endif #endif const __DRIswrastExtension driSWRastExtension = { @@ -1046,6 +1094,11 @@ static const struct { .mesa_format = MESA_FORMAT_B5G5R5A1_UNORM, .internal_format = GL_RGB5_A1, }, + { + .image_format = __DRI_IMAGE_FORMAT_ARGB4444, + .mesa_format = MESA_FORMAT_B4G4R4A4_UNORM, + .internal_format = GL_RGBA4, + }, { .image_format = __DRI_IMAGE_FORMAT_XRGB8888, .mesa_format = MESA_FORMAT_B8G8R8X8_UNORM, diff --git a/src/gallium/frontends/dri/dri_util.h b/src/gallium/frontends/dri/dri_util.h index 6e6bd76..edcdae3 100644 --- a/src/gallium/frontends/dri/dri_util.h +++ b/src/gallium/frontends/dri/dri_util.h @@ -76,6 +76,10 @@ extern const __DRIdri2Extension swkmsDRI2Extension; extern const __DRI2configQueryExtension dri2ConfigQueryExtension; extern const __DRI2flushControlExtension dri2FlushControlExtension; +#if defined(GALLIUM_PVR) +extern const __DRIdri2Extension pvrDRI2Extension; +#endif + /** * Description of the attributes used to create a config. * @@ -123,12 +127,25 @@ struct __DriverContextConfig { * * Each DRI driver must have one of these structures with all the pointers set * to appropriate functions within the driver. + * + * When glXCreateContext() is called, for example, it'll call a helper function + * dri_util.c which in turn will jump through the \a CreateContext pointer in + * this structure. */ struct __DriverAPIRec { const __DRIconfig **(*InitScreen) (__DRIscreen * priv); void (*DestroyScreen)(__DRIscreen *driScrnPriv); + GLboolean (*CreateContext)(gl_api api, + const struct gl_config *glVis, + __DRIcontext *driContextPriv, + const struct __DriverContextConfig *ctx_config, + unsigned *error, + void *sharedContextPrivate); + + void (*DestroyContext)(__DRIcontext *driContextPriv); + GLboolean (*CreateBuffer)(__DRIscreen *driScrnPriv, __DRIdrawable *driDrawPriv, const struct gl_config *glVis, @@ -138,6 +155,12 @@ struct __DriverAPIRec { void (*SwapBuffers)(__DRIdrawable *driDrawPriv); + GLboolean (*MakeCurrent)(__DRIcontext *driContextPriv, + __DRIdrawable *driDrawPriv, + __DRIdrawable *driReadPriv); + + GLboolean (*UnbindContext)(__DRIcontext *driContextPriv); + __DRIbuffer *(*AllocateBuffer) (__DRIscreen *screenPrivate, unsigned int attachment, unsigned int format, diff --git a/src/gallium/frontends/dri/drisw.c b/src/gallium/frontends/dri/drisw.c index b5c0b7a..4a0a27e 100644 --- a/src/gallium/frontends/dri/drisw.c +++ b/src/gallium/frontends/dri/drisw.c @@ -640,9 +640,13 @@ drisw_create_buffer(__DRIscreen * sPriv, const struct __DriverAPIRec galliumsw_driver_api = { .InitScreen = drisw_init_screen, .DestroyScreen = dri_destroy_screen, + .CreateContext = dri_create_context, + .DestroyContext = dri_destroy_context, .CreateBuffer = drisw_create_buffer, .DestroyBuffer = dri_destroy_buffer, .SwapBuffers = drisw_swap_buffers, + .MakeCurrent = dri_make_current, + .UnbindContext = dri_unbind_context, .CopySubBuffer = drisw_copy_sub_buffer, }; diff --git a/src/gallium/frontends/dri/kopper.c b/src/gallium/frontends/dri/kopper.c index 5268f1f..cfb9bfe 100644 --- a/src/gallium/frontends/dri/kopper.c +++ b/src/gallium/frontends/dri/kopper.c @@ -324,7 +324,7 @@ dri3_create_image_from_buffers(xcb_connection_t *c, bp_reply->width, bp_reply->height, image_format_to_fourcc(format), - bp_reply->modifier, + bp_reply->modifier == DRM_FORMAT_MOD_INVALID ? DRM_FORMAT_MOD_LINEAR : bp_reply->modifier, fds, bp_reply->nfd, strides, offsets, 0, 0, 0, 0, /* UNDEFINED */ @@ -1044,8 +1044,12 @@ const __DRIkopperExtension driKopperExtension = { const struct __DriverAPIRec galliumvk_driver_api = { .InitScreen = kopper_init_screen, .DestroyScreen = dri_destroy_screen, + .CreateContext = dri_create_context, + .DestroyContext = dri_destroy_context, .CreateBuffer = kopper_create_buffer, .DestroyBuffer = dri_destroy_buffer, + .MakeCurrent = dri_make_current, + .UnbindContext = dri_unbind_context, .SwapBuffers = kopper_swap_buffers, .CopySubBuffer = NULL, }; diff --git a/src/gallium/frontends/dri/meson.build b/src/gallium/frontends/dri/meson.build index f02aaeb..c38ee98 100644 --- a/src/gallium/frontends/dri/meson.build +++ b/src/gallium/frontends/dri/meson.build @@ -57,6 +57,10 @@ if with_gallium_softpipe libdri_c_args += '-DGALLIUM_SOFTPIPE' endif +if with_gallium_pvr + libdri_c_args += '-DGALLIUM_PVR' +endif + libdri = static_library( 'dri', files_libdri, diff --git a/src/gallium/frontends/pvr/dri_support.h b/src/gallium/frontends/pvr/dri_support.h new file mode 100644 index 0000000..3cc8f29 --- /dev/null +++ b/src/gallium/frontends/pvr/dri_support.h @@ -0,0 +1,638 @@ +/* -*- mode: c; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ +/* vi: set ts=8 sw=8 sts=8: */ +/*************************************************************************/ /*! +@File +@Title PVR DRI interface definition +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@License MIT + +The contents of this file are subject to the MIT license as set out below. + +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 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. +*/ /**************************************************************************/ + +#if !defined(__PVRDRIIFCE_H__) +#define __PVRDRIIFCE_H__ + +#include +#include + +/* API type. */ +typedef enum +{ + PVRDRI_API_NONE = 0, + PVRDRI_API_GLES1 = 2, + PVRDRI_API_GLES2 = 3, + PVRDRI_API_CL = 4, + PVRDRI_API_GL_COMPAT = 5, + PVRDRI_API_GL_CORE = 6, +} PVRDRIAPIType; + +typedef enum +{ + PVRDRI_CONFIG_ATTRIB_INVALID = 0, + PVRDRI_CONFIG_ATTRIB_RENDERABLE_TYPE = 1, + PVRDRI_CONFIG_ATTRIB_RGB_MODE = 2, + PVRDRI_CONFIG_ATTRIB_DOUBLE_BUFFER_MODE = 3, + PVRDRI_CONFIG_ATTRIB_RED_BITS = 4, + PVRDRI_CONFIG_ATTRIB_GREEN_BITS = 5, + PVRDRI_CONFIG_ATTRIB_BLUE_BITS = 6, + PVRDRI_CONFIG_ATTRIB_ALPHA_BITS = 7, + PVRDRI_CONFIG_ATTRIB_RGB_BITS = 8, + PVRDRI_CONFIG_ATTRIB_DEPTH_BITS = 9, + PVRDRI_CONFIG_ATTRIB_STENCIL_BITS = 10, + PVRDRI_CONFIG_ATTRIB_SAMPLE_BUFFERS = 11, + PVRDRI_CONFIG_ATTRIB_SAMPLES = 12, + PVRDRI_CONFIG_ATTRIB_BIND_TO_TEXTURE_RGB = 13, + PVRDRI_CONFIG_ATTRIB_BIND_TO_TEXTURE_RGBA = 14, + PVRDRI_CONFIG_ATTRIB_YUV_ORDER = 15, + PVRDRI_CONFIG_ATTRIB_YUV_NUM_OF_PLANES = 16, + PVRDRI_CONFIG_ATTRIB_YUV_SUBSAMPLE = 17, + PVRDRI_CONFIG_ATTRIB_YUV_DEPTH_RANGE = 18, + PVRDRI_CONFIG_ATTRIB_YUV_CSC_STANDARD = 19, + PVRDRI_CONFIG_ATTRIB_YUV_PLANE_BPP = 20, + PVRDRI_CONFIG_ATTRIB_RED_MASK = 21, + PVRDRI_CONFIG_ATTRIB_GREEN_MASK = 22, + PVRDRI_CONFIG_ATTRIB_BLUE_MASK = 23, + PVRDRI_CONFIG_ATTRIB_ALPHA_MASK = 24, + PVRDRI_CONFIG_ATTRIB_SRGB_CAPABLE = 25 +} PVRDRIConfigAttrib; + +/* EGL_RENDERABLE_TYPE mask bits */ +#define PVRDRI_API_BIT_GLES 0x0001 +#define PVRDRI_API_BIT_GLES2 0x0004 +#define PVRDRI_API_BIT_GL 0x0008 +#define PVRDRI_API_BIT_GLES3 0x0040 + +/* Mesa config formats. These need not match their MESA_FORMAT counterparts */ +#define PVRDRI_MESA_FORMAT_NONE 0 +#define PVRDRI_MESA_FORMAT_B8G8R8A8_UNORM 1 +#define PVRDRI_MESA_FORMAT_B8G8R8X8_UNORM 2 +#define PVRDRI_MESA_FORMAT_B5G6R5_UNORM 3 +#define PVRDRI_MESA_FORMAT_R8G8B8A8_UNORM 4 +#define PVRDRI_MESA_FORMAT_R8G8B8X8_UNORM 5 +#define PVRDRI_MESA_FORMAT_YCBCR 6 +#define PVRDRI_MESA_FORMAT_YUV420_2PLANE 7 +#define PVRDRI_MESA_FORMAT_YVU420_2PLANE 8 +#define PVRDRI_MESA_FORMAT_B8G8R8A8_SRGB 9 +#define PVRDRI_MESA_FORMAT_R8G8B8A8_SRGB 10 +#define PVRDRI_MESA_FORMAT_YUV420_3PLANE 11 +#define PVRDRI_MESA_FORMAT_YVU420_3PLANE 12 +#define PVRDRI_MESA_FORMAT_YCBCR_REV 13 +#define PVRDRI_MESA_FORMAT_YVYU 14 +#define PVRDRI_MESA_FORMAT_VYUY 15 + +typedef struct __DRIimageRec __DRIimage; + +typedef struct PVRDRIConfigRec PVRDRIConfig; + +/* The PVRDRI_GL defines match their EGL_GL counterparts */ +#define PVRDRI_GL_RENDERBUFFER 0x30B9 +#define PVRDRI_GL_TEXTURE_2D 0x30B1 +#define PVRDRI_GL_TEXTURE_3D 0x30B2 +#define PVRDRI_GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x30B3 +#define PVRDRI_GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x30B4 +#define PVRDRI_GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x30B5 +#define PVRDRI_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x30B6 +#define PVRDRI_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x30B7 +#define PVRDRI_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x30B8 + +struct __DRIscreenRec; +struct __DRIcontextRec; +struct __DRIdrawableRec; + +struct __DRIconfigRec; + +struct DRISUPScreen; +struct DRISUPContext; +struct DRISUPDrawable; +struct DRISUPBuffer; + +struct PVRDRIContextConfig +{ + unsigned int uMajorVersion; + unsigned int uMinorVersion; + uint32_t uFlags; + + int iResetStrategy; + unsigned int uPriority; + int iReleaseBehavior; +}; + +/* + * PVR DRI Support interface V2. + * This structure may change over time, as older interfaces become obsolete. + * For example, the v0 interface may be removed if superseded by newer + * interfaces. + */ +struct PVRDRISupportInterfaceV2 +{ + struct + { + struct DRISUPScreen *(*CreateScreen) + (struct __DRIscreenRec *psDRIScreen, + int iFD, + bool bUseInvalidate, + void *pvLoaderPrivate, + const struct __DRIconfigRec ***pppsConfigs, + int *piMaxGLES1Version, + int *piMaxGLES2Version); + + void (*DestroyScreen) + (struct DRISUPScreen *psDRISUPScreen); + + unsigned int (*CreateContext) + (PVRDRIAPIType eAPI, + PVRDRIConfig *psPVRDRIConfig, + struct PVRDRIContextConfig *psCtxConfig, + struct __DRIcontextRec *psDRIContext, + struct DRISUPContext *psDRISUPSharedContext, + struct DRISUPScreen *psDRISUPScreen, + struct DRISUPContext **ppsDRISUPContext); + + void (*DestroyContext) + (struct DRISUPContext *psDRISUPContext); + + struct DRISUPDrawable *(*CreateDrawable) + (struct __DRIdrawableRec *psDRIDrawable, + struct DRISUPScreen *psDRISUPDrawable, + void *pvLoaderPrivate, + PVRDRIConfig *psPVRDRIConfig); + + void (*DestroyDrawable) + (struct DRISUPDrawable *psDRISUPDrawable); + + bool (*MakeCurrent) + (struct DRISUPContext *psDRISUPContext, + struct DRISUPDrawable *psDRISUPWrite, + struct DRISUPDrawable *psDRISUPRead); + + bool (*UnbindContext) + (struct DRISUPContext *psDRISUPContext); + + struct DRISUPBuffer *(*AllocateBuffer) + (struct DRISUPScreen *psDRISUPScreen, + unsigned int uAttachment, + unsigned int uFormat, + int iWidth, + int iHeight, + unsigned int *puName, + unsigned int *puPitch, + unsigned int *puCPP, + unsigned int *puFlags); + + void (*ReleaseBuffer) + (struct DRISUPScreen *psDRISUPScreen, + struct DRISUPBuffer *psDRISUPBuffer); + + /* Functions to support the DRI TexBuffer extension */ + void (*SetTexBuffer2) + (struct DRISUPContext *psDRISUPContext, + int iTarget, + int iFormat, + struct DRISUPDrawable *psDRISUPDrawable); + + void (*ReleaseTexBuffer) + (struct DRISUPContext *psDRISUPContext, + int iTarget, + struct DRISUPDrawable *psDRISUPDrawable); + + /* Functions to support the DRI Flush extension */ + void (*Flush) + (struct DRISUPDrawable *psDRISUPDrawable); + + void (*Invalidate) + (struct DRISUPDrawable *psDRISUPDrawable); + + void (*FlushWithFlags) + (struct DRISUPContext *psDRISUPContext, + struct DRISUPDrawable *psDRISUPDrawable, + unsigned int uFlags, + unsigned int uThrottleReason); + + /* Functions to support the DRI Image extension */ + __DRIimage *(*CreateImageFromName) + (struct DRISUPScreen *psDRISUPScreen, + int iWidth, + int iHeight, + int iFourCC, + int iName, + int iPitch, + void *pvLoaderPrivate); + + __DRIimage *(*CreateImageFromRenderbuffer) + (struct DRISUPContext *psDRISUPContext, + int iRenderBuffer, + void *pvLoaderPrivate); + + void (*DestroyImage) + (__DRIimage *psImage); + + __DRIimage *(*CreateImage) + (struct DRISUPScreen *psDRISUPScreen, + int iWidth, + int iHeight, + int iFourCC, + unsigned int uUse, + void *pvLoaderPrivate); + + bool (*QueryImage) + (__DRIimage *psImage, + int iAttrib, + int *iValue); + + __DRIimage *(*DupImage) + (__DRIimage *psImage, + void *pvLoaderPrivate); + + bool (*ValidateImageUsage) + (__DRIimage *psImage, + unsigned int uUse); + + __DRIimage *(*CreateImageFromNames) + (struct DRISUPScreen *psDRISUPScreen, + int iWidth, + int iHeight, + int iFourCC, + int *piNames, + int iNumNames, + int *piStrides, + int *piOffsets, + void *pvLoaderPrivate); + __DRIimage *(*FromPlanar)(__DRIimage *psImage, + int iPlane, + void *pvLoaderPrivate); + + __DRIimage *(*CreateImageFromTexture) + (struct DRISUPContext *psDRISUPContext, + int iTarget, + unsigned int uTexture, + int iDepth, + int iLevel, + unsigned int *puError, + void *pvLoaderPrivate); + + __DRIimage *(*CreateImageFromFDs) + (struct DRISUPScreen *psDRISUPcreen, + int iWidth, + int iHeight, + int iFourCC, + int *piFDs, + int iNumFDs, + int *piStrides, + int *piOffsets, + void *pvLoaderPrivate); + + __DRIimage *(*CreateImageFromDMABufs) + (struct DRISUPScreen *psDRISUPScreen, + int iWidth, + int iHeight, + int iFourCC, + int *piFDs, + int iNumFDs, + int *piStrides, + int *piOffsets, + unsigned int uColorSpace, + unsigned int uSampleRange, + unsigned int uHorizSiting, + unsigned int uVertSiting, + unsigned int *puError, + void *pvLoaderPrivate); + + int (*GetImageCapabilities) + (struct DRISUPScreen *psDRISUPScreen); + + void (*BlitImage) + (struct DRISUPContext *psDRISUPContext, + __DRIimage *psDst, + __DRIimage *psSrc, + int iDstX0, + int iDstY0, + int iDstWidth, + int iDstHeight, + int iSrcX0, int + iSrcY0, + int iSrcWidth, + int iSrcHeight, + int iFlushFlag); + + void *(*MapImage) + (struct DRISUPContext *psDRISUPContext, + __DRIimage *psImage, + int iX0, + int iY0, + int iWidth, + int iHeight, + unsigned int uFlags, + int *piStride, + void **ppvData); + + void (*UnmapImage) + (struct DRISUPContext *psDRISUPContext, + __DRIimage *psImage, + void *pvData); + + __DRIimage *(*CreateImageWithModifiers) + (struct DRISUPScreen *psDRISUPScreen, + int iWidth, + int iHeight, + int iFourCC, + const uint64_t *puModifiers, + const unsigned int uModifierCount, + void *pvLoaderPrivate); + + __DRIimage *(*CreateImageFromDMABufs2) + (struct DRISUPScreen *psDRISUPScreen, + int iWidth, + int iHeight, + int iFourCC, + uint64_t uModifier, + int *piFDs, + int iNumFDs, + int *piStrides, + int *piOffsets, + unsigned int uColorSpace, + unsigned int uSampleRange, + unsigned int uHorizSiting, + unsigned int uVertSiting, + unsigned int *puError, + void *pvLoaderPrivate); + + bool (*QueryDMABufFormats) + (struct DRISUPScreen *psDRISUPScreen, + int iMax, + int *piFormats, + int *piCount); + + bool (*QueryDMABufModifiers) + (struct DRISUPScreen *psDRISUPScreen, + int iFourCC, + int iMax, + uint64_t *puModifiers, + unsigned int *piExternalOnly, + int *piCount); + + bool (*QueryDMABufFormatModifierAttribs) + (struct DRISUPScreen *psDRISUPScreen, + uint32_t uFourcc, + uint64_t uModifier, + int iAttrib, + uint64_t *puValue); + + __DRIimage *(*CreateImageFromRenderBuffer2) + (struct DRISUPContext *psDRISUPContext, + int iRenderBuffer, + void *pvLoaderPrivate, + unsigned int *puError); + + __DRIimage *(*CreateImageFromBuffer) + (struct DRISUPContext *psDRISUPContext, + int iTarget, + void *pvBuffer, + unsigned int *puError, + void *pvLoaderPrivate); + + /* Functions to support the DRI Renderer Query extension */ + int (*QueryRendererInteger) + (struct DRISUPScreen *psDRISUPScreen, + int iAttribute, + unsigned int *puValue); + + int (*QueryRendererString) + (struct DRISUPScreen *psDRISUPScreen, + int iAttribute, + const char **ppszValue); + + /* Functions to support the DRI Fence extension */ + void *(*CreateFence) + (struct DRISUPContext *psDRISUPContext); + + void (*DestroyFence) + (struct DRISUPScreen *psDRISUPScreen, + void *pvFence); + + bool (*ClientWaitSync) + (struct DRISUPContext *psDRISUPContext, + void *pvFence, + unsigned int uFlags, + uint64_t uTimeout); + + void (*ServerWaitSync) + (struct DRISUPContext *psDRISUPContext, + void *pvFence, + unsigned int uFlags); + + unsigned int (*GetFenceCapabilities) + (struct DRISUPScreen *psDRISUPScreen); + + void *(*CreateFenceFD) + (struct DRISUPContext *psDRISUPContext, + int iFD); + + int (*GetFenceFD) + (struct DRISUPScreen *psDRISUPScreen, + void *pvFence); + + unsigned int (*GetNumAPIProcs) + (struct DRISUPScreen *psDRISUPScreen, + PVRDRIAPIType eAPI); + + const char *(*GetAPIProcName) + (struct DRISUPScreen *psDRISUPScreen, + PVRDRIAPIType eAPI, + unsigned int uIndex); + + void *(*GetAPIProcAddress) + (struct DRISUPScreen *psDRISUPScreen, + PVRDRIAPIType eAPI, + unsigned int uIndex); + + void (*SetDamageRegion) + (struct DRISUPDrawable *psDRISUPDrawable, + unsigned int uNRects, + int *piRects); + } v0; + /* The v1 interface is an extension of v0, so v0 is required as well */ + struct { + void *(*GetFenceFromCLEvent) + (struct DRISUPScreen *psDRISUPScreen, + intptr_t iCLEvent); + } v1; + /* The v2 interface is an extension of v1, so v1 is required as well */ + struct { + int (*GetAPIVersion) + (struct DRISUPScreen *psDRISUPScreen, + PVRDRIAPIType eAPI); + } v2; + /* + * The v3 interface has no additional entry points. It indicates that + * OpenCL event based fences are available, provided the DDK is built + * with OpenCL support. + */ + /* The v4 interface is an extension of v3, so v3 is required as well */ + struct { + bool (*HaveGetFenceFromCLEvent)(void); + } v4; + /* The v5 interface is an extension of v4, so v4 is required as well */ + struct { + __DRIimage *(*CreateImageFromDMABufs3) + (struct DRISUPScreen *psDRISUPScreen, + int iWidth, + int iHeight, + int iFourCC, + uint64_t uModifier, + int *piFDs, + int iNumFDs, + int *piStrides, + int *piOffsets, + unsigned int uColorSpace, + unsigned int uSampleRange, + unsigned int uHorizSiting, + unsigned int uVertSiting, + uint32_t uFlags, + unsigned int *puError, + void *pvLoaderPrivate); + + __DRIimage *(*CreateImageWithModifiers2) + (struct DRISUPScreen *psDRISUPScreen, + int iWidth, + int iHeight, + int iFourCC, + const uint64_t *puModifiers, + const unsigned int uModifierCount, + unsigned int uUsage, + void *pvLoaderPrivate); + + __DRIimage *(*CreateImageFromFDs2) + (struct DRISUPScreen *psDRISUPcreen, + int iWidth, + int iHeight, + int iFourCC, + int *piFDs, + int iNumFDs, + uint32_t uFlags, + int *piStrides, + int *piOffsets, + void *pvLoaderPrivate); + + void (*SetInFenceFD) + (__DRIimage *psImage, + int iFD); + } v5; +}; + +struct PVRDRIImageList { + uint32_t uImageMask; + __DRIimage *psBack; + __DRIimage *psFront; + __DRIimage *psPrev; +}; + +/* + * PVR DRI Support callback interface V2. + * This structure may change over time, as older interfaces become obsolete. + * For example, the v0 interface may be removed if superseded by newer + * interfaces. + */ +struct PVRDRICallbacksV2 +{ + struct { + bool (*RegisterSupportInterface) + (const void *psInterface, + unsigned int uVersion, + unsigned int uMinVersion); + + int (*GetBuffers) + (struct __DRIdrawableRec *psDRIDrawable, + unsigned int uFourCC, + uint32_t *puStamp, + void *pvLoaderPrivate, + uint32_t uBufferMask, + struct PVRDRIImageList *psImageList); + + bool (*CreateConfigs) + (struct __DRIconfigRec ***pppsConfigs, + struct __DRIscreenRec *psDRIScreen, + int iPVRDRIMesaFormat, + const uint8_t *puDepthBits, + const uint8_t *puStencilBits, + unsigned int uNumDepthStencilBits, + const unsigned int *puDBModes, + unsigned int uNumDBModes, + const uint8_t *puMSAASamples, + unsigned int uNumMSAAModes, + bool bEnableAccum, + bool bColorDepthMatch, + bool bMutableRenderBuffer, + int iYUVDepthRange, + int iYUVCSCStandard, + uint32_t uMaxPbufferWidth, + uint32_t uMaxPbufferHeight); + + struct __DRIconfigRec **(*ConcatConfigs) + (struct __DRIscreenRec *psDRIScreen, + struct __DRIconfigRec **ppsConfigA, + struct __DRIconfigRec **ppsConfigB); + + bool (*ConfigQuery) + (const PVRDRIConfig *psConfig, + PVRDRIConfigAttrib eConfigAttrib, + unsigned int *puValueOut); + + __DRIimage *(*LookupEGLImage) + (struct __DRIscreenRec *psDRIScreen, + void *pvImage, + void *pvLoaderPrivate); + + unsigned int (*GetCapability) + (struct __DRIscreenRec *psDRIScreen, + unsigned int uCapability); + } v0; + /* The v1 interface is an extension of v0, so v0 is required as well */ + struct { + void (*FlushFrontBuffer) + (struct __DRIdrawableRec *psDRIDrawable, + void *pvLoaderPrivate); + } v1; + /* The v2 interface is an extension of v1, so v1 is required as well */ + struct { + int (*GetDisplayFD) + (struct __DRIscreenRec *psDRIScreen, + void *pvLoaderPrivate); + } v2; + /* The v3 interface is an extension of v2, so v2 is required as well */ + struct { + void *(*DrawableGetReferenceHandle) + (struct __DRIdrawableRec *psDRIDrawable); + + void (*DrawableAddReference) + (void *pvReferenceHandle); + + void (*DrawableRemoveReference) + (void *pvReferenceHandle); + } v3; + /* The v4 interface is an extension of v3, so v3 is required as well */ + struct { + void (*DestroyLoaderImageState) + (const struct __DRIscreenRec *psDRIScreen, + void *pvLoaderPrivate); + } v4; +}; + +#endif /* defined(__PVRDRIIFCE_H__) */ diff --git a/src/gallium/frontends/pvr/img_drm_fourcc.h b/src/gallium/frontends/pvr/img_drm_fourcc.h new file mode 100644 index 0000000..8d570ff --- /dev/null +++ b/src/gallium/frontends/pvr/img_drm_fourcc.h @@ -0,0 +1,113 @@ +/*************************************************************************/ /*! +@File +@Title Wrapper around drm_fourcc.h +@Description FourCCs and DRM framebuffer modifiers that are not in the + Kernel's and libdrm's drm_fourcc.h can be added here. +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@License MIT + +The contents of this file are subject to the MIT license as set out below. + +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 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. +*/ /**************************************************************************/ + +#ifndef IMG_DRM_FOURCC_H +#define IMG_DRM_FOURCC_H + +#if defined(__KERNEL__) +#include +#else +/* + * Include types.h to workaround versions of libdrm older than 2.4.68 + * not including the correct headers. + */ +#include + +#include +#endif + +/* + * Don't get too inspired by this example :) + * ADF doesn't support DRM modifiers, so the memory layout had to be + * included in the fourcc name, but the proper way to specify information + * additional to pixel formats is to use DRM modifiers. + * + * See upstream drm_fourcc.h for the proper naming convention. + */ +#ifndef DRM_FORMAT_BGRA8888_DIRECT_16x4 +#define DRM_FORMAT_BGRA8888_DIRECT_16x4 fourcc_code('I', 'M', 'G', '0') +#endif + +/* + * Upstream doesn't have a floating point format yet, so let's make one + * up. + * Note: The kernel's core DRM needs to know about this format, + * otherwise it won't be supported and should not be exposed by our + * kernel modules either. + * Refer to the provided kernel patch adding this format. + */ +#if !defined(__KERNEL__) +#define DRM_FORMAT_ABGR16_IMG fourcc_code('I', 'M', 'G', '1') +#endif + +/* + * Upstream does not have a packed 10 Bits Per Channel YVU format yet, + * so let`s make one up. + * Note: at the moment this format is not intended to be used with + * a framebuffer, so the kernels core DRM doesn`t need to know + * about this format. This means that the kernel doesn`t need + * to be patched. + */ +#if !defined(__KERNEL__) +#define DRM_FORMAT_YVU444_PACK10_IMG fourcc_code('I', 'M', 'G', '2') +#define DRM_FORMAT_YUV422_2PLANE_PACK10_IMG fourcc_code('I', 'M', 'G', '3') +#define DRM_FORMAT_YUV420_2PLANE_PACK10_IMG fourcc_code('I', 'M', 'G', '4') +#endif + +/* + * Value chosen in the middle of 255 pool to minimise the chance of hitting + * the same value potentially defined by other vendors in the drm_fourcc.h + */ +#define DRM_FORMAT_MOD_VENDOR_PVR 0x92 + +#ifndef DRM_FORMAT_MOD_VENDOR_NONE +#define DRM_FORMAT_MOD_VENDOR_NONE 0 +#endif + +#ifndef DRM_FORMAT_RESERVED +#define DRM_FORMAT_RESERVED ((1ULL << 56) - 1) +#endif + +#ifndef fourcc_mod_code +#define fourcc_mod_code(vendor, val) \ + ((((__u64)DRM_FORMAT_MOD_VENDOR_## vendor) << 56) | (val & 0x00ffffffffffffffULL)) +#endif + +#ifndef DRM_FORMAT_MOD_INVALID +#define DRM_FORMAT_MOD_INVALID fourcc_mod_code(NONE, DRM_FORMAT_RESERVED) +#endif + +#ifndef DRM_FORMAT_MOD_LINEAR +#define DRM_FORMAT_MOD_LINEAR fourcc_mod_code(NONE, 0) +#endif + +#define DRM_FORMAT_MOD_PVR_FBCDC_8x8_V7 fourcc_mod_code(PVR, 6) +#define DRM_FORMAT_MOD_PVR_FBCDC_16x4_V7 fourcc_mod_code(PVR, 12) + +#endif /* IMG_DRM_FOURCC_H */ diff --git a/src/gallium/frontends/pvr/imgpixfmts.h b/src/gallium/frontends/pvr/imgpixfmts.h new file mode 100644 index 0000000..da12a0f --- /dev/null +++ b/src/gallium/frontends/pvr/imgpixfmts.h @@ -0,0 +1,307 @@ +/*************************************************************************/ /*! +@File imgpixfmts.h +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@License MIT + +The contents of this file are subject to the MIT license as set out below. + +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 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. +*/ /**************************************************************************/ + +/****************************************************************************** + ** + ** WARNING: File is autogenerated by parsesystable.py - DO NOT EDIT. + ** Use fmts_systable.txt to add new formats. + ** + *****************************************************************************/ + +#if !defined(IMGPIXFMTS_H) +#define IMGPIXFMTS_H + +typedef enum _IMG_PIXFMT_ +{ + IMG_PIXFMT_UNKNOWN = 0, + IMG_PIXFMT_RESERVED_1 = 1, + IMG_PIXFMT_RESERVED_2 = 2, + IMG_PIXFMT_RESERVED_3 = 3, + IMG_PIXFMT_RESERVED_4 = 4, + IMG_PIXFMT_RESERVED_5 = 5, + IMG_PIXFMT_RESERVED_6 = 6, + IMG_PIXFMT_RESERVED_7 = 7, + IMG_PIXFMT_RESERVED_8 = 8, + IMG_PIXFMT_RESERVED_9 = 9, + IMG_PIXFMT_RESERVED_10 = 10, + IMG_PIXFMT_RESERVED_11 = 11, + IMG_PIXFMT_RESERVED_12 = 12, + IMG_PIXFMT_RESERVED_13 = 13, + IMG_PIXFMT_RESERVED_14 = 14, + IMG_PIXFMT_RESERVED_15 = 15, + IMG_PIXFMT_RESERVED_16 = 16, + IMG_PIXFMT_RESERVED_17 = 17, + IMG_PIXFMT_RESERVED_18 = 18, + IMG_PIXFMT_RESERVED_19 = 19, + IMG_PIXFMT_RESERVED_20 = 20, + IMG_PIXFMT_RESERVED_21 = 21, + IMG_PIXFMT_RESERVED_22 = 22, + IMG_PIXFMT_RESERVED_23 = 23, + IMG_PIXFMT_RESERVED_24 = 24, + IMG_PIXFMT_R10G10B10A2_UNORM = 25, + IMG_PIXFMT_RESERVED_26 = 26, + IMG_PIXFMT_RESERVED_27 = 27, + IMG_PIXFMT_B10G10R10A2_UNORM = 28, + IMG_PIXFMT_RESERVED_29 = 29, + IMG_PIXFMT_RESERVED_30 = 30, + IMG_PIXFMT_RESERVED_31 = 31, + IMG_PIXFMT_R8G8B8A8_UNORM = 32, + IMG_PIXFMT_R8G8B8A8_UNORM_SRGB = 33, + IMG_PIXFMT_RESERVED_34 = 34, + IMG_PIXFMT_RESERVED_35 = 35, + IMG_PIXFMT_RESERVED_36 = 36, + IMG_PIXFMT_R8G8B8X8_UNORM = 37, + IMG_PIXFMT_RESERVED_38 = 38, + IMG_PIXFMT_RESERVED_39 = 39, + IMG_PIXFMT_RESERVED_40 = 40, + IMG_PIXFMT_RESERVED_41 = 41, + IMG_PIXFMT_RESERVED_42 = 42, + IMG_PIXFMT_RESERVED_43 = 43, + IMG_PIXFMT_RESERVED_44 = 44, + IMG_PIXFMT_RESERVED_45 = 45, + IMG_PIXFMT_RESERVED_46 = 46, + IMG_PIXFMT_RESERVED_47 = 47, + IMG_PIXFMT_RESERVED_48 = 48, + IMG_PIXFMT_RESERVED_49 = 49, + IMG_PIXFMT_RESERVED_50 = 50, + IMG_PIXFMT_D32_FLOAT = 51, + IMG_PIXFMT_RESERVED_52 = 52, + IMG_PIXFMT_RESERVED_53 = 53, + IMG_PIXFMT_RESERVED_54 = 54, + IMG_PIXFMT_RESERVED_55 = 55, + IMG_PIXFMT_RESERVED_56 = 56, + IMG_PIXFMT_RESERVED_57 = 57, + IMG_PIXFMT_D24_UNORM_X8_TYPELESS = 58, + IMG_PIXFMT_RESERVED_59 = 59, + IMG_PIXFMT_RESERVED_60 = 60, + IMG_PIXFMT_RESERVED_61 = 61, + IMG_PIXFMT_R8G8_UNORM = 62, + IMG_PIXFMT_RESERVED_63 = 63, + IMG_PIXFMT_RESERVED_64 = 64, + IMG_PIXFMT_RESERVED_65 = 65, + IMG_PIXFMT_RESERVED_66 = 66, + IMG_PIXFMT_RESERVED_67 = 67, + IMG_PIXFMT_RESERVED_68 = 68, + IMG_PIXFMT_D16_UNORM = 69, + IMG_PIXFMT_RESERVED_70 = 70, + IMG_PIXFMT_RESERVED_71 = 71, + IMG_PIXFMT_RESERVED_72 = 72, + IMG_PIXFMT_RESERVED_73 = 73, + IMG_PIXFMT_RESERVED_74 = 74, + IMG_PIXFMT_RESERVED_75 = 75, + IMG_PIXFMT_R8_UNORM = 76, + IMG_PIXFMT_RESERVED_77 = 77, + IMG_PIXFMT_RESERVED_78 = 78, + IMG_PIXFMT_RESERVED_79 = 79, + IMG_PIXFMT_RESERVED_80 = 80, + IMG_PIXFMT_S8_UINT = 81, + IMG_PIXFMT_RESERVED_82 = 82, + IMG_PIXFMT_RESERVED_83 = 83, + IMG_PIXFMT_RESERVED_84 = 84, + IMG_PIXFMT_B5G6R5_UNORM = 85, + IMG_PIXFMT_R5G6B5_UNORM = 86, + IMG_PIXFMT_B5G5R5A1_UNORM = 87, + IMG_PIXFMT_B5G5R5X1_UNORM = 88, + IMG_PIXFMT_B8G8R8A8_UNORM = 89, + IMG_PIXFMT_B8G8R8X8_UNORM = 90, + IMG_PIXFMT_B8G8R8A8_UINT = 91, + IMG_PIXFMT_B8G8R8A8_SNORM = 92, + IMG_PIXFMT_B8G8R8A8_SINT = 93, + IMG_PIXFMT_B8G8R8A8_UNORM_SRGB = 94, + IMG_PIXFMT_RESERVED_95 = 95, + IMG_PIXFMT_RESERVED_96 = 96, + IMG_PIXFMT_RESERVED_97 = 97, + IMG_PIXFMT_RESERVED_98 = 98, + IMG_PIXFMT_RESERVED_99 = 99, + IMG_PIXFMT_RESERVED_100 = 100, + IMG_PIXFMT_RESERVED_101 = 101, + IMG_PIXFMT_RESERVED_102 = 102, + IMG_PIXFMT_RESERVED_103 = 103, + IMG_PIXFMT_RESERVED_104 = 104, + IMG_PIXFMT_RESERVED_105 = 105, + IMG_PIXFMT_RESERVED_106 = 106, + IMG_PIXFMT_RESERVED_107 = 107, + IMG_PIXFMT_RESERVED_108 = 108, + IMG_PIXFMT_RESERVED_109 = 109, + IMG_PIXFMT_RESERVED_110 = 110, + IMG_PIXFMT_RESERVED_111 = 111, + IMG_PIXFMT_RESERVED_112 = 112, + IMG_PIXFMT_RESERVED_113 = 113, + IMG_PIXFMT_RESERVED_114 = 114, + IMG_PIXFMT_RESERVED_115 = 115, + IMG_PIXFMT_RESERVED_116 = 116, + IMG_PIXFMT_RESERVED_117 = 117, + IMG_PIXFMT_RESERVED_118 = 118, + IMG_PIXFMT_RESERVED_119 = 119, + IMG_PIXFMT_RESERVED_120 = 120, + IMG_PIXFMT_RESERVED_121 = 121, + IMG_PIXFMT_RESERVED_122 = 122, + IMG_PIXFMT_RESERVED_123 = 123, + IMG_PIXFMT_RESERVED_124 = 124, + IMG_PIXFMT_RESERVED_125 = 125, + IMG_PIXFMT_RESERVED_126 = 126, + IMG_PIXFMT_RESERVED_127 = 127, + IMG_PIXFMT_RESERVED_128 = 128, + IMG_PIXFMT_RESERVED_129 = 129, + IMG_PIXFMT_RESERVED_130 = 130, + IMG_PIXFMT_RESERVED_131 = 131, + IMG_PIXFMT_RESERVED_132 = 132, + IMG_PIXFMT_RESERVED_133 = 133, + IMG_PIXFMT_RESERVED_134 = 134, + IMG_PIXFMT_RESERVED_135 = 135, + IMG_PIXFMT_L8_UNORM = 136, + IMG_PIXFMT_RESERVED_137 = 137, + IMG_PIXFMT_L8A8_UNORM = 138, + IMG_PIXFMT_RESERVED_139 = 139, + IMG_PIXFMT_RESERVED_140 = 140, + IMG_PIXFMT_RESERVED_141 = 141, + IMG_PIXFMT_RESERVED_142 = 142, + IMG_PIXFMT_RESERVED_143 = 143, + IMG_PIXFMT_RESERVED_144 = 144, + IMG_PIXFMT_B4G4R4A4_UNORM = 145, + IMG_PIXFMT_RESERVED_146 = 146, + IMG_PIXFMT_RESERVED_147 = 147, + IMG_PIXFMT_RESERVED_148 = 148, + IMG_PIXFMT_RESERVED_149 = 149, + IMG_PIXFMT_RESERVED_150 = 150, + IMG_PIXFMT_RESERVED_151 = 151, + IMG_PIXFMT_RESERVED_152 = 152, + IMG_PIXFMT_RESERVED_153 = 153, + IMG_PIXFMT_RESERVED_154 = 154, + IMG_PIXFMT_RESERVED_155 = 155, + IMG_PIXFMT_RESERVED_156 = 156, + IMG_PIXFMT_RESERVED_157 = 157, + IMG_PIXFMT_RESERVED_158 = 158, + IMG_PIXFMT_RESERVED_159 = 159, + IMG_PIXFMT_R8G8B8_UNORM = 160, + IMG_PIXFMT_R8G8B8_UNORM_SRGB = 161, + IMG_PIXFMT_RESERVED_162 = 162, + IMG_PIXFMT_RESERVED_163 = 163, + IMG_PIXFMT_RESERVED_164 = 164, + IMG_PIXFMT_RESERVED_165 = 165, + IMG_PIXFMT_RESERVED_166 = 166, + IMG_PIXFMT_RESERVED_167 = 167, + IMG_PIXFMT_RESERVED_168 = 168, + IMG_PIXFMT_RESERVED_169 = 169, + IMG_PIXFMT_RESERVED_170 = 170, + IMG_PIXFMT_UYVY = 171, + IMG_PIXFMT_VYUY = 172, + IMG_PIXFMT_YUYV = 173, + IMG_PIXFMT_YVYU = 174, + IMG_PIXFMT_YVU420_2PLANE = 175, + IMG_PIXFMT_YUV420_2PLANE = 176, + IMG_PIXFMT_YVU420_2PLANE_MACRO_BLOCK = 177, + IMG_PIXFMT_YUV420_3PLANE = 178, + IMG_PIXFMT_YVU420_3PLANE = 179, + IMG_PIXFMT_RESERVED_180 = 180, + IMG_PIXFMT_RESERVED_181 = 181, + IMG_PIXFMT_RESERVED_182 = 182, + IMG_PIXFMT_RESERVED_183 = 183, + IMG_PIXFMT_RESERVED_184 = 184, + IMG_PIXFMT_RESERVED_185 = 185, + IMG_PIXFMT_RESERVED_186 = 186, + IMG_PIXFMT_RESERVED_187 = 187, + IMG_PIXFMT_RESERVED_188 = 188, + IMG_PIXFMT_RESERVED_189 = 189, + IMG_PIXFMT_RESERVED_190 = 190, + IMG_PIXFMT_RESERVED_191 = 191, + IMG_PIXFMT_RESERVED_192 = 192, + IMG_PIXFMT_RESERVED_193 = 193, + IMG_PIXFMT_RESERVED_194 = 194, + IMG_PIXFMT_RESERVED_195 = 195, + IMG_PIXFMT_RESERVED_196 = 196, + IMG_PIXFMT_RESERVED_197 = 197, + IMG_PIXFMT_RESERVED_198 = 198, + IMG_PIXFMT_RESERVED_199 = 199, + IMG_PIXFMT_RESERVED_200 = 200, + IMG_PIXFMT_YVU8_422_2PLANE_PACK8 = 201, + IMG_PIXFMT_RESERVED_202 = 202, + IMG_PIXFMT_YVU10_444_1PLANE_PACK10 = 203, + IMG_PIXFMT_RESERVED_204 = 204, + IMG_PIXFMT_RESERVED_205 = 205, + IMG_PIXFMT_RESERVED_206 = 206, + IMG_PIXFMT_YUV8_422_2PLANE_PACK8 = 207, + IMG_PIXFMT_YUV8_444_3PLANE_PACK8 = 208, + IMG_PIXFMT_RESERVED_209 = 209, + IMG_PIXFMT_RESERVED_210 = 210, + IMG_PIXFMT_RESERVED_211 = 211, + IMG_PIXFMT_RESERVED_212 = 212, + IMG_PIXFMT_RESERVED_213 = 213, + IMG_PIXFMT_RESERVED_214 = 214, + IMG_PIXFMT_RESERVED_215 = 215, + IMG_PIXFMT_RESERVED_216 = 216, + IMG_PIXFMT_RESERVED_217 = 217, + IMG_PIXFMT_RESERVED_218 = 218, + IMG_PIXFMT_RESERVED_219 = 219, + IMG_PIXFMT_RESERVED_220 = 220, + IMG_PIXFMT_RESERVED_221 = 221, + IMG_PIXFMT_RESERVED_222 = 222, + IMG_PIXFMT_RESERVED_223 = 223, + IMG_PIXFMT_RESERVED_224 = 224, + IMG_PIXFMT_RESERVED_225 = 225, + IMG_PIXFMT_RESERVED_226 = 226, + IMG_PIXFMT_RESERVED_227 = 227, + IMG_PIXFMT_RESERVED_228 = 228, + IMG_PIXFMT_RESERVED_229 = 229, + IMG_PIXFMT_RESERVED_230 = 230, + IMG_PIXFMT_RESERVED_231 = 231, + IMG_PIXFMT_RESERVED_232 = 232, + IMG_PIXFMT_RESERVED_233 = 233, + IMG_PIXFMT_RESERVED_234 = 234, + IMG_PIXFMT_RESERVED_235 = 235, + IMG_PIXFMT_RESERVED_236 = 236, + IMG_PIXFMT_RESERVED_237 = 237, + IMG_PIXFMT_RESERVED_238 = 238, + IMG_PIXFMT_RESERVED_239 = 239, + IMG_PIXFMT_RESERVED_240 = 240, + IMG_PIXFMT_RESERVED_241 = 241, + IMG_PIXFMT_RESERVED_242 = 242, + IMG_PIXFMT_RESERVED_243 = 243, + IMG_PIXFMT_RESERVED_244 = 244, + IMG_PIXFMT_YVU8_420_2PLANE_PACK8_P = 245, + IMG_PIXFMT_RESERVED_246 = 246, + IMG_PIXFMT_RESERVED_247 = 247, + IMG_PIXFMT_RESERVED_248 = 248, + IMG_PIXFMT_YUV8_420_2PLANE_PACK8_P = 249, + IMG_PIXFMT_RESERVED_250 = 250, + IMG_PIXFMT_RESERVED_251 = 251, + IMG_PIXFMT_UYVY10_422_1PLANE_PACK10_CUST1 = 252, + IMG_PIXFMT_RESERVED_253 = 253, + IMG_PIXFMT_RESERVED_254 = 254, + IMG_PIXFMT_RESERVED_255 = 255, + IMG_PIXFMT_RESERVED_256 = 256, + IMG_PIXFMT_RESERVED_257 = 257, + IMG_PIXFMT_RESERVED_258 = 258, + IMG_PIXFMT_RESERVED_259 = 259, + IMG_PIXFMT_RESERVED_260 = 260, + IMG_PIXFMT_RESERVED_261 = 261, + IMG_PIXFMT_RESERVED_262 = 262, + IMG_PIXFMT_RESERVED_263 = 263, + IMG_PIXFMT_RESERVED_264 = 264, +#define IMG_PIXFMT_ENUM_COUNT 265 +} IMG_PIXFMT; + +#endif /* IMGPIXFMTS_H */ diff --git a/src/gallium/frontends/pvr/imgyuv.h b/src/gallium/frontends/pvr/imgyuv.h new file mode 100644 index 0000000..7ae8fd1 --- /dev/null +++ b/src/gallium/frontends/pvr/imgyuv.h @@ -0,0 +1,58 @@ +/*************************************************************************/ /*! +@File +@Title YUV defines +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@License MIT + +The contents of this file are subject to the MIT license as set out below. + +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 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. +*/ /**************************************************************************/ + +#if !defined(IMGYUV_H) +#define IMGYUV_H + +typedef enum +{ + IMG_COLORSPACE_UNDEFINED = 0, + IMG_COLORSPACE_BT601_CONFORMANT_RANGE = 1, + IMG_COLORSPACE_BT601_FULL_RANGE = 2, + IMG_COLORSPACE_BT709_CONFORMANT_RANGE = 3, + IMG_COLORSPACE_BT709_FULL_RANGE = 4, + IMG_COLORSPACE_BT2020_CONFORMANT_RANGE = 5, + IMG_COLORSPACE_BT2020_FULL_RANGE = 6, + IMG_COLORSPACE_BT601_CONFORMANT_RANGE_INVERSE = 7, + IMG_COLORSPACE_BT601_FULL_RANGE_INVERSE = 8, + IMG_COLORSPACE_BT709_CONFORMANT_RANGE_INVERSE = 9, + IMG_COLORSPACE_BT709_FULL_RANGE_INVERSE = 10, + IMG_COLORSPACE_BT2020_CONFORMANT_RANGE_INVERSE = 11, + IMG_COLORSPACE_BT2020_FULL_RANGE_INVERSE = 12 +} IMG_YUV_COLORSPACE; + +typedef enum +{ + IMG_CHROMA_INTERP_UNDEFINED = 0, + IMG_CHROMA_INTERP_ZERO = 1, + IMG_CHROMA_INTERP_QUARTER = 2, + IMG_CHROMA_INTERP_HALF = 3, + IMG_CHROMA_INTERP_THREEQUARTERS = 4 +} IMG_YUV_CHROMA_INTERP; + + +#endif /* IMGYUV_H */ diff --git a/src/gallium/frontends/pvr/mesa_context.c b/src/gallium/frontends/pvr/mesa_context.c new file mode 100644 index 0000000..d36bae5 --- /dev/null +++ b/src/gallium/frontends/pvr/mesa_context.c @@ -0,0 +1,208 @@ +/** + * \file context.c + * Mesa context/visual/framebuffer management functions. + * \author Brian Paul + */ + +/* + * Mesa 3-D graphics library + * Version: 7.1 + * + * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. + * + * The contents of this file are subject to the MIT license as set out below. + * + * 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 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 +#include + +#include "main/version.h" +#include "main/errors.h" + +#include "dri_support.h" +#include "dri_util.h" +#include "glapi.h" +#include "dispatch.h" +#include "pvrmesa.h" + +/** + * This is the default function we plug into all dispatch table slots This + * helps prevents a segfault when someone calls a GL function without first + * checking if the extension is supported. + */ +static int +generic_nop(void) +{ + _mesa_warning(NULL, "User called no-op dispatch function (an unsupported extension function?)"); + + return 0; +} + +/** + * Allocate and initialise a new dispatch table. + */ +static struct _glapi_table * +pvrdri_alloc_dispatch_table(void) +{ + unsigned int numEntries = _glapi_get_dispatch_table_size(); + _glapi_proc *table; + + table = malloc(numEntries * sizeof(_glapi_proc)); + if (table) + for (unsigned int i = 0; i < numEntries; i++) + table[i] = (_glapi_proc) generic_nop; + + return (struct _glapi_table *) table; +} + +/** + * Return a pointer to the pointer to the dispatch table of an API in + * PVRDRIScreen. + */ +static struct _glapi_table ** +pvrdri_get_dispatch_table_ptr(PVRDRIScreen *psPVRScreen, PVRDRIAPIType eAPI) +{ + switch (eAPI) { + case PVRDRI_API_GLES1: + return &psPVRScreen->psOGLES1Dispatch; + case PVRDRI_API_GLES2: + return &psPVRScreen->psOGLES2Dispatch; + case PVRDRI_API_GL_COMPAT: + case PVRDRI_API_GL_CORE: + return &psPVRScreen->psOGLDispatch; + default: + return NULL; + } +} + +/** + * Return a pointer to the dispatch table of an API. + */ +static struct _glapi_table * +pvrdri_get_dispatch_table(PVRDRIScreen *psPVRScreen, PVRDRIAPIType eAPI) +{ + struct _glapi_table **ppsTable = + pvrdri_get_dispatch_table_ptr(psPVRScreen, eAPI); + + return ppsTable ? *ppsTable : NULL; +} + +/** + * Free all dispatch tables. + */ +void +pvrdri_free_dispatch_tables(PVRDRIScreen *psPVRScreen) +{ + if (psPVRScreen->psOGLES1Dispatch != NULL) { + free(psPVRScreen->psOGLES1Dispatch); + psPVRScreen->psOGLES1Dispatch = NULL; + } + + if (psPVRScreen->psOGLES2Dispatch != NULL) { + free(psPVRScreen->psOGLES2Dispatch); + psPVRScreen->psOGLES2Dispatch = NULL; + } + + if (psPVRScreen->psOGLDispatch != NULL) { + free(psPVRScreen->psOGLDispatch); + psPVRScreen->psOGLDispatch = NULL; + } +} + +static void +pvrdri_add_mesa_dispatch(struct _glapi_table *psTable, PVRDRIAPIType eAPI, + struct DRISUPScreen *psDRISUPScreen, + unsigned int uIdx) +{ + const char *asFunc[] = { NULL, NULL }; + int iOffset; + const char *psFunc; + _glapi_proc pfFunc; + + pfFunc = DRISUPGetAPIProcAddress(psDRISUPScreen, eAPI, uIdx); + if (pfFunc == NULL) + return; + + psFunc = DRISUPGetAPIProcName(psDRISUPScreen, eAPI, uIdx); + assert(psFunc != NULL); + + asFunc[0] = psFunc; + iOffset = _glapi_add_dispatch(asFunc, ""); + if (iOffset == -1) { + _mesa_warning(NULL, "Couldn't add %s to the Mesa dispatch table", + psFunc); + } else { + SET_by_offset(psTable, iOffset, pfFunc); + } +} + +static void +pvrdri_set_mesa_dispatch(struct _glapi_table *psTable, PVRDRIAPIType eAPI, + struct DRISUPScreen *psDRISUPScreen, + unsigned int uNumFuncs) +{ + for (unsigned int i = 0; i < uNumFuncs; i++) + pvrdri_add_mesa_dispatch(psTable, eAPI, psDRISUPScreen, i); +} + +bool +pvrdri_create_dispatch_table(PVRDRIScreen *psPVRScreen, PVRDRIAPIType eAPI) +{ + struct DRISUPScreen *psDRISUPScreen = psPVRScreen->psDRISUPScreen; + struct _glapi_table **ppsTable; + unsigned int uNumFuncs; + + ppsTable = pvrdri_get_dispatch_table_ptr(psPVRScreen, eAPI); + if (ppsTable == NULL) + return false; + + if (*ppsTable != NULL) + return true; + + uNumFuncs = DRISUPGetNumAPIProcs(psDRISUPScreen, eAPI); + if (!uNumFuncs) + return false; + + *ppsTable = pvrdri_alloc_dispatch_table(); + if (*ppsTable == NULL) + return false; + + pvrdri_set_mesa_dispatch(*ppsTable, eAPI, psDRISUPScreen, uNumFuncs); + + return true; +} + +void +pvrdri_set_null_dispatch_table(void) +{ + _glapi_set_dispatch(NULL); +} + +void +pvrdri_set_dispatch_table(PVRDRIContext *psPVRContext) +{ + struct _glapi_table *psTable; + + psTable = pvrdri_get_dispatch_table(psPVRContext->psPVRScreen, + psPVRContext->eAPI); + + _glapi_set_dispatch(psTable); +} diff --git a/src/gallium/frontends/pvr/meson.build b/src/gallium/frontends/pvr/meson.build new file mode 100644 index 0000000..e13b8be --- /dev/null +++ b/src/gallium/frontends/pvr/meson.build @@ -0,0 +1,46 @@ +# Copyright (c) Imagination Technologies Ltd. +# +# The contents of this file are subject to the MIT license as set out below. +# +# 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 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. + +files_libpvr = files( + 'mesa_context.c', + 'pvrcb.c', + 'pvrcompat.c', + 'pvrdri.c', + 'pvrext.c', + 'pvrutil.c', +) + +libpvr_c_args = ['-DGALLIUM_PVR'] + +libpvr_dep = [dep_libdrm] + +libpvr = static_library( + 'pvr', + [files_libpvr, main_dispatch_h], + include_directories : [ + inc_include, inc_util, inc_mesa, inc_mapi, inc_src, inc_gallium, + inc_gallium_aux, inc_pvr, + ], + c_args : [libpvr_c_args], + gnu_symbol_visibility : 'hidden', + dependencies : [libpvr_dep], +) diff --git a/src/gallium/frontends/pvr/pvrcb.c b/src/gallium/frontends/pvr/pvrcb.c new file mode 100644 index 0000000..060f176 --- /dev/null +++ b/src/gallium/frontends/pvr/pvrcb.c @@ -0,0 +1,344 @@ +/* + * Copyright (c) Imagination Technologies Ltd. + * + * The contents of this file are subject to the MIT license as set out below. + * + * 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 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 + +#include "dri_screen.h" +#include "pvrdri.h" + +int +MODSUPGetBuffers(__DRIdrawable *psDRIDrawable, unsigned int uFourCC, + uint32_t *puStamp, void *pvLoaderPrivate, + uint32_t uBufferMask, struct PVRDRIImageList *psImageList) +{ + PVRDRIDrawable *psPVRDrawable = psDRIDrawable->driverPrivate; + __DRIscreen *psDRIScreen = psDRIDrawable->driScreenPriv; + struct __DRIimageList sDRIList; + int res; + +#if !defined(DRI_IMAGE_HAS_BUFFER_PREV) + uBufferMask &= ~PVRDRI_IMAGE_BUFFER_PREV; +#endif + + if (psPVRDrawable->uFourCC != uFourCC) { + psPVRDrawable->uDRIFormat = PVRDRIFourCCToDRIFormat(uFourCC); + psPVRDrawable->uFourCC = uFourCC; + } + + res = psDRIScreen->image.loader->getBuffers(psDRIDrawable, + psPVRDrawable->uDRIFormat, + puStamp, + pvLoaderPrivate, + uBufferMask, &sDRIList); + + if (res) { + psImageList->uImageMask = sDRIList.image_mask; + psImageList->psBack = sDRIList.back; + psImageList->psFront = sDRIList.front; + psImageList->psPrev = sDRIList.prev; + } + + return res; +} + +bool +MODSUPCreateConfigs(__DRIconfig ***pppsConfigs, __DRIscreen *psDRIScreen, + int iPVRDRIMesaFormat, const uint8_t *puDepthBits, + const uint8_t *puStencilBits, + unsigned int uNumDepthStencilBits, + const unsigned int *puDBModes, unsigned int uNumDBModes, + const uint8_t *puMSAASamples, unsigned int uNumMSAAModes, + bool bEnableAccum, bool bColorDepthMatch, + UNUSED bool bMutableRenderBuffer, + int iYUVDepthRange, int iYUVCSCStandard, + uint32_t uMaxPbufferWidth, uint32_t uMaxPbufferHeight) +{ + __DRIconfig **ppsConfigs; + mesa_format eFormat = PVRDRIMesaFormatToMesaFormat(iPVRDRIMesaFormat); + unsigned int i; + + (void) psDRIScreen; + + switch (eFormat) { + case MESA_FORMAT_NONE: + __driUtilMessage("%s: Unknown PVR DRI format: %u", + __func__, iPVRDRIMesaFormat); + return false; + default: + break; + } + + /* + * The double buffered modes array argument for driCreateConfigs has + * entries of type GLenum. + */ + static_assert(sizeof(GLenum) == sizeof(unsigned int), + "Size mismatch between GLenum and unsigned int"); + + ppsConfigs = driCreateConfigs(eFormat, puDepthBits, puStencilBits, + uNumDepthStencilBits, (GLenum *) puDBModes, + uNumDBModes, puMSAASamples, uNumMSAAModes, + bEnableAccum, bColorDepthMatch, + iYUVDepthRange, iYUVCSCStandard); + if (!ppsConfigs) + return false; + + for (i = 0; ppsConfigs[i]; i++) { + ppsConfigs[i]->modes.maxPbufferWidth = uMaxPbufferWidth; + ppsConfigs[i]->modes.maxPbufferHeight = uMaxPbufferHeight; + ppsConfigs[i]->modes.maxPbufferPixels = + uMaxPbufferWidth * uMaxPbufferHeight; + } + + *pppsConfigs = ppsConfigs; + + return true; +} + +__DRIconfig ** +MODSUPConcatConfigs(__DRIscreen *psDRIScreen, + __DRIconfig **ppsConfigA, __DRIconfig **ppsConfigB) +{ + (void) psDRIScreen; + + return driConcatConfigs(ppsConfigA, ppsConfigB); +} + +struct __DRIimageRec * +MODSUPLookupEGLImage(__DRIscreen *psDRIScreen, void *pvImage, + void *pvLoaderPrivate) +{ + return psDRIScreen->dri2.image->lookupEGLImage(psDRIScreen, + pvImage, + pvLoaderPrivate); +} + + +unsigned int +MODSUPGetCapability(__DRIscreen *psDRIScreen, unsigned int uCapability) +{ + if (psDRIScreen->image.loader->base.version >= 2 && + psDRIScreen->image.loader->getCapability) { + enum dri_loader_cap eCapability = + (enum dri_loader_cap) uCapability; + + return psDRIScreen->image.loader->getCapability( + psDRIScreen->loaderPrivate, + eCapability); + } + + return 0; +} + +int +MODSUPGetDisplayFD(__DRIscreen *psDRIScreen, void *pvLoaderPrivate) +{ +#if __DRI_IMAGE_LOADER_VERSION >= 5 + if (psDRIScreen->image.loader->base.version >= 5 && + psDRIScreen->image.loader->getDisplayFD) + return psDRIScreen->image.loader->getDisplayFD(pvLoaderPrivate); +#else + (void) psDRIScreen; + (void) pvLoaderPrivate; +#endif + + return -1; +} + +static bool +PVRDRIConfigQueryUnsigned(const PVRDRIConfig *psConfig, + PVRDRIConfigAttrib eConfigAttrib, + unsigned int *puValueOut) +{ + if (!psConfig || !puValueOut) + return false; + + switch (eConfigAttrib) { + case PVRDRI_CONFIG_ATTRIB_RENDERABLE_TYPE: + *puValueOut = psConfig->iSupportedAPIs; + return true; + case PVRDRI_CONFIG_ATTRIB_RGB_MODE: + *puValueOut = psConfig->sGLMode.rgbMode; + return true; + case PVRDRI_CONFIG_ATTRIB_DOUBLE_BUFFER_MODE: + *puValueOut = psConfig->sGLMode.doubleBufferMode; + return true; + case PVRDRI_CONFIG_ATTRIB_RED_BITS: + *puValueOut = psConfig->sGLMode.redBits; + return true; + case PVRDRI_CONFIG_ATTRIB_GREEN_BITS: + *puValueOut = psConfig->sGLMode.greenBits; + return true; + case PVRDRI_CONFIG_ATTRIB_BLUE_BITS: + *puValueOut = psConfig->sGLMode.blueBits; + return true; + case PVRDRI_CONFIG_ATTRIB_ALPHA_BITS: + *puValueOut = psConfig->sGLMode.alphaBits; + return true; + case PVRDRI_CONFIG_ATTRIB_RGB_BITS: + *puValueOut = psConfig->sGLMode.rgbBits; + return true; + case PVRDRI_CONFIG_ATTRIB_DEPTH_BITS: + *puValueOut = psConfig->sGLMode.depthBits; + return true; + case PVRDRI_CONFIG_ATTRIB_STENCIL_BITS: + *puValueOut = psConfig->sGLMode.stencilBits; + return true; + case PVRDRI_CONFIG_ATTRIB_SAMPLE_BUFFERS: + *puValueOut = !!psConfig->sGLMode.samples; + return true; + case PVRDRI_CONFIG_ATTRIB_SAMPLES: + *puValueOut = psConfig->sGLMode.samples; + return true; + case PVRDRI_CONFIG_ATTRIB_BIND_TO_TEXTURE_RGB: + *puValueOut = GL_TRUE; + return true; + case PVRDRI_CONFIG_ATTRIB_BIND_TO_TEXTURE_RGBA: + *puValueOut = GL_TRUE; + return true; +#if defined(__DRI_ATTRIB_YUV_BIT) + case PVRDRI_CONFIG_ATTRIB_YUV_ORDER: + *puValueOut = psConfig->sGLMode.YUVOrder; + return true; + case PVRDRI_CONFIG_ATTRIB_YUV_NUM_OF_PLANES: + *puValueOut = psConfig->sGLMode.YUVNumberOfPlanes; + return true; + case PVRDRI_CONFIG_ATTRIB_YUV_SUBSAMPLE: + *puValueOut = psConfig->sGLMode.YUVSubsample; + return true; + case PVRDRI_CONFIG_ATTRIB_YUV_DEPTH_RANGE: + *puValueOut = psConfig->sGLMode.YUVDepthRange; + return true; + case PVRDRI_CONFIG_ATTRIB_YUV_CSC_STANDARD: + *puValueOut = psConfig->sGLMode.YUVCSCStandard; + return true; + case PVRDRI_CONFIG_ATTRIB_YUV_PLANE_BPP: + *puValueOut = psConfig->sGLMode.YUVPlaneBPP; + return true; +#endif +#if !defined(__DRI_ATTRIB_YUV_BIT) + case PVRDRI_CONFIG_ATTRIB_YUV_ORDER: + case PVRDRI_CONFIG_ATTRIB_YUV_NUM_OF_PLANES: + case PVRDRI_CONFIG_ATTRIB_YUV_SUBSAMPLE: + case PVRDRI_CONFIG_ATTRIB_YUV_DEPTH_RANGE: + case PVRDRI_CONFIG_ATTRIB_YUV_CSC_STANDARD: + case PVRDRI_CONFIG_ATTRIB_YUV_PLANE_BPP: + return false; +#endif + case PVRDRI_CONFIG_ATTRIB_RED_MASK: + *puValueOut = psConfig->sGLMode.redMask; + return true; + case PVRDRI_CONFIG_ATTRIB_GREEN_MASK: + *puValueOut = psConfig->sGLMode.greenMask; + return true; + case PVRDRI_CONFIG_ATTRIB_BLUE_MASK: + *puValueOut = psConfig->sGLMode.blueMask; + return true; + case PVRDRI_CONFIG_ATTRIB_ALPHA_MASK: + *puValueOut = psConfig->sGLMode.alphaMask; + return true; + case PVRDRI_CONFIG_ATTRIB_SRGB_CAPABLE: + *puValueOut = psConfig->sGLMode.sRGBCapable; + return true; + case PVRDRI_CONFIG_ATTRIB_INVALID: + errorMessage("%s: Invalid attribute", __func__); + assert(0); + return false; + default: + return false; + } +} + +bool +PVRDRIConfigQuery(const PVRDRIConfig *psConfig, + PVRDRIConfigAttrib eConfigAttrib, int *piValueOut) +{ + bool bRes; + unsigned int uValue; + + bRes = PVRDRIConfigQueryUnsigned(psConfig, eConfigAttrib, &uValue); + if (bRes) + *piValueOut = (int) uValue; + + return bRes; +} + +bool +MODSUPConfigQuery(const PVRDRIConfig *psConfig, + PVRDRIConfigAttrib eConfigAttrib, unsigned int *puValueOut) +{ + return PVRDRIConfigQueryUnsigned(psConfig, eConfigAttrib, puValueOut); +} + +void +MODSUPFlushFrontBuffer(struct __DRIdrawableRec *psDRIDrawable, + void *pvLoaderPrivate) +{ + PVRDRIDrawable *psPVRDrawable = psDRIDrawable->driverPrivate; + __DRIscreen *psDRIScreen = psDRIDrawable->driScreenPriv; + + if (!psPVRDrawable->sConfig.sGLMode.doubleBufferMode) + psDRIScreen->image.loader->flushFrontBuffer(psDRIDrawable, + pvLoaderPrivate); +} + +void * +MODSUPDrawableGetReferenceHandle(struct __DRIdrawableRec *psDRIDrawable) +{ + PVRDRIDrawable *psPVRDrawable = psDRIDrawable->driverPrivate; + + return psPVRDrawable; +} + +void +MODSUPDrawableAddReference(void *pvReferenceHandle) +{ + PVRDRIDrawable *psPVRDrawable = pvReferenceHandle; + + PVRDRIDrawableAddReference(psPVRDrawable); +} + +void +MODSUPDrawableRemoveReference(void *pvReferenceHandle) +{ + PVRDRIDrawable *psPVRDrawable = pvReferenceHandle; + + PVRDRIDrawableRemoveReference(psPVRDrawable); +} + +void +MODSUPDestroyLoaderImageState(const struct __DRIscreenRec *psDRIScreen, + void *pvLoaderPrivate) +{ + const __DRIimageLoaderExtension *psImageLoader = psDRIScreen->image.loader; + const __DRIdri2LoaderExtension *psDRI2Loader = psDRIScreen->dri2.loader; + + if (psImageLoader && psImageLoader->base.version >= 4 && + psImageLoader->destroyLoaderImageState) { + psImageLoader->destroyLoaderImageState(pvLoaderPrivate); + } else if (psDRI2Loader && psDRI2Loader->base.version >= 5 && + psDRI2Loader->destroyLoaderImageState) { + psDRI2Loader->destroyLoaderImageState(pvLoaderPrivate); + } +} diff --git a/src/gallium/frontends/pvr/pvrcompat.c b/src/gallium/frontends/pvr/pvrcompat.c new file mode 100644 index 0000000..782c900 --- /dev/null +++ b/src/gallium/frontends/pvr/pvrcompat.c @@ -0,0 +1,912 @@ +/* + * Copyright (c) Imagination Technologies Ltd. + * + * The contents of this file are subject to the MIT license as set out below. + * + * 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 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 +#include +#include +#include +#include +#include + +#include + +#include "pvrdri.h" + +#ifndef DRM_FORMAT_MOD_INVALID +#define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1) +#endif + +#define _MAKESTRING(x) # x +#define MAKESTRING(x) _MAKESTRING(x) + +#define PVRDRI_SUPPORT_LIB "libpvr_dri_support.so" + +static void *gpvSupLib; +static int giSupLibRef; + +static struct PVRDRISupportInterfaceV2 gsSupV2; + +static pthread_mutex_t gsCompatLock = PTHREAD_MUTEX_INITIALIZER; + +/* Lookup a function, and set the pointer to the function address */ +#define LookupFunc(func, ptr) \ + do { \ + ptr = dlsym(gpvSupLib, MAKESTRING(func)); \ + } while(0) + +/* Check if a function exists in the DRI Support interface structure */ +#define HaveFuncV2(field) \ + ((gsSupV2.field) != NULL) \ + +/* Call a function via the DRI Support interface structure */ +#define CallFuncV2(field, ...) \ + do { \ + if (gsSupV2.field) \ + return gsSupV2.field(__VA_ARGS__); \ + } while(0) + +/* Calculate the start of the PVRDRISupportInterfaceV2 structure */ +#define PVRDRIInterfaceV2Start(field) \ + (offsetof(struct PVRDRISupportInterfaceV2, field)) + +/* Calculate the end of the PVRDRISupportInterfaceV2 structure */ +#define PVRDRIInterfaceV2End(field) \ + (offsetof(struct PVRDRISupportInterfaceV2, field) + \ + sizeof((struct PVRDRISupportInterfaceV2 *)0)->field) + +static void +CompatLock(void) +{ + int ret; + + ret = pthread_mutex_lock(&gsCompatLock); + if (ret) { + errorMessage("%s: Failed to lock mutex (%d)", __func__, ret); + abort(); + } +} + +static void +CompatUnlock(void) +{ + int ret; + + ret = pthread_mutex_unlock(&gsCompatLock); + if (ret) { + errorMessage("%s: Failed to unlock mutex (%d)", __func__, ret); + abort(); + } +} + +static void * +LoadLib(const char *path) +{ + void *handle; + + /* Clear the error */ + (void) dlerror(); + + handle = dlopen(path, RTLD_NOW); + if (handle) { + __driUtilMessage("Loaded %s", path); + } else { + const char *error; + + error = dlerror(); + if (!error) + error = "unknown error"; + + errorMessage("%s: Couldn't load %s: %s", __func__, path, error); + } + + return handle; +} + +static void +UnloadLib(void *handle, const char *name) +{ + if (!handle) + return; + + /* Clear the error */ + (void) dlerror(); + + if (dlclose(handle)) { + const char *error; + + error = dlerror(); + if (!error) + error = "unknown error"; + + errorMessage("%s: Couldn't unload %s: %s", __func__, name, error); + } else { + __driUtilMessage("Unloaded %s", name); + } +} + +static bool +LoadSupportLib(void) +{ + gpvSupLib = LoadLib(PVRDRI_SUPPORT_LIB); + + return gpvSupLib != NULL; +} + +static void +UnloadSupportLib(void) +{ + UnloadLib(gpvSupLib, PVRDRI_SUPPORT_LIB); + gpvSupLib = NULL; +} + +static void +CompatDeinit(void) +{ + UnloadSupportLib(); + memset(&gsSupV2, 0, sizeof(gsSupV2)); +} + +bool +PVRDRICompatInit(const struct PVRDRICallbacksV2 *psCallbacksV2, + unsigned int uVersionV2, unsigned int uMinVersionV2) +{ + bool (*pfRegisterVersionedCallbacksV2)(const void *pvCallbacks, + unsigned int uVersion, + unsigned int uMinVersion); + bool res; + + CompatLock(); + res = (giSupLibRef++ != 0); + if (res) + goto Exit; + + res = LoadSupportLib(); + if (!res) + goto Exit; + + LookupFunc(PVRDRIRegisterVersionedCallbacksV2, + pfRegisterVersionedCallbacksV2); + + res = (pfRegisterVersionedCallbacksV2 != NULL); + if (!res) + goto Exit; + + res = pfRegisterVersionedCallbacksV2(psCallbacksV2, + uVersionV2, uMinVersionV2); + +Exit: + if (!res) { + CompatDeinit(); + giSupLibRef--; + } + CompatUnlock(); + + return res; +} + +void +PVRDRICompatDeinit(void) +{ + CompatLock(); + if (--giSupLibRef == 0) + CompatDeinit(); + CompatUnlock(); +} + +bool +MODSUPRegisterSupportInterfaceV2(const void *pvInterface, + unsigned int uVersion, + unsigned int uMinVersion) +{ + size_t uStart, uEnd; + + memset(&gsSupV2, 0, sizeof(gsSupV2)); + + if (uVersion < uMinVersion) + return false; + + /* + * Minimum versions we support. To prevent the accumulation of old unused + * interfaces in the PVRDRIInterfaceV2 structure, the caller specifies the + * minimum version it supports. This will be pointed to be the psInterface + * argument. Assuming we support that version, we must copy the structure + * passed to us into the correct place in our version of the interface + * structure. + */ + switch (uMinVersion) { + case 0: + uStart = PVRDRIInterfaceV2Start(v0); + break; + case 1: + case 2: + case 3: + case 4: + case 5: + /* These versions require version 0 */ + return false; + default: + return false; + } + + /* The "default" case should be associated with the latest version */ + switch (uVersion) { + default: + case 5: + /* This version is an extension of versions 0 to 4 */ + if (uMinVersion > 0) + return false; + + uEnd = PVRDRIInterfaceV2End(v5); + break; + case 4: + /* This version is an extension of versions 0 to 3 */ + if (uMinVersion > 0) + return false; + + uEnd = PVRDRIInterfaceV2End(v4); + break; + case 3: + /* + * This version is an extension of version 2, with no new + * entry points. + */ + case 2: + /* This version is an extension of versions 0 and 1 */ + if (uMinVersion > 0) + return false; + + uEnd = PVRDRIInterfaceV2End(v2); + break; + case 1: + /* This version is an extension of version 0 */ + if (uMinVersion > 0) + return false; + + uEnd = PVRDRIInterfaceV2End(v1); + break; + case 0: + uEnd = PVRDRIInterfaceV2End(v0); + break; + } + + memcpy(((char *) &gsSupV2) + uStart, pvInterface, uEnd - uStart); + + PVRDRIAdjustExtensions(uVersion, uMinVersion); + + return true; +} + +struct DRISUPScreen * +DRISUPCreateScreen(struct __DRIscreenRec *psDRIScreen, int iFD, + bool bUseInvalidate, void *pvLoaderPrivate, + const struct __DRIconfigRec ***pppsConfigs, + int *piMaxGLES1Version, int *piMaxGLES2Version) +{ + CallFuncV2(v0.CreateScreen, + psDRIScreen, iFD, bUseInvalidate, pvLoaderPrivate, pppsConfigs, + piMaxGLES1Version, piMaxGLES2Version); + + return NULL; +} + +void +DRISUPDestroyScreen(struct DRISUPScreen *psDRISUPScreen) +{ + CallFuncV2(v0.DestroyScreen, + psDRISUPScreen); +} + +unsigned int +DRISUPCreateContext(PVRDRIAPIType eAPI, PVRDRIConfig *psPVRDRIConfig, + struct PVRDRIContextConfig *psCtxConfig, + struct __DRIcontextRec *psDRIContext, + struct DRISUPContext *psDRISUPSharedContext, + struct DRISUPScreen *psDRISUPScreen, + struct DRISUPContext **ppsDRISUPContext) +{ + CallFuncV2(v0.CreateContext, + eAPI, psPVRDRIConfig, psCtxConfig, psDRIContext, + psDRISUPSharedContext, psDRISUPScreen, ppsDRISUPContext); + + return __DRI_CTX_ERROR_BAD_API; +} + +void +DRISUPDestroyContext(struct DRISUPContext *psDRISUPContext) +{ + CallFuncV2(v0.DestroyContext, + psDRISUPContext); +} + +struct DRISUPDrawable * +DRISUPCreateDrawable(struct __DRIdrawableRec *psDRIDrawable, + struct DRISUPScreen *psDRISUPScreen, + void *pvLoaderPrivate, PVRDRIConfig *psPVRDRIConfig) +{ + CallFuncV2(v0.CreateDrawable, + psDRIDrawable, psDRISUPScreen, pvLoaderPrivate, psPVRDRIConfig); + + return NULL; +} + +void +DRISUPDestroyDrawable(struct DRISUPDrawable *psDRISUPDrawable) +{ + CallFuncV2(v0.DestroyDrawable, + psDRISUPDrawable); +} + +bool +DRISUPMakeCurrent(struct DRISUPContext *psDRISUPContext, + struct DRISUPDrawable *psDRISUPWrite, + struct DRISUPDrawable *psDRISUPRead) +{ + CallFuncV2(v0.MakeCurrent, + psDRISUPContext, psDRISUPWrite, psDRISUPRead); + + return false; +} + +bool +DRISUPUnbindContext(struct DRISUPContext *psDRISUPContext) +{ + CallFuncV2(v0.UnbindContext, + psDRISUPContext); + + return false; +} + +struct DRISUPBuffer * +DRISUPAllocateBuffer(struct DRISUPScreen *psDRISUPScreen, + unsigned int uAttachment, unsigned int uFormat, + int iWidth, int iHeight, unsigned int *puName, + unsigned int *puPitch, unsigned int *puCPP, + unsigned int *puFlags) +{ + CallFuncV2(v0.AllocateBuffer, + psDRISUPScreen, uAttachment, uFormat, iWidth, iHeight, puName, + puPitch, puCPP, puFlags); + + return NULL; +} + +void +DRISUPReleaseBuffer(struct DRISUPScreen *psDRISUPScreen, + struct DRISUPBuffer *psDRISUPBuffer) +{ + CallFuncV2(v0.ReleaseBuffer, + psDRISUPScreen, psDRISUPBuffer); +} + +void +DRISUPSetTexBuffer2(struct DRISUPContext *psDRISUPContext, int iTarget, + int iFormat, struct DRISUPDrawable *psDRISUPDrawable) +{ + CallFuncV2(v0.SetTexBuffer2, + psDRISUPContext, iTarget, iFormat, psDRISUPDrawable); +} + +void +DRISUPReleaseTexBuffer(struct DRISUPContext *psDRISUPContext, int iTarget, + struct DRISUPDrawable *psDRISUPDrawable) +{ + CallFuncV2(v0.ReleaseTexBuffer, + psDRISUPContext, iTarget, psDRISUPDrawable); +} + +void +DRISUPFlush(struct DRISUPDrawable *psDRISUPDrawable) +{ + CallFuncV2(v0.Flush, + psDRISUPDrawable); +} + +void +DRISUPInvalidate(struct DRISUPDrawable *psDRISUPDrawable) +{ + CallFuncV2(v0.Invalidate, + psDRISUPDrawable); +} + +void +DRISUPFlushWithFlags(struct DRISUPContext *psDRISUPContext, + struct DRISUPDrawable *psDRISUPDrawable, + unsigned int uFlags, unsigned int uThrottleReason) +{ + CallFuncV2(v0.FlushWithFlags, + psDRISUPContext, psDRISUPDrawable, uFlags, uThrottleReason); +} + +__DRIimage * +DRISUPCreateImageFromName(struct DRISUPScreen *psDRISUPScreen, + int iWidth, int iHeight, int iFourCC, int iName, + int iPitch, void *pvLoaderPrivate) +{ + CallFuncV2(v0.CreateImageFromName, + psDRISUPScreen, iWidth, iHeight, iFourCC, iName, iPitch, + pvLoaderPrivate); + + return NULL; +} + +__DRIimage * +DRISUPCreateImageFromRenderbuffer(struct DRISUPContext *psDRISUPContext, + int iRenderBuffer, void *pvLoaderPrivate) +{ + CallFuncV2(v0.CreateImageFromRenderbuffer, + psDRISUPContext, iRenderBuffer, pvLoaderPrivate); + + return NULL; +} + +void +DRISUPDestroyImage(__DRIimage *psImage) +{ + CallFuncV2(v0.DestroyImage, psImage); +} + +__DRIimage * +DRISUPCreateImage(struct DRISUPScreen *psDRISUPScreen, + int iWidth, int iHeight, int iFourCC, unsigned int uUse, + void *pvLoaderPrivate) +{ + CallFuncV2(v0.CreateImage, + psDRISUPScreen, iWidth, iHeight, iFourCC, uUse, pvLoaderPrivate); + + return NULL; +} + +bool +DRISUPQueryImage(__DRIimage *psImage, int iAttrib, int *piValue) +{ + CallFuncV2(v0.QueryImage, + psImage, iAttrib, piValue); + + return false; +} + +__DRIimage * +DRISUPDupImage(__DRIimage *psImage, void *pvLoaderPrivate) +{ + CallFuncV2(v0.DupImage, + psImage, pvLoaderPrivate); + + return NULL; +} + +bool +DRISUPValidateImageUsage(__DRIimage *psImage, unsigned int uUse) +{ + CallFuncV2(v0.ValidateImageUsage, + psImage, uUse); + + return false; +} + +__DRIimage * +DRISUPCreateImageFromNames(struct DRISUPScreen *psDRISUPScreen, + int iWidth, int iHeight, int iFourCC, + int *piNames, int iNumNames, + int *piStrides, int *piOffsets, + void *pvLoaderPrivate) +{ + CallFuncV2(v0.CreateImageFromNames, + psDRISUPScreen, iWidth, iHeight, iFourCC, piNames, iNumNames, + piStrides, piOffsets, pvLoaderPrivate); + + return NULL; +} + +__DRIimage * +DRISUPFromPlanar(__DRIimage *psImage, int iPlane, void *pvLoaderPrivate) +{ + CallFuncV2(v0.FromPlanar, + psImage, iPlane, pvLoaderPrivate); + + return NULL; +} + +__DRIimage * +DRISUPCreateImageFromTexture(struct DRISUPContext *psDRISUPContext, + int iTarget, unsigned int uTexture, int iDepth, + int iLevel, unsigned int *puError, + void *pvLoaderPrivate) +{ + CallFuncV2(v0.CreateImageFromTexture, + psDRISUPContext, iTarget, uTexture, iDepth, iLevel, puError, + pvLoaderPrivate); + + return NULL; +} + +__DRIimage * +DRISUPCreateImageFromFDs(struct DRISUPScreen *psDRISUPcreen, + int iWidth, int iHeight, int iFourCC, + int *piFDs, int iNumFDs, int *piStrides, + int *piOffsets, void *pvLoaderPrivate) +{ + CallFuncV2(v0.CreateImageFromFDs, + psDRISUPcreen, iWidth, iHeight, iFourCC, piFDs, iNumFDs, + piStrides, piOffsets, pvLoaderPrivate); + + return NULL; +} + +__DRIimage * +DRISUPCreateImageFromDmaBufs(struct DRISUPScreen *psDRISUPScreen, + int iWidth, int iHeight, int iFourCC, + int *piFDs, int iNumFDs, + int *piStrides, int *piOffsets, + unsigned int uColorSpace, + unsigned int uSampleRange, + unsigned int uHorizSiting, + unsigned int uVertSiting, + unsigned int *puError, + void *pvLoaderPrivate) +{ + CallFuncV2(v0.CreateImageFromDMABufs, + psDRISUPScreen, iWidth, iHeight, iFourCC, piFDs, iNumFDs, + piStrides, piOffsets, uColorSpace, uSampleRange, + uHorizSiting, uVertSiting, puError, pvLoaderPrivate); + + return NULL; +} + +int +DRISUPGetImageCapabilities(struct DRISUPScreen *psDRISUPScreen) +{ + CallFuncV2(v0.GetImageCapabilities, + psDRISUPScreen); + + return 0; +} + +void +DRISUPBlitImage(struct DRISUPContext *psDRISUPContext, + __DRIimage *psDst, __DRIimage *psSrc, int iDstX0, int iDstY0, + int iDstWidth, int iDstHeight, int iSrcX0, int iSrcY0, + int iSrcWidth, int iSrcHeight, int iFlushFlag) +{ + CallFuncV2(v0.BlitImage, + psDRISUPContext, psDst, psSrc, iDstX0, iDstY0, + iDstWidth, iDstHeight, iSrcX0, iSrcY0, + iSrcWidth, iSrcHeight, iFlushFlag); +} + +void * +DRISUPMapImage(struct DRISUPContext *psDRISUPContext, __DRIimage* psImage, + int iX0, int iY0, int iWidth, int iHeight, unsigned int uFlags, + int *piStride, void **ppvData) +{ + CallFuncV2(v0.MapImage, + psDRISUPContext, psImage, iX0, iY0, iWidth, iHeight, uFlags, + piStride, ppvData); + + return NULL; +} + +void +DRISUPUnmapImage(struct DRISUPContext *psDRISUPContext, __DRIimage *psImage, + void *pvData) +{ + CallFuncV2(v0.UnmapImage, + psDRISUPContext, psImage, pvData); +} + +__DRIimage * +DRISUPCreateImageWithModifiers(struct DRISUPScreen *psDRISUPScreen, + int iWidth, int iHeight, int iFourCC, + const uint64_t *puModifiers, + const unsigned int uModifierCount, + void *pvLoaderPrivate) +{ + CallFuncV2(v0.CreateImageWithModifiers, + psDRISUPScreen, iWidth, iHeight, iFourCC, puModifiers, + uModifierCount, pvLoaderPrivate); + + return NULL; +} + +__DRIimage * +DRISUPCreateImageFromDMABufs2(struct DRISUPScreen *psDRISUPScreen, + int iWidth, int iHeight, int iFourCC, + uint64_t uModifier, int *piFDs, int iNumFDs, + int *piStrides, int *piOffsets, + unsigned int uColorSpace, + unsigned int uSampleRange, + unsigned int uHorizSiting, + unsigned int uVertSiting, + unsigned int *puError, void *pvLoaderPrivate) +{ + CallFuncV2(v0.CreateImageFromDMABufs2, + psDRISUPScreen, iWidth, iHeight, iFourCC, uModifier, + piFDs, iNumFDs, piStrides, piOffsets, uColorSpace, uSampleRange, + uHorizSiting, uVertSiting, puError, pvLoaderPrivate); + + return NULL; +} + +bool +DRISUPQueryDMABufFormats(struct DRISUPScreen *psDRISUPScreen, int iMax, + int *piFormats, int *piCount) +{ + CallFuncV2(v0.QueryDMABufFormats, + psDRISUPScreen, iMax, piFormats, piCount); + + return false; +} + +bool +DRISUPQueryDMABufModifiers(struct DRISUPScreen *psDRISUPScreen, int iFourCC, + int iMax, uint64_t *puModifiers, + unsigned int *piExternalOnly, int *piCount) +{ + CallFuncV2(v0.QueryDMABufModifiers, + psDRISUPScreen, iFourCC, iMax, puModifiers, piExternalOnly, + piCount); + + return false; +} + +bool +DRISUPQueryDMABufFormatModifierAttribs(struct DRISUPScreen *psDRISUPScreen, + uint32_t iFourCC, uint64_t uModifier, + int iAttrib, uint64_t *puValue) +{ + CallFuncV2(v0.QueryDMABufFormatModifierAttribs, + psDRISUPScreen, iFourCC, uModifier, iAttrib, puValue); + + return false; +} + +__DRIimage * +DRISUPCreateImageFromRenderBuffer2(struct DRISUPContext *psDRISUPContext, + int iRenderBuffer, void *pvLoaderPrivate, + unsigned int *puError) +{ + CallFuncV2(v0.CreateImageFromRenderBuffer2, + psDRISUPContext, iRenderBuffer, pvLoaderPrivate, puError); + + return NULL; +} + +__DRIimage * +DRISUPCreateImageFromBuffer(struct DRISUPContext *psDRISUPContext, + int iTarget, void *pvBuffer, + unsigned int *puError, void *pvLoaderPrivate) +{ + CallFuncV2(v0.CreateImageFromBuffer, + psDRISUPContext, iTarget, pvBuffer, puError, pvLoaderPrivate); + + return NULL; +} + +int +DRISUPQueryRendererInteger(struct DRISUPScreen *psDRISUPScreen, + int iAttribute, unsigned int *puValue) +{ + CallFuncV2(v0.QueryRendererInteger, + psDRISUPScreen, iAttribute, puValue); + + return -1; +} + +int +DRISUPQueryRendererString(struct DRISUPScreen *psDRISUPScreen, + int iAttribute, const char **ppszValue) +{ + CallFuncV2(v0.QueryRendererString, + psDRISUPScreen, iAttribute, ppszValue); + + return -1; +} + +void * +DRISUPCreateFence(struct DRISUPContext *psDRISUPContext) +{ + CallFuncV2(v0.CreateFence, + psDRISUPContext); + + return NULL; +} + +void +DRISUPDestroyFence(struct DRISUPScreen *psDRISUPScreen, void *pvFence) +{ + CallFuncV2(v0.DestroyFence, + psDRISUPScreen, pvFence); +} + +bool +DRISUPClientWaitSync(struct DRISUPContext *psDRISUPContext, void *pvFence, + unsigned int uFlags, uint64_t uTimeout) +{ + CallFuncV2(v0.ClientWaitSync, + psDRISUPContext, pvFence, uFlags, uTimeout); + + return false; +} + +void +DRISUPServerWaitSync(struct DRISUPContext *psDRISUPContext, void *pvFence, + unsigned int uFlags) +{ + CallFuncV2(v0.ServerWaitSync, + psDRISUPContext, pvFence, uFlags); +} + +unsigned int +DRISUPGetFenceCapabilities(struct DRISUPScreen *psDRISUPScreen) +{ + CallFuncV2(v0.GetFenceCapabilities, + psDRISUPScreen); + + return 0; +} + +void * +DRISUPCreateFenceFD(struct DRISUPContext *psDRISUPContext, int iFD) +{ + CallFuncV2(v0.CreateFenceFD, + psDRISUPContext, iFD); + + return NULL; +} + +int +DRISUPGetFenceFD(struct DRISUPScreen *psDRISUPScreen, void *pvFence) +{ + CallFuncV2(v0.GetFenceFD, + psDRISUPScreen, pvFence); + + return -1; +} + +void * +DRISUPGetFenceFromCLEvent(struct DRISUPScreen *psDRISUPScreen, + intptr_t iCLEvent) +{ + CallFuncV2(v1.GetFenceFromCLEvent, + psDRISUPScreen, iCLEvent); + + return NULL; +} + +int +DRISUPGetAPIVersion(struct DRISUPScreen *psDRISUPScreen, + PVRDRIAPIType eAPI) +{ + CallFuncV2(v2.GetAPIVersion, + psDRISUPScreen, eAPI); + + return 0; +} + +unsigned int +DRISUPGetNumAPIProcs(struct DRISUPScreen *psDRISUPScreen, + PVRDRIAPIType eAPI) +{ + CallFuncV2(v0.GetNumAPIProcs, + psDRISUPScreen, eAPI); + + return 0; +} + +const char * +DRISUPGetAPIProcName(struct DRISUPScreen *psDRISUPScreen, PVRDRIAPIType eAPI, + unsigned int uIndex) +{ + CallFuncV2(v0.GetAPIProcName, + psDRISUPScreen, eAPI, uIndex); + + return NULL; +} + +void * +DRISUPGetAPIProcAddress(struct DRISUPScreen *psDRISUPScreen, + PVRDRIAPIType eAPI, unsigned int uIndex) +{ + CallFuncV2(v0.GetAPIProcAddress, + psDRISUPScreen, eAPI, uIndex); + + return NULL; +} + +void +DRISUPSetDamageRegion(struct DRISUPDrawable *psDRISUPDrawable, + unsigned int uNRects, int *piRects) +{ + CallFuncV2(v0.SetDamageRegion, + psDRISUPDrawable, uNRects, piRects); +} + +bool +DRISUPHaveGetFenceFromCLEvent(void) +{ + CallFuncV2(v4.HaveGetFenceFromCLEvent); + + return true; +} + +__DRIimage * +DRISUPCreateImageFromDMABufs3(struct DRISUPScreen *psDRISUPScreen, + int iWidth, int iHeight, int iFourCC, + uint64_t uModifier, int *piFDs, int iNumFDs, + int *piStrides, int *piOffsets, + unsigned int uColorSpace, + unsigned int uSampleRange, + unsigned int uHorizSiting, + unsigned int uVertSiting, + uint32_t uFlags, + unsigned int *puError, void *pvLoaderPrivate) +{ + CallFuncV2(v5.CreateImageFromDMABufs3, + psDRISUPScreen, iWidth, iHeight, iFourCC, uModifier, + piFDs, iNumFDs, piStrides, piOffsets, uColorSpace, uSampleRange, + uHorizSiting, uVertSiting, uFlags, puError, pvLoaderPrivate); + + return NULL; +} + +__DRIimage * +DRISUPCreateImageWithModifiers2(struct DRISUPScreen *psDRISUPScreen, + int iWidth, int iHeight, int iFourCC, + const uint64_t *puModifiers, + const unsigned int uModifierCount, + unsigned int uUse, + void *pvLoaderPrivate) +{ + CallFuncV2(v5.CreateImageWithModifiers2, + psDRISUPScreen, iWidth, iHeight, iFourCC, puModifiers, + uModifierCount, uUse, pvLoaderPrivate); + + return NULL; +} + +__DRIimage * +DRISUPCreateImageFromFDs2(struct DRISUPScreen *psDRISUPcreen, + int iWidth, int iHeight, int iFourCC, + int *piFDs, int iNumFDs, uint32_t uFlags, + int *piStrides, int *piOffsets, + void *pvLoaderPrivate) +{ + CallFuncV2(v5.CreateImageFromFDs2, + psDRISUPcreen, iWidth, iHeight, iFourCC, piFDs, iNumFDs, + uFlags, piStrides, piOffsets, pvLoaderPrivate); + + return NULL; +} + +bool +DRISUPHaveSetInFenceFd(void) +{ + return HaveFuncV2(v5.SetInFenceFD); +} + +void +DRISUPSetInFenceFd(__DRIimage *psImage, int iFd) +{ + CallFuncV2(v5.SetInFenceFD, + psImage, iFd); +} diff --git a/src/gallium/frontends/pvr/pvrdri.c b/src/gallium/frontends/pvr/pvrdri.c new file mode 100644 index 0000000..3a910a9 --- /dev/null +++ b/src/gallium/frontends/pvr/pvrdri.c @@ -0,0 +1,630 @@ +/* + * Copyright (c) Imagination Technologies Ltd. + * + * The contents of this file are subject to the MIT license as set out below. + * + * 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 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 +#include + +#include "util/u_atomic.h" +#include +#include + +#include "dri_screen.h" + +#include "pvrdri.h" +#include "pvrmesa.h" + +#define PVR_IMAGE_LOADER_VER_MIN 1 + +struct PVRBuffer { + __DRIbuffer sDRIBuffer; + struct DRISUPBuffer *psDRISUPBuffer; +}; + +/*************************************************************************//*! + Local functions + *//**************************************************************************/ + +static bool +PVRLoaderIsSupported(__DRIscreen *psDRIScreen) +{ + if (psDRIScreen->image.loader) { + if (psDRIScreen->image.loader->base.version < PVR_IMAGE_LOADER_VER_MIN) { + __driUtilMessage("%s: Image loader extension version %d but need %d", + __func__, psDRIScreen->image.loader->base.version, + PVR_IMAGE_LOADER_VER_MIN); + return false; + } else if (!psDRIScreen->image.loader->getBuffers) { + __driUtilMessage("%s: Image loader extension missing support for getBuffers", + __func__); + return false; + } + } else { + __driUtilMessage("%s: Image loader extension required", __func__); + return false; + } + + return true; +} + +static inline struct DRISUPContext * +getSharedContextImpl(void *pvSharedContextPrivate) +{ + if (pvSharedContextPrivate == NULL) + return NULL; + + return ((PVRDRIContext *) pvSharedContextPrivate)->psDRISUPContext; +} + +static void +PVRDRIScreenAddReference(PVRDRIScreen *psPVRScreen) +{ + int iRefCount = p_atomic_inc_return(&psPVRScreen->iRefCount); + + (void) iRefCount; + assert(iRefCount > 1); +} + +static void +PVRDRIScreenRemoveReference(PVRDRIScreen *psPVRScreen) +{ + int iRefCount = p_atomic_dec_return(&psPVRScreen->iRefCount); + + assert(iRefCount >= 0); + + if (iRefCount != 0) + return; + + pvrdri_free_dispatch_tables(psPVRScreen); + DRISUPDestroyScreen(psPVRScreen->psDRISUPScreen); + PVRDRICompatDeinit(); + free(psPVRScreen); +} + +void +PVRDRIDrawableAddReference(PVRDRIDrawable *psPVRDrawable) +{ + int iRefCount = p_atomic_inc_return(&psPVRDrawable->iRefCount); + + (void) iRefCount; + assert(iRefCount > 1); +} + +void +PVRDRIDrawableRemoveReference(PVRDRIDrawable *psPVRDrawable) +{ + int iRefCount = p_atomic_dec_return(&psPVRDrawable->iRefCount); + + assert(iRefCount >= 0); + + if (iRefCount != 0) + return; + + DRISUPDestroyDrawable(psPVRDrawable->psDRISUPDrawable); + +#if defined(DEBUG) + p_atomic_dec(&psPVRDrawable->psPVRScreen->iDrawableAlloc); +#endif + + PVRDRIScreenRemoveReference(psPVRDrawable->psPVRScreen); + free(psPVRDrawable); +} + +static void +PVRScreenPrintExtensions(__DRIscreen *psDRIScreen) +{ + /* Don't attempt to print anything if LIBGL_DEBUG isn't in the environment */ + if (getenv("LIBGL_DEBUG") == NULL) + return; + + if (psDRIScreen->extensions) { + const __DRIextension *psScreenExtensionVersionInfo = + PVRDRIScreenExtensionVersionInfo(); + int i; + int j; + + __driUtilMessage("Supported screen extensions:"); + + for (i = 0; psDRIScreen->extensions[i]; i++) { + for (j = 0; psScreenExtensionVersionInfo[j].name; j++) { + if (strcmp(psDRIScreen->extensions[i]->name, + psScreenExtensionVersionInfo[j].name) == 0) { + __driUtilMessage("\t%s (supported version: %u - max version: %u)", + psDRIScreen->extensions[i]->name, + psDRIScreen->extensions[i]->version, + psScreenExtensionVersionInfo[j].version); + break; + } + } + + if (psScreenExtensionVersionInfo[j].name == NULL) { + __driUtilMessage("\t%s (supported version: %u - max version: unknown)", + psDRIScreen->extensions[i]->name, + psDRIScreen->extensions[i]->version); + } + } + } else { + __driUtilMessage("No screen extensions found"); + } +} + +/*************************************************************************//*! + Mesa driver API functions + *//**************************************************************************/ + +static const __DRIconfig ** +PVRDRIInitScreen(__DRIscreen *psDRIScreen) +{ + PVRDRIScreen *psPVRScreen; + const __DRIconfig **ppsConfigs; + int iMaxGLES1Version, iMaxGLES2Version; + const struct PVRDRICallbacksV2 sDRICallbacksV2 = { + /* Version 0 callbacks */ + .v0.RegisterSupportInterface = MODSUPRegisterSupportInterfaceV2, + .v0.GetBuffers = MODSUPGetBuffers, + .v0.CreateConfigs = MODSUPCreateConfigs, + .v0.ConcatConfigs = MODSUPConcatConfigs, + .v0.ConfigQuery = MODSUPConfigQuery, + .v0.LookupEGLImage = MODSUPLookupEGLImage, + .v0.GetCapability = MODSUPGetCapability, + /* Version 1 callbacks */ + .v1.FlushFrontBuffer = MODSUPFlushFrontBuffer, + /* Version 2 callbacks */ + .v2.GetDisplayFD = MODSUPGetDisplayFD, + /* Version 3 callbacks */ + .v3.DrawableGetReferenceHandle = MODSUPDrawableGetReferenceHandle, + .v3.DrawableAddReference = MODSUPDrawableAddReference, + .v3.DrawableRemoveReference = MODSUPDrawableRemoveReference, + /* Version 4 callbacks */ + .v4.DestroyLoaderImageState = MODSUPDestroyLoaderImageState, + }; + + if (!PVRLoaderIsSupported(psDRIScreen)) + return NULL; + + if (!PVRDRICompatInit(&sDRICallbacksV2, 4, 0)) + return NULL; + + psPVRScreen = calloc(1, sizeof(*psPVRScreen)); + if (psPVRScreen == NULL) { + __driUtilMessage("%s: Couldn't allocate PVRDRIScreen", __func__); + goto ErrorCompatDeinit; + } + + psDRIScreen->driverPrivate = psPVRScreen; + psPVRScreen->psDRIScreen = psDRIScreen; + psPVRScreen->iRefCount = 1; + + psPVRScreen->psDRISUPScreen = + DRISUPCreateScreen(psDRIScreen, psDRIScreen->fd, + psDRIScreen->dri2.useInvalidate != NULL, + psDRIScreen->loaderPrivate, + &ppsConfigs, &iMaxGLES1Version, &iMaxGLES2Version); + if (!psPVRScreen->psDRISUPScreen) + goto ErrorScreenFree; + + psDRIScreen->max_gl_es1_version = iMaxGLES1Version; + psDRIScreen->max_gl_es2_version = iMaxGLES2Version; + + psDRIScreen->max_gl_compat_version = + DRISUPGetAPIVersion(psPVRScreen->psDRISUPScreen, PVRDRI_API_GL_COMPAT); + psDRIScreen->max_gl_core_version = + DRISUPGetAPIVersion(psPVRScreen->psDRISUPScreen, PVRDRI_API_GL_CORE); + + psDRIScreen->extensions = PVRDRIScreenExtensions(); + + PVRScreenPrintExtensions(psDRIScreen); + + return ppsConfigs; + +ErrorScreenFree: + psDRIScreen->driverPrivate = NULL; + free(psPVRScreen); + +ErrorCompatDeinit: + PVRDRICompatDeinit(); + + return NULL; +} + +static void +PVRDRIDestroyScreen(__DRIscreen *psDRIScreen) +{ + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + +#if defined(DEBUG) + if (psPVRScreen->iBufferAlloc != 0 || + psPVRScreen->iDrawableAlloc != 0 || + psPVRScreen->iContextAlloc != 0) { + errorMessage("%s: Outstanding allocations: Contexts: %d Drawables: %d Buffers: %d", + __func__, psPVRScreen->iContextAlloc, + psPVRScreen->iDrawableAlloc, psPVRScreen->iBufferAlloc); + + if (psPVRScreen->iRefCount > 1) { + errorMessage("%s: PVRDRIScreen resources will not be freed until its %d references are removed", + __func__, psPVRScreen->iRefCount - 1); + } + } +#endif + + PVRDRIScreenRemoveReference(psPVRScreen); +} + +static int +PVRDRIScreenSupportedAPIs(PVRDRIScreen *psPVRScreen) +{ + unsigned int api_mask = psPVRScreen->psDRIScreen->api_mask; + int supported = 0; + + if ((api_mask & (1 << __DRI_API_GLES)) != 0) + supported |= PVRDRI_API_BIT_GLES; + + if ((api_mask & (1 << __DRI_API_GLES2)) != 0) + supported |= PVRDRI_API_BIT_GLES2; + + if ((api_mask & (1 << __DRI_API_GLES3)) != 0) + supported |= PVRDRI_API_BIT_GLES3; + + if ((api_mask & (1 << __DRI_API_OPENGL)) != 0) + supported |= PVRDRI_API_BIT_GL; + + if ((api_mask & (1 << __DRI_API_OPENGL_CORE)) != 0) + supported |= PVRDRI_API_BIT_GL; + + return supported; +} + +static GLboolean +PVRDRICreateContext(gl_api eMesaAPI, const struct gl_config *psGLMode, + __DRIcontext *psDRIContext, + const struct __DriverContextConfig *psCtxConfig, + unsigned int *puError, void *pvSharedContextPrivate) +{ + __DRIscreen *psDRIScreen = psDRIContext->driScreenPriv; + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + PVRDRIContext *psPVRContext; + struct DRISUPContext *psDRISUPContext; + struct DRISUPContext *psDRISUPSharedContext; + struct PVRDRIContextConfig sCtxConfig; + PVRDRIAPIType eAPI; + + psDRISUPSharedContext = getSharedContextImpl(pvSharedContextPrivate); + + sCtxConfig.uMajorVersion = psCtxConfig->major_version; + sCtxConfig.uMinorVersion = psCtxConfig->minor_version; + sCtxConfig.uFlags = psCtxConfig->flags; + sCtxConfig.iResetStrategy = __DRI_CTX_RESET_NO_NOTIFICATION; + sCtxConfig.uPriority = __DRI_CTX_PRIORITY_MEDIUM; + sCtxConfig.iReleaseBehavior = __DRI_CTX_RELEASE_BEHAVIOR_FLUSH; + + psPVRContext = calloc(1, sizeof(*psPVRContext)); + if (psPVRContext == NULL) { + __driUtilMessage("%s: Couldn't allocate PVRDRIContext", __func__); + *puError = __DRI_CTX_ERROR_NO_MEMORY; + return GL_FALSE; + } + + psPVRContext->psDRIContext = psDRIContext; + psPVRContext->psPVRScreen = psPVRScreen; + + if (psGLMode) + psPVRContext->sConfig.sGLMode = *psGLMode; + + switch (eMesaAPI) { + case API_OPENGLES: + eAPI = PVRDRI_API_GLES1; + break; + case API_OPENGLES2: + eAPI = PVRDRI_API_GLES2; + break; + case API_OPENGL_COMPAT: + eAPI = PVRDRI_API_GL_COMPAT; + break; + case API_OPENGL_CORE: + eAPI = PVRDRI_API_GL_CORE; + break; + default: + __driUtilMessage("%s: Unsupported API: %d", + __func__, (int) eMesaAPI); + *puError = __DRI_CTX_ERROR_BAD_API; + goto ErrorContextFree; + } + psPVRContext->eAPI = eAPI; + + if ((psCtxConfig->attribute_mask & + __DRIVER_CONTEXT_ATTRIB_RESET_STRATEGY) != 0) { + sCtxConfig.iResetStrategy = psCtxConfig->reset_strategy; + } + + if ((psCtxConfig->attribute_mask & + __DRIVER_CONTEXT_ATTRIB_RELEASE_BEHAVIOR) != 0) { + sCtxConfig.iReleaseBehavior = psCtxConfig->release_behavior; + } + + if ((psCtxConfig->attribute_mask & + __DRIVER_CONTEXT_ATTRIB_PRIORITY) != 0) { + sCtxConfig.uPriority = psCtxConfig->priority; + } + + *puError = DRISUPCreateContext(eAPI, &psPVRContext->sConfig, &sCtxConfig, + psDRIContext, psDRISUPSharedContext, + psPVRScreen->psDRISUPScreen, + &psDRISUPContext); + if (*puError != __DRI_CTX_ERROR_SUCCESS) + goto ErrorContextFree; + + psPVRContext->psDRISUPContext = psDRISUPContext; + + if (!pvrdri_create_dispatch_table(psPVRScreen, eAPI)) { + __driUtilMessage("%s: Couldn't create dispatch table", __func__); + *puError = __DRI_CTX_ERROR_BAD_API; + goto ErrorContextDestroy; + } +#if defined(DEBUG) + p_atomic_inc(&psPVRScreen->iContextAlloc); +#endif + + psDRIContext->driverPrivate = (void *) psPVRContext; + PVRDRIScreenAddReference(psPVRScreen); + + *puError = __DRI_CTX_ERROR_SUCCESS; + + return GL_TRUE; + +ErrorContextDestroy: + DRISUPDestroyContext(psPVRContext->psDRISUPContext); + +ErrorContextFree: + free(psPVRContext); + + return GL_FALSE; +} + +static void +PVRDRIDestroyContext(__DRIcontext *psDRIContext) +{ + PVRDRIContext *psPVRContext = psDRIContext->driverPrivate; + PVRDRIScreen *psPVRScreen = psPVRContext->psPVRScreen; + + DRISUPDestroyContext(psPVRContext->psDRISUPContext); + +#if defined(DEBUG) + p_atomic_dec(&psPVRScreen->iContextAlloc); +#endif + + PVRDRIScreenRemoveReference(psPVRScreen); + free(psPVRContext); +} + +static GLboolean +PVRDRICreateBuffer(__DRIscreen *psDRIScreen, __DRIdrawable *psDRIDrawable, + const struct gl_config *psGLMode, GLboolean bIsPixmap) +{ + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + PVRDRIDrawable *psPVRDrawable = NULL; + + /* No known callers ever set this to true */ + if (bIsPixmap) + return GL_FALSE; + + if (!psGLMode) { + __driUtilMessage("%s: Invalid GL config", __func__); + return GL_FALSE; + } + + psPVRDrawable = calloc(1, sizeof(*psPVRDrawable)); + if (!psPVRDrawable) { + __driUtilMessage("%s: Couldn't allocate PVR drawable", __func__); + goto ErrorDrawableFree; + } + + psDRIDrawable->driverPrivate = (void *) psPVRDrawable; + psPVRDrawable->iRefCount = 1; + psPVRDrawable->psDRIDrawable = psDRIDrawable; + psPVRDrawable->psPVRScreen = psPVRScreen; + psPVRDrawable->sConfig.sGLMode = *psGLMode; + psPVRDrawable->sConfig.iSupportedAPIs = + PVRDRIScreenSupportedAPIs(psPVRScreen); + + psPVRDrawable->psDRISUPDrawable = + DRISUPCreateDrawable(psDRIDrawable, psPVRScreen->psDRISUPScreen, + psDRIDrawable->loaderPrivate, + &psPVRDrawable->sConfig); + if (!psPVRDrawable->psDRISUPDrawable) { + __driUtilMessage("%s: Couldn't create DRI Support drawable", + __func__); + goto ErrorDrawableFree; + } + + /* Initialisation is completed in MakeCurrent */ +#if defined(DEBUG) + p_atomic_inc(&psPVRScreen->iDrawableAlloc); +#endif + PVRDRIScreenAddReference(psPVRScreen); + return GL_TRUE; + +ErrorDrawableFree: + DRISUPDestroyDrawable(psPVRDrawable->psDRISUPDrawable); + free(psPVRDrawable); + psDRIDrawable->driverPrivate = NULL; + + return GL_FALSE; +} + +static void +PVRDRIDestroyBuffer(__DRIdrawable *psDRIDrawable) +{ + PVRDRIDrawable *psPVRDrawable = psDRIDrawable->driverPrivate; + + PVRDRIDrawableRemoveReference(psPVRDrawable); +} + +static GLboolean +PVRDRIMakeCurrent(__DRIcontext *psDRIContext, + __DRIdrawable *psDRIWrite, __DRIdrawable *psDRIRead) +{ + PVRDRIContext *psPVRContext = psDRIContext->driverPrivate; + struct DRISUPDrawable *psDRISUPWrite; + struct DRISUPDrawable *psDRISUPRead; + + if (psDRIWrite) { + PVRDRIDrawable *psPVRWrite = psDRIWrite->driverPrivate; + + psDRISUPWrite = psPVRWrite->psDRISUPDrawable; + } else { + psDRISUPWrite = NULL; + } + + if (psDRIRead) { + PVRDRIDrawable *psPVRRead = psDRIRead->driverPrivate; + + psDRISUPRead = psPVRRead->psDRISUPDrawable; + } else { + psDRISUPRead = NULL; + } + + if (!DRISUPMakeCurrent(psPVRContext->psDRISUPContext, + psDRISUPWrite, psDRISUPRead)) + goto ErrorUnlock; + + pvrdri_set_dispatch_table(psPVRContext); + + return GL_TRUE; + +ErrorUnlock: + return GL_FALSE; +} + +static GLboolean +PVRDRIUnbindContext(__DRIcontext *psDRIContext) +{ + PVRDRIContext *psPVRContext = psDRIContext->driverPrivate; + + pvrdri_set_null_dispatch_table(); + DRISUPUnbindContext(psPVRContext->psDRISUPContext); + + return GL_TRUE; +} + +static __DRIbuffer * +PVRDRIAllocateBuffer(__DRIscreen *psDRIScreen, unsigned int uAttachment, + unsigned int uFormat, int iWidth, int iHeight) +{ + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + struct PVRBuffer *psBuffer; + + psBuffer = calloc(1, sizeof(*psBuffer)); + if (psBuffer == NULL) { + __driUtilMessage("%s: Failed to allocate buffer", __func__); + return NULL; + } + + psBuffer->psDRISUPBuffer = + DRISUPAllocateBuffer(psPVRScreen->psDRISUPScreen, uAttachment, uFormat, + iWidth, iHeight, &psBuffer->sDRIBuffer.name, + &psBuffer->sDRIBuffer.pitch, + &psBuffer->sDRIBuffer.cpp, + &psBuffer->sDRIBuffer.flags); + if (!psBuffer->psDRISUPBuffer) { + __driUtilMessage("%s: Failed to create DRI Support buffer", __func__); + goto ErrorFreeDRIBuffer; + } + + psBuffer->sDRIBuffer.attachment = uAttachment; + +#if defined(DEBUG) + p_atomic_inc(&psPVRScreen->iBufferAlloc); +#endif + + return &psBuffer->sDRIBuffer; + +ErrorFreeDRIBuffer: + free(psBuffer); + + return NULL; +} + +static void +PVRDRIReleaseBuffer(__DRIscreen *psDRIScreen, __DRIbuffer *psDRIBuffer) +{ + struct PVRBuffer *psPVRBuffer = (struct PVRBuffer *) psDRIBuffer; + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + + DRISUPReleaseBuffer(psPVRScreen->psDRISUPScreen, + psPVRBuffer->psDRISUPBuffer); + +#if defined(DEBUG) + p_atomic_dec(&psPVRScreen->iBufferAlloc); +#endif + + free(psPVRBuffer); +} + +static char * +PVRDRIGetXMLConfigOptions(const char *pszDriverName) +{ + const driOptionDescription asConfigOptions[] = + { + DRI_CONF_SECTION_MISCELLANEOUS + DRI_CONF_OPT_B("pvr_driconf_not_used", true, + "The PowerVR driver does not use DRIConf") + DRI_CONF_SECTION_END + }; + + (void) pszDriverName; + + return driGetOptionsXml(&asConfigOptions[0], ARRAY_SIZE(asConfigOptions)); +} + +const struct __DriverAPIRec pvr_driver_api = { + .InitScreen = PVRDRIInitScreen, + .DestroyScreen = PVRDRIDestroyScreen, + .CreateContext = PVRDRICreateContext, + .DestroyContext = PVRDRIDestroyContext, + .CreateBuffer = PVRDRICreateBuffer, + .DestroyBuffer = PVRDRIDestroyBuffer, + .SwapBuffers = NULL, + .MakeCurrent = PVRDRIMakeCurrent, + .UnbindContext = PVRDRIUnbindContext, + .AllocateBuffer = PVRDRIAllocateBuffer, + .ReleaseBuffer = PVRDRIReleaseBuffer, +}; + +static const struct __DRIDriverVtableExtensionRec pvr_vtable = { + .base = {__DRI_DRIVER_VTABLE, 1}, + .vtable = &pvr_driver_api, +}; + +const __DRIconfigOptionsExtension pvr_config_options = { + .base = { __DRI_CONFIG_OPTIONS, 2 }, + .getXml = PVRDRIGetXMLConfigOptions, +}; + +const __DRIextension *pvr_driver_extensions[] = { + &driCoreExtension.base, + &driImageDriverExtension.base, + &pvrDRI2Extension.base, + &pvr_vtable.base, + &pvr_config_options.base, + NULL +}; diff --git a/src/gallium/frontends/pvr/pvrdri.h b/src/gallium/frontends/pvr/pvrdri.h new file mode 100644 index 0000000..58591d8 --- /dev/null +++ b/src/gallium/frontends/pvr/pvrdri.h @@ -0,0 +1,190 @@ +/* + * Copyright (c) Imagination Technologies Ltd. + * + * The contents of this file are subject to the MIT license as set out below. + * + * 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 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. + */ + +#if !defined(__PVRDRI_H__) +#define __PVRDRI_H__ + +#include +#include +#include + +#include + +#include "main/mtypes.h" +#include "util/macros.h" +#include "dri_util.h" +#include "pvrdri_support.h" + +struct PVRDRIConfigRec { + struct gl_config sGLMode; + int iSupportedAPIs; +}; + +/* PVR screen data */ +typedef struct PVRDRIScreen_TAG { + /* DRI screen structure pointer */ + __DRIscreen *psDRIScreen; + + /* Opaque PVR DRI Support screen structure pointer */ + struct DRISUPScreen *psDRISUPScreen; + + /* Reference count */ + int iRefCount; + +#if defined(DEBUG) + /* Counters of outstanding allocations */ + int iContextAlloc; + int iDrawableAlloc; + int iBufferAlloc; +#endif + + /* PVR OGLES 1 dispatch table */ + struct _glapi_table *psOGLES1Dispatch; + /* PVR OGLES 2/3 dispatch table */ + struct _glapi_table *psOGLES2Dispatch; + /* PVR OGL dispatch table */ + struct _glapi_table *psOGLDispatch; +} PVRDRIScreen; + +/* PVR context data */ +typedef struct PVRDRIContext_TAG { + /* Pointer to DRI context */ + __DRIcontext *psDRIContext; + + /* Opaque PVR DRI Support context structure pointer */ + struct DRISUPContext *psDRISUPContext; + + /* Pointer to PVRDRIScreen structure */ + PVRDRIScreen *psPVRScreen; + + /* GL config */ + PVRDRIConfig sConfig; + + /* API */ + PVRDRIAPIType eAPI; +} PVRDRIContext; + +/* PVR drawable data */ +typedef struct PVRDRIDrawable_TAG { + PVRDRIScreen *psPVRScreen; + __DRIdrawable *psDRIDrawable; + int iRefCount; + PVRDRIConfig sConfig; + struct DRISUPDrawable *psDRISUPDrawable; + unsigned int uFourCC; + unsigned int uDRIFormat; +} PVRDRIDrawable; + +/*************************************************************************//*! + pvrdri.c + *//**************************************************************************/ +void PVRDRIDrawableAddReference(PVRDRIDrawable *psPVRDrawable); +void PVRDRIDrawableRemoveReference(PVRDRIDrawable *psPVRDrawable); + +/*************************************************************************//*! + pvrutil.c + *//**************************************************************************/ + +void PRINTFLIKE(1, 2) __driUtilMessage(const char *f, ...); +void PRINTFLIKE(1, 2) errorMessage(const char *f, ...); + +mesa_format PVRDRIMesaFormatToMesaFormat(int pvrdri_mesa_format); +int PVRDRIFormatToFourCC(int dri_format); +int PVRDRIFourCCToDRIFormat(int iFourCC); + +/*************************************************************************//*! + pvrext.c + *//**************************************************************************/ + +const __DRIextension **PVRDRIScreenExtensions(void); +const __DRIextension *PVRDRIScreenExtensionVersionInfo(void); + +void PVRDRIAdjustExtensions(unsigned int uVersion, unsigned int uMinVersion); + +/*************************************************************************//*! + pvrcompat.c + *//**************************************************************************/ + +bool PVRDRICompatInit(const struct PVRDRICallbacksV2 *psCallbacksV2, + unsigned int uVersionV2, unsigned int uMinVersionV2); +void PVRDRICompatDeinit(void); + +bool MODSUPRegisterSupportInterfaceV2(const void *pvInterface, + unsigned int uVersion, + unsigned int uMinVersion); + +/*************************************************************************//*! + pvrcb.c + *//**************************************************************************/ + +int MODSUPGetBuffers(struct __DRIdrawableRec *psDRIDrawable, + unsigned int uFourCC, uint32_t *puStamp, + void *pvLoaderPrivate, uint32_t uBufferMask, + struct PVRDRIImageList *psImageList); + +bool MODSUPCreateConfigs(struct __DRIconfigRec ***psConfigs, + struct __DRIscreenRec *psDRIScreen, + int iPVRDRIMesaFormat, const uint8_t *puDepthBits, + const uint8_t *puStencilBits, + unsigned int uNumDepthStencilBits, + const unsigned int *puDBModes, + unsigned int uNumDBModes, + const uint8_t *puMSAASamples, + unsigned int uNumMSAAModes, bool bEnableAccum, + bool bColorDepthMatch, bool bMutableRenderBuffer, + int iYUVDepthRange, int iYUVCSCStandard, + uint32_t uMaxPbufferWidth, uint32_t uMaxPbufferHeight); + +struct __DRIconfigRec **MODSUPConcatConfigs(struct __DRIscreenRec *psDRIScreen, + struct __DRIconfigRec **ppsConfigA, + struct __DRIconfigRec **ppsConfigB); + +__DRIimage *MODSUPLookupEGLImage(struct __DRIscreenRec *psDRIScreen, + void *pvImage, void *pvLoaderPrivate); + +unsigned int MODSUPGetCapability(struct __DRIscreenRec *psDRIScreen, + unsigned int uCapability); + +int MODSUPGetDisplayFD(struct __DRIscreenRec *psDRIScreen, + void *pvLoaderPrivate); + +bool PVRDRIConfigQuery(const PVRDRIConfig *psConfig, + PVRDRIConfigAttrib eConfigAttrib, int *piValueOut); + +bool MODSUPConfigQuery(const PVRDRIConfig *psConfig, + PVRDRIConfigAttrib eConfigAttrib, + unsigned int *puValueOut); + +void MODSUPFlushFrontBuffer(struct __DRIdrawableRec *psDRIDrawable, + void *pvLoaderPrivate); + +void *MODSUPDrawableGetReferenceHandle(struct __DRIdrawableRec *psDRIDrawable); + +void MODSUPDrawableAddReference(void *pvReferenceHandle); + +void MODSUPDrawableRemoveReference(void *pvReferenceHandle); + +void MODSUPDestroyLoaderImageState(const struct __DRIscreenRec *psDRIScreen, + void *pvLoaderPrivate); +#endif /* defined(__PVRDRI_H__) */ diff --git a/src/gallium/frontends/pvr/pvrdri_support.h b/src/gallium/frontends/pvr/pvrdri_support.h new file mode 100644 index 0000000..f735354 --- /dev/null +++ b/src/gallium/frontends/pvr/pvrdri_support.h @@ -0,0 +1,233 @@ +/* + * Copyright (c) Imagination Technologies Ltd. + * + * The contents of this file are subject to the MIT license as set out below. + * + * 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 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. + */ + +#if !defined(__PVRDRI_SUPPORT_H__) +#define __PVRDRI_SUPPORT_H__ + +#include +#include + +#include "dri_support.h" + +struct DRISUPScreen *DRISUPCreateScreen(struct __DRIscreenRec *psDRIScreen, + int iFD, bool bUseInvalidate, + void *pvLoaderPrivate, + const struct __DRIconfigRec ***pppsConfigs, + int *piMaxGLES1Version, + int *piMaxGLES2Version); +void DRISUPDestroyScreen(struct DRISUPScreen *psDRISUPScreen); + +unsigned int DRISUPCreateContext(PVRDRIAPIType eAPI, + PVRDRIConfig *psPVRDRIConfig, + struct PVRDRIContextConfig *psCtxConfig, + struct __DRIcontextRec *psDRIContext, + struct DRISUPContext *psDRISUPSharedContext, + struct DRISUPScreen *psDRISUPScreen, + struct DRISUPContext **ppsDRISUPContext); +void DRISUPDestroyContext(struct DRISUPContext *psDRISUPContext); + +struct DRISUPDrawable *DRISUPCreateDrawable(struct __DRIdrawableRec *psDRIDrawable, + struct DRISUPScreen *psDRISUPScreen, + void *pvLoaderPrivate, + PVRDRIConfig *psPVRDRIConfig); +void DRISUPDestroyDrawable(struct DRISUPDrawable *psDRISUPDrawable); + +bool DRISUPMakeCurrent(struct DRISUPContext *psDRISUPContext, + struct DRISUPDrawable *psDRISUPWrite, + struct DRISUPDrawable *psDRISUPRead); +bool DRISUPUnbindContext(struct DRISUPContext *psDRISUPContext); + +struct DRISUPBuffer *DRISUPAllocateBuffer(struct DRISUPScreen *psDRISUPScreen, + unsigned int uAttchment, + unsigned int uFormat, + int iWidth, int iHeight, + unsigned int *puName, + unsigned int *puPitch, + unsigned int *puCPP, + unsigned int *puFlags); +void DRISUPReleaseBuffer(struct DRISUPScreen *psDRISUPScreen, + struct DRISUPBuffer *psDRISUPBuffer); +void DRISUPSetTexBuffer2(struct DRISUPContext *psDRISUPContext, + int iTarget, int iFormat, + struct DRISUPDrawable *psDRISUPDrawable); +void DRISUPReleaseTexBuffer(struct DRISUPContext *psDRISUPContext, + int iTarget, + struct DRISUPDrawable *psDRISUPDrawable); + +void DRISUPFlush(struct DRISUPDrawable *psDRISUPDrawable); +void DRISUPInvalidate(struct DRISUPDrawable *psDRISUPDrawable); +void DRISUPFlushWithFlags(struct DRISUPContext *psDRISUPContext, + struct DRISUPDrawable *psDRISUPDrawable, + unsigned int uFlags, unsigned int uThrottleReason); + +__DRIimage *DRISUPCreateImageFromName(struct DRISUPScreen *psDRISUPScreen, + int iWidth, int iHeight, int iFourCC, + int iName, int iPitch, + void *pvLoaderPrivate); +__DRIimage *DRISUPCreateImageFromRenderbuffer(struct DRISUPContext *psDRISUPContext, + int iRenderBuffer, + void *pvLoaderPrivate); +void DRISUPDestroyImage(__DRIimage *psImage); +__DRIimage *DRISUPCreateImage(struct DRISUPScreen *psDRISUPScreen, + int iWidth, int iHeight, int iFourCC, + unsigned int uUse, void *pvLoaderPrivate); +bool DRISUPQueryImage(__DRIimage *psImage, int iAttrib, int *piValue); +__DRIimage *DRISUPDupImage(__DRIimage *psImage, void *pvLoaderPrivate); +bool DRISUPValidateImageUsage(__DRIimage *psImage, unsigned int uUse); +__DRIimage *DRISUPCreateImageFromNames(struct DRISUPScreen *psDRISUPScreen, + int iWidth, int iHeight, int iFourCC, + int *piNames, int iNumNames, + int *piStrides, int *piOffsets, + void *pvLoaderPrivate); +__DRIimage *DRISUPFromPlanar(__DRIimage *psImage, int iPlane, + void *pvLoaderPrivate); +__DRIimage *DRISUPCreateImageFromTexture(struct DRISUPContext *psDRISUPContext, + int iTarget, unsigned int uTexture, + int iDepth, int iLevel, + unsigned int *puError, + void *pvLoaderPrivate); +__DRIimage *DRISUPCreateImageFromFDs(struct DRISUPScreen *psDRISUPcreen, + int iWidth, int iHeight, int iFourCC, + int *piFDs, int iNumFDs, + int *piStrides, int *piOffsets, + void *pvLoaderPrivate); +__DRIimage *DRISUPCreateImageFromDmaBufs(struct DRISUPScreen *psDRISUPScreen, + int iWidth, int iHeight, int iFourCC, + int *piFDs, int iNumFDs, + int *piStrides, int *piOffsets, + unsigned int uColorSpace, + unsigned int uSampleRange, + unsigned int uHorizSiting, + unsigned int uVertSiting, + unsigned int *puError, + void *pvLoaderPrivate); +int DRISUPGetImageCapabilities(struct DRISUPScreen *psDRISUPScreen); +void DRISUPBlitImage(struct DRISUPContext *psDRISUPContext, + __DRIimage *psDst, __DRIimage *psSrc, + int iDstX0, int iDstY0, int iDstWidth, int iDstHeight, + int iSrcX0, int iSrcY0, int iSrcWidth, int iSrcHeight, + int iFlushFlag); +void *DRISUPMapImage(struct DRISUPContext *psDRISUPContext, + __DRIimage *psImage, + int iX0, int iY0, int iWidth, int iHeight, + unsigned int uFlags, int *piStride, void **ppvData); +void DRISUPUnmapImage(struct DRISUPContext *psDRISUPContext, + __DRIimage *psImage, void *pvData); +__DRIimage *DRISUPCreateImageWithModifiers(struct DRISUPScreen *psDRISUPScreen, + int iWidth, int iHeight, int iFourCC, + const uint64_t *puModifiers, + const unsigned int uModifierCount, + void *pvLoaderPrivate); +__DRIimage *DRISUPCreateImageFromDMABufs2(struct DRISUPScreen *psDRISUPScreen, + int iWidth, int iHeight, + int iFourCC, uint64_t uModifier, + int *piFDs, int iNumFDs, + int *piStrides, int *piOffsets, + unsigned int uColorSpace, + unsigned int uSampleRange, + unsigned int uHorizSiting, + unsigned int uVertSiting, + unsigned int *puError, + void *pvLoaderPrivate); + +bool DRISUPQueryDMABufFormats(struct DRISUPScreen *psDRISUPScreen, int iMax, + int *piFormats, int *piCount); +bool DRISUPQueryDMABufModifiers(struct DRISUPScreen *psDRISUPScreen, + int iFourCC, int iMax, uint64_t *puModifiers, + unsigned int *piExternalOnly, int *piCount); +bool DRISUPQueryDMABufFormatModifierAttribs(struct DRISUPScreen *psDRISUPScreen, + uint32_t uFourcc, + uint64_t uModifier, + int iAttrib, uint64_t *puValue); + +__DRIimage *DRISUPCreateImageFromRenderBuffer2(struct DRISUPContext *psDRISUPContext, + int iRenderBuffer, + void *pvLoaderPrivate, + unsigned int *puError); + +__DRIimage *DRISUPCreateImageFromBuffer(struct DRISUPContext *psDRISUPContext, + int iTarget, void *pvBuffer, + unsigned int *puError, + void *pvLoaderPrivate); + +int DRISUPQueryRendererInteger(struct DRISUPScreen *psDRISUPScreen, + int iAttribute, unsigned int *puValue); +int DRISUPQueryRendererString(struct DRISUPScreen *psDRISUPScreen, + int iAttribute, const char **ppszValue); + +void *DRISUPCreateFence(struct DRISUPContext *psDRISUPContext); +void DRISUPDestroyFence(struct DRISUPScreen *psDRISUPScreen, void *pvFence); +bool DRISUPClientWaitSync(struct DRISUPContext *psDRISUPContext, + void *pvFence, unsigned int uFlags, + uint64_t uTimeout); +void DRISUPServerWaitSync(struct DRISUPContext *psDRISUPContext, + void *pvFence, unsigned int uFlags); +unsigned int DRISUPGetFenceCapabilities(struct DRISUPScreen *psDRISUPScreen); +void *DRISUPCreateFenceFD(struct DRISUPContext *psDRISUPContext, int iFD); +int DRISUPGetFenceFD(struct DRISUPScreen *psDRISUPScreen, void *pvFence); +void *DRISUPGetFenceFromCLEvent(struct DRISUPScreen *psDRISUPScreen, + intptr_t iCLEvent); +int DRISUPGetAPIVersion(struct DRISUPScreen *psDRISUPScreen, + PVRDRIAPIType eAPI); + +unsigned int DRISUPGetNumAPIProcs(struct DRISUPScreen *psDRISUPScreen, + PVRDRIAPIType eAPI); +const char *DRISUPGetAPIProcName(struct DRISUPScreen *psDRISUPScreen, + PVRDRIAPIType eAPI, unsigned int uIndex); +void *DRISUPGetAPIProcAddress(struct DRISUPScreen *psDRISUPScreen, + PVRDRIAPIType eAPI, unsigned int uIndex); + +void DRISUPSetDamageRegion(struct DRISUPDrawable *psDRISUPDrawable, + unsigned int uNRects, int *piRects); + +bool DRISUPHaveGetFenceFromCLEvent(void); + +__DRIimage *DRISUPCreateImageFromDMABufs3(struct DRISUPScreen *psDRISUPScreen, + int iWidth, int iHeight, + int iFourCC, uint64_t uModifier, + int *piFDs, int iNumFDs, + int *piStrides, int *piOffsets, + unsigned int uColorSpace, + unsigned int uSampleRange, + unsigned int uHorizSiting, + unsigned int uVertSiting, + uint32_t uFlags, + unsigned int *puError, + void *pvLoaderPrivate); +__DRIimage *DRISUPCreateImageWithModifiers2(struct DRISUPScreen *psDRISUPScreen, + int iWidth, int iHeight, + int iFourCC, + const uint64_t *puModifiers, + const unsigned int uModifierCount, + unsigned int uUse, + void *pvLoaderPrivate); +__DRIimage *DRISUPCreateImageFromFDs2(struct DRISUPScreen *psDRISUPcreen, + int iWidth, int iHeight, int iFourCC, + int *piFDs, int iNumFDs, uint32_t uFlags, + int *piStrides, int *piOffsets, + void *pvLoaderPrivate); + +bool DRISUPHaveSetInFenceFd(void); +void DRISUPSetInFenceFd(__DRIimage *psImage, int iFd); +#endif /* defined(__PVRDRI_SUPPORT_H__) */ diff --git a/src/gallium/frontends/pvr/pvrext.c b/src/gallium/frontends/pvr/pvrext.c new file mode 100644 index 0000000..f34863b --- /dev/null +++ b/src/gallium/frontends/pvr/pvrext.c @@ -0,0 +1,796 @@ +/* + * Copyright (c) Imagination Technologies Ltd. + * + * The contents of this file are subject to the MIT license as set out below. + * + * 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 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. + */ + +/* + * EXTENSION SUPPORT + * + * As the driver supports a range of Mesa versions it can be the case that it + * needs to support different extensions and extension versions depending on + * the version of Mesa that it's built against. As a guide the following rules + * should be followed: + * + * 1) If an extension appears in some supported versions of Mesa but not others + * then it should be protected by the extension define, e.g.: + * #if defined(__DRI_IMAGE) + * + * #endif + * + * However, if it appears in all versions then there's no need for it to + * be protected. + * + * 2) Each driver supported extension should have a define for the maximum + * version supported by the driver. This should be used when initialising + * the corresponding extension structure. The Mesa extension version define + * should *NOT* be used. + * + * 3) If the driver supports a range of versions for a given extension then + * it should protect the extension code based on the Mesa extension version + * define. For example, if the driver has to support versions 7 to 8 of the + * __DRI_IMAGE extension then any fields, in the __DRIimageExtension + * structure, that appear in version 8 but not 7 should be protected as + * follows: + * #if (__DRI_IMAGE_VERSION >= 8) + * .createImageFromDmaBufs = PVRDRICreateImageFromDmaBufs, + * #endif + * + * Obviously any other associated code should also be protected in the same + * way. + */ + +#include "dri_util.h" +#include "dri_query_renderer.h" + +#include "dri_support.h" +#include "pvrdri.h" + +#include "EGL/egl.h" +#include "EGL/eglext.h" +#include "EGL/eglmesaext.h" + +/* Maximum version numbers for each supported extension */ +#define PVR_DRI_TEX_BUFFER_VERSION 3 +#define PVR_DRI2_FLUSH_VERSION 4 +#define PVR_DRI_IMAGE_VERSION 21 +#define PVR_DRI2_ROBUSTNESS_VERSION 1 +#define PVR_DRI2_FENCE_VERSION 2 +#define PVR_DRI2_RENDERER_QUERY_VERSION 1 +#define PVR_DRI2_BUFFER_DAMAGE_VERSION 1 + +static void +PVRDRIExtSetTexBuffer(__DRIcontext *psDRIContext, GLint iTarget, + GLint iFormat, __DRIdrawable *psDRIDrawable) +{ + PVRDRIDrawable *psPVRDrawable = psDRIDrawable->driverPrivate; + PVRDRIContext *psPVRContext = psDRIContext->driverPrivate; + + DRISUPSetTexBuffer2(psPVRContext->psDRISUPContext, + iTarget, iFormat, psPVRDrawable->psDRISUPDrawable); +} + +static void +PVRDRIExtReleaseTexBuffer(__DRIcontext *psDRIContext, GLint iTarget, + __DRIdrawable *psDRIDrawable) +{ + PVRDRIDrawable *psPVRDrawable = psDRIDrawable->driverPrivate; + PVRDRIContext *psPVRContext = psDRIContext->driverPrivate; + + DRISUPReleaseTexBuffer(psPVRContext->psDRISUPContext, + iTarget, psPVRDrawable->psDRISUPDrawable); + +} + +static __DRItexBufferExtension pvrDRITexBufferExtension = { + .base = { + .name = __DRI_TEX_BUFFER, + .version = PVR_DRI_TEX_BUFFER_VERSION, + }, + .setTexBuffer = NULL, + .setTexBuffer2 = PVRDRIExtSetTexBuffer, + .releaseTexBuffer = PVRDRIExtReleaseTexBuffer, +}; + +static void +PVRDRI2Flush(__DRIdrawable *psDRIDrawable) +{ + PVRDRIDrawable *psPVRDrawable = psDRIDrawable->driverPrivate; + + DRISUPFlush(psPVRDrawable->psDRISUPDrawable); +} + +static void +PVRDRI2Invalidate(__DRIdrawable *psDRIDrawable) +{ + PVRDRIDrawable *psPVRDrawable = psDRIDrawable->driverPrivate; + + DRISUPInvalidate(psPVRDrawable->psDRISUPDrawable); +} + +static void +PVRDRI2FlushWithFlags(__DRIcontext *psDRIContext, + __DRIdrawable *psDRIDrawable, + unsigned int uFlags, + enum __DRI2throttleReason eThrottleReason) +{ + PVRDRIContext *psPVRContext = psDRIContext->driverPrivate; + struct DRISUPDrawable *psDRISUPDrawable; + + if ((uFlags & __DRI2_FLUSH_DRAWABLE) != 0) { + PVRDRIDrawable *psPVRDrawable = psDRIDrawable->driverPrivate; + + psDRISUPDrawable = psPVRDrawable->psDRISUPDrawable; + } else { + psDRISUPDrawable = NULL; + } + + DRISUPFlushWithFlags(psPVRContext->psDRISUPContext, psDRISUPDrawable, + uFlags, (unsigned int) eThrottleReason); +} + +static __DRI2flushExtension pvrDRI2FlushExtension = { + .base = { + .name = __DRI2_FLUSH, + .version = PVR_DRI2_FLUSH_VERSION, + }, + .flush = PVRDRI2Flush, + .invalidate = PVRDRI2Invalidate, + .flush_with_flags = PVRDRI2FlushWithFlags, +}; + +static __DRIimage * +PVRDRICreateImageFromName(__DRIscreen *psDRIScreen, int iWidth, int iHeight, + int iFormat, int iName, int iPitch, + void *pvLoaderPrivate) +{ + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + int iFourCC = PVRDRIFormatToFourCC(iFormat); + + return DRISUPCreateImageFromName(psPVRScreen->psDRISUPScreen, + iWidth, iHeight, iFourCC, iName, iPitch, + pvLoaderPrivate); +} + +static __DRIimage * +PVRDRICreateImageFromRenderbuffer(__DRIcontext *psDRIContext, + int iRenderBuffer, void *pvLoaderPrivate) +{ + PVRDRIContext *psPVRContext = psDRIContext->driverPrivate; + + return DRISUPCreateImageFromRenderbuffer(psPVRContext->psDRISUPContext, + iRenderBuffer, pvLoaderPrivate); +} + +static void +PVRDRIDestroyImage(__DRIimage *psImage) +{ + DRISUPDestroyImage(psImage); +} + +static __DRIimage * +PVRDRICreateImage(__DRIscreen *psDRIScreen, int iWidth, int iHeight, + int iFormat, unsigned int uUse, void *pvLoaderPrivate) +{ + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + int iFourCC = PVRDRIFormatToFourCC(iFormat); + + return DRISUPCreateImage(psPVRScreen->psDRISUPScreen, iWidth, iHeight, + iFourCC, uUse, pvLoaderPrivate); +} + +static GLboolean +PVRDRIQueryImage(__DRIimage *psImage, int iAttrib, int *piValue) +{ + int iFourCC; + + switch (iAttrib) { + case __DRI_IMAGE_ATTRIB_FORMAT: + if (DRISUPQueryImage(psImage, + __DRI_IMAGE_ATTRIB_FOURCC, &iFourCC)) { + *piValue = PVRDRIFourCCToDRIFormat(iFourCC); + return GL_TRUE; + } + return GL_FALSE; + default: + return DRISUPQueryImage(psImage, iAttrib, piValue); + } + +} + +static __DRIimage * +PVRDRIDupImage(__DRIimage *psImage, void *pvLoaderPrivate) +{ + return DRISUPDupImage(psImage, pvLoaderPrivate); +} + +static GLboolean +PVRDRIValidateImageUsage(__DRIimage *psImage, unsigned int uUse) +{ + return DRISUPValidateImageUsage(psImage, uUse); +} + +static __DRIimage * +PVRDRICreateImageFromNames(__DRIscreen *psDRIScreen, int iWidth, int iHeight, + int iFourCC, int *piNames, int iNumNames, + int *piStrides, int *piOffsets, + void *pvLoaderPrivate) +{ + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + + return DRISUPCreateImageFromNames(psPVRScreen->psDRISUPScreen, + iWidth, iHeight, iFourCC, + piNames, iNumNames, + piStrides, piOffsets, pvLoaderPrivate); +} + +static __DRIimage * +PVRDRIFromPlanar(__DRIimage *psImage, int iPlane, void *pvLoaderPrivate) +{ + return DRISUPFromPlanar(psImage, iPlane, pvLoaderPrivate); +} + +static __DRIimage * +PVRDRICreateImageFromTexture(__DRIcontext *psDRIContext, int iTarget, + unsigned int uTexture, int iDepth, int iLevel, + unsigned int *puError, void *pvLoaderPrivate) +{ + PVRDRIContext *psPVRContext = psDRIContext->driverPrivate; + int iEGLTarget; + + switch (iTarget) { + case GL_TEXTURE_2D: + iEGLTarget = PVRDRI_GL_TEXTURE_2D; + break; + case GL_TEXTURE_3D: + iEGLTarget = PVRDRI_GL_TEXTURE_3D; + break; + case GL_TEXTURE_CUBE_MAP: + iEGLTarget = PVRDRI_GL_TEXTURE_CUBE_MAP_POSITIVE_X; + break; + default: + errorMessage("%s: GL Target %d is not supported", + __func__, iTarget); + *puError = __DRI_IMAGE_ERROR_BAD_PARAMETER; + return NULL; + } + + return DRISUPCreateImageFromTexture(psPVRContext->psDRISUPContext, + iEGLTarget, uTexture, iDepth, iLevel, + puError, pvLoaderPrivate); +} + +static __DRIimage * +PVRDRICreateImageFromFds(__DRIscreen *psDRIScreen, int iWidth, int iHeight, + int iFourCC, int *piFDs, int iNumFDs, + int *piStrides, int *piOffsets, + void *pvLoaderPrivate) +{ + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + + return DRISUPCreateImageFromFDs(psPVRScreen->psDRISUPScreen, + iWidth, iHeight, iFourCC, piFDs, iNumFDs, + piStrides, piOffsets, pvLoaderPrivate); +} + +static __DRIimage * +PVRDRICreateImageFromDmaBufs(__DRIscreen *psDRIScreen, + int iWidth, int iHeight, int iFourCC, + int *piFDs, int iNumFDs, + int *piStrides, int *piOffsets, + enum __DRIYUVColorSpace eColorSpace, + enum __DRISampleRange eSampleRange, + enum __DRIChromaSiting eHorizSiting, + enum __DRIChromaSiting eVertSiting, + unsigned int *puError, void *pvLoaderPrivate) +{ + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + + return DRISUPCreateImageFromDmaBufs(psPVRScreen->psDRISUPScreen, + iWidth, iHeight, iFourCC, + piFDs, iNumFDs, piStrides, piOffsets, + (unsigned int) eColorSpace, + (unsigned int) eSampleRange, + (unsigned int) eHorizSiting, + (unsigned int) eVertSiting, + puError, pvLoaderPrivate); +} + +static void +PVRDRIBlitImage(__DRIcontext *psDRIContext, + __DRIimage *psDst, __DRIimage *psSrc, + int iDstX0, int iDstY0, int iDstWidth, int iDstHeight, + int iSrcX0, int iSrcY0, int iSrcWidth, int iSrcHeight, + int iFlushFlag) +{ + PVRDRIContext *psPVRContext = psDRIContext->driverPrivate; + + return DRISUPBlitImage(psPVRContext->psDRISUPContext, + psDst, psSrc, + iDstX0, iDstY0, iDstWidth, iDstHeight, + iSrcX0, iSrcY0, iSrcWidth, iSrcHeight, + iFlushFlag); +} + +static int +PVRDRIGetCapabilities(__DRIscreen *psDRIScreen) +{ + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + + return DRISUPGetImageCapabilities(psPVRScreen->psDRISUPScreen); +} + +static void * +PVRDRIMapImage(__DRIcontext *psDRIContext, __DRIimage *psImage, + int iX0, int iY0, int iWidth, int iHeight, + unsigned int iFlags, int *piStride, void **ppvData) +{ + PVRDRIContext *psPVRContext = psDRIContext->driverPrivate; + + return DRISUPMapImage(psPVRContext->psDRISUPContext, psImage, + iX0, iY0, iWidth, iHeight, iFlags, piStride, + ppvData); +} + +static void +PVRDRIUnmapImage(__DRIcontext *psDRIContext, __DRIimage *psImage, + void *pvData) +{ + PVRDRIContext *psPVRContext = psDRIContext->driverPrivate; + + return DRISUPUnmapImage(psPVRContext->psDRISUPContext, psImage, pvData); +} + +static __DRIimage * +PVRDRICreateImageWithModifiers(__DRIscreen *psDRIScreen, + int iWidth, int iHeight, int iFormat, + const uint64_t *puModifiers, + const unsigned int uModifierCount, + void *pvLoaderPrivate) +{ + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + int iFourCC = PVRDRIFormatToFourCC(iFormat); + + return DRISUPCreateImageWithModifiers(psPVRScreen->psDRISUPScreen, + iWidth, iHeight, iFourCC, + puModifiers, uModifierCount, + pvLoaderPrivate); +} + +static __DRIimage * +PVRDRICreateImageFromDmaBufs2(__DRIscreen *psDRIScreen, + int iWidth, int iHeight, + int iFourCC, uint64_t uModifier, + int *piFDs, int iNumFDs, + int *piStrides, int *piOffsets, + enum __DRIYUVColorSpace eColorSpace, + enum __DRISampleRange eSampleRange, + enum __DRIChromaSiting eHorizSiting, + enum __DRIChromaSiting eVertSiting, + unsigned int *puError, void *pvLoaderPrivate) +{ + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + + return DRISUPCreateImageFromDMABufs2(psPVRScreen->psDRISUPScreen, + iWidth, iHeight, iFourCC, uModifier, + piFDs, iNumFDs, piStrides, piOffsets, + (unsigned int) eColorSpace, + (unsigned int) eSampleRange, + (unsigned int) eHorizSiting, + (unsigned int) eVertSiting, + puError, pvLoaderPrivate); +} + +static GLboolean +PVRDRIQueryDmaBufFormats(__DRIscreen *psDRIScreen, int iMax, + int *piFormats, int *piCount) +{ + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + + return DRISUPQueryDMABufFormats(psPVRScreen->psDRISUPScreen, iMax, + piFormats, piCount); +} + +static GLboolean +PVRDRIQueryDmaBufModifiers(__DRIscreen *psDRIScreen, int iFourCC, int iMax, + uint64_t *puModifiers, + unsigned int *puExternalOnly, int *piCount) +{ + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + + return DRISUPQueryDMABufModifiers(psPVRScreen->psDRISUPScreen, iFourCC, + iMax, + puModifiers, puExternalOnly, piCount); +} + +static GLboolean +PVRDRIQueryDmaBufFormatModifierAttribs(__DRIscreen *psDRIScreen, + uint32_t uFourCC, uint64_t uModifier, + int iAttrib, uint64_t *puValue) +{ + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + struct DRISUPScreen *psDRISUPScreen = psPVRScreen->psDRISUPScreen; + + return DRISUPQueryDMABufFormatModifierAttribs(psDRISUPScreen, uFourCC, + uModifier, iAttrib, puValue); +} + +static __DRIimage * +PVRDRICreateImageFromRenderbuffer2(__DRIcontext *psDRIContext, + int iRenderBuffer, void *pvLoaderPrivate, + unsigned int *puError) +{ + PVRDRIContext *psPVRContext = psDRIContext->driverPrivate; + struct DRISUPContext *psDRISUPContext = psPVRContext->psDRISUPContext; + + return DRISUPCreateImageFromRenderBuffer2(psDRISUPContext, iRenderBuffer, + pvLoaderPrivate, puError); +} + +static __DRIimage * +PVRDRICreateImageFromDmaBufs3(__DRIscreen *psDRIScreen, + int iWidth, int iHeight, + int iFourCC, uint64_t uModifier, + int *piFDs, int iNumFDs, + int *piStrides, int *piOffsets, + enum __DRIYUVColorSpace eColorSpace, + enum __DRISampleRange eSampleRange, + enum __DRIChromaSiting eHorizSiting, + enum __DRIChromaSiting eVertSiting, + uint32_t uFlags, unsigned int *puError, + void *pvLoaderPrivate) +{ + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + + return DRISUPCreateImageFromDMABufs3(psPVRScreen->psDRISUPScreen, + iWidth, iHeight, iFourCC, uModifier, + piFDs, iNumFDs, piStrides, piOffsets, + (unsigned int) eColorSpace, + (unsigned int) eSampleRange, + (unsigned int) eHorizSiting, + (unsigned int) eVertSiting, + uFlags, puError, pvLoaderPrivate); +} + +static __DRIimage * +PVRDRICreateImageWithModifiers2(__DRIscreen *psDRIScreen, + int iWidth, int iHeight, int iFormat, + const uint64_t *puModifiers, + const unsigned int uModifierCount, + unsigned int uUse, + void *pvLoaderPrivate) +{ + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + int iFourCC = PVRDRIFormatToFourCC(iFormat); + + return DRISUPCreateImageWithModifiers2(psPVRScreen->psDRISUPScreen, + iWidth, iHeight, iFourCC, + puModifiers, uModifierCount, + uUse, pvLoaderPrivate); +} + +static __DRIimage * +PVRDRICreateImageFromFds2(__DRIscreen *psDRIScreen, int iWidth, int iHeight, + int iFourCC, int *piFDs, int iNumFDs, + uint32_t uFlags, int *piStrides, int *piOffsets, + void *pvLoaderPrivate) +{ + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + + return DRISUPCreateImageFromFDs2(psPVRScreen->psDRISUPScreen, + iWidth, iHeight, iFourCC, piFDs, iNumFDs, + uFlags, piStrides, piOffsets, + pvLoaderPrivate); +} + +static void +PVRDRISetInFenceFd(__DRIimage *psImage, int iFd) +{ + return DRISUPSetInFenceFd(psImage, iFd); +} + +#if defined(EGL_IMG_cl_image) +static __DRIimage * +PVRDRICreateImageFromBuffer(__DRIcontext *psDRIContext, int iTarget, + void *pvBuffer, unsigned int *puError, + void *pvLoaderPrivate) +{ + PVRDRIContext *psPVRContext = psDRIContext->driverPrivate; + + return DRISUPCreateImageFromBuffer(psPVRContext->psDRISUPContext, iTarget, + pvBuffer, puError, pvLoaderPrivate); +} +#endif + +static __DRIimageExtension pvrDRIImage = { + .base = { + .name = __DRI_IMAGE, + .version = PVR_DRI_IMAGE_VERSION, + }, + .createImageFromName = PVRDRICreateImageFromName, + .createImageFromRenderbuffer = PVRDRICreateImageFromRenderbuffer, + .destroyImage = PVRDRIDestroyImage, + .createImage = PVRDRICreateImage, + .queryImage = PVRDRIQueryImage, + .dupImage = PVRDRIDupImage, + .validateUsage = PVRDRIValidateImageUsage, + .createImageFromNames = PVRDRICreateImageFromNames, + .fromPlanar = PVRDRIFromPlanar, + .createImageFromTexture = PVRDRICreateImageFromTexture, + .createImageFromFds = PVRDRICreateImageFromFds, + .createImageFromDmaBufs = PVRDRICreateImageFromDmaBufs, + .blitImage = PVRDRIBlitImage, + .getCapabilities = PVRDRIGetCapabilities, + .mapImage = PVRDRIMapImage, + .unmapImage = PVRDRIUnmapImage, + .createImageWithModifiers = PVRDRICreateImageWithModifiers, + .createImageFromDmaBufs2 = PVRDRICreateImageFromDmaBufs2, + .queryDmaBufFormats = PVRDRIQueryDmaBufFormats, + .queryDmaBufModifiers = PVRDRIQueryDmaBufModifiers, + .queryDmaBufFormatModifierAttribs = + PVRDRIQueryDmaBufFormatModifierAttribs, + .createImageFromRenderbuffer2 = PVRDRICreateImageFromRenderbuffer2, + .createImageFromDmaBufs3 = PVRDRICreateImageFromDmaBufs3, + .createImageWithModifiers2 = PVRDRICreateImageWithModifiers2, + .createImageFromFds2 = PVRDRICreateImageFromFds2, + .setInFenceFd = PVRDRISetInFenceFd, +#if defined(EGL_IMG_cl_image) + .createImageFromBuffer = PVRDRICreateImageFromBuffer, +#endif +}; + +static __DRIrobustnessExtension pvrDRIRobustness = { + .base = { + .name = __DRI2_ROBUSTNESS, + .version = PVR_DRI2_ROBUSTNESS_VERSION, + } +}; + +static int +PVRDRIQueryRendererInteger(__DRIscreen *psDRIScreen, int iAttribute, + unsigned int *puValue) +{ + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + int res; + + res = DRISUPQueryRendererInteger(psPVRScreen->psDRISUPScreen, + iAttribute, puValue); + if (res == -1) + return driQueryRendererIntegerCommon(psDRIScreen, iAttribute, puValue); + + return res; +} + +static int +PVRDRIQueryRendererString(__DRIscreen *psDRIScreen, int iAttribute, + const char **ppszValue) +{ + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + + return DRISUPQueryRendererString(psPVRScreen->psDRISUPScreen, iAttribute, + ppszValue); +} + +static const __DRI2rendererQueryExtension pvrDRIRendererQueryExtension = { + .base = { + .name = __DRI2_RENDERER_QUERY, + .version = PVR_DRI2_RENDERER_QUERY_VERSION, + }, + .queryInteger = PVRDRIQueryRendererInteger, + .queryString = PVRDRIQueryRendererString, +}; + + +static void * +PVRDRICreateFenceEXT(__DRIcontext *psDRIContext) +{ + PVRDRIContext *psPVRContext = psDRIContext->driverPrivate; + + return DRISUPCreateFence(psPVRContext->psDRISUPContext); +} + +static void +PVRDRIDestroyFenceEXT(__DRIscreen *psDRIScreen, void *pvFence) +{ + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + + return DRISUPDestroyFence(psPVRScreen->psDRISUPScreen, pvFence); +} + +static GLboolean +PVRDRIClientWaitSyncEXT(__DRIcontext *psDRIContext, void *pvFence, + unsigned int uFlags, uint64_t uTimeout) +{ + struct DRISUPContext *psDRISUPContext; + + if (psDRIContext) { + PVRDRIContext *psPVRContext = psDRIContext->driverPrivate; + + psDRISUPContext = psPVRContext->psDRISUPContext; + } else { + psDRISUPContext = NULL; + } + + return DRISUPClientWaitSync(psDRISUPContext, pvFence, uFlags, uTimeout); +} + +static void +PVRDRIServerWaitSyncEXT(__DRIcontext *psDRIContext, void *pvFence, + unsigned int uFlags) +{ + PVRDRIContext *psPVRContext = psDRIContext->driverPrivate; + + return DRISUPServerWaitSync(psPVRContext->psDRISUPContext, pvFence, uFlags); +} + +static unsigned int +PVRDRIGetFenceCapabilitiesEXT(__DRIscreen *psDRIScreen) +{ + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + + return DRISUPGetFenceCapabilities(psPVRScreen->psDRISUPScreen); +} + +static void * +PVRDRICreateFenceFdEXT(__DRIcontext *psDRIContext, int iFD) +{ + PVRDRIContext *psPVRContext = psDRIContext->driverPrivate; + + return DRISUPCreateFenceFD(psPVRContext->psDRISUPContext, iFD); +} + +static int +PVRDRIGetFenceFdEXT(__DRIscreen *psDRIScreen, void *pvFence) +{ + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + + return DRISUPGetFenceFD(psPVRScreen->psDRISUPScreen, pvFence); +} + +static void * +PVRDRIGetFenceFromClEventEXT(__DRIscreen *psDRIScreen, intptr_t iClEvent) +{ + PVRDRIScreen *psPVRScreen = psDRIScreen->driverPrivate; + + return DRISUPGetFenceFromCLEvent(psPVRScreen->psDRISUPScreen, iClEvent); +} + +__DRI2fenceExtension pvrDRIFenceExtension = { + .base = { + .name = __DRI2_FENCE, + .version = PVR_DRI2_FENCE_VERSION, + }, + .create_fence = PVRDRICreateFenceEXT, + .get_fence_from_cl_event = PVRDRIGetFenceFromClEventEXT, + .destroy_fence = PVRDRIDestroyFenceEXT, + .client_wait_sync = PVRDRIClientWaitSyncEXT, + .server_wait_sync = PVRDRIServerWaitSyncEXT, + .get_capabilities = PVRDRIGetFenceCapabilitiesEXT, + .create_fence_fd = PVRDRICreateFenceFdEXT, + .get_fence_fd = PVRDRIGetFenceFdEXT, +}; + +static void +PVRDRISetDamageRegion(__DRIdrawable *psDRIDrawable, + unsigned int uNRects, int *piRects) +{ + PVRDRIDrawable *psPVRDrawable = psDRIDrawable->driverPrivate; + + DRISUPSetDamageRegion(psPVRDrawable->psDRISUPDrawable, uNRects, piRects); +} + +const __DRI2bufferDamageExtension pvrDRIbufferDamageExtension = { + .base = { + .name = __DRI2_BUFFER_DAMAGE, + .version = PVR_DRI2_BUFFER_DAMAGE_VERSION, + }, + .set_damage_region = PVRDRISetDamageRegion, +}; + +/* + * Extension lists + * + * NOTE: When adding a new screen extension asScreenExtensionVersionInfo + * should also be updated accordingly. + */ +static const __DRIextension *apsScreenExtensions[] = { + &pvrDRITexBufferExtension.base, + &pvrDRI2FlushExtension.base, + &pvrDRIImage.base, + &pvrDRIRobustness.base, + &pvrDRIRendererQueryExtension.base, + &pvrDRIFenceExtension.base, + &pvrDRIbufferDamageExtension.base, + &dri2ConfigQueryExtension.base, + NULL +}; + +static const __DRIextension asScreenExtensionVersionInfo[] = { + {.name = __DRI_TEX_BUFFER,.version = __DRI_TEX_BUFFER_VERSION}, + {.name = __DRI2_FLUSH,.version = __DRI2_FLUSH_VERSION}, + {.name = __DRI_IMAGE,.version = __DRI_IMAGE_VERSION}, + {.name = __DRI2_ROBUSTNESS,.version = __DRI2_ROBUSTNESS_VERSION}, + {.name = __DRI2_RENDERER_QUERY,.version = __DRI2_RENDERER_QUERY_VERSION}, + {.name = __DRI2_FENCE,.version = __DRI2_FENCE_VERSION}, + {.name = __DRI2_BUFFER_DAMAGE,.version = __DRI2_BUFFER_DAMAGE_VERSION}, + {.name = __DRI2_CONFIG_QUERY,.version = __DRI2_CONFIG_QUERY_VERSION}, + {.name = NULL,.version = 0}, +}; + +const __DRIextension ** +PVRDRIScreenExtensions(void) +{ + return apsScreenExtensions; +} + +const __DRIextension * +PVRDRIScreenExtensionVersionInfo(void) +{ + return asScreenExtensionVersionInfo; +} + +void +PVRDRIAdjustExtensions(unsigned int uVersion, unsigned int uMinVersion) +{ + /* __DRI2fenceExtension adjustment */ + switch (uVersion) { + default: + case 5: + case 4: + /* Is the KHR_cl_event2 EGL extension supported? */ + if (!DRISUPHaveGetFenceFromCLEvent()) + pvrDRIFenceExtension.get_fence_from_cl_event = NULL; + + break; + case 3: + break; + case 2: + case 1: + case 0: + /* The KHR_cl_event2 EGL extension is not supported */ + pvrDRIFenceExtension.get_fence_from_cl_event = NULL; + break; + } + + /* __DRIimageExtension adjustment */ + switch (uVersion) { + default: + case 5: + if (!DRISUPHaveSetInFenceFd()) + pvrDRIImage.setInFenceFd = NULL; + + break; + case 4: + case 3: + case 2: + case 1: + case 0: + /* + * The following are not supported: + * createImageFromDmaBufs3 + * createImageWithModifiers2 + * createImageFromFds2 + * setInFenceFd + */ + pvrDRIImage.base.version = 17; + break; + } +} diff --git a/src/gallium/frontends/pvr/pvrmesa.h b/src/gallium/frontends/pvr/pvrmesa.h new file mode 100644 index 0000000..5e1c9c1 --- /dev/null +++ b/src/gallium/frontends/pvr/pvrmesa.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) Imagination Technologies Ltd. + * + * The contents of this file are subject to the MIT license as set out below. + * + * 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 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. + */ + +#if !defined(__PVRMESA_H__) +#define __PVRMESA_H__ + +#include "pvrdri.h" + +void pvrdri_free_dispatch_tables(PVRDRIScreen *psPVRScreen); +bool pvrdri_create_dispatch_table(PVRDRIScreen *psPVRScreen, + PVRDRIAPIType eAPI); +void pvrdri_set_null_dispatch_table(void); +void pvrdri_set_dispatch_table(PVRDRIContext *psPVRContext); + +#endif /* !defined(__PVRMESA_H__) */ diff --git a/src/gallium/frontends/pvr/pvrutil.c b/src/gallium/frontends/pvr/pvrutil.c new file mode 100644 index 0000000..39f0d1e --- /dev/null +++ b/src/gallium/frontends/pvr/pvrutil.c @@ -0,0 +1,272 @@ +/* + * Copyright (c) Imagination Technologies Ltd. + * + * The contents of this file are subject to the MIT license as set out below. + * + * 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 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 +#include +#include +#include + +#include "drm-uapi/drm_fourcc.h" + +#include "dri_util.h" +#include "pvrdri.h" + +#define MESSAGE_LENGTH_MAX 1024 + +/* + * Define before including android/log.h and dlog.h as this is used by these + * headers. + */ +#define LOG_TAG "PVR-MESA" + +#if defined(HAVE_ANDROID_PLATFORM) +#include +#define err_printf(f, args...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, f, ##args)) +#define dbg_printf(f, args...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, f, ##args)) +#else +#define err_printf(f, args...) fprintf(stderr, f "\n", ##args) +#define dbg_printf(f, args...) fprintf(stderr, "LibGL: " f "\n", ##args) +#endif /* HAVE_ANDROID_PLATFORM */ + +/* Standard error message */ +void PRINTFLIKE(1, 2) +errorMessage(const char *f, ...) +{ + char message[MESSAGE_LENGTH_MAX]; + va_list args; + + va_start(args, f); + vsnprintf(message, sizeof message, f, args); + va_end(args); + + err_printf("%s", message); +} + +void PRINTFLIKE(1, 2) +__driUtilMessage(const char *f, ...) +{ + char message[MESSAGE_LENGTH_MAX]; + va_list args; + + /* + * On Android, always print messages; otherwise, only print if + * the environment variable LIBGL_DEBUG=verbose. + */ +#if !defined(HAVE_ANDROID_PLATFORM) + char *ev = getenv("LIBGL_DEBUG"); + + if (!ev || strcmp(ev, "verbose") != 0) + return; +#endif + + va_start(args, f); + vsnprintf(message, sizeof message, f, args); + va_end(args); + + dbg_printf("%s", message); +} + +mesa_format +PVRDRIMesaFormatToMesaFormat(int pvrdri_mesa_format) +{ + switch (pvrdri_mesa_format) { + case PVRDRI_MESA_FORMAT_NONE: + return MESA_FORMAT_NONE; + case PVRDRI_MESA_FORMAT_B8G8R8A8_UNORM: + return MESA_FORMAT_B8G8R8A8_UNORM; + case PVRDRI_MESA_FORMAT_B8G8R8X8_UNORM: + return MESA_FORMAT_B8G8R8X8_UNORM; + case PVRDRI_MESA_FORMAT_B5G6R5_UNORM: + return MESA_FORMAT_B5G6R5_UNORM; + case PVRDRI_MESA_FORMAT_R8G8B8A8_UNORM: + return MESA_FORMAT_R8G8B8A8_UNORM; + case PVRDRI_MESA_FORMAT_R8G8B8X8_UNORM: + return MESA_FORMAT_R8G8B8X8_UNORM; + case PVRDRI_MESA_FORMAT_YCBCR: + return MESA_FORMAT_YCBCR; + case PVRDRI_MESA_FORMAT_YUV420_2PLANE: + return MESA_FORMAT_YUV420_2PLANE; + case PVRDRI_MESA_FORMAT_YVU420_2PLANE: + return MESA_FORMAT_YVU420_2PLANE; + case PVRDRI_MESA_FORMAT_B8G8R8A8_SRGB: + return MESA_FORMAT_B8G8R8A8_SRGB; + case PVRDRI_MESA_FORMAT_R8G8B8A8_SRGB: + return MESA_FORMAT_R8G8B8A8_SRGB; + case PVRDRI_MESA_FORMAT_YUV420_3PLANE: + return MESA_FORMAT_YUV420_3PLANE; + case PVRDRI_MESA_FORMAT_YVU420_3PLANE: + return MESA_FORMAT_YVU420_3PLANE; + case PVRDRI_MESA_FORMAT_YCBCR_REV: + return MESA_FORMAT_YCBCR_REV; + case PVRDRI_MESA_FORMAT_YVYU: + return MESA_FORMAT_YVYU; + case PVRDRI_MESA_FORMAT_VYUY: + return MESA_FORMAT_VYUY; + default: + __driUtilMessage("%s: Unknown format: %d", __func__, pvrdri_mesa_format); + break; + } + + return MESA_FORMAT_NONE; +} + +int +PVRDRIFormatToFourCC(int dri_format) +{ + switch (dri_format) { + case __DRI_IMAGE_FORMAT_RGB565: + return DRM_FORMAT_RGB565; + case __DRI_IMAGE_FORMAT_XRGB8888: + return DRM_FORMAT_XRGB8888; + case __DRI_IMAGE_FORMAT_ARGB8888: + return DRM_FORMAT_ARGB8888; + case __DRI_IMAGE_FORMAT_ABGR8888: + return DRM_FORMAT_ABGR8888; + case __DRI_IMAGE_FORMAT_XBGR8888: + return DRM_FORMAT_XBGR8888; + case __DRI_IMAGE_FORMAT_R8: + return DRM_FORMAT_R8; + case __DRI_IMAGE_FORMAT_GR88: + return DRM_FORMAT_GR88; + case __DRI_IMAGE_FORMAT_NONE: + return 0; + case __DRI_IMAGE_FORMAT_XRGB2101010: + return DRM_FORMAT_XRGB2101010; + case __DRI_IMAGE_FORMAT_ARGB2101010: + return DRM_FORMAT_ARGB2101010; + case __DRI_IMAGE_FORMAT_SARGB8: + return __DRI_IMAGE_FOURCC_SARGB8888; + case __DRI_IMAGE_FORMAT_ARGB1555: + return DRM_FORMAT_ARGB1555; + case __DRI_IMAGE_FORMAT_R16: + return DRM_FORMAT_R16; + case __DRI_IMAGE_FORMAT_GR1616: + return DRM_FORMAT_GR1616; + case __DRI_IMAGE_FORMAT_YUYV: + return DRM_FORMAT_YUYV; + case __DRI_IMAGE_FORMAT_XBGR2101010: + return DRM_FORMAT_XBGR2101010; + case __DRI_IMAGE_FORMAT_ABGR2101010: + return DRM_FORMAT_ABGR2101010; + case __DRI_IMAGE_FORMAT_SABGR8: + return __DRI_IMAGE_FOURCC_SABGR8888; + case __DRI_IMAGE_FORMAT_UYVY: + return DRM_FORMAT_UYVY; + case __DRI_IMAGE_FORMAT_ARGB4444: + return DRM_FORMAT_ARGB4444; + case __DRI_IMAGE_FORMAT_YVU444_PACK10_IMG: + return DRM_FORMAT_YVU444_PACK10_IMG; + case __DRI_IMAGE_FORMAT_BGR888: + return DRM_FORMAT_BGR888; + case __DRI_IMAGE_FORMAT_AXBXGXRX106106106106: + return DRM_FORMAT_AXBXGXRX106106106106; + case __DRI_IMAGE_FORMAT_NV12: + return DRM_FORMAT_NV12; + case __DRI_IMAGE_FORMAT_NV21: + return DRM_FORMAT_NV21; + case __DRI_IMAGE_FORMAT_YU12: + return DRM_FORMAT_YUV420; + case __DRI_IMAGE_FORMAT_YV12: + return DRM_FORMAT_YVU420; + case __DRI_IMAGE_FORMAT_YVYU: + return DRM_FORMAT_YVYU; + case __DRI_IMAGE_FORMAT_VYUY: + return DRM_FORMAT_VYUY; + default: + __driUtilMessage("%s: Unknown format: %d", __func__, dri_format); + break; + } + + return 0; +} + +int +PVRDRIFourCCToDRIFormat(int iFourCC) +{ + switch (iFourCC) { + case 0: + return __DRI_IMAGE_FORMAT_NONE; + case DRM_FORMAT_RGB565: + return __DRI_IMAGE_FORMAT_RGB565; + case DRM_FORMAT_XRGB8888: + return __DRI_IMAGE_FORMAT_XRGB8888; + case DRM_FORMAT_ARGB8888: + return __DRI_IMAGE_FORMAT_ARGB8888; + case DRM_FORMAT_ABGR8888: + return __DRI_IMAGE_FORMAT_ABGR8888; + case DRM_FORMAT_XBGR8888: + return __DRI_IMAGE_FORMAT_XBGR8888; + case DRM_FORMAT_R8: + return __DRI_IMAGE_FORMAT_R8; + case DRM_FORMAT_GR88: + return __DRI_IMAGE_FORMAT_GR88; + case DRM_FORMAT_XRGB2101010: + return __DRI_IMAGE_FORMAT_XRGB2101010; + case DRM_FORMAT_ARGB2101010: + return __DRI_IMAGE_FORMAT_ARGB2101010; + case __DRI_IMAGE_FOURCC_SARGB8888: + return __DRI_IMAGE_FORMAT_SARGB8; + case DRM_FORMAT_ARGB1555: + return __DRI_IMAGE_FORMAT_ARGB1555; + case DRM_FORMAT_R16: + return __DRI_IMAGE_FORMAT_R16; + case DRM_FORMAT_GR1616: + return __DRI_IMAGE_FORMAT_GR1616; + case DRM_FORMAT_YUYV: + return __DRI_IMAGE_FORMAT_YUYV; + case DRM_FORMAT_XBGR2101010: + return __DRI_IMAGE_FORMAT_XBGR2101010; + case DRM_FORMAT_ABGR2101010: + return __DRI_IMAGE_FORMAT_ABGR2101010; + case __DRI_IMAGE_FOURCC_SABGR8888: + return __DRI_IMAGE_FORMAT_SABGR8; + case DRM_FORMAT_UYVY: + return __DRI_IMAGE_FORMAT_UYVY; + case DRM_FORMAT_ARGB4444: + return __DRI_IMAGE_FORMAT_ARGB4444; + case DRM_FORMAT_YVU444_PACK10_IMG: + return __DRI_IMAGE_FORMAT_YVU444_PACK10_IMG; + case DRM_FORMAT_BGR888: + return __DRI_IMAGE_FORMAT_BGR888; + case DRM_FORMAT_AXBXGXRX106106106106: + return __DRI_IMAGE_FORMAT_AXBXGXRX106106106106; + case DRM_FORMAT_NV12: + return __DRI_IMAGE_FORMAT_NV12; + case DRM_FORMAT_NV21: + return __DRI_IMAGE_FORMAT_NV21; + case DRM_FORMAT_YUV420: + return __DRI_IMAGE_FORMAT_YU12; + case DRM_FORMAT_YVU420: + return __DRI_IMAGE_FORMAT_YV12; + case DRM_FORMAT_YVYU: + return __DRI_IMAGE_FORMAT_YVYU; + case DRM_FORMAT_VYUY: + return __DRI_IMAGE_FORMAT_VYUY; + default: + __driUtilMessage("%s: Unknown format: %d", __func__, iFourCC); + break; + } + + return 0; +} diff --git a/src/gallium/include/pipe/p_format.h b/src/gallium/include/pipe/p_format.h index 3387d30..7a0e191 100644 --- a/src/gallium/include/pipe/p_format.h +++ b/src/gallium/include/pipe/p_format.h @@ -189,6 +189,8 @@ enum pipe_format { PIPE_FORMAT_L16_UNORM, /**< ushort luminance */ PIPE_FORMAT_UYVY, PIPE_FORMAT_YUYV, + PIPE_FORMAT_YVYU, + PIPE_FORMAT_VYUY, PIPE_FORMAT_Z16_UNORM, PIPE_FORMAT_Z16_UNORM_S8_UINT, PIPE_FORMAT_Z32_UNORM, @@ -627,6 +629,8 @@ pipe_format_to_chroma_format(enum pipe_format format) return PIPE_VIDEO_CHROMA_FORMAT_420; case PIPE_FORMAT_UYVY: case PIPE_FORMAT_YUYV: + case PIPE_FORMAT_VYUY: + case PIPE_FORMAT_YVYU: case PIPE_FORMAT_YV16: case PIPE_FORMAT_Y8_U8_V8_422_UNORM: case PIPE_FORMAT_Y8_U8V8_422_UNORM: diff --git a/src/gallium/meson.build b/src/gallium/meson.build index 148c722..b589e94 100644 --- a/src/gallium/meson.build +++ b/src/gallium/meson.build @@ -151,6 +151,16 @@ if with_gallium_svga else driver_svga = declare_dependency() endif +if with_gallium_pvr + subdir('drivers/pvr') +else + driver_pvr = declare_dependency() +endif +if with_gallium_pvr_alias + subdir('drivers/pvr_alias') +else + driver_pvr_alias = declare_dependency() +endif if with_gallium_virgl subdir('winsys/virgl/common') subdir('winsys/virgl/drm') @@ -187,6 +197,11 @@ if with_gallium_rusticl subdir('frontends/rusticl') subdir('targets/rusticl') endif +if with_gallium_pvr + subdir('frontends/pvr') +else + libpvr = [] +endif if with_dri subdir('frontends/dri') subdir('targets/dri') diff --git a/src/gallium/targets/dri/meson.build b/src/gallium/targets/dri/meson.build index d0a9b91..1fd98bc 100644 --- a/src/gallium/targets/dri/meson.build +++ b/src/gallium/targets/dri/meson.build @@ -50,7 +50,7 @@ libgallium_dri = shared_library( link_with : [ libdri, libmesa, libgalliumvl, libgallium, libglapi, libpipe_loader_static, libws_null, libwsw, libswdri, - libswkmsdri, + libswkmsdri, libpvr, ], dependencies : [ dep_selinux, dep_libdrm, dep_llvm, dep_thread, idep_xmlconfig, idep_mesautil, @@ -58,7 +58,7 @@ libgallium_dri = shared_library( driver_kmsro, driver_v3d, driver_vc4, driver_freedreno, driver_etnaviv, driver_tegra, driver_i915, driver_svga, driver_virgl, driver_panfrost, driver_iris, driver_lima, driver_zink, driver_d3d12, - driver_asahi, driver_crocus + driver_asahi, driver_crocus, driver_pvr, driver_pvr_alias ], # Will be deleted during installation, see install_megadrivers.py install : true, @@ -115,7 +115,9 @@ foreach d : [[with_gallium_kmsro, [ [with_gallium_lima, 'lima_dri.so'], [with_gallium_zink, 'zink_dri.so'], [with_gallium_d3d12, 'd3d12_dri.so'], - [with_gallium_asahi, 'asahi_dri.so']] + [with_gallium_asahi, 'asahi_dri.so'], + [with_gallium_pvr, 'pvr_dri.so'], + [with_gallium_pvr_alias, gallium_pvr_alias + '_dri.so']] if d[0] gallium_dri_drivers += d[1] endif diff --git a/src/gallium/targets/dri/target.c b/src/gallium/targets/dri/target.c index d506869..e66bdaa 100644 --- a/src/gallium/targets/dri/target.c +++ b/src/gallium/targets/dri/target.c @@ -10,6 +10,16 @@ PUBLIC const __DRIextension **__driDriverGetExtensions_##drivername(void) \ return galliumdrm_driver_extensions; \ } +#define DEFINE_LOADER_PVR_ENTRYPOINT(drivername) \ +const __DRIextension **__driDriverGetExtensions_##drivername(void); \ +PUBLIC const __DRIextension **__driDriverGetExtensions_##drivername(void) \ +{ \ + return pvr_driver_extensions; \ +} + +#define DEFINE_LOADER_PVR_ALIAS_ENTRYPOINT(drivername) \ + DEFINE_LOADER_PVR_ENTRYPOINT(drivername) + #if defined(GALLIUM_SOFTPIPE) const __DRIextension **__driDriverGetExtensions_swrast(void); @@ -144,3 +154,11 @@ PUBLIC const __DRIextension **__driDriverGetExtensions_zink(void) #if defined(GALLIUM_D3D12) DEFINE_LOADER_DRM_ENTRYPOINT(d3d12); #endif + +#if defined(GALLIUM_PVR) +DEFINE_LOADER_PVR_ENTRYPOINT(pvr); +#endif + +#if defined(GALLIUM_PVR_ALIAS) +DEFINE_LOADER_PVR_ALIAS_ENTRYPOINT(GALLIUM_PVR_ALIAS); +#endif diff --git a/src/gbm/backends/dri/gbm_dri.c b/src/gbm/backends/dri/gbm_dri.c index 36cee87..bfb4876 100644 --- a/src/gbm/backends/dri/gbm_dri.c +++ b/src/gbm/backends/dri/gbm_dri.c @@ -52,6 +52,7 @@ #include "loader.h" #include "util/u_debug.h" #include "util/macros.h" +#include "util/os_file.h" /* For importing wl_buffer */ #if HAVE_WAYLAND_PLATFORM @@ -164,6 +165,14 @@ image_get_buffers(__DRIdrawable *driDrawable, surf->dri_private, buffer_mask, buffers); } +static int +dri_get_display_fd(void *loaderPrivate) +{ + struct gbm_dri_device *dri = loaderPrivate; + + return dri->base.v0.fd; +} + static void swrast_get_drawable_info(__DRIdrawable *driDrawable, int *x, @@ -245,20 +254,22 @@ static const __DRIimageLookupExtension image_lookup_extension = { }; static const __DRIdri2LoaderExtension dri2_loader_extension = { - .base = { __DRI_DRI2_LOADER, 4 }, + .base = { __DRI_DRI2_LOADER, 6 }, .getBuffers = dri_get_buffers, .flushFrontBuffer = dri_flush_front_buffer, .getBuffersWithFormat = dri_get_buffers_with_format, .getCapability = dri_get_capability, + .getDisplayFD = dri_get_display_fd, }; static const __DRIimageLoaderExtension image_loader_extension = { - .base = { __DRI_IMAGE_LOADER, 2 }, + .base = { __DRI_IMAGE_LOADER, 5 }, .getBuffers = image_get_buffers, .flushFrontBuffer = dri_flush_front_buffer, .getCapability = dri_get_capability, + .getDisplayFD = dri_get_display_fd, }; static const __DRIswrastLoaderExtension swrast_loader_extension = { @@ -431,12 +442,12 @@ dri_screen_create_dri2(struct gbm_dri_device *dri, char *driver_name) return -1; if (dri->dri2->base.version >= 4) { - dri->screen = dri->dri2->createNewScreen2(0, dri->base.v0.fd, + dri->screen = dri->dri2->createNewScreen2(0, dri->fd, dri->loader_extensions, dri->driver_extensions, &dri->driver_configs, dri); } else { - dri->screen = dri->dri2->createNewScreen(0, dri->base.v0.fd, + dri->screen = dri->dri2->createNewScreen(0, dri->fd, dri->loader_extensions, &dri->driver_configs, dri); } @@ -503,8 +514,20 @@ static int dri_screen_create(struct gbm_dri_device *dri) { char *driver_name; + int dup_fd, new_fd; + bool is_different_gpu; - driver_name = loader_get_driver_for_fd(dri->base.v0.fd); + dup_fd = os_dupfd_cloexec(dri->fd); + if (dup_fd < 0) + return -1; + + new_fd = loader_get_user_preferred_fd(dup_fd, &is_different_gpu); + if (new_fd == dup_fd) + close(new_fd); + else + dri->fd = new_fd; + + driver_name = loader_get_driver_for_fd(dri->fd); if (!driver_name) return -1; @@ -564,11 +587,21 @@ static const struct gbm_dri_visual gbm_dri_visuals_table[] = { { 10, 5, 0, 11 }, { 5, 5, 5, 1 }, }, + { + GBM_FORMAT_ARGB4444, __DRI_IMAGE_FORMAT_ARGB4444, + { 8, 4, 0, 12 }, + { 4, 4, 4, 4 }, + }, { GBM_FORMAT_RGB565, __DRI_IMAGE_FORMAT_RGB565, { 11, 5, 0, -1 }, { 5, 6, 5, 0 }, }, + { + GBM_FORMAT_BGR888, __DRI_IMAGE_FORMAT_BGR888, + { 0, 8, 16, -1 }, + { 8, 8, 8, 0 }, + }, { GBM_FORMAT_XRGB8888, __DRI_IMAGE_FORMAT_XRGB8888, { 16, 8, 0, -1 }, @@ -619,6 +652,11 @@ static const struct gbm_dri_visual gbm_dri_visuals_table[] = { { 0, 16, 32, 48 }, { 16, 16, 16, 16 }, }, + { + GBM_FORMAT_AXBXGXRX106106106106, __DRI_IMAGE_FORMAT_AXBXGXRX106106106106, + { 6, 22, 38, 54 }, + { 10, 10, 10, 10 }, + }, { GBM_FORMAT_XBGR16161616F, __DRI_IMAGE_FORMAT_XBGR16161616F, { 0, 16, 32, -1 }, @@ -631,6 +669,12 @@ static const struct gbm_dri_visual gbm_dri_visuals_table[] = { { 16, 16, 16, 16 }, true, }, + { + GBM_FORMAT_YUYV, __DRI_IMAGE_FORMAT_YUYV, + }, + { + GBM_FORMAT_YVU444_PACK10_IMG, __DRI_IMAGE_FORMAT_YVU444_PACK10_IMG, + }, }; static int @@ -1302,8 +1346,11 @@ gbm_dri_bo_map(struct gbm_bo *_bo, if (!dri->context) dri->context = dri->dri2->createNewContext(dri->screen, NULL, NULL, NULL); - assert(dri->context); mtx_unlock(&dri->mutex); + if (!dri->context) { + errno = ENOSYS; + return NULL; + } /* GBM flags and DRI flags are the same, so just pass them on */ return dri->image->mapImage(dri->context, bo->image, x, y, @@ -1412,6 +1459,40 @@ gbm_dri_surface_destroy(struct gbm_surface *_surf) free(surf); } +static int +gbm_dri_bo_blit(struct gbm_bo *_dst_bo, struct gbm_bo *_src_bo, + int dst_x0, int dst_y0, int dst_width, int dst_height, + int src_x0, int src_y0, int src_width, int src_height, + enum gbm_blit_flags flags) +{ + struct gbm_dri_device *dri = gbm_dri_device(_dst_bo->gbm); + struct gbm_dri_bo *dst_bo = gbm_dri_bo(_dst_bo); + struct gbm_dri_bo *src_bo = gbm_dri_bo(_src_bo); + + if (!dri->image || dri->image->base.version < 9 || !dri->image->blitImage) { + errno = ENOSYS; + return 0; + } + + mtx_lock(&dri->mutex); + if (!dri->context) + dri->context = dri->dri2->createNewContext(dri->screen, NULL, + NULL, NULL); + mtx_unlock(&dri->mutex); + if (!dri->context) { + errno = ENOSYS; + return 0; + } + + /* GBM flags and DRI flags are the same, so just pass them on */ + dri->image->blitImage(dri->context, dst_bo->image, src_bo->image, + dst_x0, dst_y0, dst_width, dst_height, + src_x0, src_y0, src_width, src_height, + flags); + + return 1; +} + static void dri_destroy(struct gbm_device *gbm) { @@ -1428,6 +1509,9 @@ dri_destroy(struct gbm_device *gbm) dlclose(dri->driver); free(dri->driver_name); + if (dri->fd >= 0 && dri->fd != dri->base.v0.fd) + close (dri->fd); + free(dri); } @@ -1449,6 +1533,8 @@ dri_device_create(int fd, uint32_t gbm_backend_version) if (!dri) return NULL; + dri->fd = fd; + dri->base.v0.fd = fd; dri->base.v0.backend_version = gbm_backend_version; dri->base.v0.bo_create = gbm_dri_bo_create; @@ -1473,6 +1559,8 @@ dri_device_create(int fd, uint32_t gbm_backend_version) dri->base.v0.name = "drm"; + dri->base.v1.bo_blit = gbm_dri_bo_blit; + dri->visual_table = gbm_dri_visuals_table; dri->num_visuals = ARRAY_SIZE(gbm_dri_visuals_table); diff --git a/src/gbm/backends/dri/gbm_driint.h b/src/gbm/backends/dri/gbm_driint.h index 31f6b67..3f94352 100644 --- a/src/gbm/backends/dri/gbm_driint.h +++ b/src/gbm/backends/dri/gbm_driint.h @@ -62,6 +62,8 @@ struct gbm_dri_visual { struct gbm_dri_device { struct gbm_device base; + int fd; + void *driver; char *driver_name; /* Name of the DRI module, without the _dri suffix */ bool software; /* A software driver was loaded */ @@ -195,4 +197,10 @@ gbm_dri_bo_unmap_dumb(struct gbm_dri_bo *bo) bo->map = NULL; } +static inline int +gbm_dri_device_get_fd(struct gbm_dri_device *dri) +{ + return dri->fd; +} + #endif diff --git a/src/gbm/main/gbm.c b/src/gbm/main/gbm.c index 599f7aa..1b14320 100644 --- a/src/gbm/main/gbm.c +++ b/src/gbm/main/gbm.c @@ -277,6 +277,7 @@ gbm_bo_get_bpp(struct gbm_bo *bo) case GBM_FORMAT_ABGR16161616: case GBM_FORMAT_XBGR16161616F: case GBM_FORMAT_ABGR16161616F: + case GBM_FORMAT_AXBXGXRX106106106106: return 64; } } @@ -827,6 +828,37 @@ gbm_format_get_name(uint32_t gbm_format, struct gbm_format_name_desc *desc) return desc->name; } +/** + * Blit from one buffer object to another + * + * \param dst_bo The destination buffer object + * \param src_bo The source buffer object + * \param dst_x0 The X coordinate (top left origin) of the destination rectangle + * \param dst_y0 The Y coordinate (top left origin) of the destination rectangle + * \param dst_width The width of the destination rectangle + * \param dst_height The height of the destination rectangle + * \param src_x0 The X coordinate (top left origin) of the source rectangle + * \param src_y0 The Y coordinate (top left origin) of the source rectangle + * \param src_width The width of the source rectangle + * \param src_height The height of the source rectangle + * \param flags The flags for the blit + * \return 1 on success, 0 otherwise + */ +GBM_EXPORT int +gbm_bo_blit(struct gbm_bo *dst_bo, struct gbm_bo *src_bo, + int dst_x0, int dst_y0, int dst_width, int dst_height, + int src_x0, int src_y0, int src_width, int src_height, + enum gbm_blit_flags flags) +{ + if (dst_bo->gbm->v0.backend_version >= 1) + return dst_bo->gbm->v1.bo_blit(dst_bo, src_bo, + dst_x0, dst_y0, dst_width, dst_height, + src_x0, src_y0, src_width, src_height, + flags); + else + return 0; +} + /** * A global table of functions and global variables defined in the core GBM * code that need to be accessed directly by GBM backends. diff --git a/src/gbm/main/gbm.h b/src/gbm/main/gbm.h index 1a1e2ca..067d36f 100644 --- a/src/gbm/main/gbm.h +++ b/src/gbm/main/gbm.h @@ -171,6 +171,12 @@ enum gbm_bo_format { #define GBM_FORMAT_ABGR16161616F __gbm_fourcc_code('A', 'B', '4', 'H') /* [63:0] A:B:G:R 16:16:16:16 little endian */ +/* + * RGBA format with 10-bit components packed in 64-bit per pixel, with 6 bits + * of unused padding per component: + */ +#define GBM_FORMAT_AXBXGXRX106106106106 __gbm_fourcc_code('A', 'B', '1', '0') /* [63:0] A:x:B:x:G:x:R:x 10:6:10:6:10:6:10:6 little endian */ + /* packed YCbCr */ #define GBM_FORMAT_YUYV __gbm_fourcc_code('Y', 'U', 'Y', 'V') /* [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian */ #define GBM_FORMAT_YVYU __gbm_fourcc_code('Y', 'V', 'Y', 'U') /* [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian */ @@ -179,6 +185,8 @@ enum gbm_bo_format { #define GBM_FORMAT_AYUV __gbm_fourcc_code('A', 'Y', 'U', 'V') /* [31:0] A:Y:Cb:Cr 8:8:8:8 little endian */ +#define GBM_FORMAT_YVU444_PACK10_IMG __gbm_fourcc_code('I', 'M', 'G', '2') /* [31:0] unused:Y:Cr:Cb 2:10:10:10 little endian */ + /* * 2 plane YCbCr * index 0 = Y plane, [7:0] Y @@ -266,6 +274,21 @@ enum gbm_bo_flags { GBM_BO_USE_FRONT_RENDERING = (1 << 6), }; +/** + * Flags to control the behaviour of a blit - these are passed to + * gbm_bo_blit(). + */ +enum gbm_blit_flags { + /** + * Force blit execution in finite time + */ + GBM_BLIT_FLAG_FLUSH = 0x0001, + /** + * Flush, and wait for the blit to complete + */ + GBM_BLIT_FLAG_FINISH = 0x0002 +}; + int gbm_device_get_fd(struct gbm_device *gbm); @@ -462,6 +485,12 @@ gbm_surface_destroy(struct gbm_surface *surface); char * gbm_format_get_name(uint32_t gbm_format, struct gbm_format_name_desc *desc); +int +gbm_bo_blit(struct gbm_bo *dst_bo, struct gbm_bo *src_bo, + int dst_x0, int dst_y0, int dst_width, int dst_height, + int src_x0, int src_y0, int src_width, int src_height, + enum gbm_blit_flags flags); + #ifdef __cplusplus } #endif diff --git a/src/gbm/main/gbm_abi_check.c b/src/gbm/main/gbm_abi_check.c index feca099..0153b5a 100644 --- a/src/gbm/main/gbm_abi_check.c +++ b/src/gbm/main/gbm_abi_check.c @@ -106,6 +106,21 @@ struct gbm_device_abi0 { struct gbm_device_v0_abi0 v0; }; +#define GBM_BACKEND_ABI_VERSION_abi1 1 +struct gbm_device_v1_abi1 { + int (*bo_blit)(struct gbm_bo *dst_bo, struct gbm_bo *src_bo, + int dst_x0, int dst_y0, int dst_width, int dst_height, + int src_x0, int src_y0, int src_width, int src_height, + enum gbm_blit_flags flags); +}; + +struct gbm_device_abi1 { + /* Hack to make a gbm_device detectable by its first element. */ + struct gbm_device *(*dummy)(int); + struct gbm_device_v0_abi0 v0; + struct gbm_device_v1_abi1 v1; +}; + /** * GBM buffer object interface corresponding to GBM_BACKEND_ABI_VERSION = 0 * @@ -364,8 +379,11 @@ int main(int argc, char **argv) CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, surface_has_free_buffers); CHECK_MEMBER_CURRENT(gbm_device_v0, _abi0, surface_destroy); + CHECK_MEMBER_CURRENT(gbm_device_v1, _abi1, bo_blit); + /* Size of ABI-versioned substructures verified by above member checks */ - CHECK_SIZE_CURRENT (gbm_device, _abi0); + CHECK_SIZE (gbm_device, _abi0, _abi1); + CHECK_SIZE_CURRENT (gbm_device, _abi1); /* Check current gbm_bo ABI against gbm_bo_abi0*/ diff --git a/src/gbm/main/gbm_backend_abi.h b/src/gbm/main/gbm_backend_abi.h index 222ce34..17f5e0c 100644 --- a/src/gbm/main/gbm_backend_abi.h +++ b/src/gbm/main/gbm_backend_abi.h @@ -157,6 +157,13 @@ struct gbm_device_v0 { void (*surface_destroy)(struct gbm_surface *surface); }; +struct gbm_device_v1 { + int (*bo_blit)(struct gbm_bo *dst_bo, struct gbm_bo *src_bo, + int dst_x0, int dst_y0, int dst_width, int dst_height, + int src_x0, int src_y0, int src_width, int src_height, + enum gbm_blit_flags flags); +}; + /** * The device used for the memory allocation. * @@ -169,6 +176,7 @@ struct gbm_device { /* Hack to make a gbm_device detectable by its first element. */ struct gbm_device *(*dummy)(int); struct gbm_device_v0 v0; + struct gbm_device_v1 v1; }; /** diff --git a/src/glx/dri3_glx.c b/src/glx/dri3_glx.c index e8996dd..6921ed9 100644 --- a/src/glx/dri3_glx.c +++ b/src/glx/dri3_glx.c @@ -78,6 +78,7 @@ #include "loader.h" #include "loader_dri_helper.h" #include "dri2.h" +#include "util/os_file.h" static struct dri3_drawable * loader_drawable_to_dri3_drawable(struct loader_dri3_drawable *draw) { @@ -357,6 +358,21 @@ glx_to_loader_dri3_drawable_type(int type) } } +static bool +dri3_has_multibuffer(const __DRIimageExtension *image, + const struct dri3_display *pdp) +{ +#ifdef HAVE_DRI3_MODIFIERS + return (image && image->base.version >= 15) && + (pdp->dri3Major > 1 || + (pdp->dri3Major == 1 && pdp->dri3Minor >= 2)) && + (pdp->presentMajor > 1 || + (pdp->presentMajor == 1 && pdp->presentMinor >= 2)); +#else + return false; +#endif +} + static __GLXDRIdrawable * dri3_create_drawable(struct glx_screen *base, XID xDrawable, GLXDrawable drawable, int type, @@ -365,11 +381,9 @@ dri3_create_drawable(struct glx_screen *base, XID xDrawable, struct dri3_drawable *pdraw; struct dri3_screen *psc = (struct dri3_screen *) base; __GLXDRIconfigPrivate *config = (__GLXDRIconfigPrivate *) config_base; - bool has_multibuffer = false; -#ifdef HAVE_DRI3_MODIFIERS const struct dri3_display *const pdp = (struct dri3_display *) base->display->dri3Display; -#endif + bool has_multibuffer = dri3_has_multibuffer(psc->image, pdp); pdraw = calloc(1, sizeof(*pdraw)); if (!pdraw) @@ -380,14 +394,6 @@ dri3_create_drawable(struct glx_screen *base, XID xDrawable, pdraw->base.drawable = drawable; pdraw->base.psc = &psc->base; -#ifdef HAVE_DRI3_MODIFIERS - if ((psc->image && psc->image->base.version >= 15) && - (pdp->dri3Major > 1 || (pdp->dri3Major == 1 && pdp->dri3Minor >= 2)) && - (pdp->presentMajor > 1 || - (pdp->presentMajor == 1 && pdp->presentMinor >= 2))) - has_multibuffer = true; -#endif - (void) __glXInitialize(psc->base.dpy); if (loader_dri3_drawable_init(XGetXCBConnection(base->dpy), @@ -537,6 +543,14 @@ dri3_flush_swap_buffers(__DRIdrawable *driDrawable, void *loaderPrivate) loader_dri3_swapbuffer_barrier(draw); } +static int +dri3_get_display_fd(void *loaderPrivate) +{ + struct dri3_screen *psc = (struct dri3_screen *)loaderPrivate; + + return psc->fd_dpy; +} + static void dri_set_background_context(void *loaderPrivate) { @@ -555,11 +569,12 @@ dri_is_thread_safe(void *loaderPrivate) /* The image loader extension record for DRI3 */ static const __DRIimageLoaderExtension imageLoaderExtension = { - .base = { __DRI_IMAGE_LOADER, 3 }, + .base = { __DRI_IMAGE_LOADER, 5 }, .getBuffers = loader_dri3_get_buffers, .flushFrontBuffer = dri3_flush_front_buffer, .flushSwapBuffers = dri3_flush_swap_buffers, + .getDisplayFD = dri3_get_display_fd, }; const __DRIuseInvalidateExtension dri3UseInvalidate = { @@ -625,6 +640,10 @@ dri3_destroy_screen(struct glx_screen *base) loader_dri3_close_screen(psc->driScreen); (*psc->core->destroyScreen) (psc->driScreen); driDestroyConfigs(psc->driver_configs); + + if (psc->fd_dpy != psc->fd) + close(psc->fd_dpy); + close(psc->fd); free(psc); } @@ -714,13 +733,14 @@ static const struct glx_context_vtable dri3_context_vtable = { .interop_flush_objects = dri3_interop_flush_objects }; -/** dri3_bind_extensions +/** dri3_bind_extensions_part1 * - * Enable all of the extensions supported on DRI3 + * Enable the extensions supported on DRI3 that don't depend on + * whether we are using a different GPU. */ static void -dri3_bind_extensions(struct dri3_screen *psc, struct glx_display * priv, - const char *driverName) +dri3_bind_extensions_part1(struct dri3_screen *psc, struct glx_display * priv, + const char *driverName) { const __DRIextension **extensions; unsigned mask; @@ -751,16 +771,6 @@ dri3_bind_extensions(struct dri3_screen *psc, struct glx_display * priv, } for (i = 0; extensions[i]; i++) { - /* when on a different gpu than the server, the server pixmaps - * can have a tiling mode we can't read. Thus we can't create - * a texture from them. - */ - if (!psc->is_different_gpu && - (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) { - psc->texBuffer = (__DRItexBufferExtension *) extensions[i]; - __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap"); - } - if ((strcmp(extensions[i]->name, __DRI2_FLUSH) == 0)) { psc->f = (__DRI2flushExtension *) extensions[i]; /* internal driver extension, no GL extension exposed */ @@ -796,6 +806,33 @@ dri3_bind_extensions(struct dri3_screen *psc, struct glx_display * priv, } } +/** dri3_bind_extensions_part2 + * + * Enable the extensions supported on DRI3 that depend on whether we + * are using a different GPU. + */ +static void +dri3_bind_extensions_part2(struct dri3_screen *psc, struct glx_display * priv, + const char *driverName) +{ + const __DRIextension **extensions; + int i; + + extensions = psc->core->getExtensions(psc->driScreen); + + for (i = 0; extensions[i]; i++) { + /* when on a different gpu than the server, the server pixmaps + * can have a tiling mode we can't read. Thus we can't create + * a texture from them. + */ + if (!psc->is_different_gpu && + (strcmp(extensions[i]->name, __DRI_TEX_BUFFER) == 0)) { + psc->texBuffer = (__DRItexBufferExtension *) extensions[i]; + __glXEnableDirectExtension(&psc->base, "GLX_EXT_texture_from_pixmap"); + } + } +} + static char * dri3_get_driver_name(struct glx_screen *glx_screen) { @@ -835,8 +872,11 @@ dri3_create_screen(int screen, struct glx_display * priv) struct dri3_screen *psc; __GLXDRIscreen *psp; struct glx_config *configs = NULL, *visuals = NULL; - char *driverName, *driverNameDisplayGPU, *tmp; + char *driverName = NULL, *driverNameDisplayGPU, *tmp; int i; + int fd_old; + bool is_different_gpu; + bool have_modifiers; psc = calloc(1, sizeof *psc); if (psc == NULL) @@ -844,6 +884,7 @@ dri3_create_screen(int screen, struct glx_display * priv) psc->fd = -1; psc->fd_display_gpu = -1; + psc->fd_dpy = -1; if (!glx_screen_init(&psc->base, screen, priv)) { free(psc); @@ -864,12 +905,23 @@ dri3_create_screen(int screen, struct glx_display * priv) return NULL; } + fd_old = psc->fd; + psc->fd_dpy = os_dupfd_cloexec(psc->fd); psc->fd_display_gpu = fcntl(psc->fd, F_DUPFD_CLOEXEC, 3); - psc->fd = loader_get_user_preferred_fd(psc->fd, &psc->is_different_gpu); - if (!psc->is_different_gpu) { + psc->fd = loader_get_user_preferred_fd(psc->fd, &is_different_gpu); + if (!is_different_gpu) { close(psc->fd_display_gpu); psc->fd_display_gpu = -1; } + if (psc->fd == fd_old) { + if (psc->fd_dpy != -1) + close(psc->fd_dpy); + + psc->fd_dpy = psc->fd; + } else if (psc->fd_dpy == -1) { + ErrorMessageF("Unable to dup the display FD"); + goto handle_error; + } driverName = loader_get_driver_for_fd(psc->fd); if (!driverName) { @@ -899,27 +951,6 @@ dri3_create_screen(int screen, struct glx_display * priv) goto handle_error; } - if (psc->is_different_gpu) { - driverNameDisplayGPU = loader_get_driver_for_fd(psc->fd_display_gpu); - if (driverNameDisplayGPU) { - - /* check if driver name is matching so that non mesa drivers - * will not crash. Also need this check since image extension - * pointer from render gpu is shared with display gpu. Image - * extension pointer is shared because it keeps things simple. - */ - if (strcmp(driverName, driverNameDisplayGPU) == 0) { - psc->driScreenDisplayGPU = - psc->image_driver->createNewScreen2(screen, psc->fd_display_gpu, - pdp->loader_extensions, - extensions, - &driver_configs, psc); - } - - free(driverNameDisplayGPU); - } - } - psc->driScreen = psc->image_driver->createNewScreen2(screen, psc->fd, pdp->loader_extensions, @@ -931,7 +962,42 @@ dri3_create_screen(int screen, struct glx_display * priv) goto handle_error; } - dri3_bind_extensions(psc, priv, driverName); + dri3_bind_extensions_part1(psc, priv, driverName); + + have_modifiers = loader_dri3_has_modifiers(dri3_has_multibuffer(psc->image, + pdp), + psc->image); + + if (is_different_gpu) { + if (have_modifiers) { + close(psc->fd_display_gpu); + psc->fd_display_gpu = -1; + } else { + driverNameDisplayGPU = loader_get_driver_for_fd(psc->fd_display_gpu); + if (driverNameDisplayGPU) { + + /* check if driver name is matching so that non mesa drivers + * will not crash. Also need this check since image extension + * pointer from render gpu is shared with display gpu. Image + * extension pointer is shared because it keeps things simple. + */ + if (strcmp(driverName, driverNameDisplayGPU) == 0) { + psc->driScreenDisplayGPU = + psc->image_driver->createNewScreen2(screen, + psc->fd_display_gpu, + pdp->loader_extensions, + extensions, + &driver_configs, psc); + } + + free(driverNameDisplayGPU); + } + } + } + + psc->is_different_gpu = is_different_gpu && !have_modifiers; + + dri3_bind_extensions_part2(psc, priv, driverName); if (!psc->image || psc->image->base.version < 7 || !psc->image->createImageFromFds) { ErrorMessageF("Version 7 or imageFromFds image extension not found\n"); @@ -1075,6 +1141,8 @@ handle_error: if (psc->driScreenDisplayGPU) psc->core->destroyScreen(psc->driScreenDisplayGPU); psc->driScreenDisplayGPU = NULL; + if (psc->fd_dpy >= 0 && psc->fd_dpy != psc->fd) + close(psc->fd_dpy); if (psc->fd >= 0) close(psc->fd); if (psc->fd_display_gpu >= 0) diff --git a/src/glx/dri3_priv.h b/src/glx/dri3_priv.h index 09dcefd..bd3073d 100644 --- a/src/glx/dri3_priv.h +++ b/src/glx/dri3_priv.h @@ -101,6 +101,7 @@ struct dri3_screen { void *driver; int fd; + int fd_dpy; bool is_different_gpu; bool prefer_back_buffer_reuse; diff --git a/src/glx/meson.build b/src/glx/meson.build index 20f0474..93470d0 100644 --- a/src/glx/meson.build +++ b/src/glx/meson.build @@ -122,7 +122,15 @@ else ) endif -libglx = static_library( +gl_lib_cargs = [ + '-D_REENTRANT', +] + +if with_glx == 'null' + libglx_link = [libglapi] + libglx_link_whole = [libglapi_static] +else + libglx = static_library( 'glx', [files_libglx, glx_generated], include_directories : [inc_include, inc_src, inc_mapi, inc_mesa, inc_gallium, inc_gallium_aux, inc_glapi, inc_loader], @@ -138,13 +146,17 @@ libglx = static_library( idep_mesautil, idep_xmlconfig, dep_libdrm, dep_dri2proto, dep_glproto, dep_x11, dep_glvnd, dep_xxf86vm, dep_xshmfence ], -) + ) + + libglx_link = [libglapi_static,libglapi] + libglx_link_whole = [libglx] +endif libgl = shared_library( gl_lib_name, [], - link_with : [libglapi_static, libglapi], - link_whole : libglx, + link_with : libglx_link, + link_whole : libglx_link_whole, link_args : [ld_args_bsymbolic, ld_args_gc_sections, extra_ld_args_libgl], dependencies : [ dep_libdrm, dep_dl, dep_m, dep_thread, dep_x11, dep_xcb_glx, dep_xcb, diff --git a/src/loader/loader_dri3_helper.c b/src/loader/loader_dri3_helper.c index ad6f0b6..2192b20 100644 --- a/src/loader/loader_dri3_helper.c +++ b/src/loader/loader_dri3_helper.c @@ -2597,3 +2597,18 @@ dri3_find_back_alloc(struct loader_dri3_drawable *draw) return back; } + +bool +loader_dri3_has_modifiers(bool multiplanes_available, + const __DRIimageExtension *image) +{ +#ifdef HAVE_DRI3_MODIFIERS + return multiplanes_available && image && + image->base.version >= 15 && + image->queryDmaBufModifiers && + image->createImageWithModifiers && + image->createImageFromDmaBufs2; +#else + return false; +#endif +} diff --git a/src/loader/loader_dri3_helper.h b/src/loader/loader_dri3_helper.h index 6d20162..8b39af0 100644 --- a/src/loader/loader_dri3_helper.h +++ b/src/loader/loader_dri3_helper.h @@ -330,5 +330,8 @@ loader_dri3_update_screen_resources(struct loader_dri3_screen_resources *res); void loader_dri3_destroy_screen_resources(struct loader_dri3_screen_resources *res); +bool +loader_dri3_has_modifiers(bool multiplanes_available, + const __DRIimageExtension *image); #endif diff --git a/src/mapi/glapi/gen/ARB_geometry_shader4.xml b/src/mapi/glapi/gen/ARB_geometry_shader4.xml new file mode 100644 index 0000000..d92dc57 --- /dev/null +++ b/src/mapi/glapi/gen/ARB_geometry_shader4.xml @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mapi/glapi/gen/EXT_framebuffer_object.xml b/src/mapi/glapi/gen/EXT_framebuffer_object.xml index 6dd90b8..e2dfa6b 100644 --- a/src/mapi/glapi/gen/EXT_framebuffer_object.xml +++ b/src/mapi/glapi/gen/EXT_framebuffer_object.xml @@ -70,7 +70,7 @@ - + @@ -81,30 +81,30 @@ - + - + - + - + - + @@ -116,22 +116,22 @@ - + - + - + - + @@ -139,7 +139,7 @@ - + @@ -147,7 +147,7 @@ - + @@ -156,21 +156,21 @@ - + - + - + diff --git a/src/mapi/glapi/gen/EXT_shader_pixel_local_storage2.xml b/src/mapi/glapi/gen/EXT_shader_pixel_local_storage2.xml new file mode 100644 index 0000000..20e186c --- /dev/null +++ b/src/mapi/glapi/gen/EXT_shader_pixel_local_storage2.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mapi/glapi/gen/EXT_sparse_texture.xml b/src/mapi/glapi/gen/EXT_sparse_texture.xml new file mode 100644 index 0000000..ebeab7d --- /dev/null +++ b/src/mapi/glapi/gen/EXT_sparse_texture.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mapi/glapi/gen/IMG_framebuffer_downsample.xml b/src/mapi/glapi/gen/IMG_framebuffer_downsample.xml new file mode 100644 index 0000000..b5ce77d --- /dev/null +++ b/src/mapi/glapi/gen/IMG_framebuffer_downsample.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mapi/glapi/gen/OVR_multiview_multisampled_render_to_texture.xml b/src/mapi/glapi/gen/OVR_multiview_multisampled_render_to_texture.xml new file mode 100644 index 0000000..86bebc7 --- /dev/null +++ b/src/mapi/glapi/gen/OVR_multiview_multisampled_render_to_texture.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/mapi/glapi/gen/api_exec_init.py b/src/mapi/glapi/gen/api_exec_init.py index 3f86228..28b2395 100644 --- a/src/mapi/glapi/gen/api_exec_init.py +++ b/src/mapi/glapi/gen/api_exec_init.py @@ -34,6 +34,7 @@ import apiexec exec_flavor_map = { 'beginend': None, + 'dynamic': None, 'dlist': '_mesa_', 'mesa': '_mesa_', 'skip': None, diff --git a/src/mapi/glapi/gen/es_EXT.xml b/src/mapi/glapi/gen/es_EXT.xml index e96f5b8..6ff5432 100644 --- a/src/mapi/glapi/gen/es_EXT.xml +++ b/src/mapi/glapi/gen/es_EXT.xml @@ -285,28 +285,25 @@ - + - - + - + - + - + - + @@ -680,6 +677,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1117,6 +1140,25 @@ + + + + + + + + + + + + + + + + + + + @@ -1459,6 +1501,18 @@ + + + + + + + + + + + + diff --git a/src/mapi/glapi/gen/gl_API.xml b/src/mapi/glapi/gen/gl_API.xml index 8ead49d..0e30eb1 100644 --- a/src/mapi/glapi/gen/gl_API.xml +++ b/src/mapi/glapi/gen/gl_API.xml @@ -8068,7 +8068,7 @@ - + @@ -12683,6 +12683,23 @@ + + + + + + + + + + + + + + + + + diff --git a/src/mapi/glapi/gen/static_data.py b/src/mapi/glapi/gen/static_data.py index adddef3..c906125 100644 --- a/src/mapi/glapi/gen/static_data.py +++ b/src/mapi/glapi/gen/static_data.py @@ -1701,6 +1701,41 @@ offsets = { "DrawElementsUserBuf": 1665, "MultiDrawArraysUserBuf": 1666, "MultiDrawElementsUserBuf": 1667, + "TexPageCommitmentEXT": 1668, + "CurrentPaletteMatrixOES" : 1669, + "LoadPaletteFromModelViewMatrixOES" : 1670, + "MatrixIndexPointerOES" : 1671, + "WeightPointerOES" : 1672, + "RenderbufferStorageMultisampleIMG" : 1673, + "FramebufferTexture2DMultisampleIMG" : 1674, + "ClearPixelLocalStorageuiEXT" : 1675, + "FramebufferPixelLocalStorageSizeEXT" : 1676, + "GetFramebufferPixelLocalStorageSizeEXT" : 1677, + "FramebufferTexture2DDownsampleIMG" : 1678, + "FramebufferTextureLayerDownsampleIMG" : 1679, + "FramebufferTextureMultiviewOVR" : 1680, + "FramebufferTextureMultisampleMultiviewOVR" : 1681, + "MultiDrawArraysIndirectEXT" : 1682, + "MultiDrawElementsIndirectEXT" : 1683, + "IsRenderbufferEXT" : 1684, + "DeleteRenderbuffersEXT" : 1685, + "GenRenderbuffersEXT" : 1686, + "RenderbufferStorageEXT" : 1687, + "GetRenderbufferParameterivEXT" : 1688, + "IsFramebufferEXT" : 1689, + "DeleteFramebuffersEXT" : 1690, + "GenFramebuffersEXT" : 1691, + "CheckFramebufferStatusEXT" : 1692, + "FramebufferTexture1DEXT" : 1693, + "FramebufferTexture2DEXT" : 1694, + "FramebufferTexture3DEXT" : 1695, + "FramebufferRenderbufferEXT" : 1696, + "GetFramebufferAttachmentParameterivEXT" : 1697, + "GenerateMipmapEXT" : 1698, + "ProgramParameteriARB" : 1699, + "FramebufferTextureARB" : 1700, + "FramebufferTextureLayerARB" : 1701, + "FramebufferTextureFaceARB" : 1702, } functions = [ diff --git a/src/mesa/main/context.h b/src/mesa/main/context.h index a2c8a30..fbfdd2d 100644 --- a/src/mesa/main/context.h +++ b/src/mesa/main/context.h @@ -416,6 +416,29 @@ _mesa_hw_select_enabled(const struct gl_context *ctx) ctx->Const.HardwareAcceleratedSelect; } +static inline bool +_mesa_has_occlusion_query(const struct gl_context *ctx) +{ + return _mesa_has_ARB_occlusion_query(ctx) || + _mesa_has_ARB_occlusion_query2(ctx) || + (_mesa_is_desktop_gl(ctx) && ctx->Version >= 15); +} + +static inline bool +_mesa_has_occlusion_query_boolean(const struct gl_context *ctx) +{ + return _mesa_has_ARB_occlusion_query2(ctx) || + _mesa_has_EXT_occlusion_query_boolean(ctx) || + (_mesa_is_desktop_gl(ctx) && ctx->Version >= 33); +} + +static inline bool +_mesa_has_pipeline_statistics(const struct gl_context *ctx) +{ + return _mesa_has_ARB_pipeline_statistics_query(ctx) || + (_mesa_is_desktop_gl(ctx) && ctx->Version >= 46); +} + #ifdef __cplusplus } #endif diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c index be1d619..74f6e9b 100644 --- a/src/mesa/main/fbobject.c +++ b/src/mesa/main/fbobject.c @@ -2168,6 +2168,11 @@ _mesa_detach_renderbuffer(struct gl_context *ctx, return progress; } +GLboolean GLAPIENTRY +_mesa_IsRenderbufferEXT(GLuint renderbuffer) +{ + return _mesa_IsRenderbuffer(renderbuffer); +} void GLAPIENTRY _mesa_DeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) @@ -2895,6 +2900,12 @@ renderbuffer_storage_target(GLenum target, GLenum internalFormat, } +void GLAPIENTRY +_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers) +{ + _mesa_DeleteRenderbuffers(n, renderbuffers); +} + void GLAPIENTRY _mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) { @@ -2932,6 +2943,11 @@ _mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) st_egl_image_target_renderbuffer_storage(ctx, rb, image); } +void GLAPIENTRY +_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers) +{ + _mesa_GenRenderbuffers(n, renderbuffers); +} /** * Helper function for _mesa_GetRenderbufferParameteriv() and @@ -2964,6 +2980,12 @@ _mesa_RenderbufferStorage(GLenum target, GLenum internalFormat, NO_SAMPLES, 0, "glRenderbufferStorage"); } +void GLAPIENTRY +_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalFormat, + GLsizei width, GLsizei height) +{ + _mesa_RenderbufferStorage(target, internalFormat, width, height); +} void GLAPIENTRY _mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples, @@ -3144,6 +3166,11 @@ _mesa_GetNamedRenderbufferParameteriv(GLuint renderbuffer, GLenum pname, "glGetNamedRenderbufferParameteriv"); } +void GLAPIENTRY +_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, GLint *params) +{ + _mesa_GetRenderbufferParameteriv(target, pname, params); +} void GLAPIENTRY _mesa_GetNamedRenderbufferParameterivEXT(GLuint renderbuffer, GLenum pname, @@ -3177,6 +3204,11 @@ _mesa_IsFramebuffer(GLuint framebuffer) return GL_FALSE; } +GLboolean GLAPIENTRY +_mesa_IsFramebufferEXT(GLuint framebuffer) +{ + return _mesa_IsFramebuffer(framebuffer); +} /** * Check if any of the attachments of the given framebuffer are textures @@ -3401,6 +3433,11 @@ _mesa_DeleteFramebuffers(GLsizei n, const GLuint *framebuffers) } } +void GLAPIENTRY +_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers) +{ + _mesa_DeleteFramebuffers(n, framebuffers); +} /** * This is the implementation for glGenFramebuffers and glCreateFramebuffers. @@ -3447,6 +3484,11 @@ create_framebuffers(GLsizei n, GLuint *framebuffers, bool dsa) _mesa_HashUnlockMutex(ctx->Shared->FrameBuffers); } +void GLAPIENTRY +_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers) +{ + _mesa_GenFramebuffers(n, framebuffers); +} void GLAPIENTRY _mesa_GenFramebuffers(GLsizei n, GLuint *framebuffers) @@ -3486,6 +3528,11 @@ _mesa_check_framebuffer_status(struct gl_context *ctx, return buffer->_Status; } +GLenum GLAPIENTRY +_mesa_CheckFramebufferStatusEXT(GLenum target) +{ + return _mesa_CheckFramebufferStatus(target); +} GLenum GLAPIENTRY _mesa_CheckFramebufferStatus_no_error(GLenum target) @@ -4099,6 +4146,12 @@ _mesa_FramebufferTexture1D_no_error(GLenum target, GLenum attachment, texture, level, 0); } +void GLAPIENTRY +_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, GLint level) +{ + _mesa_FramebufferTexture1D(target, attachment, textarget, texture, level); +} void GLAPIENTRY _mesa_FramebufferTexture1D(GLenum target, GLenum attachment, @@ -4139,6 +4192,12 @@ _mesa_FramebufferTexture2DMultisampleEXT(GLenum target, GLenum attachment, false); } +void GLAPIENTRY +_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, GLint level) +{ + _mesa_FramebufferTexture2D(target, attachment, textarget, texture, level); +} void GLAPIENTRY _mesa_FramebufferTexture3D_no_error(GLenum target, GLenum attachment, @@ -4249,6 +4308,15 @@ frame_buffer_texture(GLuint framebuffer, GLenum target, level, 0, layer, layered); } +void GLAPIENTRY +_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, + GLint level, GLint zoffset) +{ + _mesa_FramebufferTexture3D(target, attachment, textarget, texture, + level, zoffset); +} + void GLAPIENTRY _mesa_FramebufferTextureLayer_no_error(GLenum target, GLenum attachment, GLuint texture, GLint level, @@ -4501,6 +4569,15 @@ _mesa_FramebufferRenderbuffer(GLenum target, GLenum attachment, renderbuffer, "glFramebufferRenderbuffer"); } +void GLAPIENTRY +_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment, + GLenum renderbufferTarget, + GLuint renderbuffer) +{ + _mesa_FramebufferRenderbuffer(target, attachment, renderbufferTarget, + renderbuffer); +} + void GLAPIENTRY _mesa_NamedFramebufferRenderbuffer_no_error(GLuint framebuffer, GLenum attachment, @@ -4902,6 +4979,12 @@ invalid_pname_enum: return; } +void GLAPIENTRY +_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, + GLenum pname, GLint *params) +{ + _mesa_GetFramebufferAttachmentParameteriv(target, attachment, pname, params); +} void GLAPIENTRY _mesa_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, diff --git a/src/mesa/main/format_info.py b/src/mesa/main/format_info.py index 37b46a2..9aa1bb9 100644 --- a/src/mesa/main/format_info.py +++ b/src/mesa/main/format_info.py @@ -27,7 +27,7 @@ import sys def get_gl_base_format(fmat): if fmat.name == 'MESA_FORMAT_NONE': return 'GL_NONE' - elif fmat.name in ['MESA_FORMAT_YCBCR', 'MESA_FORMAT_YCBCR_REV']: + elif fmat.name in ['MESA_FORMAT_YCBCR', 'MESA_FORMAT_YCBCR_REV', 'MESA_FORMAT_YUV420_2PLANE', 'MESA_FORMAT_YVU420_2PLANE', 'MESA_FORMAT_YUV420_3PLANE', 'MESA_FORMAT_YVU420_3PLANE', 'MESA_FORMAT_YVYU', 'MESA_FORMAT_VYUY']: return 'GL_YCBCR_MESA' elif fmat.has_channel('r'): if fmat.has_channel('g'): diff --git a/src/mesa/main/formats.c b/src/mesa/main/formats.c index a465725..79402f7 100644 --- a/src/mesa/main/formats.c +++ b/src/mesa/main/formats.c @@ -1019,6 +1019,8 @@ _mesa_uncompressed_format_to_type_and_comps(mesa_format format, case MESA_FORMAT_YCBCR: case MESA_FORMAT_YCBCR_REV: + case MESA_FORMAT_YVYU: + case MESA_FORMAT_VYUY: case MESA_FORMAT_RG_RB_UNORM8: case MESA_FORMAT_GR_BR_UNORM8: *datatype = GL_UNSIGNED_SHORT; @@ -1447,6 +1449,17 @@ _mesa_format_matches_format_and_type(mesa_format mformat, if (error) *error = GL_NO_ERROR; + switch (mformat) { + case MESA_FORMAT_YUV420_2PLANE: + case MESA_FORMAT_YVU420_2PLANE: + case MESA_FORMAT_YUV420_3PLANE: + case MESA_FORMAT_YVU420_3PLANE: + return false; + + default: + break; + } + if (_mesa_is_format_compressed(mformat)) { if (error) *error = GL_INVALID_ENUM; diff --git a/src/mesa/main/formats.csv b/src/mesa/main/formats.csv index 21cdea2..d1532b1 100644 --- a/src/mesa/main/formats.csv +++ b/src/mesa/main/formats.csv @@ -92,6 +92,12 @@ MESA_FORMAT_A2R10G10B10_UNORM , packed, 1, 1, 1, un2 , un10, un10, u MESA_FORMAT_YCBCR , other , 1, 1, 1, x16 , , , , xyzw, yuv MESA_FORMAT_YCBCR_REV , other , 1, 1, 1, x16 , , , , xyzw, yuv +MESA_FORMAT_YUV420_2PLANE , other , 1, 1, 1, x8 , , , , y___, yuv +MESA_FORMAT_YVU420_2PLANE , other , 1, 1, 1, x8 , , , , y___, yuv +MESA_FORMAT_YUV420_3PLANE , other , 1, 1, 1, x8 , , , , y___, yuv +MESA_FORMAT_YVU420_3PLANE , other , 1, 1, 1, x8 , , , , y___, yuv +MESA_FORMAT_YVYU , other , 1, 1, 1, x16 , , , , xyzw, yuv +MESA_FORMAT_VYUY , other , 1, 1, 1, x16 , , , , xyzw, yuv MESA_FORMAT_RG_RB_UNORM8 , other , 2, 1, 1, x16 , , , , xyz1, rgb MESA_FORMAT_GR_BR_UNORM8 , other , 2, 1, 1, x16 , , , , xyz1, rgb diff --git a/src/mesa/main/formats.h b/src/mesa/main/formats.h index aee6217..6c07281 100644 --- a/src/mesa/main/formats.h +++ b/src/mesa/main/formats.h @@ -617,6 +617,21 @@ typedef enum pipe_format mesa_format; #define MESA_FORMAT_ATC_RGB PIPE_FORMAT_ATC_RGB #define MESA_FORMAT_ATC_RGBA_EXPLICIT PIPE_FORMAT_ATC_RGBA_EXPLICIT #define MESA_FORMAT_ATC_RGBA_INTERPOLATED PIPE_FORMAT_ATC_RGBA_INTERPOLATED +#define MESA_FORMAT_YVYU PIPE_FORMAT_YVYU +#define MESA_FORMAT_VYUY PIPE_FORMAT_VYUY + +#define HAVE_MESA_FORMAT_YUV420_2PLANE +#define MESA_FORMAT_YUV420_2PLANE PIPE_FORMAT_NV12 + +#define HAVE_MESA_FORMAT_YVU420_2PLANE +#define MESA_FORMAT_YVU420_2PLANE PIPE_FORMAT_NV21 + +#define HAVE_MESA_FORMAT_YUV420_3PLANE +#define MESA_FORMAT_YUV420_3PLANE PIPE_FORMAT_IYUV + +#define HAVE_MESA_FORMAT_YVU420_3PLANE +#define MESA_FORMAT_YVU420_3PLANE PIPE_FORMAT_YV12 + #define MESA_FORMAT_COUNT PIPE_FORMAT_COUNT /* Packed to array format adapters */ diff --git a/src/mesa/main/genmipmap.c b/src/mesa/main/genmipmap.c index 97d0ab3..b30cf4f 100644 --- a/src/mesa/main/genmipmap.c +++ b/src/mesa/main/genmipmap.c @@ -286,3 +286,9 @@ _mesa_GenerateMultiTexMipmapEXT(GLenum texunit, GLenum target) validate_params_and_generate_mipmap(texObj, "glGenerateMultiTexMipmapEXT"); } + +void GLAPIENTRY +_mesa_GenerateMipmapEXT(GLenum target) +{ + _mesa_GenerateMipmap(target); +} diff --git a/src/mesa/main/glconfig.h b/src/mesa/main/glconfig.h index 80414d5..f9aa5a0 100644 --- a/src/mesa/main/glconfig.h +++ b/src/mesa/main/glconfig.h @@ -10,6 +10,7 @@ */ struct gl_config { + GLboolean rgbMode; GLboolean floatMode; GLuint doubleBufferMode; GLuint stereoMode; @@ -26,11 +27,24 @@ struct gl_config /* ARB_multisample / SGIS_multisample */ GLuint samples; + /* GLX 1.3 */ + GLint maxPbufferWidth; + GLint maxPbufferHeight; + GLint maxPbufferPixels; + /* OML_swap_method */ GLint swapMethod; /* EXT_framebuffer_sRGB */ GLint sRGBCapable; + + /* EXT_yuv_surface */ + GLint YUVOrder; + GLint YUVNumberOfPlanes; + GLint YUVSubsample; + GLint YUVDepthRange; + GLint YUVCSCStandard; + GLint YUVPlaneBPP; }; diff --git a/src/mesa/main/queryobj.c b/src/mesa/main/queryobj.c index a5385aa..a524a6c 100644 --- a/src/mesa/main/queryobj.c +++ b/src/mesa/main/queryobj.c @@ -133,6 +133,10 @@ query_type_is_dummy(struct gl_context *ctx, unsigned type) case PIPE_QUERY_OCCLUSION_PREDICATE: case PIPE_QUERY_OCCLUSION_PREDICATE_CONSERVATIVE: return !st->has_occlusion_query; + case PIPE_QUERY_PIPELINE_STATISTICS: + return !st->has_pipeline_stat; + case PIPE_QUERY_PIPELINE_STATISTICS_SINGLE: + return !st->has_single_pipe_stat; default: break; } @@ -467,7 +471,7 @@ get_pipe_stats_binding_point(struct gl_context *ctx, const int which = target - GL_VERTICES_SUBMITTED; assert(which < MAX_PIPELINE_STATISTICS); - if (!_mesa_has_ARB_pipeline_statistics_query(ctx)) + if (!_mesa_has_pipeline_statistics(ctx)) return NULL; return &ctx->Query.pipeline_stats[which]; @@ -483,14 +487,12 @@ get_query_binding_point(struct gl_context *ctx, GLenum target, GLuint index) { switch (target) { case GL_SAMPLES_PASSED: - if (_mesa_has_ARB_occlusion_query(ctx) || - _mesa_has_ARB_occlusion_query2(ctx)) + if (_mesa_has_occlusion_query(ctx)) return &ctx->Query.CurrentOcclusionObject; else return NULL; case GL_ANY_SAMPLES_PASSED: - if (_mesa_has_ARB_occlusion_query2(ctx) || - _mesa_has_EXT_occlusion_query_boolean(ctx)) + if (_mesa_has_occlusion_query_boolean(ctx)) return &ctx->Query.CurrentOcclusionObject; else return NULL; @@ -1353,17 +1355,32 @@ _mesa_init_queryobj(struct gl_context *ctx) ctx->Const.QueryCounterBits.PrimitivesGenerated = 64; ctx->Const.QueryCounterBits.PrimitivesWritten = 64; - ctx->Const.QueryCounterBits.VerticesSubmitted = 64; - ctx->Const.QueryCounterBits.PrimitivesSubmitted = 64; - ctx->Const.QueryCounterBits.VsInvocations = 64; - ctx->Const.QueryCounterBits.TessPatches = 64; - ctx->Const.QueryCounterBits.TessInvocations = 64; - ctx->Const.QueryCounterBits.GsInvocations = 64; - ctx->Const.QueryCounterBits.GsPrimitives = 64; - ctx->Const.QueryCounterBits.FsInvocations = 64; - ctx->Const.QueryCounterBits.ComputeInvocations = 64; - ctx->Const.QueryCounterBits.ClInPrimitives = 64; - ctx->Const.QueryCounterBits.ClOutPrimitives = 64; + if (screen->get_param(screen, PIPE_CAP_QUERY_PIPELINE_STATISTICS) || + screen->get_param(screen, PIPE_CAP_QUERY_PIPELINE_STATISTICS_SINGLE)) { + ctx->Const.QueryCounterBits.VerticesSubmitted = 64; + ctx->Const.QueryCounterBits.PrimitivesSubmitted = 64; + ctx->Const.QueryCounterBits.VsInvocations = 64; + ctx->Const.QueryCounterBits.TessPatches = 64; + ctx->Const.QueryCounterBits.TessInvocations = 64; + ctx->Const.QueryCounterBits.GsInvocations = 64; + ctx->Const.QueryCounterBits.GsPrimitives = 64; + ctx->Const.QueryCounterBits.FsInvocations = 64; + ctx->Const.QueryCounterBits.ComputeInvocations = 64; + ctx->Const.QueryCounterBits.ClInPrimitives = 64; + ctx->Const.QueryCounterBits.ClOutPrimitives = 64; + } else { + ctx->Const.QueryCounterBits.VerticesSubmitted = 0; + ctx->Const.QueryCounterBits.PrimitivesSubmitted = 0; + ctx->Const.QueryCounterBits.VsInvocations = 0; + ctx->Const.QueryCounterBits.TessPatches = 0; + ctx->Const.QueryCounterBits.TessInvocations = 0; + ctx->Const.QueryCounterBits.GsInvocations = 0; + ctx->Const.QueryCounterBits.GsPrimitives = 0; + ctx->Const.QueryCounterBits.FsInvocations = 0; + ctx->Const.QueryCounterBits.ComputeInvocations = 0; + ctx->Const.QueryCounterBits.ClInPrimitives = 0; + ctx->Const.QueryCounterBits.ClOutPrimitives = 0; + } } diff --git a/src/mesa/main/version.c b/src/mesa/main/version.c index a564b8c..d60724b 100644 --- a/src/mesa/main/version.c +++ b/src/mesa/main/version.c @@ -252,8 +252,7 @@ compute_version(const struct gl_extensions *extensions, GLuint major, minor, version; const bool ver_1_4 = (extensions->ARB_shadow); - const bool ver_1_5 = (ver_1_4 && - extensions->ARB_occlusion_query); + const bool ver_1_5 = ver_1_4; const bool ver_2_0 = (ver_1_5 && extensions->ARB_vertex_shader && extensions->ARB_fragment_shader && @@ -313,7 +312,6 @@ compute_version(const struct gl_extensions *extensions, extensions->ARB_blend_func_extended && extensions->ARB_explicit_attrib_location && extensions->ARB_instanced_arrays && - extensions->ARB_occlusion_query2 && extensions->ARB_shader_bit_encoding && extensions->ARB_texture_rgb10_a2ui && extensions->ARB_timer_query && @@ -395,7 +393,6 @@ compute_version(const struct gl_extensions *extensions, extensions->ARB_gl_spirv && extensions->ARB_spirv_extensions && extensions->ARB_indirect_parameters && - extensions->ARB_pipeline_statistics_query && extensions->ARB_polygon_offset_clamp && extensions->ARB_shader_atomic_counter_ops && extensions->ARB_shader_draw_parameters && diff --git a/src/mesa/state_tracker/st_context.c b/src/mesa/state_tracker/st_context.c index 9573b5f..d711bd1 100644 --- a/src/mesa/state_tracker/st_context.c +++ b/src/mesa/state_tracker/st_context.c @@ -629,6 +629,8 @@ st_create_context_priv(struct gl_context *ctx, struct pipe_context *pipe, screen->get_param(screen, PIPE_CAP_OCCLUSION_QUERY); st->has_single_pipe_stat = screen->get_param(screen, PIPE_CAP_QUERY_PIPELINE_STATISTICS_SINGLE); + st->has_pipeline_stat = + screen->get_param(screen, PIPE_CAP_QUERY_PIPELINE_STATISTICS); st->has_indep_blend_func = screen->get_param(screen, PIPE_CAP_INDEP_BLEND_FUNC); st->needs_rgb_dst_alpha_override = diff --git a/src/mesa/state_tracker/st_context.h b/src/mesa/state_tracker/st_context.h index 11937cb..7f5c5dc 100644 --- a/src/mesa/state_tracker/st_context.h +++ b/src/mesa/state_tracker/st_context.h @@ -158,6 +158,7 @@ struct st_context boolean has_indirect_partial_stride; boolean has_occlusion_query; boolean has_single_pipe_stat; + boolean has_pipeline_stat; boolean has_indep_blend_func; boolean needs_rgb_dst_alpha_override; boolean can_dither; diff --git a/src/meson.build b/src/meson.build index 1e9a39b..9569a10 100644 --- a/src/meson.build +++ b/src/meson.build @@ -24,6 +24,8 @@ inc_src = include_directories('.') inc_gallium = include_directories('gallium/include') inc_gallium_aux = include_directories('gallium/auxiliary') inc_amd_common = include_directories('amd/common') +inc_pvr = include_directories('mesa/main', 'mapi/glapi', + 'gallium/frontends/dri') inc_tool = include_directories('tool') inc_virtio_gpu = include_directories('virtio/virtio-gpu') pps_datasources = [] @@ -102,6 +104,9 @@ endif if with_gallium_panfrost or with_gallium_lima or with_panfrost_vk or with_tools.contains('panfrost') subdir('panfrost') endif +if with_pvr_vk + subdir('pvr') +endif if with_gallium_virgl or with_virtio_vk subdir('virtio') endif @@ -126,7 +131,7 @@ endif if with_gallium subdir('mesa') subdir('gallium') - if with_glx == 'dri' + if with_glx == 'dri' or with_glx == 'null' subdir('glx') endif # This has to be here since it requires libgallium, and subdir cannot diff --git a/src/pvr/meson.build b/src/pvr/meson.build new file mode 100644 index 0000000..09a6986 --- /dev/null +++ b/src/pvr/meson.build @@ -0,0 +1,23 @@ +# Copyright (c) Imagination Technologies Ltd. + +# 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 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. + +if with_pvr_vk + subdir('wsi') +endif diff --git a/src/pvr/wsi/meson.build b/src/pvr/wsi/meson.build new file mode 100644 index 0000000..f843ceb --- /dev/null +++ b/src/pvr/wsi/meson.build @@ -0,0 +1,82 @@ +# Copyright (c) Imagination Technologies Ltd. + +# 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 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. + +pvr_wsi_args = [] + +pvr_wsi_depends = [ + dep_libdrm, + idep_vulkan_util, + idep_xmlconfig, + idep_vulkan_wsi, + idep_vulkan_runtime_headers, + idep_vulkan_runtime, + idep_nir +] + +pvr_wsi_includes = [ + inc_include, + inc_src, + inc_vulkan_util +] + +pvr_wsi_src = [ 'pvr_wsi.c' ] + +if with_platform_wayland + pvr_wsi_args += '-DVK_USE_PLATFORM_WAYLAND_KHR' + + pvr_wsi_depends += dep_wayland_client + + pvr_wsi_src += 'pvr_wsi_wayland.c' +endif + +if with_platform_x11 + pvr_wsi_args += [ + '-DVK_USE_PLATFORM_XCB_KHR', + '-DVK_USE_PLATFORM_XLIB_KHR', + ] + + pvr_wsi_depends += dep_xcb_dri2 + + pvr_wsi_src += 'pvr_wsi_x11.c' +endif + +if system_has_kms_drm and not with_platform_android + pvr_wsi_args += '-DVK_USE_PLATFORM_DISPLAY_KHR' + + pvr_wsi_src += 'pvr_wsi_display.c' +endif + +if with_xlib_lease + pvr_wsi_args += '-DVK_USE_PLATFORM_XLIB_XRANDR_EXT' + + pvr_wsi_depends += dep_xlib_xrandr +endif + +libpvr_mesa_wsi = shared_library( + 'pvr_mesa_wsi', + pvr_wsi_src, + include_directories : pvr_wsi_includes, + dependencies : pvr_wsi_depends, + c_args : pvr_wsi_args, + link_with: libvulkan_wsi, + gnu_symbol_visibility : 'hidden', + build_by_default : true, + install : true +) diff --git a/src/pvr/wsi/pvr_mesa_wsi_interface.h b/src/pvr/wsi/pvr_mesa_wsi_interface.h new file mode 100644 index 0000000..46430b5 --- /dev/null +++ b/src/pvr/wsi/pvr_mesa_wsi_interface.h @@ -0,0 +1,330 @@ +/*************************************************************************/ /*! +@File +@Title PVR interface to the Vulkan WSI layer in Mesa +@Copyright Copyright (c) Imagination Technologies Ltd. All Rights Reserved +@License MIT + +The contents of this file are subject to the MIT license as set out below. + +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 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. +*/ /**************************************************************************/ + +#ifndef PVR_MESA_WSI_INTERFACE_H +#define PVR_MESA_WSI_INTERFACE_H + +#include +#include + +#include + +/* + * The pvr_mesa_wsi structure holds the Mesa WSI state, and is opaque to + * the PowerVK DDK. + */ +struct pvr_mesa_wsi; + +/* + * Functions defined in Mesa for use by the PowerVR DDK. + * All functions have a "pvr_mesa_wsi" prefix. + * Since the introduction of version 1 of the interface, the following + * functions are now regarded as forming version 0 of the interface. + */ + +void * +pvr_mesa_wsi_sym_addr(struct pvr_mesa_wsi *mwsi, + const char *name); + +VkResult +pvr_mesa_wsi_init(struct pvr_mesa_wsi **mwsi, + VkPhysicalDevice physicalDevice, + PFN_vkVoidFunction (VKAPI_PTR *pvr_vk_mesa_wsi_sym_addr) + (VkPhysicalDevice physicalDevice, const char *), + const VkAllocationCallbacks *alloc, + int fd, + bool sw); + +void +pvr_mesa_wsi_finish(struct pvr_mesa_wsi *mwsi, + const VkAllocationCallbacks *alloc); + +VkResult +pvr_mesa_wsi_common_get_surface_support(struct pvr_mesa_wsi *mwsi, + uint32_t queueFamilyIndex, + VkSurfaceKHR surface, + VkBool32 *pSupported); + +VkResult +pvr_mesa_wsi_common_get_surface_capabilities(struct pvr_mesa_wsi *mwsi, + VkSurfaceKHR surface, + VkSurfaceCapabilitiesKHR *pSurfaceCapabilities); + +VkResult +pvr_mesa_wsi_common_get_surface_capabilities2(struct pvr_mesa_wsi *mwsi, + const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, + VkSurfaceCapabilities2KHR *pSurfaceCapabilities); + +VkResult +pvr_mesa_wsi_common_get_surface_capabilities2ext(struct pvr_mesa_wsi *mwsi, + VkSurfaceKHR surface, + VkSurfaceCapabilities2EXT *pSurfaceCapabilities); + +VkResult +pvr_mesa_wsi_common_get_surface_formats(struct pvr_mesa_wsi *mwsi, + VkSurfaceKHR surface, + uint32_t *pSurfaceFormatCount, + VkSurfaceFormatKHR *pSurfaceFormats); + +VkResult +pvr_mesa_wsi_common_get_surface_formats2(struct pvr_mesa_wsi *mwsi, + const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, + uint32_t *pSurfaceFormatCount, + VkSurfaceFormat2KHR *pSurfaceFormats); + +VkResult +pvr_mesa_wsi_common_get_surface_present_modes(struct pvr_mesa_wsi *mwsi, + VkSurfaceKHR surface, + uint32_t *pPresentModeCount, + VkPresentModeKHR *pPresentModes); + +VkResult +pvr_mesa_wsi_common_create_swapchain(struct pvr_mesa_wsi *mwsi, + VkDevice device, + const VkSwapchainCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkSwapchainKHR *pSwapchain); +void +pvr_mesa_wsi_common_destroy_swapchain(struct pvr_mesa_wsi *mwsi, + VkDevice device, + VkSwapchainKHR swapchain, + const VkAllocationCallbacks *pAllocator); + +VkResult +pvr_mesa_wsi_common_get_images(struct pvr_mesa_wsi *mwsi, + VkSwapchainKHR swapchain, + uint32_t *pSwapchainImageCount, + VkImage *pSwapchainImages); + +VkResult +pvr_mesa_wsi_common_acquire_next_image2(struct pvr_mesa_wsi *mwsi, + VkDevice device, + const VkAcquireNextImageInfoKHR *pAcquireInfo, + uint32_t *pImageIndex); + +VkResult +pvr_mesa_wsi_common_queue_present(struct pvr_mesa_wsi *mwsi, + VkDevice device, + VkQueue queue, + int queue_family_index, + const VkPresentInfoKHR *pPresentInfo); + +VkResult +pvr_mesa_wsi_common_get_present_rectangles(struct pvr_mesa_wsi *mwsi, + VkSurfaceKHR surface, + uint32_t* pRectCount, + VkRect2D* pRects); + +#if defined(VK_USE_PLATFORM_WAYLAND_KHR) +VkBool32 +pvr_mesa_wsi_get_physical_device_wayland_presentation_support(struct pvr_mesa_wsi *mwsi, + uint32_t queueFamilyIndex, + void *display); + +VkResult +pvr_mesa_wsi_create_wayland_surface(struct pvr_mesa_wsi *mwsi, + const VkAllocationCallbacks *pAllocator, + const VkWaylandSurfaceCreateInfoKHR *pCreateInfo, + VkSurfaceKHR *pSurface); +#endif + +#if defined(VK_USE_PLATFORM_XCB_KHR) +VkBool32 +pvr_mesa_wsi_get_physical_device_xcb_presentation_support(struct pvr_mesa_wsi *mwsi, + uint32_t queueFamilyIndex, + void *connection, + uint32_t visualId); +VkResult +pvr_mesa_wsi_create_xcb_surface(struct pvr_mesa_wsi *mwsi, + const VkAllocationCallbacks *pAllocator, + const VkXcbSurfaceCreateInfoKHR *pCreateInfo, + VkSurfaceKHR *pSurface); +#endif + +#if defined(VK_USE_PLATFORM_XLIB_KHR) +VkResult +pvr_mesa_wsi_create_xlib_surface(struct pvr_mesa_wsi *mwsi, + const VkAllocationCallbacks *pAllocator, + const VkXlibSurfaceCreateInfoKHR *pCreateInfo, + VkSurfaceKHR *pSurface); +#endif + +VkResult +pvr_mesa_wsi_display_get_physical_device_display_properties(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + uint32_t *pPropertyCount, + VkDisplayPropertiesKHR *pProperties); + +VkResult +pvr_mesa_wsi_display_get_physical_device_display_properties2(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + uint32_t *pPropertyCount, + VkDisplayProperties2KHR *pProperties); + +VkResult +pvr_mesa_wsi_display_get_physical_device_display_plane_properties(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + uint32_t *pPropertyCount, + VkDisplayPlanePropertiesKHR *pProperties); + +VkResult +pvr_mesa_wsi_display_get_physical_device_display_plane_properties2(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + uint32_t *pPropertyCount, + VkDisplayPlaneProperties2KHR *pProperties); + +VkResult +pvr_mesa_wsi_display_get_display_plane_supported_displays(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + uint32_t planeIndex, + uint32_t *pDisplayCount, + VkDisplayKHR *pDisplays); + +VkResult +pvr_mesa_wsi_display_get_display_mode_properties(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + VkDisplayKHR display, + uint32_t *pPropertyCount, + VkDisplayModePropertiesKHR *pProperties); + +VkResult +pvr_mesa_wsi_display_get_display_mode_properties2(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + VkDisplayKHR display, + uint32_t *pPropertyCount, + VkDisplayModeProperties2KHR *pProperties); + +VkResult +pvr_mesa_wsi_display_create_display_mode(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + VkDisplayKHR display, + const VkDisplayModeCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDisplayModeKHR *pMode); + +VkResult +pvr_mesa_wsi_get_display_plane_capabilities(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + VkDisplayModeKHR modeKhr, + uint32_t planeIndex, + VkDisplayPlaneCapabilitiesKHR *pCapabilities); + +VkResult +pvr_mesa_wsi_get_display_plane_capabilities2(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + const VkDisplayPlaneInfo2KHR *pDisplayPlaneInfo, + VkDisplayPlaneCapabilities2KHR *pCapabilities); + +VkResult +pvr_mesa_wsi_create_display_surface(struct pvr_mesa_wsi *mwsi, + VkInstance instance, + const VkAllocationCallbacks *pAllocator, + const VkDisplaySurfaceCreateInfoKHR *pCreateInfo, + VkSurfaceKHR *pSurface); + +VkResult +pvr_mesa_wsi_release_display(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + VkDisplayKHR display); + +#if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) +VkResult +pvr_mesa_wsi_acquire_xlib_display(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + void *dpy, + VkDisplayKHR display); + +VkResult +pvr_mesa_wsi_get_randr_output_display(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + void *dpy, + uint32_t output, + VkDisplayKHR *pDisplay); + +#endif + +VkResult +pvr_mesa_wsi_display_power_control(struct pvr_mesa_wsi *mwsi, + VkDevice device, + VkDisplayKHR display, + const VkDisplayPowerInfoEXT *pDisplayPowerInfo); + +VkResult +pvr_mesa_wsi_register_device_event(struct pvr_mesa_wsi *mwsi, + VkDevice device, + const VkDeviceEventInfoEXT *pDeviceEventInfo, + const VkAllocationCallbacks *pAllocator, + void **pFence, + int syncFd); + +VkResult +pvr_mesa_wsi_register_display_event(struct pvr_mesa_wsi *mwsi, + VkDevice device, + VkDisplayKHR display, + const VkDisplayEventInfoEXT *pDisplayEventInfo, + const VkAllocationCallbacks *pAllocator, + void **pFence, + int syncFd); + +VkResult +pvr_mesa_wsi_get_swapchain_counter(struct pvr_mesa_wsi *mwsi, + VkDevice device, + VkSwapchainKHR swapchain, + VkSurfaceCounterFlagBitsEXT flagBits, + uint64_t *pValue); + +/* + * The following are available in version 1 of the interface. + * Version 1 also supports the version 0 interface. + */ + +uint32_t +pvr_mesa_wsi_get_version(struct pvr_mesa_wsi *mwsi); + +void +pvr_mesa_wsi_surface_destroy(struct pvr_mesa_wsi *mwsi, + VkSurfaceKHR surface, + const VkAllocationCallbacks *pAllocator); + +/* + * Functions defined in the PowerVR DDK for use by Mesa. + * All functions have a "pvr_vk_mesa_wsi" prefix. + * Since the introduction of version 1 of the interface, the following + * function is now regarded as forming version 0 of the interface. + */ +VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL +pvr_vk_mesa_wsi_sym_addr(VkPhysicalDevice physicalDevice, + const char *name); + +/* + * The following is available in version 1 of the interface. + * Version 1 also supports the version 0 interface. + */ +uint32_t +pvr_vk_mesa_wsi_get_version(VkPhysicalDevice physicalDevice); + +#endif /* PVR_MESA_WSI_INTERFACE_H */ diff --git a/src/pvr/wsi/pvr_wsi.c b/src/pvr/wsi/pvr_wsi.c new file mode 100644 index 0000000..cbf2b7a --- /dev/null +++ b/src/pvr/wsi/pvr_wsi.c @@ -0,0 +1,368 @@ +/* + * Copyright © Imagination Technologies Ltd. + * + * The contents of this file are subject to the MIT license as set out below. + * + * 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 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 + +#include "pvr_wsi.h" +#include "pvr_mesa_wsi_interface.h" + +static inline uint32_t +pvr_vk_wsi_get_version(struct pvr_mesa_wsi *mwsi) +{ + JUMP_DDK(mwsi, pvr_vk_mesa_wsi_get_version, + mwsi->physicalDevice); + + return 0; +} + + +VkResult +pvr_mesa_wsi_init(struct pvr_mesa_wsi **pmwsi, + VkPhysicalDevice physicalDevice, + PFN_vkVoidFunction (VKAPI_PTR *pvr_vk_mesa_wsi_sym_addr) + (VkPhysicalDevice physicalDevice, const char *), + const VkAllocationCallbacks *alloc, + int fd, + bool sw) +{ + struct pvr_mesa_wsi *mwsi; + VkResult result; + + mwsi = vk_zalloc(alloc, sizeof(*mwsi), 8, + VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE); + if (!mwsi) + return VK_ERROR_OUT_OF_HOST_MEMORY; + + mwsi->symtab.pvr_vk_mesa_wsi_sym_addr = pvr_vk_mesa_wsi_sym_addr; + mwsi->physicalDevice = physicalDevice; + + mwsi->pvr_vk_wsi_version = pvr_vk_wsi_get_version(mwsi); + if (mwsi->pvr_vk_wsi_version < 1) { + vk_free(alloc, mwsi); + return VK_ERROR_FEATURE_NOT_PRESENT; + } + + result = wsi_device_init2(&mwsi->wsi, + physicalDevice, + pvr_vk_mesa_wsi_sym_addr, + alloc, + fd, NULL, sw, + true, NULL); + if (result != VK_SUCCESS) { + vk_free(alloc, mwsi); + return result; + } + + if (!sw) + mwsi->wsi.supports_modifiers = true; + + *pmwsi = mwsi; + + return VK_SUCCESS; +} + +void +pvr_mesa_wsi_finish(struct pvr_mesa_wsi *mwsi, + const VkAllocationCallbacks *alloc) +{ + wsi_device_finish(&mwsi->wsi, alloc); + + vk_free(alloc, mwsi); +} + +VkResult +pvr_mesa_wsi_common_get_surface_support(struct pvr_mesa_wsi *mwsi, + uint32_t queueFamilyIndex, + VkSurfaceKHR surface, + VkBool32 *pSupported) +{ + return wsi_common_get_surface_support(&mwsi->wsi, + queueFamilyIndex, + surface, + pSupported); +} + +VkResult +pvr_mesa_wsi_common_get_surface_capabilities(struct pvr_mesa_wsi *mwsi, + VkSurfaceKHR surface, + VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) +{ + return wsi_common_get_surface_capabilities(&mwsi->wsi, + surface, + pSurfaceCapabilities); +} + +VkResult +pvr_mesa_wsi_common_get_surface_capabilities2(struct pvr_mesa_wsi *mwsi, + const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, + VkSurfaceCapabilities2KHR *pSurfaceCapabilities) +{ + return wsi_common_get_surface_capabilities2(&mwsi->wsi, + pSurfaceInfo, + pSurfaceCapabilities); +} + +VkResult +pvr_mesa_wsi_common_get_surface_capabilities2ext(struct pvr_mesa_wsi *mwsi, + VkSurfaceKHR surface, + VkSurfaceCapabilities2EXT *pSurfaceCapabilities) +{ + return wsi_common_get_surface_capabilities2ext(&mwsi->wsi, + surface, + pSurfaceCapabilities); +} + +VkResult +pvr_mesa_wsi_common_get_surface_formats(struct pvr_mesa_wsi *mwsi, + VkSurfaceKHR surface, + uint32_t *pSurfaceFormatCount, + VkSurfaceFormatKHR *pSurfaceFormats) +{ + return wsi_common_get_surface_formats(&mwsi->wsi, + surface, + pSurfaceFormatCount, + pSurfaceFormats); +} + +VkResult +pvr_mesa_wsi_common_get_surface_formats2(struct pvr_mesa_wsi *mwsi, + const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, + uint32_t *pSurfaceFormatCount, + VkSurfaceFormat2KHR *pSurfaceFormats) +{ + return wsi_common_get_surface_formats2(&mwsi->wsi, + pSurfaceInfo, + pSurfaceFormatCount, + pSurfaceFormats); +} + +VkResult +pvr_mesa_wsi_common_get_surface_present_modes(struct pvr_mesa_wsi *mwsi, + VkSurfaceKHR surface, + uint32_t *pPresentModeCount, + VkPresentModeKHR *pPresentModes) +{ + return wsi_common_get_surface_present_modes(&mwsi->wsi, + surface, + pPresentModeCount, + pPresentModes); +} + +VkResult +pvr_mesa_wsi_common_create_swapchain(struct pvr_mesa_wsi *mwsi, + VkDevice device, + const VkSwapchainCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkSwapchainKHR *pSwapchain) +{ + return wsi_common_create_swapchain(&mwsi->wsi, + device, + pCreateInfo, + pAllocator, + pSwapchain); +} + +void +pvr_mesa_wsi_common_destroy_swapchain(UNUSED struct pvr_mesa_wsi *mwsi, + VkDevice device, + VkSwapchainKHR swapchain, + const VkAllocationCallbacks *pAllocator) +{ + return wsi_common_destroy_swapchain(device, + swapchain, + pAllocator); +} + +VkResult +pvr_mesa_wsi_common_get_images(UNUSED struct pvr_mesa_wsi *mwsi, + VkSwapchainKHR swapchain, + uint32_t *pSwapchainImageCount, + VkImage *pSwapchainImages) +{ + return wsi_common_get_images(swapchain, + pSwapchainImageCount, + pSwapchainImages); +} + +VkResult +pvr_mesa_wsi_common_acquire_next_image2(struct pvr_mesa_wsi *mwsi, + VkDevice device, + const VkAcquireNextImageInfoKHR *pAcquireInfo, + uint32_t *pImageIndex) +{ + return wsi_common_acquire_next_image2(&mwsi->wsi, + device, + pAcquireInfo, + pImageIndex); +} + +VkResult +pvr_mesa_wsi_common_queue_present(struct pvr_mesa_wsi *mwsi, + VkDevice device, + VkQueue queue, + int queue_family_index, + const VkPresentInfoKHR *pPresentInfo) +{ + return wsi_common_queue_present(&mwsi->wsi, + device, + queue, + queue_family_index, + pPresentInfo); +} + +VkResult +pvr_mesa_wsi_common_get_present_rectangles(struct pvr_mesa_wsi *mwsi, + VkSurfaceKHR surface, + uint32_t* pRectCount, + VkRect2D* pRects) +{ + return wsi_common_get_present_rectangles(&mwsi->wsi, + surface, + pRectCount, + pRects); +} + +uint32_t +pvr_mesa_wsi_get_version(UNUSED struct pvr_mesa_wsi *mwsi) +{ + return 1; +} + +void +pvr_mesa_wsi_surface_destroy(UNUSED struct pvr_mesa_wsi *mwsi, + VkSurfaceKHR surface, + const VkAllocationCallbacks *pAllocator) +{ + wsi_surface_destroy(surface, pAllocator); +} + +/* + * The mwsi parameter is currently unused. Note that it is invalid for + * pvr_mesa_wsi_init, which is responsible for allocating it. +*/ +PUBLIC void * +pvr_mesa_wsi_sym_addr(UNUSED struct pvr_mesa_wsi *mwsi, const char *name) +{ + static const struct { + char *name; + void *addr; + } lookup[] = { + { "pvr_mesa_wsi_init", + pvr_mesa_wsi_init }, + { "pvr_mesa_wsi_finish", + pvr_mesa_wsi_finish }, + { "pvr_mesa_wsi_common_get_surface_support", + pvr_mesa_wsi_common_get_surface_support }, + { "pvr_mesa_wsi_common_get_surface_capabilities", + pvr_mesa_wsi_common_get_surface_capabilities }, + { "pvr_mesa_wsi_common_get_surface_capabilities2", + pvr_mesa_wsi_common_get_surface_capabilities2 }, + { "pvr_mesa_wsi_common_get_surface_capabilities2ext", + pvr_mesa_wsi_common_get_surface_capabilities2ext }, + { "pvr_mesa_wsi_common_get_surface_formats", + pvr_mesa_wsi_common_get_surface_formats }, + { "pvr_mesa_wsi_common_get_surface_formats2", + pvr_mesa_wsi_common_get_surface_formats2 }, + { "pvr_mesa_wsi_common_get_surface_present_modes", + pvr_mesa_wsi_common_get_surface_present_modes }, + { "pvr_mesa_wsi_common_create_swapchain", + pvr_mesa_wsi_common_create_swapchain }, + { "pvr_mesa_wsi_common_destroy_swapchain", + pvr_mesa_wsi_common_destroy_swapchain }, + { "pvr_mesa_wsi_common_get_images", + pvr_mesa_wsi_common_get_images }, + { "pvr_mesa_wsi_common_acquire_next_image2", + pvr_mesa_wsi_common_acquire_next_image2 }, + { "pvr_mesa_wsi_common_queue_present", + pvr_mesa_wsi_common_queue_present }, + { "pvr_mesa_wsi_common_get_present_rectangles", + pvr_mesa_wsi_common_get_present_rectangles }, +#if defined(VK_USE_PLATFORM_WAYLAND_KHR) + { "pvr_mesa_wsi_get_physical_device_wayland_presentation_support", + pvr_mesa_wsi_get_physical_device_wayland_presentation_support }, + { "pvr_mesa_wsi_create_wayland_surface", + pvr_mesa_wsi_create_wayland_surface }, +#endif +#if defined(VK_USE_PLATFORM_XCB_KHR) + { "pvr_mesa_wsi_get_physical_device_xcb_presentation_support", + pvr_mesa_wsi_get_physical_device_xcb_presentation_support }, + { "pvr_mesa_wsi_create_xcb_surface", + pvr_mesa_wsi_create_xcb_surface }, +#endif +#if defined(VK_USE_PLATFORM_XLIB_KHR) + { "pvr_mesa_wsi_create_xlib_surface", + pvr_mesa_wsi_create_xlib_surface }, +#endif + { "pvr_mesa_wsi_display_get_physical_device_display_properties", + pvr_mesa_wsi_display_get_physical_device_display_properties }, + { "pvr_mesa_wsi_display_get_physical_device_display_properties2", + pvr_mesa_wsi_display_get_physical_device_display_properties2 }, + { "pvr_mesa_wsi_display_get_physical_device_display_plane_properties", + pvr_mesa_wsi_display_get_physical_device_display_plane_properties }, + { "pvr_mesa_wsi_display_get_physical_device_display_plane_properties2", + pvr_mesa_wsi_display_get_physical_device_display_plane_properties2 }, + { "pvr_mesa_wsi_display_get_display_plane_supported_displays", + pvr_mesa_wsi_display_get_display_plane_supported_displays }, + { "pvr_mesa_wsi_display_get_display_mode_properties", + pvr_mesa_wsi_display_get_display_mode_properties }, + { "pvr_mesa_wsi_display_get_display_mode_properties2", + pvr_mesa_wsi_display_get_display_mode_properties2 }, + { "pvr_mesa_wsi_display_create_display_mode", + pvr_mesa_wsi_display_create_display_mode }, + { "pvr_mesa_wsi_get_display_plane_capabilities", + pvr_mesa_wsi_get_display_plane_capabilities }, + { "pvr_mesa_wsi_get_display_plane_capabilities2", + pvr_mesa_wsi_get_display_plane_capabilities2 }, + { "pvr_mesa_wsi_create_display_surface", + pvr_mesa_wsi_create_display_surface }, + { "pvr_mesa_wsi_release_display", + pvr_mesa_wsi_release_display }, +#if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) + { "pvr_mesa_wsi_acquire_xlib_display", + pvr_mesa_wsi_acquire_xlib_display }, + { "pvr_mesa_wsi_get_randr_output_display", + pvr_mesa_wsi_get_randr_output_display }, +#endif + { "pvr_mesa_wsi_display_power_control", + pvr_mesa_wsi_display_power_control }, + { "pvr_mesa_wsi_register_device_event", + pvr_mesa_wsi_register_device_event }, + { "pvr_mesa_wsi_register_display_event", + pvr_mesa_wsi_register_display_event }, + { "pvr_mesa_wsi_get_swapchain_counter", + pvr_mesa_wsi_get_swapchain_counter }, + { "pvr_mesa_wsi_get_version", + pvr_mesa_wsi_get_version }, + { "pvr_mesa_wsi_surface_destroy", + pvr_mesa_wsi_surface_destroy }, + }; + unsigned i; + + for (i = 0; i < ARRAY_SIZE(lookup); i++) { + if (!strcmp(name, lookup[i].name)) + return lookup[i].addr; + } + + return NULL; +} diff --git a/src/pvr/wsi/pvr_wsi.h b/src/pvr/wsi/pvr_wsi.h new file mode 100644 index 0000000..0c734fd --- /dev/null +++ b/src/pvr/wsi/pvr_wsi.h @@ -0,0 +1,81 @@ +/* + * Copyright © Imagination Technologies Ltd. + * + * The contents of this file are subject to the MIT license as set out below. + * + * 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 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. + */ + +#if !defined PVR_WSI_H +#define PVR_WSI_H + +#include "util/macros.h" +#include "util/u_memory.h" +#include "util/u_atomic.h" + +#include "wsi_common.h" + +#define Container(p, s, m) ((s *) ((uintptr_t)(p) - Offset(s, m))) + +#define _MAKE_STRING(x) # x +#define MAKE_STRING(x) _MAKE_STRING(x) + +#define LOOKUP_DDK(mwsi, sym) \ + mwsi->symtab.pvr_vk_mesa_wsi_sym_addr(mwsi->physicalDevice, MAKE_STRING(sym)) + +#define JUMP_DDK(mwsi, sym, ...) \ + do { \ + void *_entry = p_atomic_read(&mwsi->symtab.sym); \ + \ + if (!_entry) { \ + _entry = LOOKUP_DDK(mwsi, sym); \ + \ + if (_entry) \ + p_atomic_set(&mwsi->symtab.sym, _entry); \ + } \ + \ + if (_entry) { \ + __typeof__(mwsi->symtab.sym) _func = _entry; \ + \ + return _func(__VA_ARGS__); \ + } \ + } while(0) + +struct pvr_vk_mesa_wsi_sym_tab +{ + PFN_vkVoidFunction (VKAPI_PTR *pvr_vk_mesa_wsi_sym_addr) + (VkPhysicalDevice physicalDevice, const char *); + + uint32_t (*pvr_vk_mesa_wsi_get_version)(VkPhysicalDevice physicalDevice); +}; + +struct pvr_mesa_wsi +{ + struct wsi_device wsi; + struct pvr_vk_mesa_wsi_sym_tab symtab; + VkPhysicalDevice physicalDevice; + uint32_t pvr_vk_wsi_version; +}; + +static inline struct pvr_mesa_wsi *pvr_mesa_wsi(struct wsi_device *wsi_ptr) +{ + return Container(wsi_ptr, struct pvr_mesa_wsi, wsi); +} + +#endif diff --git a/src/pvr/wsi/pvr_wsi_display.c b/src/pvr/wsi/pvr_wsi_display.c new file mode 100644 index 0000000..8ee1389 --- /dev/null +++ b/src/pvr/wsi/pvr_wsi_display.c @@ -0,0 +1,293 @@ +/* + * Copyright © Imagination Technologies Ltd. + * + * The contents of this file are subject to the MIT license as set out below. + * + * 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 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 "wsi_common_display.h" + +#if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) +#include "wsi_common_x11.h" +#endif + +#include "pvr_wsi.h" +#include "pvr_mesa_wsi_interface.h" + +VkResult +pvr_mesa_wsi_display_get_physical_device_display_properties(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + uint32_t *pPropertyCount, + VkDisplayPropertiesKHR *pProperties) +{ + return wsi_display_get_physical_device_display_properties(physicalDevice, + &mwsi->wsi, + pPropertyCount, + pProperties); +} + +VkResult +pvr_mesa_wsi_display_get_physical_device_display_properties2(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + uint32_t *pPropertyCount, + VkDisplayProperties2KHR *pProperties) +{ + return wsi_display_get_physical_device_display_properties2(physicalDevice, + &mwsi->wsi, + pPropertyCount, + pProperties); +} + +VkResult +pvr_mesa_wsi_display_get_physical_device_display_plane_properties(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + uint32_t *pPropertyCount, + VkDisplayPlanePropertiesKHR *pProperties) +{ + return wsi_display_get_physical_device_display_plane_properties(physicalDevice, + &mwsi->wsi, + pPropertyCount, + pProperties); +} + +VkResult +pvr_mesa_wsi_display_get_physical_device_display_plane_properties2(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + uint32_t *pPropertyCount, + VkDisplayPlaneProperties2KHR *pProperties) +{ + return wsi_display_get_physical_device_display_plane_properties2(physicalDevice, + &mwsi->wsi, + pPropertyCount, + pProperties); +} + +VkResult +pvr_mesa_wsi_display_get_display_plane_supported_displays(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + uint32_t planeIndex, + uint32_t *pDisplayCount, + VkDisplayKHR *pDisplays) +{ + return wsi_display_get_display_plane_supported_displays(physicalDevice, + &mwsi->wsi, + planeIndex, + pDisplayCount, + pDisplays); + +} + +VkResult +pvr_mesa_wsi_display_get_display_mode_properties(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + VkDisplayKHR display, + uint32_t *pPropertyCount, + VkDisplayModePropertiesKHR *pProperties) +{ + return wsi_display_get_display_mode_properties(physicalDevice, + &mwsi->wsi, + display, + pPropertyCount, + pProperties); +} + +VkResult +pvr_mesa_wsi_display_get_display_mode_properties2(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + VkDisplayKHR display, + uint32_t *pPropertyCount, + VkDisplayModeProperties2KHR *pProperties) +{ + return wsi_display_get_display_mode_properties2(physicalDevice, + &mwsi->wsi, + display, + pPropertyCount, + pProperties); +} + +VkResult +pvr_mesa_wsi_display_create_display_mode(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + VkDisplayKHR display, + const VkDisplayModeCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDisplayModeKHR *pMode) +{ + return wsi_display_create_display_mode(physicalDevice, + &mwsi->wsi, + display, + pCreateInfo, + pAllocator, + pMode); +} + +VkResult +pvr_mesa_wsi_get_display_plane_capabilities(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + VkDisplayModeKHR modeKhr, + uint32_t planeIndex, + VkDisplayPlaneCapabilitiesKHR *pCapabilities) +{ + return wsi_get_display_plane_capabilities(physicalDevice, + &mwsi->wsi, + modeKhr, + planeIndex, + pCapabilities); +} + +VkResult +pvr_mesa_wsi_get_display_plane_capabilities2(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + const VkDisplayPlaneInfo2KHR *pDisplayPlaneInfo, + VkDisplayPlaneCapabilities2KHR *pCapabilities) +{ + return wsi_get_display_plane_capabilities2(physicalDevice, + &mwsi->wsi, + pDisplayPlaneInfo, + pCapabilities); +} + +VkResult +pvr_mesa_wsi_create_display_surface(UNUSED struct pvr_mesa_wsi *mwsi, + VkInstance instance, + const VkAllocationCallbacks *pAllocator, + const VkDisplaySurfaceCreateInfoKHR *pCreateInfo, + VkSurfaceKHR *pSurface) +{ + return wsi_create_display_surface(instance, + pAllocator, + pCreateInfo, + pSurface); +} + +VkResult +pvr_mesa_wsi_release_display(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + VkDisplayKHR display) +{ + return wsi_release_display(physicalDevice, + &mwsi->wsi, + display); +} + +#if defined(VK_USE_PLATFORM_XLIB_XRANDR_EXT) +VkResult +pvr_mesa_wsi_acquire_xlib_display(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + void *dpy, + VkDisplayKHR display) +{ + return wsi_acquire_xlib_display(physicalDevice, + &mwsi->wsi, + dpy, + display); +} + +VkResult +pvr_mesa_wsi_get_randr_output_display(struct pvr_mesa_wsi *mwsi, + VkPhysicalDevice physicalDevice, + void *dpy, + uint32_t output, + VkDisplayKHR *pDisplay) +{ + return wsi_get_randr_output_display(physicalDevice, + &mwsi->wsi, + dpy, + output, + pDisplay); +} +#endif + +VkResult +pvr_mesa_wsi_display_power_control(struct pvr_mesa_wsi *mwsi, + VkDevice device, + VkDisplayKHR display, + const VkDisplayPowerInfoEXT *pDisplayPowerInfo) +{ + return wsi_display_power_control(device, + &mwsi->wsi, + display, + pDisplayPowerInfo); +} + +VkResult +pvr_mesa_wsi_register_device_event(struct pvr_mesa_wsi *mwsi, + VkDevice device, + const VkDeviceEventInfoEXT *pDeviceEventInfo, + const VkAllocationCallbacks *pAllocator, + void **pFence, + int syncFd) +{ + struct vk_sync *fence; + VkResult ret; + + ret = wsi_register_device_event(device, + &mwsi->wsi, + pDeviceEventInfo, + pAllocator, + pFence ? &fence : NULL, + syncFd); + + if (ret == VK_SUCCESS && pFence != NULL) + *pFence = fence; + + return ret; +} + +VkResult +pvr_mesa_wsi_register_display_event(struct pvr_mesa_wsi *mwsi, + VkDevice device, + VkDisplayKHR display, + const VkDisplayEventInfoEXT *pDisplayEventInfo, + const VkAllocationCallbacks *pAllocator, + void **pFence, + int syncFd) +{ + struct vk_sync *fence; + VkResult ret; + + ret = wsi_register_display_event(device, + &mwsi->wsi, + display, + pDisplayEventInfo, + pAllocator, + pFence ? &fence : NULL, + syncFd); + + if (ret == VK_SUCCESS && pFence != NULL) + *pFence = fence; + + return ret; +} + +VkResult +pvr_mesa_wsi_get_swapchain_counter(struct pvr_mesa_wsi *mwsi, + VkDevice device, + VkSwapchainKHR swapchain, + VkSurfaceCounterFlagBitsEXT flagBits, + uint64_t *pValue) +{ + return wsi_get_swapchain_counter(device, + &mwsi->wsi, + swapchain, + flagBits, + pValue); +} + diff --git a/src/pvr/wsi/pvr_wsi_wayland.c b/src/pvr/wsi/pvr_wsi_wayland.c new file mode 100644 index 0000000..5b05266 --- /dev/null +++ b/src/pvr/wsi/pvr_wsi_wayland.c @@ -0,0 +1,45 @@ +/* + * Copyright © Imagination Technologies Ltd. + * + * The contents of this file are subject to the MIT license as set out below. + * + * 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 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 "wsi_common_wayland.h" + +#include "pvr_wsi.h" +#include "pvr_mesa_wsi_interface.h" + +VkBool32 +pvr_mesa_wsi_get_physical_device_wayland_presentation_support(struct pvr_mesa_wsi *mwsi, + uint32_t queueFamilyIndex, + void *display) +{ + return wsi_wl_get_presentation_support(&mwsi->wsi, display); +} + +VkResult +pvr_mesa_wsi_create_wayland_surface(UNUSED struct pvr_mesa_wsi *mwsi, + const VkAllocationCallbacks *pAllocator, + const VkWaylandSurfaceCreateInfoKHR *pCreateInfo, + VkSurfaceKHR *pSurface) +{ + return wsi_create_wl_surface(pAllocator, pCreateInfo, pSurface); +} diff --git a/src/pvr/wsi/pvr_wsi_x11.c b/src/pvr/wsi/pvr_wsi_x11.c new file mode 100644 index 0000000..0a69e92 --- /dev/null +++ b/src/pvr/wsi/pvr_wsi_x11.c @@ -0,0 +1,62 @@ +/* + * Copyright © Imagination Technologies Ltd. + * + * The contents of this file are subject to the MIT license as set out below. + * + * 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 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 "wsi_common_x11.h" + +#include "pvr_wsi.h" +#include "pvr_mesa_wsi_interface.h" + +VkBool32 +pvr_mesa_wsi_get_physical_device_xcb_presentation_support(struct pvr_mesa_wsi *mwsi, + uint32_t queueFamilyIndex, + void *connection, + uint32_t visual_id) +{ + return wsi_get_physical_device_xcb_presentation_support(&mwsi->wsi, + queueFamilyIndex, + connection, + visual_id); +} + +VkResult +pvr_mesa_wsi_create_xcb_surface(UNUSED struct pvr_mesa_wsi *mwsi, + const VkAllocationCallbacks *pAllocator, + const VkXcbSurfaceCreateInfoKHR *pCreateInfo, + VkSurfaceKHR *pSurface) +{ + return wsi_create_xcb_surface(pAllocator, + pCreateInfo, + pSurface); +} + +VkResult +pvr_mesa_wsi_create_xlib_surface(UNUSED struct pvr_mesa_wsi *mwsi, + const VkAllocationCallbacks *pAllocator, + const VkXlibSurfaceCreateInfoKHR *pCreateInfo, + VkSurfaceKHR *pSurface) +{ + return wsi_create_xlib_surface(pAllocator, + pCreateInfo, + pSurface); +} diff --git a/src/util/u_dynarray.h b/src/util/u_dynarray.h index 6f91b82..b41b0d4 100644 --- a/src/util/u_dynarray.h +++ b/src/util/u_dynarray.h @@ -168,6 +168,16 @@ util_dynarray_trim(struct util_dynarray *buf) } } +static inline void +util_dynarray_append_dynarray(struct util_dynarray *buf, + const struct util_dynarray *other) +{ + if (other->size > 0) { + void *p = util_dynarray_grow_bytes(buf, 1, other->size); + memcpy(p, other->data, other->size); + } +} + #define util_dynarray_append(buf, type, v) do {type __v = (v); memcpy(util_dynarray_grow_bytes((buf), 1, sizeof(type)), &__v, sizeof(type));} while(0) /* Returns a pointer to the space of the first new element (in case of growth) or NULL on failure. */ #define util_dynarray_resize(buf, type, nelts) util_dynarray_resize_bytes(buf, (nelts), sizeof(type)) diff --git a/src/vulkan/wsi/meson.build b/src/vulkan/wsi/meson.build index a92c7f3..68d53d5 100644 --- a/src/vulkan/wsi/meson.build +++ b/src/vulkan/wsi/meson.build @@ -31,6 +31,8 @@ endif if with_platform_wayland files_vulkan_wsi += files('wsi_common_wayland.c') files_vulkan_wsi += [ + wayland_drm_client_protocol_h, + wayland_drm_protocol_c, linux_dmabuf_unstable_v1_client_protocol_h, linux_dmabuf_unstable_v1_protocol_c, ] diff --git a/src/vulkan/wsi/wsi_common.c b/src/vulkan/wsi/wsi_common.c index b2974fa..8067781 100644 --- a/src/vulkan/wsi/wsi_common.c +++ b/src/vulkan/wsi/wsi_common.c @@ -57,13 +57,15 @@ static const struct debug_control debug_control[] = { }; VkResult -wsi_device_init(struct wsi_device *wsi, - VkPhysicalDevice pdevice, - WSI_FN_GetPhysicalDeviceProcAddr proc_addr, - const VkAllocationCallbacks *alloc, - int display_fd, - const struct driOptionCache *dri_options, - bool sw_device) +wsi_device_init2(struct wsi_device *wsi, + VkPhysicalDevice pdevice, + WSI_FN_GetPhysicalDeviceProcAddr proc_addr, + const VkAllocationCallbacks *alloc, + int display_fd, + const struct driOptionCache *dri_options, + bool sw_device, + bool opaque_vk_handles, + const struct vk_device_extension_table *device_extensions) { const char *present_mode; UNUSED VkResult result; @@ -79,6 +81,7 @@ wsi_device_init(struct wsi_device *wsi, wsi->supports_scanout = true; wsi->sw = sw_device || (WSI_DEBUG & WSI_DEBUG_SW); wsi->wants_linear = (WSI_DEBUG & WSI_DEBUG_LINEAR) != 0; + wsi->opaque_vk_handles = opaque_vk_handles; #define WSI_GET_CB(func) \ PFN_vk##func func = (PFN_vk##func)proc_addr(pdevice, "vk" #func) WSI_GET_CB(GetPhysicalDeviceExternalSemaphoreProperties); @@ -89,12 +92,18 @@ wsi_device_init(struct wsi_device *wsi, wsi->drm_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT; +#if defined(VULKAN_WSI_USE_PCI_BUS_INFO) wsi->pci_bus_info.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT; wsi->pci_bus_info.pNext = &wsi->drm_info; +#endif VkPhysicalDeviceProperties2 pdp2 = { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, +#if defined(VULKAN_WSI_USE_PCI_BUS_INFO) .pNext = &wsi->pci_bus_info, +#else + .pNext = &wsi->drm_info, +#endif }; GetPhysicalDeviceProperties2(pdevice, &pdp2); @@ -124,10 +133,19 @@ wsi_device_init(struct wsi_device *wsi, wsi->semaphore_export_handle_types |= handle_type; } - const struct vk_device_extension_table *supported_extensions = - &vk_physical_device_from_handle(pdevice)->supported_extensions; - wsi->has_import_memory_host = - supported_extensions->EXT_external_memory_host; + const struct vk_device_extension_table *supported_extensions; + + if (device_extensions) + supported_extensions = device_extensions; + else if (!opaque_vk_handles) + supported_extensions = + &vk_physical_device_from_handle(pdevice)->supported_extensions; + else + supported_extensions = NULL; + + if (supported_extensions) + wsi->has_import_memory_host = + supported_extensions->EXT_external_memory_host; list_inithead(&wsi->hotplug_fences); @@ -219,6 +237,10 @@ wsi_device_init(struct wsi_device *wsi, driQueryOptionb(dri_options, "vk_wsi_force_bgra8_unorm_first"); } } +#if !defined(VULKAN_WSI_BGRA8_SNORM_FIRST) + else + wsi->force_bgra8_unorm_first = true; +#endif return VK_SUCCESS; #if defined(VK_USE_PLATFORM_XCB_KHR) || \ @@ -231,6 +253,26 @@ fail: #endif } +VkResult +wsi_device_init(struct wsi_device *wsi, + VkPhysicalDevice pdevice, + WSI_FN_GetPhysicalDeviceProcAddr proc_addr, + const VkAllocationCallbacks *alloc, + int display_fd, + const struct driOptionCache *dri_options, + bool sw_device) +{ + return wsi_device_init2(wsi, + pdevice, + proc_addr, + alloc, + display_fd, + dri_options, + sw_device, + false, + NULL); +} + void wsi_device_finish(struct wsi_device *wsi, const VkAllocationCallbacks *alloc) @@ -249,12 +291,10 @@ wsi_device_finish(struct wsi_device *wsi, #endif } -VKAPI_ATTR void VKAPI_CALL -wsi_DestroySurfaceKHR(VkInstance _instance, - VkSurfaceKHR _surface, - const VkAllocationCallbacks *pAllocator) +void +wsi_surface_destroy(VkSurfaceKHR _surface, + const VkAllocationCallbacks *pAllocator) { - VK_FROM_HANDLE(vk_instance, instance, _instance); ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); if (!surface) @@ -262,12 +302,28 @@ wsi_DestroySurfaceKHR(VkInstance _instance, #ifdef VK_USE_PLATFORM_WAYLAND_KHR if (surface->platform == VK_ICD_WSI_PLATFORM_WAYLAND) { - wsi_wl_surface_destroy(surface, _instance, pAllocator); + wsi_wl_surface_destroy(surface, pAllocator); return; } #endif - vk_free2(&instance->alloc, pAllocator, surface); + vk_free(pAllocator, surface); +} + +VKAPI_ATTR void VKAPI_CALL +wsi_DestroySurfaceKHR(VkInstance _instance, + VkSurfaceKHR _surface, + const VkAllocationCallbacks *pAllocator) +{ + VK_FROM_HANDLE(vk_instance, instance, _instance); + const VkAllocationCallbacks *allocator; + + if (pAllocator) + allocator = pAllocator; + else + allocator = &instance->alloc; + + wsi_surface_destroy(_surface, allocator); } void @@ -305,6 +361,7 @@ static VkResult configure_image(const struct wsi_swapchain *chain, const VkSwapchainCreateInfoKHR *pCreateInfo, const struct wsi_base_image_params *params, + UNUSED int display_fd, struct wsi_image_info *info) { switch (params->image_type) { @@ -317,7 +374,8 @@ configure_image(const struct wsi_swapchain *chain, case WSI_IMAGE_TYPE_DRM: { const struct wsi_drm_image_params *drm_params = container_of(params, const struct wsi_drm_image_params, base); - return wsi_drm_configure_image(chain, pCreateInfo, drm_params, info); + return wsi_drm_configure_image(chain, pCreateInfo, drm_params, + display_fd, info); } #endif default: @@ -331,14 +389,20 @@ wsi_swapchain_init(const struct wsi_device *wsi, VkDevice _device, const VkSwapchainCreateInfoKHR *pCreateInfo, const struct wsi_base_image_params *image_params, - const VkAllocationCallbacks *pAllocator) + const VkAllocationCallbacks *pAllocator, + int display_fd) { - VK_FROM_HANDLE(vk_device, device, _device); VkResult result; memset(chain, 0, sizeof(*chain)); - vk_object_base_init(device, &chain->base, VK_OBJECT_TYPE_SWAPCHAIN_KHR); + if (wsi->opaque_vk_handles) { + vk_object_base_init(NULL, &chain->base, VK_OBJECT_TYPE_SWAPCHAIN_KHR); + } else { + VK_FROM_HANDLE(vk_device, device, _device); + + vk_object_base_init(device, &chain->base, VK_OBJECT_TYPE_SWAPCHAIN_KHR); + } chain->wsi = wsi; chain->device = _device; @@ -377,7 +441,7 @@ wsi_swapchain_init(const struct wsi_device *wsi, } result = configure_image(chain, pCreateInfo, image_params, - &chain->image_info); + display_fd, &chain->image_info); if (result != VK_SUCCESS) goto fail; @@ -476,6 +540,7 @@ VkResult wsi_configure_image(const struct wsi_swapchain *chain, const VkSwapchainCreateInfoKHR *pCreateInfo, VkExternalMemoryHandleTypeFlags handle_types, + int display_fd, struct wsi_image_info *info) { memset(info, 0, sizeof(*info)); @@ -534,6 +599,12 @@ wsi_configure_image(const struct wsi_swapchain *chain, }; __vk_append_struct(&info->create, &info->wsi); + info->wsi2 = (struct wsi_image_create_info2) { + .sType = VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO2_MESA, + .display_fd = display_fd, + }; + __vk_append_struct(&info->create, &info->wsi2); + if (pCreateInfo->flags & VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR) { info->create.flags |= VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT | VK_IMAGE_CREATE_EXTENDED_USAGE_BIT; @@ -599,6 +670,7 @@ wsi_destroy_image_info(const struct wsi_swapchain *chain, VkResult wsi_create_image(const struct wsi_swapchain *chain, const struct wsi_image_info *info, + int display_fd, struct wsi_image *image) { const struct wsi_device *wsi = chain->wsi; @@ -615,7 +687,7 @@ wsi_create_image(const struct wsi_swapchain *chain, if (result != VK_SUCCESS) goto fail; - result = info->create_mem(chain, info, image); + result = info->create_mem(chain, info, display_fd, image); if (result != VK_SUCCESS) goto fail; @@ -670,15 +742,13 @@ wsi_destroy_image(const struct wsi_swapchain *chain, wsi->DestroyBuffer(chain->device, image->buffer.buffer, &chain->alloc); } -VKAPI_ATTR VkResult VKAPI_CALL -wsi_GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, - uint32_t queueFamilyIndex, - VkSurfaceKHR _surface, - VkBool32 *pSupported) +VkResult +wsi_common_get_surface_support(struct wsi_device *wsi_device, + uint32_t queueFamilyIndex, + VkSurfaceKHR _surface, + VkBool32 *pSupported) { - VK_FROM_HANDLE(vk_physical_device, device, physicalDevice); ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); - struct wsi_device *wsi_device = device->wsi_device; struct wsi_interface *iface = wsi_device->wsi[surface->platform]; return iface->get_support(surface, wsi_device, @@ -686,14 +756,26 @@ wsi_GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, } VKAPI_ATTR VkResult VKAPI_CALL -wsi_GetPhysicalDeviceSurfaceCapabilitiesKHR( - VkPhysicalDevice physicalDevice, - VkSurfaceKHR _surface, - VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) +wsi_GetPhysicalDeviceSurfaceSupportKHR(VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + VkSurfaceKHR _surface, + VkBool32 *pSupported) { VK_FROM_HANDLE(vk_physical_device, device, physicalDevice); - ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); struct wsi_device *wsi_device = device->wsi_device; + + return wsi_common_get_surface_support(wsi_device, + queueFamilyIndex, + _surface, + pSupported); +} + +VkResult +wsi_common_get_surface_capabilities(struct wsi_device *wsi_device, + VkSurfaceKHR _surface, + VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) +{ + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); struct wsi_interface *iface = wsi_device->wsi[surface->platform]; VkSurfaceCapabilities2KHR caps2 = { @@ -709,14 +791,26 @@ wsi_GetPhysicalDeviceSurfaceCapabilitiesKHR( } VKAPI_ATTR VkResult VKAPI_CALL -wsi_GetPhysicalDeviceSurfaceCapabilities2KHR( +wsi_GetPhysicalDeviceSurfaceCapabilitiesKHR( VkPhysicalDevice physicalDevice, + VkSurfaceKHR _surface, + VkSurfaceCapabilitiesKHR *pSurfaceCapabilities) +{ + VK_FROM_HANDLE(vk_physical_device, device, physicalDevice); + struct wsi_device *wsi_device = device->wsi_device; + + return wsi_common_get_surface_capabilities(wsi_device, + _surface, + pSurfaceCapabilities); +} + +VkResult +wsi_common_get_surface_capabilities2( + struct wsi_device *wsi_device, const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, VkSurfaceCapabilities2KHR *pSurfaceCapabilities) { - VK_FROM_HANDLE(vk_physical_device, device, physicalDevice); ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pSurfaceInfo->surface); - struct wsi_device *wsi_device = device->wsi_device; struct wsi_interface *iface = wsi_device->wsi[surface->platform]; return iface->get_capabilities2(surface, wsi_device, pSurfaceInfo->pNext, @@ -724,14 +818,26 @@ wsi_GetPhysicalDeviceSurfaceCapabilities2KHR( } VKAPI_ATTR VkResult VKAPI_CALL -wsi_GetPhysicalDeviceSurfaceCapabilities2EXT( +wsi_GetPhysicalDeviceSurfaceCapabilities2KHR( VkPhysicalDevice physicalDevice, + const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, + VkSurfaceCapabilities2KHR *pSurfaceCapabilities) +{ + VK_FROM_HANDLE(vk_physical_device, device, physicalDevice); + struct wsi_device *wsi_device = device->wsi_device; + + return wsi_common_get_surface_capabilities2(wsi_device, + pSurfaceInfo, + pSurfaceCapabilities); +} + +VkResult +wsi_common_get_surface_capabilities2ext( + struct wsi_device *wsi_device, VkSurfaceKHR _surface, VkSurfaceCapabilities2EXT *pSurfaceCapabilities) { - VK_FROM_HANDLE(vk_physical_device, device, physicalDevice); ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); - struct wsi_device *wsi_device = device->wsi_device; struct wsi_interface *iface = wsi_device->wsi[surface->platform]; assert(pSurfaceCapabilities->sType == @@ -770,6 +876,33 @@ wsi_GetPhysicalDeviceSurfaceCapabilities2EXT( return result; } +VKAPI_ATTR VkResult VKAPI_CALL +wsi_GetPhysicalDeviceSurfaceCapabilities2EXT( + VkPhysicalDevice physicalDevice, + VkSurfaceKHR _surface, + VkSurfaceCapabilities2EXT *pSurfaceCapabilities) +{ + VK_FROM_HANDLE(vk_physical_device, device, physicalDevice); + struct wsi_device *wsi_device = device->wsi_device; + + return wsi_common_get_surface_capabilities2ext(wsi_device, + _surface, + pSurfaceCapabilities); +} + +VkResult +wsi_common_get_surface_formats(struct wsi_device *wsi_device, + VkSurfaceKHR _surface, + uint32_t *pSurfaceFormatCount, + VkSurfaceFormatKHR *pSurfaceFormats) +{ + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); + struct wsi_interface *iface = wsi_device->wsi[surface->platform]; + + return iface->get_formats(surface, wsi_device, + pSurfaceFormatCount, pSurfaceFormats); +} + VKAPI_ATTR VkResult VKAPI_CALL wsi_GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceKHR _surface, @@ -777,12 +910,25 @@ wsi_GetPhysicalDeviceSurfaceFormatsKHR(VkPhysicalDevice physicalDevice, VkSurfaceFormatKHR *pSurfaceFormats) { VK_FROM_HANDLE(vk_physical_device, device, physicalDevice); - ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); struct wsi_device *wsi_device = device->wsi_device; + + return wsi_common_get_surface_formats(wsi_device, + _surface, + pSurfaceFormatCount, + pSurfaceFormats); +} + +VkResult +wsi_common_get_surface_formats2(struct wsi_device *wsi_device, + const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, + uint32_t *pSurfaceFormatCount, + VkSurfaceFormat2KHR *pSurfaceFormats) +{ + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pSurfaceInfo->surface); struct wsi_interface *iface = wsi_device->wsi[surface->platform]; - return iface->get_formats(surface, wsi_device, - pSurfaceFormatCount, pSurfaceFormats); + return iface->get_formats2(surface, wsi_device, pSurfaceInfo->pNext, + pSurfaceFormatCount, pSurfaceFormats); } VKAPI_ATTR VkResult VKAPI_CALL @@ -792,12 +938,25 @@ wsi_GetPhysicalDeviceSurfaceFormats2KHR(VkPhysicalDevice physicalDevice, VkSurfaceFormat2KHR *pSurfaceFormats) { VK_FROM_HANDLE(vk_physical_device, device, physicalDevice); - ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pSurfaceInfo->surface); struct wsi_device *wsi_device = device->wsi_device; + + return wsi_common_get_surface_formats2(wsi_device, + pSurfaceInfo, + pSurfaceFormatCount, + pSurfaceFormats); +} + +VkResult +wsi_common_get_surface_present_modes(struct wsi_device *wsi_device, + VkSurfaceKHR _surface, + uint32_t *pPresentModeCount, + VkPresentModeKHR *pPresentModes) +{ + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); struct wsi_interface *iface = wsi_device->wsi[surface->platform]; - return iface->get_formats2(surface, wsi_device, pSurfaceInfo->pNext, - pSurfaceFormatCount, pSurfaceFormats); + return iface->get_present_modes(surface, pPresentModeCount, + pPresentModes); } VKAPI_ATTR VkResult VKAPI_CALL @@ -807,12 +966,25 @@ wsi_GetPhysicalDeviceSurfacePresentModesKHR(VkPhysicalDevice physicalDevice, VkPresentModeKHR *pPresentModes) { VK_FROM_HANDLE(vk_physical_device, device, physicalDevice); - ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); struct wsi_device *wsi_device = device->wsi_device; + + return wsi_common_get_surface_present_modes(wsi_device, + _surface, + pPresentModeCount, + pPresentModes); +} + +VkResult +wsi_common_get_present_rectangles(struct wsi_device *wsi_device, + VkSurfaceKHR _surface, + uint32_t* pRectCount, + VkRect2D* pRects) +{ + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); struct wsi_interface *iface = wsi_device->wsi[surface->platform]; - return iface->get_present_modes(surface, pPresentModeCount, - pPresentModes); + return iface->get_present_rectangles(surface, wsi_device, + pRectCount, pRects); } VKAPI_ATTR VkResult VKAPI_CALL @@ -822,12 +994,54 @@ wsi_GetPhysicalDevicePresentRectanglesKHR(VkPhysicalDevice physicalDevice, VkRect2D *pRects) { VK_FROM_HANDLE(vk_physical_device, device, physicalDevice); - ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, _surface); struct wsi_device *wsi_device = device->wsi_device; - struct wsi_interface *iface = wsi_device->wsi[surface->platform]; - return iface->get_present_rectangles(surface, wsi_device, - pRectCount, pRects); + return wsi_common_get_present_rectangles(wsi_device, + _surface, + pRectCount, + pRects); +} + +VkResult +wsi_common_create_swapchain(struct wsi_device *wsi_device, + VkDevice _device, + const VkSwapchainCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *allocator, + VkSwapchainKHR *pSwapchain) +{ + ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pCreateInfo->surface); + struct wsi_interface *iface = wsi_device->wsi[surface->platform]; + struct wsi_swapchain *swapchain; + + VkResult result = iface->create_swapchain(surface, _device, wsi_device, + pCreateInfo, allocator, + &swapchain); + if (result != VK_SUCCESS) + return result; + + swapchain->fences = vk_zalloc(allocator, + sizeof (*swapchain->fences) * swapchain->image_count, + sizeof (*swapchain->fences), + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!swapchain->fences) { + swapchain->destroy(swapchain, allocator); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + + if (swapchain->buffer_blit_queue != VK_NULL_HANDLE) { + swapchain->buffer_blit_semaphores = vk_zalloc(allocator, + sizeof (*swapchain->buffer_blit_semaphores) * swapchain->image_count, + sizeof (*swapchain->buffer_blit_semaphores), + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!swapchain->buffer_blit_semaphores) { + swapchain->destroy(swapchain, allocator); + return VK_ERROR_OUT_OF_HOST_MEMORY; + } + } + + *pSwapchain = wsi_swapchain_to_handle(swapchain); + + return VK_SUCCESS; } VKAPI_ATTR VkResult VKAPI_CALL @@ -838,46 +1052,32 @@ wsi_CreateSwapchainKHR(VkDevice _device, { MESA_TRACE_FUNC(); VK_FROM_HANDLE(vk_device, device, _device); - ICD_FROM_HANDLE(VkIcdSurfaceBase, surface, pCreateInfo->surface); struct wsi_device *wsi_device = device->physical->wsi_device; - struct wsi_interface *iface = wsi_device->wsi[surface->platform]; - const VkAllocationCallbacks *alloc; - struct wsi_swapchain *swapchain; + const VkAllocationCallbacks *allocator; if (pAllocator) - alloc = pAllocator; + allocator = pAllocator; else - alloc = &device->alloc; + allocator = &device->alloc; - VkResult result = iface->create_swapchain(surface, _device, wsi_device, - pCreateInfo, alloc, - &swapchain); - if (result != VK_SUCCESS) - return result; + return wsi_common_create_swapchain(wsi_device, + _device, + pCreateInfo, + allocator, + pSwapchain); +} - swapchain->fences = vk_zalloc(alloc, - sizeof (*swapchain->fences) * swapchain->image_count, - sizeof (*swapchain->fences), - VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); - if (!swapchain->fences) { - swapchain->destroy(swapchain, alloc); - return VK_ERROR_OUT_OF_HOST_MEMORY; - } +void +wsi_common_destroy_swapchain(VkDevice _device, + VkSwapchainKHR _swapchain, + const VkAllocationCallbacks *allocator) +{ + VK_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain); - if (swapchain->buffer_blit_queue != VK_NULL_HANDLE) { - swapchain->buffer_blit_semaphores = vk_zalloc(alloc, - sizeof (*swapchain->buffer_blit_semaphores) * swapchain->image_count, - sizeof (*swapchain->buffer_blit_semaphores), - VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); - if (!swapchain->buffer_blit_semaphores) { - swapchain->destroy(swapchain, alloc); - return VK_ERROR_OUT_OF_HOST_MEMORY; - } - } + if (!swapchain) + return; - *pSwapchain = wsi_swapchain_to_handle(swapchain); - - return VK_SUCCESS; + swapchain->destroy(swapchain, allocator); } VKAPI_ATTR void VKAPI_CALL @@ -887,18 +1087,14 @@ wsi_DestroySwapchainKHR(VkDevice _device, { MESA_TRACE_FUNC(); VK_FROM_HANDLE(vk_device, device, _device); - VK_FROM_HANDLE(wsi_swapchain, swapchain, _swapchain); - const VkAllocationCallbacks *alloc; - - if (!swapchain) - return; + const VkAllocationCallbacks *allocator; if (pAllocator) - alloc = pAllocator; + allocator = pAllocator; else - alloc = &device->alloc; + allocator = &device->alloc; - swapchain->destroy(swapchain, alloc); + wsi_common_destroy_swapchain(_device, _swapchain, allocator); } VkResult @@ -1033,7 +1229,6 @@ wsi_common_acquire_next_image2(const struct wsi_device *wsi, uint32_t *pImageIndex) { VK_FROM_HANDLE(wsi_swapchain, swapchain, pAcquireInfo->swapchain); - VK_FROM_HANDLE(vk_device, device, _device); VkResult result = swapchain->acquire_next_image(swapchain, pAcquireInfo, pImageIndex); @@ -1042,7 +1237,8 @@ wsi_common_acquire_next_image2(const struct wsi_device *wsi, struct wsi_image *image = swapchain->get_wsi_image(swapchain, *pImageIndex); - if (pAcquireInfo->semaphore != VK_NULL_HANDLE) { + if (pAcquireInfo->semaphore != VK_NULL_HANDLE && !wsi->opaque_vk_handles) { + VK_FROM_HANDLE(vk_device, device, _device); VkResult signal_result = wsi_signal_semaphore_for_image(device, swapchain, image, pAcquireInfo->semaphore); @@ -1050,7 +1246,8 @@ wsi_common_acquire_next_image2(const struct wsi_device *wsi, return signal_result; } - if (pAcquireInfo->fence != VK_NULL_HANDLE) { + if (pAcquireInfo->fence != VK_NULL_HANDLE && !wsi->opaque_vk_handles) { + VK_FROM_HANDLE(vk_device, device, _device); VkResult signal_result = wsi_signal_fence_for_image(device, swapchain, image, pAcquireInfo->fence); @@ -1420,7 +1617,8 @@ wsi_create_buffer_image_mem(const struct wsi_swapchain *chain, const struct wsi_image_info *info, struct wsi_image *image, VkExternalMemoryHandleTypeFlags handle_types, - bool implicit_sync) + bool implicit_sync, + int display_fd) { const struct wsi_device *wsi = chain->wsi; VkResult result; @@ -1484,6 +1682,13 @@ wsi_create_buffer_image_mem(const struct wsi_swapchain *chain, .handleTypes = handle_types, }; __vk_append_struct(&buf_mem_info, &memory_export_info); + + struct wsi_memory_allocate_info2 memory_wsi_info2 = { + .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO2_MESA, + .pNext = &memory_wsi_info, + .display_fd = display_fd, + }; + __vk_append_struct(&buf_mem_info, &memory_wsi_info2); } result = wsi->AllocateMemory(chain->device, &buf_mem_info, @@ -1630,6 +1835,7 @@ VkResult wsi_configure_buffer_image(UNUSED const struct wsi_swapchain *chain, const VkSwapchainCreateInfoKHR *pCreateInfo, uint32_t stride_align, uint32_t size_align, + int display_fd, struct wsi_image_info *info) { const struct wsi_device *wsi = chain->wsi; @@ -1638,7 +1844,8 @@ wsi_configure_buffer_image(UNUSED const struct wsi_swapchain *chain, assert(util_is_power_of_two_nonzero(size_align)); VkResult result = wsi_configure_image(chain, pCreateInfo, - 0 /* handle_types */, info); + 0 /* handle_types */, + display_fd, info); if (result != VK_SUCCESS) return result; @@ -1667,6 +1874,7 @@ wsi_configure_buffer_image(UNUSED const struct wsi_swapchain *chain, static VkResult wsi_create_cpu_linear_image_mem(const struct wsi_swapchain *chain, const struct wsi_image_info *info, + int display_fd, struct wsi_image *image) { const struct wsi_device *wsi = chain->wsi; @@ -1732,12 +1940,14 @@ wsi_create_cpu_linear_image_mem(const struct wsi_swapchain *chain, static VkResult wsi_create_cpu_buffer_image_mem(const struct wsi_swapchain *chain, const struct wsi_image_info *info, + int display_fd, struct wsi_image *image) { VkResult result; result = wsi_create_buffer_image_mem(chain, info, image, 0, - false /* implicit_sync */); + false /* implicit_sync */, + display_fd); if (result != VK_SUCCESS) return result; @@ -1778,6 +1988,7 @@ wsi_configure_cpu_image(const struct wsi_swapchain *chain, VkResult result = wsi_configure_buffer_image(chain, pCreateInfo, 1 /* stride_align */, 1 /* size_align */, + -1, info); if (result != VK_SUCCESS) return result; @@ -1787,7 +1998,7 @@ wsi_configure_cpu_image(const struct wsi_swapchain *chain, info->create_mem = wsi_create_cpu_buffer_image_mem; } else { VkResult result = wsi_configure_image(chain, pCreateInfo, - handle_types, info); + handle_types, -1, info); if (result != VK_SUCCESS) return result; diff --git a/src/vulkan/wsi/wsi_common.h b/src/vulkan/wsi/wsi_common.h index 886bac9..3a47be6 100644 --- a/src/vulkan/wsi/wsi_common.h +++ b/src/vulkan/wsi/wsi_common.h @@ -50,6 +50,8 @@ extern const struct vk_device_entrypoint_table wsi_device_entrypoints; #define VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO_MESA (VkStructureType)1000001003 #define VK_STRUCTURE_TYPE_WSI_SURFACE_SUPPORTED_COUNTERS_MESA (VkStructureType)1000001005 #define VK_STRUCTURE_TYPE_WSI_MEMORY_SIGNAL_SUBMIT_INFO_MESA (VkStructureType)1000001006 +#define VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO2_MESA (VkStructureType)1000001007 +#define VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO2_MESA (VkStructureType)1000001008 /* This is always chained to VkImageCreateInfo when a wsi image is created. * It indicates that the image can be transitioned to/from @@ -86,6 +88,18 @@ struct wsi_memory_signal_submit_info { VkDeviceMemory memory; }; +struct wsi_image_create_info2 { + VkStructureType sType; + const void *pNext; + int display_fd; +}; + +struct wsi_memory_allocate_info2 { + VkStructureType sType; + const void *pNext; + int display_fd; +}; + struct wsi_interface; struct driOptionCache; @@ -101,7 +115,10 @@ struct wsi_device { uint32_t queue_family_count; VkPhysicalDeviceDrmPropertiesEXT drm_info; + +#if defined(VULKAN_WSI_USE_PCI_BUS_INFO) VkPhysicalDevicePCIBusInfoPropertiesEXT pci_bus_info; +#endif VkExternalSemaphoreHandleTypeFlags semaphore_export_handle_types; @@ -122,6 +139,10 @@ struct wsi_device { * available. Not all window systems might support this. */ bool enable_adaptive_sync; + /* Handles, such as VKDevice, cannot be converted to Mesa data + * structures using VK_FROM_HANDLE. */ + bool opaque_vk_handles; + /* List of fences to signal when hotplug event happens. */ struct list_head hotplug_fences; @@ -236,6 +257,17 @@ struct wsi_device { typedef PFN_vkVoidFunction (VKAPI_PTR *WSI_FN_GetPhysicalDeviceProcAddr)(VkPhysicalDevice physicalDevice, const char* pName); +VkResult +wsi_device_init2(struct wsi_device *wsi, + VkPhysicalDevice pdevice, + WSI_FN_GetPhysicalDeviceProcAddr proc_addr, + const VkAllocationCallbacks *alloc, + int display_fd, + const struct driOptionCache *dri_options, + bool sw_device, + bool opaque_vk_handles, + const struct vk_device_extension_table *device_extensions); + VkResult wsi_device_init(struct wsi_device *wsi, VkPhysicalDevice pdevice, @@ -273,6 +305,51 @@ wsi_device_setup_syncobj_fd(struct wsi_device *wsi_device, ICD_DEFINE_NONDISP_HANDLE_CASTS(VkIcdSurfaceBase, VkSurfaceKHR) +VkResult +wsi_common_get_surface_support(struct wsi_device *wsi_device, + uint32_t queueFamilyIndex, + VkSurfaceKHR surface, + VkBool32 *pSupported); + +VkResult +wsi_common_get_surface_capabilities(struct wsi_device *wsi_device, + VkSurfaceKHR surface, + VkSurfaceCapabilitiesKHR *pSurfaceCapabilities); + +VkResult +wsi_common_get_surface_capabilities2(struct wsi_device *wsi_device, + const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, + VkSurfaceCapabilities2KHR *pSurfaceCapabilities); + +VkResult +wsi_common_get_surface_formats(struct wsi_device *wsi_device, + VkSurfaceKHR surface, + uint32_t *pSurfaceFormatCount, + VkSurfaceFormatKHR *pSurfaceFormats); + +VkResult +wsi_common_get_surface_formats2(struct wsi_device *wsi_device, + const VkPhysicalDeviceSurfaceInfo2KHR *pSurfaceInfo, + uint32_t *pSurfaceFormatCount, + VkSurfaceFormat2KHR *pSurfaceFormats); + +VkResult +wsi_common_get_surface_present_modes(struct wsi_device *wsi_device, + VkSurfaceKHR surface, + uint32_t *pPresentModeCount, + VkPresentModeKHR *pPresentModes); + +VkResult +wsi_common_get_present_rectangles(struct wsi_device *wsi_device, + VkSurfaceKHR surface, + uint32_t* pRectCount, + VkRect2D* pRects); + +VkResult +wsi_common_get_surface_capabilities2ext(struct wsi_device *wsi_device, + VkSurfaceKHR surface, + VkSurfaceCapabilities2EXT *pSurfaceCapabilities); + VkResult wsi_common_get_images(VkSwapchainKHR _swapchain, uint32_t *pSwapchainImageCount, @@ -287,6 +364,17 @@ wsi_common_acquire_next_image2(const struct wsi_device *wsi, const VkAcquireNextImageInfoKHR *pAcquireInfo, uint32_t *pImageIndex); +VkResult +wsi_common_create_swapchain(struct wsi_device *wsi, + VkDevice device, + const VkSwapchainCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkSwapchainKHR *pSwapchain); +void +wsi_common_destroy_swapchain(VkDevice device, + VkSwapchainKHR swapchain, + const VkAllocationCallbacks *pAllocator); + VkResult wsi_common_queue_present(const struct wsi_device *wsi, VkDevice device_h, @@ -305,6 +393,10 @@ wsi_common_bind_swapchain_image(const struct wsi_device *wsi, VkSwapchainKHR _swapchain, uint32_t image_idx); +void +wsi_surface_destroy(VkSurfaceKHR _surface, + const VkAllocationCallbacks *pAllocator); + #ifdef __cplusplus } #endif diff --git a/src/vulkan/wsi/wsi_common_display.c b/src/vulkan/wsi/wsi_common_display.c index 0e5d272..e0232e0 100644 --- a/src/vulkan/wsi/wsi_common_display.c +++ b/src/vulkan/wsi/wsi_common_display.c @@ -434,20 +434,19 @@ wsi_display_fill_in_display_properties(struct wsi_device *wsi_device, properties->persistentContent = VK_FALSE; } -VKAPI_ATTR VkResult VKAPI_CALL -wsi_GetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physicalDevice, - uint32_t *pPropertyCount, - VkDisplayPropertiesKHR *pProperties) +VkResult +wsi_display_get_physical_device_display_properties( + VkPhysicalDevice physicalDevice, + struct wsi_device *wsi_device, + uint32_t *pPropertyCount, + VkDisplayPropertiesKHR *pProperties) { - VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); - struct wsi_device *wsi_device = pdevice->wsi_device; struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; if (pProperties == NULL) { - return wsi_GetPhysicalDeviceDisplayProperties2KHR(physicalDevice, - pPropertyCount, - NULL); + return wsi_display_get_physical_device_display_properties2( + physicalDevice, wsi_device, pPropertyCount, NULL); } else { /* If we're actually returning properties, allocate a temporary array of * VkDisplayProperties2KHR structs, call properties2 to fill them out, @@ -465,9 +464,8 @@ wsi_GetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physicalDevice, for (uint32_t i = 0; i < *pPropertyCount; i++) props2[i].sType = VK_STRUCTURE_TYPE_DISPLAY_PROPERTIES_2_KHR; - VkResult result = - wsi_GetPhysicalDeviceDisplayProperties2KHR(physicalDevice, - pPropertyCount, props2); + VkResult result = wsi_display_get_physical_device_display_properties2( + physicalDevice, wsi_device, pPropertyCount, props2); if (result == VK_SUCCESS || result == VK_INCOMPLETE) { for (uint32_t i = 0; i < *pPropertyCount; i++) @@ -480,14 +478,23 @@ wsi_GetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physicalDevice, } } -static VkResult -wsi_get_connectors(VkPhysicalDevice physicalDevice) +VKAPI_ATTR VkResult VKAPI_CALL +wsi_GetPhysicalDeviceDisplayPropertiesKHR(VkPhysicalDevice physicalDevice, + uint32_t *pPropertyCount, + VkDisplayPropertiesKHR *pProperties) { VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); struct wsi_device *wsi_device = pdevice->wsi_device; - struct wsi_display *wsi = - (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; + return wsi_display_get_physical_device_display_properties(physicalDevice, + wsi_device, + pPropertyCount, + pProperties); +} + +static VkResult +wsi_get_connectors(struct wsi_device *wsi_device, struct wsi_display *wsi) +{ if (wsi->fd < 0) return VK_SUCCESS; @@ -511,18 +518,18 @@ wsi_get_connectors(VkPhysicalDevice physicalDevice) return VK_SUCCESS; } -VKAPI_ATTR VkResult VKAPI_CALL -wsi_GetPhysicalDeviceDisplayProperties2KHR(VkPhysicalDevice physicalDevice, - uint32_t *pPropertyCount, - VkDisplayProperties2KHR *pProperties) +VkResult +wsi_display_get_physical_device_display_properties2( + VkPhysicalDevice physicalDevice, + struct wsi_device *wsi_device, + uint32_t *pPropertyCount, + VkDisplayProperties2KHR *pProperties) { - VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); - struct wsi_device *wsi_device = pdevice->wsi_device; struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; /* Get current information */ - VkResult result = wsi_get_connectors(physicalDevice); + VkResult result = wsi_get_connectors(wsi_device, wsi); if (result != VK_SUCCESS) goto bail; @@ -546,6 +553,20 @@ bail: return result; } +VKAPI_ATTR VkResult VKAPI_CALL +wsi_GetPhysicalDeviceDisplayProperties2KHR(VkPhysicalDevice physicalDevice, + uint32_t *pPropertyCount, + VkDisplayProperties2KHR *pProperties) +{ + VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); + struct wsi_device *wsi_device = pdevice->wsi_device; + + return wsi_display_get_physical_device_display_properties2(physicalDevice, + wsi_device, + pPropertyCount, + pProperties); +} + /* * Implement vkGetPhysicalDeviceDisplayPlanePropertiesKHR (VK_KHR_display */ @@ -567,17 +588,17 @@ wsi_display_fill_in_display_plane_properties( } } -VKAPI_ATTR VkResult VKAPI_CALL -wsi_GetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice physicalDevice, - uint32_t *pPropertyCount, - VkDisplayPlanePropertiesKHR *pProperties) +VkResult +wsi_display_get_physical_device_display_plane_properties( + VkPhysicalDevice physicalDevice, + struct wsi_device *wsi_device, + uint32_t *pPropertyCount, + VkDisplayPlanePropertiesKHR *pProperties) { - VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); - struct wsi_device *wsi_device = pdevice->wsi_device; struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; - VkResult result = wsi_get_connectors(physicalDevice); + VkResult result = wsi_get_connectors(wsi_device, wsi); if (result != VK_SUCCESS) goto bail; @@ -602,17 +623,32 @@ bail: } VKAPI_ATTR VkResult VKAPI_CALL -wsi_GetPhysicalDeviceDisplayPlaneProperties2KHR(VkPhysicalDevice physicalDevice, - uint32_t *pPropertyCount, - VkDisplayPlaneProperties2KHR *pProperties) +wsi_GetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice physicalDevice, + uint32_t *pPropertyCount, + VkDisplayPlanePropertiesKHR *pProperties) { VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); struct wsi_device *wsi_device = pdevice->wsi_device; + + return wsi_display_get_physical_device_display_plane_properties( + physicalDevice, + wsi_device, + pPropertyCount, + pProperties); +} + +VkResult +wsi_display_get_physical_device_display_plane_properties2( + VkPhysicalDevice physicalDevice, + struct wsi_device *wsi_device, + uint32_t *pPropertyCount, + VkDisplayPlaneProperties2KHR *pProperties) +{ struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; /* Get current information */ - VkResult result = wsi_get_connectors(physicalDevice); + VkResult result = wsi_get_connectors(wsi_device, wsi); if (result != VK_SUCCESS) goto bail; @@ -632,18 +668,34 @@ bail: return result; } +VKAPI_ATTR VkResult VKAPI_CALL +wsi_GetPhysicalDeviceDisplayPlaneProperties2KHR(VkPhysicalDevice physicalDevice, + uint32_t *pPropertyCount, + VkDisplayPlaneProperties2KHR *pProperties) +{ + VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); + struct wsi_device *wsi_device = pdevice->wsi_device; + + return wsi_display_get_physical_device_display_plane_properties2( + physicalDevice, + wsi_device, + pPropertyCount, + pProperties); +} + + /* * Implement vkGetDisplayPlaneSupportedDisplaysKHR (VK_KHR_display) */ -VKAPI_ATTR VkResult VKAPI_CALL -wsi_GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physicalDevice, - uint32_t planeIndex, - uint32_t *pDisplayCount, - VkDisplayKHR *pDisplays) +VkResult +wsi_display_get_display_plane_supported_displays( + VkPhysicalDevice physicalDevice, + struct wsi_device *wsi_device, + uint32_t planeIndex, + uint32_t *pDisplayCount, + VkDisplayKHR *pDisplays) { - VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); - struct wsi_device *wsi_device = pdevice->wsi_device; struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; @@ -662,6 +714,22 @@ wsi_GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physicalDevice, return vk_outarray_status(&conn); } +VKAPI_ATTR VkResult VKAPI_CALL +wsi_GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physicalDevice, + uint32_t planeIndex, + uint32_t *pDisplayCount, + VkDisplayKHR *pDisplays) +{ + VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); + struct wsi_device *wsi_device = pdevice->wsi_device; + + return wsi_display_get_display_plane_supported_displays(physicalDevice, + wsi_device, + planeIndex, + pDisplayCount, + pDisplays); +} + /* * Implement vkGetDisplayModePropertiesKHR (VK_KHR_display) */ @@ -682,14 +750,13 @@ wsi_display_fill_in_display_mode_properties( (uint32_t) (wsi_display_mode_refresh(display_mode) * 1000 + 0.5); } -VKAPI_ATTR VkResult VKAPI_CALL -wsi_GetDisplayModePropertiesKHR(VkPhysicalDevice physicalDevice, - VkDisplayKHR display, - uint32_t *pPropertyCount, - VkDisplayModePropertiesKHR *pProperties) +VkResult +wsi_display_get_display_mode_properties(VkPhysicalDevice physicalDevice, + struct wsi_device *wsi_device, + VkDisplayKHR display, + uint32_t *pPropertyCount, + VkDisplayModePropertiesKHR *pProperties) { - VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); - struct wsi_device *wsi_device = pdevice->wsi_device; struct wsi_display_connector *connector = wsi_display_connector_from_handle(display); @@ -713,13 +780,28 @@ wsi_GetDisplayModePropertiesKHR(VkPhysicalDevice physicalDevice, } VKAPI_ATTR VkResult VKAPI_CALL -wsi_GetDisplayModeProperties2KHR(VkPhysicalDevice physicalDevice, - VkDisplayKHR display, - uint32_t *pPropertyCount, - VkDisplayModeProperties2KHR *pProperties) +wsi_GetDisplayModePropertiesKHR(VkPhysicalDevice physicalDevice, + VkDisplayKHR display, + uint32_t *pPropertyCount, + VkDisplayModePropertiesKHR *pProperties) { VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); struct wsi_device *wsi_device = pdevice->wsi_device; + + return wsi_display_get_display_mode_properties(physicalDevice, + wsi_device, + display, + pPropertyCount, + pProperties); +} + +VkResult +wsi_display_get_display_mode_properties2(VkPhysicalDevice physicalDevice, + struct wsi_device *wsi_device, + VkDisplayKHR display, + uint32_t *pPropertyCount, + VkDisplayModeProperties2KHR *pProperties) +{ struct wsi_display_connector *connector = wsi_display_connector_from_handle(display); @@ -738,6 +820,22 @@ wsi_GetDisplayModeProperties2KHR(VkPhysicalDevice physicalDevice, return vk_outarray_status(&conn); } +VKAPI_ATTR VkResult VKAPI_CALL +wsi_GetDisplayModeProperties2KHR(VkPhysicalDevice physicalDevice, + VkDisplayKHR display, + uint32_t *pPropertyCount, + VkDisplayModeProperties2KHR *pProperties) +{ + VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); + struct wsi_device *wsi_device = pdevice->wsi_device; + + return wsi_display_get_display_mode_properties2(physicalDevice, + wsi_device, + display, + pPropertyCount, + pProperties); +} + static bool wsi_display_mode_matches_vk(wsi_display_mode *wsi, const VkDisplayModeParametersKHR *vk) @@ -750,12 +848,13 @@ wsi_display_mode_matches_vk(wsi_display_mode *wsi, /* * Implement vkCreateDisplayModeKHR (VK_KHR_display) */ -VKAPI_ATTR VkResult VKAPI_CALL -wsi_CreateDisplayModeKHR(VkPhysicalDevice physicalDevice, - VkDisplayKHR display, - const VkDisplayModeCreateInfoKHR *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkDisplayModeKHR *pMode) +VkResult +wsi_display_create_display_mode(VkPhysicalDevice physicalDevice, + struct wsi_device *wsi_device, + VkDisplayKHR display, + const VkDisplayModeCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDisplayModeKHR *pMode) { struct wsi_display_connector *connector = wsi_display_connector_from_handle(display); @@ -779,11 +878,31 @@ wsi_CreateDisplayModeKHR(VkPhysicalDevice physicalDevice, return VK_ERROR_INITIALIZATION_FAILED; } +VKAPI_ATTR VkResult VKAPI_CALL +wsi_CreateDisplayModeKHR(VkPhysicalDevice physicalDevice, + VkDisplayKHR display, + const VkDisplayModeCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDisplayModeKHR *pMode) +{ + VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); + struct wsi_device *wsi_device = pdevice->wsi_device; + + return wsi_display_create_display_mode(physicalDevice, + wsi_device, + display, + pCreateInfo, + pAllocator, + pMode); +} + + /* * Implement vkGetDisplayPlaneCapabilities */ -VKAPI_ATTR VkResult VKAPI_CALL -wsi_GetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice physicalDevice, +VkResult +wsi_get_display_plane_capabilities(VkPhysicalDevice physicalDevice, + struct wsi_device *wsi_device, VkDisplayModeKHR _mode, uint32_t planeIndex, VkDisplayPlaneCapabilitiesKHR *pCapabilities) @@ -812,15 +931,33 @@ wsi_GetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice physicalDevice, } VKAPI_ATTR VkResult VKAPI_CALL -wsi_GetDisplayPlaneCapabilities2KHR(VkPhysicalDevice physicalDevice, - const VkDisplayPlaneInfo2KHR *pDisplayPlaneInfo, - VkDisplayPlaneCapabilities2KHR *pCapabilities) +wsi_GetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice physicalDevice, + VkDisplayModeKHR _mode, + uint32_t planeIndex, + VkDisplayPlaneCapabilitiesKHR *pCapabilities) +{ + VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); + struct wsi_device *wsi_device = pdevice->wsi_device; + + return wsi_get_display_plane_capabilities(physicalDevice, + wsi_device, + _mode, + planeIndex, + pCapabilities); +} + +VkResult +wsi_get_display_plane_capabilities2( + VkPhysicalDevice physicalDevice, + struct wsi_device *wsi_device, + const VkDisplayPlaneInfo2KHR *pDisplayPlaneInfo, + VkDisplayPlaneCapabilities2KHR *pCapabilities) { assert(pCapabilities->sType == VK_STRUCTURE_TYPE_DISPLAY_PLANE_CAPABILITIES_2_KHR); VkResult result = - wsi_GetDisplayPlaneCapabilitiesKHR(physicalDevice, + wsi_get_display_plane_capabilities(physicalDevice, wsi_device, pDisplayPlaneInfo->mode, pDisplayPlaneInfo->planeIndex, &pCapabilities->capabilities); @@ -843,18 +980,31 @@ wsi_GetDisplayPlaneCapabilities2KHR(VkPhysicalDevice physicalDevice, } VKAPI_ATTR VkResult VKAPI_CALL -wsi_CreateDisplayPlaneSurfaceKHR(VkInstance _instance, - const VkDisplaySurfaceCreateInfoKHR *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkSurfaceKHR *pSurface) +wsi_GetDisplayPlaneCapabilities2KHR(VkPhysicalDevice physicalDevice, + const VkDisplayPlaneInfo2KHR *pDisplayPlaneInfo, + VkDisplayPlaneCapabilities2KHR *pCapabilities) +{ + VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); + struct wsi_device *wsi_device = pdevice->wsi_device; + + return wsi_get_display_plane_capabilities2(physicalDevice, + wsi_device, + pDisplayPlaneInfo, + pCapabilities); +} + +VkResult +wsi_create_display_surface(VkInstance instance, + const VkAllocationCallbacks *allocator, + const VkDisplaySurfaceCreateInfoKHR *pCreateInfo, + VkSurfaceKHR *pSurface) { - VK_FROM_HANDLE(vk_instance, instance, _instance); VkIcdSurfaceDisplay *surface; assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR); - surface = vk_zalloc2(&instance->alloc, pAllocator, sizeof(*surface), 8, - VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + surface = vk_zalloc(allocator, sizeof(*surface), 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); if (surface == NULL) return VK_ERROR_OUT_OF_HOST_MEMORY; @@ -873,6 +1023,27 @@ wsi_CreateDisplayPlaneSurfaceKHR(VkInstance _instance, return VK_SUCCESS; } +VKAPI_ATTR VkResult VKAPI_CALL +wsi_CreateDisplayPlaneSurfaceKHR(VkInstance _instance, + const VkDisplaySurfaceCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkSurfaceKHR *pSurface) +{ + VK_FROM_HANDLE(vk_instance, instance, _instance); + const VkAllocationCallbacks *allocator; + + if (pAllocator) + allocator = pAllocator; + else + allocator = &instance->alloc; + + return wsi_create_display_surface(_instance, + allocator, + pCreateInfo, + pSurface); +} + + static VkResult wsi_display_surface_get_support(VkIcdSurfaceBase *surface, struct wsi_device *wsi_device, @@ -963,6 +1134,7 @@ static const struct { } available_surface_formats[] = { { .format = VK_FORMAT_B8G8R8A8_SRGB, .drm_format = DRM_FORMAT_XRGB8888 }, { .format = VK_FORMAT_B8G8R8A8_UNORM, .drm_format = DRM_FORMAT_XRGB8888 }, + { .format = VK_FORMAT_R5G6B5_UNORM_PACK16, .drm_format = DRM_FORMAT_RGB565 }, }; static void @@ -1097,7 +1269,7 @@ wsi_display_image_init(VkDevice device_h, return VK_ERROR_DEVICE_LOST; VkResult result = wsi_create_image(&chain->base, &chain->base.image_info, - &image->base); + wsi->fd, &image->base); if (result != VK_SUCCESS) return result; @@ -1957,7 +2129,7 @@ wsi_display_surface_create_swapchain( VkResult result = wsi_swapchain_init(wsi_device, &chain->base, device, create_info, &image_params.base, - allocator); + allocator, wsi->fd); if (result != VK_SUCCESS) { vk_free(allocator, chain); return result; @@ -2224,12 +2396,11 @@ wsi_display_finish_wsi(struct wsi_device *wsi_device, /* * Implement vkReleaseDisplay */ -VKAPI_ATTR VkResult VKAPI_CALL -wsi_ReleaseDisplayEXT(VkPhysicalDevice physicalDevice, - VkDisplayKHR display) +VkResult +wsi_release_display(VkPhysicalDevice physicalDevice, + struct wsi_device *wsi_device, + VkDisplayKHR display) { - VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); - struct wsi_device *wsi_device = pdevice->wsi_device; struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; @@ -2646,12 +2817,23 @@ wsi_display_find_crtc_for_output(xcb_connection_t *connection, } VKAPI_ATTR VkResult VKAPI_CALL -wsi_AcquireXlibDisplayEXT(VkPhysicalDevice physicalDevice, - Display *dpy, - VkDisplayKHR display) +wsi_ReleaseDisplayEXT(VkPhysicalDevice physicalDevice, + VkDisplayKHR display) { VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); struct wsi_device *wsi_device = pdevice->wsi_device; + + return wsi_release_display(physicalDevice, + wsi_device, + display); +} + +VkResult +wsi_acquire_xlib_display(VkPhysicalDevice physicalDevice, + struct wsi_device *wsi_device, + Display *dpy, + VkDisplayKHR display) +{ struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; xcb_connection_t *connection = XGetXCBConnection(dpy); @@ -2710,13 +2892,26 @@ wsi_AcquireXlibDisplayEXT(VkPhysicalDevice physicalDevice, } VKAPI_ATTR VkResult VKAPI_CALL -wsi_GetRandROutputDisplayEXT(VkPhysicalDevice physicalDevice, +wsi_AcquireXlibDisplayEXT(VkPhysicalDevice physicalDevice, + Display *dpy, + VkDisplayKHR display) +{ + VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); + struct wsi_device *wsi_device = pdevice->wsi_device; + + return wsi_acquire_xlib_display(physicalDevice, + wsi_device, + dpy, + display); +} + +VkResult +wsi_get_randr_output_display(VkPhysicalDevice physicalDevice, + struct wsi_device *wsi_device, Display *dpy, RROutput rrOutput, VkDisplayKHR *pDisplay) { - VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); - struct wsi_device *wsi_device = pdevice->wsi_device; xcb_connection_t *connection = XGetXCBConnection(dpy); struct wsi_display_connector *connector = wsi_display_get_output(wsi_device, connection, @@ -2729,16 +2924,31 @@ wsi_GetRandROutputDisplayEXT(VkPhysicalDevice physicalDevice, return VK_SUCCESS; } +VKAPI_ATTR VkResult VKAPI_CALL +wsi_GetRandROutputDisplayEXT(VkPhysicalDevice physicalDevice, + Display *dpy, + RROutput rrOutput, + VkDisplayKHR *pDisplay) +{ + VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); + struct wsi_device *wsi_device = pdevice->wsi_device; + + return wsi_get_randr_output_display(physicalDevice, + wsi_device, + dpy, + rrOutput, + pDisplay); +} + #endif /* VK_EXT_display_control */ -VKAPI_ATTR VkResult VKAPI_CALL -wsi_DisplayPowerControlEXT(VkDevice _device, - VkDisplayKHR display, - const VkDisplayPowerInfoEXT *pDisplayPowerInfo) +VkResult +wsi_display_power_control(VkDevice _device, + struct wsi_device *wsi_device, + VkDisplayKHR display, + const VkDisplayPowerInfoEXT *pDisplayPowerInfo) { - VK_FROM_HANDLE(vk_device, device, _device); - struct wsi_device *wsi_device = device->physical->wsi_device; struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; struct wsi_display_connector *connector = @@ -2766,6 +2976,20 @@ wsi_DisplayPowerControlEXT(VkDevice _device, return VK_SUCCESS; } +VKAPI_ATTR VkResult VKAPI_CALL +wsi_DisplayPowerControlEXT(VkDevice _device, + VkDisplayKHR display, + const VkDisplayPowerInfoEXT *pDisplayPowerInfo) +{ + VK_FROM_HANDLE(vk_device, device, _device); + struct wsi_device *wsi_device = device->physical->wsi_device; + + return wsi_display_power_control(_device, + wsi_device, + display, + pDisplayPowerInfo); +} + VkResult wsi_register_device_event(VkDevice _device, struct wsi_device *wsi_device, @@ -2774,7 +2998,6 @@ wsi_register_device_event(VkDevice _device, struct vk_sync **sync_out, int sync_fd) { - VK_FROM_HANDLE(vk_device, device, _device); struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; VkResult ret = VK_SUCCESS; @@ -2808,6 +3031,8 @@ wsi_register_device_event(VkDevice _device, mtx_unlock(&wsi->wait_mutex); if (sync_out) { + VK_FROM_HANDLE(vk_device, device, _device); + ret = wsi_display_sync_create(device, fence, sync_out); if (ret != VK_SUCCESS) wsi_display_fence_destroy(fence); @@ -2856,7 +3081,6 @@ wsi_register_display_event(VkDevice _device, struct vk_sync **sync_out, int sync_fd) { - VK_FROM_HANDLE(vk_device, device, _device); struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; struct wsi_display_fence *fence; @@ -2875,6 +3099,8 @@ wsi_register_display_event(VkDevice _device, if (ret == VK_SUCCESS) { if (sync_out) { + VK_FROM_HANDLE(vk_device, device, _device); + ret = wsi_display_sync_create(device, fence, sync_out); if (ret != VK_SUCCESS) wsi_display_fence_destroy(fence); @@ -2933,14 +3159,13 @@ wsi_display_setup_syncobj_fd(struct wsi_device *wsi_device, wsi->syncobj_fd = fd; } -VKAPI_ATTR VkResult VKAPI_CALL -wsi_GetSwapchainCounterEXT(VkDevice _device, - VkSwapchainKHR _swapchain, - VkSurfaceCounterFlagBitsEXT counter, - uint64_t *pCounterValue) +VkResult +wsi_get_swapchain_counter(VkDevice _device, + struct wsi_device *wsi_device, + VkSwapchainKHR _swapchain, + VkSurfaceCounterFlagBitsEXT counter, + uint64_t *pCounterValue) { - VK_FROM_HANDLE(vk_device, device, _device); - struct wsi_device *wsi_device = device->physical->wsi_device; struct wsi_display *wsi = (struct wsi_display *) wsi_device->wsi[VK_ICD_WSI_PLATFORM_DISPLAY]; struct wsi_display_swapchain *swapchain = @@ -2965,13 +3190,27 @@ wsi_GetSwapchainCounterEXT(VkDevice _device, } VKAPI_ATTR VkResult VKAPI_CALL -wsi_AcquireDrmDisplayEXT(VkPhysicalDevice physicalDevice, - int32_t drmFd, - VkDisplayKHR display) +wsi_GetSwapchainCounterEXT(VkDevice _device, + VkSwapchainKHR _swapchain, + VkSurfaceCounterFlagBitsEXT counter, + uint64_t *pCounterValue) { - VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); - struct wsi_device *wsi_device = pdevice->wsi_device; + VK_FROM_HANDLE(vk_device, device, _device); + struct wsi_device *wsi_device = device->physical->wsi_device; + return wsi_get_swapchain_counter(_device, + wsi_device, + _swapchain, + counter, + pCounterValue); +} + +VkResult +wsi_acquire_drm_display(VkPhysicalDevice physicalDevice, + struct wsi_device *wsi_device, + int drmFd, + VkDisplayKHR display) +{ if (!wsi_device_matches_drm_fd(wsi_device, drmFd)) return VK_ERROR_UNKNOWN; @@ -2998,14 +3237,26 @@ wsi_AcquireDrmDisplayEXT(VkPhysicalDevice physicalDevice, } VKAPI_ATTR VkResult VKAPI_CALL -wsi_GetDrmDisplayEXT(VkPhysicalDevice physicalDevice, - int32_t drmFd, - uint32_t connectorId, - VkDisplayKHR *pDisplay) +wsi_AcquireDrmDisplayEXT(VkPhysicalDevice physicalDevice, + int32_t drmFd, + VkDisplayKHR display) { VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); struct wsi_device *wsi_device = pdevice->wsi_device; + return wsi_acquire_drm_display(physicalDevice, + wsi_device, + drmFd, + display); +} + +VkResult +wsi_get_drm_display(VkPhysicalDevice physicalDevice, + struct wsi_device *wsi_device, + int drmFd, + int connectorId, + VkDisplayKHR *pDisplay) +{ if (!wsi_device_matches_drm_fd(wsi_device, drmFd)) return VK_ERROR_UNKNOWN; @@ -3020,3 +3271,20 @@ wsi_GetDrmDisplayEXT(VkPhysicalDevice physicalDevice, *pDisplay = wsi_display_connector_to_handle(connector); return VK_SUCCESS; } + +VKAPI_ATTR VkResult VKAPI_CALL +wsi_GetDrmDisplayEXT(VkPhysicalDevice physicalDevice, + int32_t drmFd, + uint32_t connectorId, + VkDisplayKHR *pDisplay) +{ + VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); + struct wsi_device *wsi_device = pdevice->wsi_device; + + return wsi_get_drm_display(physicalDevice, + wsi_device, + drmFd, + connectorId, + pDisplay); +} + diff --git a/src/vulkan/wsi/wsi_common_display.h b/src/vulkan/wsi/wsi_common_display.h index dd54b9b..cdfbda5 100644 --- a/src/vulkan/wsi/wsi_common_display.h +++ b/src/vulkan/wsi/wsi_common_display.h @@ -29,7 +29,112 @@ struct vk_sync; +VkResult +wsi_display_get_physical_device_display_properties( + VkPhysicalDevice physical_device, + struct wsi_device *wsi_device, + uint32_t *property_count, + VkDisplayPropertiesKHR *properties); + +VkResult +wsi_display_get_physical_device_display_properties2( + VkPhysicalDevice physical_device, + struct wsi_device *wsi_device, + uint32_t *pPropertyCount, + VkDisplayProperties2KHR *pProperties); + +VkResult +wsi_display_get_physical_device_display_plane_properties( + VkPhysicalDevice physical_device, + struct wsi_device *wsi_device, + uint32_t *property_count, + VkDisplayPlanePropertiesKHR *properties); + +VkResult +wsi_display_get_physical_device_display_plane_properties2( + VkPhysicalDevice physical_device, + struct wsi_device *wsi_device, + uint32_t *property_count, + VkDisplayPlaneProperties2KHR *properties); + +VkResult +wsi_display_get_display_plane_supported_displays( + VkPhysicalDevice physical_device, + struct wsi_device *wsi_device, + uint32_t plane_index, + uint32_t *display_count, + VkDisplayKHR *displays); + +VkResult +wsi_display_get_display_mode_properties(VkPhysicalDevice physical_device, + struct wsi_device *wsi_device, + VkDisplayKHR display, + uint32_t *property_count, + VkDisplayModePropertiesKHR *properties); + +VkResult +wsi_display_get_display_mode_properties2(VkPhysicalDevice physical_device, + struct wsi_device *wsi_device, + VkDisplayKHR display, + uint32_t *property_count, + VkDisplayModeProperties2KHR *properties); + +VkResult +wsi_display_create_display_mode(VkPhysicalDevice physical_device, + struct wsi_device *wsi_device, + VkDisplayKHR display, + const VkDisplayModeCreateInfoKHR *create_info, + const VkAllocationCallbacks *allocator, + VkDisplayModeKHR *mode); + +VkResult +wsi_get_display_plane_capabilities(VkPhysicalDevice physical_device, + struct wsi_device *wsi_device, + VkDisplayModeKHR mode_khr, + uint32_t plane_index, + VkDisplayPlaneCapabilitiesKHR *capabilities); + +VkResult +wsi_get_display_plane_capabilities2(VkPhysicalDevice physical_device, + struct wsi_device *wsi_device, + const VkDisplayPlaneInfo2KHR *pDisplayPlaneInfo, + VkDisplayPlaneCapabilities2KHR *capabilities); + +VkResult +wsi_create_display_surface(VkInstance instance, + const VkAllocationCallbacks *pAllocator, + const VkDisplaySurfaceCreateInfoKHR *pCreateInfo, + VkSurfaceKHR *pSurface); + +VkResult +wsi_release_display(VkPhysicalDevice physical_device, + struct wsi_device *wsi_device, + VkDisplayKHR display); + + +#ifdef VK_USE_PLATFORM_XLIB_XRANDR_EXT +VkResult +wsi_acquire_xlib_display(VkPhysicalDevice physical_device, + struct wsi_device *wsi_device, + Display *dpy, + VkDisplayKHR display); + +VkResult +wsi_get_randr_output_display(VkPhysicalDevice physical_device, + struct wsi_device *wsi_device, + Display *dpy, + RROutput output, + VkDisplayKHR *display); + +#endif /* VK_USE_PLATFORM_XLIB_XRANDR_EXT */ + /* VK_EXT_display_control */ +VkResult +wsi_display_power_control(VkDevice device, + struct wsi_device *wsi_device, + VkDisplayKHR display, + const VkDisplayPowerInfoEXT *display_power_info); + VkResult wsi_register_device_event(VkDevice device, struct wsi_device *wsi_device, @@ -47,4 +152,25 @@ wsi_register_display_event(VkDevice device, struct vk_sync **sync, int sync_fd); +VkResult +wsi_get_swapchain_counter(VkDevice device, + struct wsi_device *wsi_device, + VkSwapchainKHR swapchain, + VkSurfaceCounterFlagBitsEXT flag_bits, + uint64_t *value); + +/* VK_EXT_acquire_drm_display */ +VkResult +wsi_acquire_drm_display(VkPhysicalDevice pDevice, + struct wsi_device *wsi_device, + int drmFd, + VkDisplayKHR display); + +VkResult +wsi_get_drm_display(VkPhysicalDevice pDevice, + struct wsi_device *wsi_device, + int drmFd, + int connectorId, + VkDisplayKHR *display); + #endif diff --git a/src/vulkan/wsi/wsi_common_drm.c b/src/vulkan/wsi/wsi_common_drm.c index 728e451..0a78873 100644 --- a/src/vulkan/wsi/wsi_common_drm.c +++ b/src/vulkan/wsi/wsi_common_drm.c @@ -275,6 +275,7 @@ wsi_device_matches_drm_fd(const struct wsi_device *wsi, int drm_fd) if (ret) return false; +#if defined(VULKAN_WSI_USE_PCI_BUS_INFO) bool match = false; switch (fd_device->bustype) { case DRM_BUS_PCI: @@ -287,6 +288,9 @@ wsi_device_matches_drm_fd(const struct wsi_device *wsi, int drm_fd) default: break; } +#else + const bool match = true; +#endif drmFreeDevice(&fd_device); @@ -315,6 +319,7 @@ get_modifier_props(const struct wsi_image_info *info, uint64_t modifier) static VkResult wsi_create_native_image_mem(const struct wsi_swapchain *chain, const struct wsi_image_info *info, + int display_fd, struct wsi_image *image); static VkResult @@ -323,6 +328,7 @@ wsi_configure_native_image(const struct wsi_swapchain *chain, uint32_t num_modifier_lists, const uint32_t *num_modifiers, const uint64_t *const *modifiers, + int display_fd, struct wsi_image_info *info) { const struct wsi_device *wsi = chain->wsi; @@ -330,7 +336,8 @@ wsi_configure_native_image(const struct wsi_swapchain *chain, VkExternalMemoryHandleTypeFlags handle_type = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT; - VkResult result = wsi_configure_image(chain, pCreateInfo, handle_type, info); + VkResult result = wsi_configure_image(chain, pCreateInfo, handle_type, + display_fd, info); if (result != VK_SUCCESS) return result; @@ -467,6 +474,7 @@ fail_oom: static VkResult wsi_create_native_image_mem(const struct wsi_swapchain *chain, const struct wsi_image_info *info, + int display_fd, struct wsi_image *image) { const struct wsi_device *wsi = chain->wsi; @@ -480,9 +488,14 @@ wsi_create_native_image_mem(const struct wsi_swapchain *chain, .pNext = NULL, .implicit_sync = true, }; + const struct wsi_memory_allocate_info2 memory_wsi_info2 = { + .sType = VK_STRUCTURE_TYPE_WSI_MEMORY_ALLOCATE_INFO2_MESA, + .pNext = &memory_wsi_info, + .display_fd = display_fd, + }; const VkExportMemoryAllocateInfo memory_export_info = { .sType = VK_STRUCTURE_TYPE_EXPORT_MEMORY_ALLOCATE_INFO, - .pNext = &memory_wsi_info, + .pNext = &memory_wsi_info2, .handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, }; const VkMemoryDedicatedAllocateInfo memory_dedicated_info = { @@ -570,13 +583,14 @@ wsi_create_native_image_mem(const struct wsi_swapchain *chain, static VkResult wsi_create_prime_image_mem(const struct wsi_swapchain *chain, const struct wsi_image_info *info, + int display_fd, struct wsi_image *image) { const struct wsi_device *wsi = chain->wsi; VkResult result = wsi_create_buffer_image_mem(chain, info, image, VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT, - true); + true, display_fd); if (result != VK_SUCCESS) return result; @@ -602,11 +616,13 @@ wsi_configure_prime_image(UNUSED const struct wsi_swapchain *chain, const VkSwapchainCreateInfoKHR *pCreateInfo, bool use_modifier, wsi_memory_type_select_cb select_buffer_memory_type, + int display_fd, struct wsi_image_info *info) { VkResult result = wsi_configure_buffer_image(chain, pCreateInfo, WSI_PRIME_LINEAR_STRIDE_ALIGN, 4096, + display_fd, info); if (result != VK_SUCCESS) return result; @@ -637,6 +653,7 @@ VkResult wsi_drm_configure_image(const struct wsi_swapchain *chain, const VkSwapchainCreateInfoKHR *pCreateInfo, const struct wsi_drm_image_params *params, + int display_fd, struct wsi_image_info *info) { assert(params->base.image_type == WSI_IMAGE_TYPE_DRM); @@ -647,12 +664,14 @@ wsi_drm_configure_image(const struct wsi_swapchain *chain, params->same_gpu ? wsi_select_device_memory_type : prime_select_buffer_memory_type; return wsi_configure_prime_image(chain, pCreateInfo, use_modifier, - select_buffer_memory_type, info); + select_buffer_memory_type, + display_fd, info); } else { return wsi_configure_native_image(chain, pCreateInfo, params->num_modifier_lists, params->num_modifiers, params->modifiers, + display_fd, info); } } diff --git a/src/vulkan/wsi/wsi_common_private.h b/src/vulkan/wsi/wsi_common_private.h index fe3e855..631ea93 100644 --- a/src/vulkan/wsi/wsi_common_private.h +++ b/src/vulkan/wsi/wsi_common_private.h @@ -69,6 +69,7 @@ typedef uint32_t (*wsi_memory_type_select_cb)(const struct wsi_device *wsi, struct wsi_image_info { VkImageCreateInfo create; struct wsi_image_create_info wsi; + struct wsi_image_create_info2 wsi2; VkExternalMemoryImageCreateInfo ext_mem; VkImageFormatListCreateInfo format_list; VkImageDrmFormatModifierListCreateInfoEXT drm_mod_list; @@ -94,6 +95,7 @@ struct wsi_image_info { VkResult (*create_mem)(const struct wsi_swapchain *chain, const struct wsi_image_info *info, + int display_fd, struct wsi_image *image); VkResult (*finish_create)(const struct wsi_swapchain *chain, @@ -169,7 +171,7 @@ bool wsi_device_matches_drm_fd(const struct wsi_device *wsi, int drm_fd); void -wsi_wl_surface_destroy(VkIcdSurfaceBase *icd_surface, VkInstance _instance, +wsi_wl_surface_destroy(VkIcdSurfaceBase *icd_surface, const VkAllocationCallbacks *pAllocator); VkResult @@ -178,7 +180,8 @@ wsi_swapchain_init(const struct wsi_device *wsi, VkDevice device, const VkSwapchainCreateInfoKHR *pCreateInfo, const struct wsi_base_image_params *image_params, - const VkAllocationCallbacks *pAllocator); + const VkAllocationCallbacks *pAllocator, + int display_fd); enum VkPresentModeKHR wsi_swapchain_get_present_mode(struct wsi_device *wsi, @@ -203,6 +206,7 @@ VkResult wsi_drm_configure_image(const struct wsi_swapchain *chain, const VkSwapchainCreateInfoKHR *pCreateInfo, const struct wsi_drm_image_params *params, + int display_fd, struct wsi_image_info *info); bool @@ -220,7 +224,8 @@ wsi_create_buffer_image_mem(const struct wsi_swapchain *chain, const struct wsi_image_info *info, struct wsi_image *image, VkExternalMemoryHandleTypeFlags handle_types, - bool implicit_sync); + bool implicit_sync, + int display_fd); VkResult wsi_finish_create_buffer_image(const struct wsi_swapchain *chain, @@ -231,12 +236,14 @@ VkResult wsi_configure_buffer_image(UNUSED const struct wsi_swapchain *chain, const VkSwapchainCreateInfoKHR *pCreateInfo, uint32_t stride_align, uint32_t size_align, + int display_fd, struct wsi_image_info *info); VkResult wsi_configure_image(const struct wsi_swapchain *chain, const VkSwapchainCreateInfoKHR *pCreateInfo, VkExternalMemoryHandleTypeFlags handle_types, + int display_fd, struct wsi_image_info *info); void wsi_destroy_image_info(const struct wsi_swapchain *chain, @@ -244,6 +251,7 @@ wsi_destroy_image_info(const struct wsi_swapchain *chain, VkResult wsi_create_image(const struct wsi_swapchain *chain, const struct wsi_image_info *info, + int display_fd, struct wsi_image *image); void wsi_image_init(struct wsi_image *image); diff --git a/src/vulkan/wsi/wsi_common_wayland.c b/src/vulkan/wsi/wsi_common_wayland.c index 70b0042..bf242e1 100644 --- a/src/vulkan/wsi/wsi_common_wayland.c +++ b/src/vulkan/wsi/wsi_common_wayland.c @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include "drm-uapi/drm_fourcc.h" @@ -41,6 +43,8 @@ #include "vk_util.h" #include "wsi_common_entrypoints.h" #include "wsi_common_private.h" +#include "wsi_common_wayland.h" +#include "wayland-drm-client-protocol.h" #include "linux-dmabuf-unstable-v1-client-protocol.h" #include @@ -95,6 +99,7 @@ struct wsi_wl_display { struct wl_event_queue *queue; struct wl_shm *wl_shm; + struct wl_drm *wl_drm; struct zwp_linux_dmabuf_v1 *wl_dmabuf; struct zwp_linux_dmabuf_feedback_v1 *wl_dmabuf_feedback; @@ -104,6 +109,8 @@ struct wsi_wl_display { /* Formats populated by zwp_linux_dmabuf_v1 or wl_shm interfaces */ struct u_vector formats; + int fd; + bool authenticated; bool sw; @@ -530,6 +537,79 @@ wl_shm_format_for_vk_format(VkFormat vk_format, bool alpha) } } +static int +open_display_device(const char *name) +{ + int fd; + +#ifdef O_CLOEXEC + fd = open(name, O_RDWR | O_CLOEXEC); + if (fd != -1 || errno != EINVAL) { + return fd; + } +#endif + + fd = open(name, O_RDWR); + if (fd != -1) { + long flags = fcntl(fd, F_GETFD); + + if (flags != -1) { + if (!fcntl(fd, F_SETFD, flags | FD_CLOEXEC)) + return fd; + } + close (fd); + } + + return -1; +} + +static void +drm_handle_device(void *data, struct wl_drm *drm, const char *name) +{ + struct wsi_wl_display *display = data; + const int fd = open_display_device(name); + + if (fd != -1) { + if (drmGetNodeTypeFromFd(fd) != DRM_NODE_RENDER) { + drm_magic_t magic; + + if (drmGetMagic(fd, &magic)) { + close(fd); + return; + } + wl_drm_authenticate(drm, magic); + } else { + display->authenticated = true; + } + display->fd = fd; + } +} + +static void +drm_handle_format(void *data, struct wl_drm *drm, uint32_t wl_format) +{ +} + +static void +drm_handle_authenticated(void *data, struct wl_drm *drm) +{ + struct wsi_wl_display *display = data; + + display->authenticated = true; +} + +static void +drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t capabilities) +{ +} + +static const struct wl_drm_listener drm_listener = { + drm_handle_device, + drm_handle_format, + drm_handle_authenticated, + drm_handle_capabilities, +}; + static void dmabuf_handle_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf, uint32_t format) @@ -741,6 +821,15 @@ registry_handle_global(void *data, struct wl_registry *registry, return; } + if (strcmp(interface, "wl_drm") == 0) { + assert(display->wl_drm == NULL); + assert(version >= 2); + + display->wl_drm = + wl_registry_bind(registry, name, &wl_drm_interface, 2); + wl_drm_add_listener(display->wl_drm, &drm_listener, display); + } + if (strcmp(interface, zwp_linux_dmabuf_v1_interface.name) == 0 && version >= 3) { display->wl_dmabuf = wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface, @@ -769,12 +858,17 @@ wsi_wl_display_finish(struct wsi_wl_display *display) u_vector_finish(&display->formats); if (display->wl_shm) wl_shm_destroy(display->wl_shm); + if (display->wl_drm) + wl_drm_destroy(display->wl_drm); if (display->wl_dmabuf) zwp_linux_dmabuf_v1_destroy(display->wl_dmabuf); if (display->wl_display_wrapper) wl_proxy_wrapper_destroy(display->wl_display_wrapper); if (display->queue) wl_event_queue_destroy(display->queue); + + if (display->fd != -1) + close(display->fd); } static VkResult @@ -792,6 +886,7 @@ wsi_wl_display_init(struct wsi_wayland *wsi_wl, display->wsi_wl = wsi_wl; display->wl_display = wl_display; display->sw = sw; + display->fd = -1; display->queue = wl_display_create_queue(wl_display); if (!display->queue) { @@ -817,17 +912,13 @@ wsi_wl_display_init(struct wsi_wayland *wsi_wl, wl_registry_add_listener(registry, ®istry_listener, display); - /* Round-trip to get wl_shm and zwp_linux_dmabuf_v1 globals */ + /* Round-trip to get wl_shm, wl_drm and zwp_linux_dmabuf_v1 globals */ wl_display_roundtrip_queue(display->wl_display, display->queue); if (!display->wl_dmabuf && !display->wl_shm) { result = VK_ERROR_SURFACE_LOST_KHR; goto fail_registry; } - /* Caller doesn't expect us to query formats/modifiers, so return */ - if (!get_format_list) - goto out; - /* Default assumption */ display->same_gpu = true; @@ -858,14 +949,38 @@ wsi_wl_display_init(struct wsi_wayland *wsi_wl, } } - /* Round-trip again to get formats and modifiers */ - wl_display_roundtrip_queue(display->wl_display, display->queue); + if (display->wl_dmabuf && !display->wl_drm) { + result = VK_ERROR_SURFACE_LOST_KHR; + goto fail_registry; + } + + /* Round-trip to get display FD, formats and modifiers */ + if (display->wl_drm || get_format_list) + wl_display_roundtrip_queue(display->wl_display, display->queue); + + if (display->wl_drm && display->fd == -1) { + result = VK_ERROR_SURFACE_LOST_KHR; + goto fail_registry; + } + + if (display->wl_drm) { + wl_display_roundtrip_queue(display->wl_display, display->queue); + + if (!display->authenticated) { + result = VK_ERROR_SURFACE_LOST_KHR; + goto fail_registry; + } + } + + /* Caller doesn't expect us to query formats/modifiers, so return */ + if (!get_format_list) + goto out; if (wsi_wl->wsi->force_bgra8_unorm_first) { /* Find BGRA8_UNORM in the list and swap it to the first position if we * can find it. Some apps get confused if SRGB is first in the list. */ - struct wsi_wl_format *first_fmt = u_vector_head(&display->formats); + struct wsi_wl_format *first_fmt = u_vector_tail(&display->formats); struct wsi_wl_format *f, tmp_fmt; f = find_format(&display->formats, VK_FORMAT_B8G8R8A8_UNORM); if (f) { @@ -928,13 +1043,10 @@ wsi_wl_display_destroy(struct wsi_wl_display *display) vk_free(wsi->alloc, display); } -VKAPI_ATTR VkBool32 VKAPI_CALL -wsi_GetPhysicalDeviceWaylandPresentationSupportKHR(VkPhysicalDevice physicalDevice, - uint32_t queueFamilyIndex, - struct wl_display *wl_display) +VkBool32 +wsi_wl_get_presentation_support(struct wsi_device *wsi_device, + struct wl_display *wl_display) { - VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); - struct wsi_device *wsi_device = pdevice->wsi_device; struct wsi_wayland *wsi = (struct wsi_wayland *)wsi_device->wsi[VK_ICD_WSI_PLATFORM_WAYLAND]; @@ -947,6 +1059,18 @@ wsi_GetPhysicalDeviceWaylandPresentationSupportKHR(VkPhysicalDevice physicalDevi return ret == VK_SUCCESS; } +VKAPI_ATTR VkBool32 VKAPI_CALL +wsi_GetPhysicalDeviceWaylandPresentationSupportKHR(VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + struct wl_display *wl_display) +{ + VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); + struct wsi_device *wsi_device = pdevice->wsi_device; + + return wsi_wl_get_presentation_support(wsi_device, + wl_display); +} + static VkResult wsi_wl_surface_get_support(VkIcdSurfaceBase *surface, struct wsi_device *wsi_device, @@ -1149,10 +1273,9 @@ wsi_wl_surface_get_present_rectangles(VkIcdSurfaceBase *surface, } void -wsi_wl_surface_destroy(VkIcdSurfaceBase *icd_surface, VkInstance _instance, +wsi_wl_surface_destroy(VkIcdSurfaceBase *icd_surface, const VkAllocationCallbacks *pAllocator) { - VK_FROM_HANDLE(vk_instance, instance, _instance); struct wsi_wl_surface *wsi_wl_surface = wl_container_of((VkIcdSurfaceWayland *)icd_surface, wsi_wl_surface, base); @@ -1168,7 +1291,7 @@ wsi_wl_surface_destroy(VkIcdSurfaceBase *icd_surface, VkInstance _instance, dmabuf_feedback_fini(&wsi_wl_surface->pending_dmabuf_feedback); } - vk_free2(&instance->alloc, pAllocator, wsi_wl_surface); + vk_free(pAllocator, wsi_wl_surface); } static struct wsi_wl_format * @@ -1423,20 +1546,17 @@ fail: return result; } -VKAPI_ATTR VkResult VKAPI_CALL -wsi_CreateWaylandSurfaceKHR(VkInstance _instance, - const VkWaylandSurfaceCreateInfoKHR *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkSurfaceKHR *pSurface) +VkResult wsi_create_wl_surface(const VkAllocationCallbacks *allocator, + const VkWaylandSurfaceCreateInfoKHR *pCreateInfo, + VkSurfaceKHR *pSurface) { - VK_FROM_HANDLE(vk_instance, instance, _instance); struct wsi_wl_surface *wsi_wl_surface; VkIcdSurfaceWayland *surface; assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR); - wsi_wl_surface = vk_zalloc2(&instance->alloc, pAllocator, sizeof *wsi_wl_surface, - 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + wsi_wl_surface = vk_zalloc(allocator, sizeof *wsi_wl_surface, 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); if (wsi_wl_surface == NULL) return VK_ERROR_OUT_OF_HOST_MEMORY; @@ -1451,6 +1571,25 @@ wsi_CreateWaylandSurfaceKHR(VkInstance _instance, return VK_SUCCESS; } +VKAPI_ATTR VkResult VKAPI_CALL +wsi_CreateWaylandSurfaceKHR(VkInstance _instance, + const VkWaylandSurfaceCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkSurfaceKHR *pSurface) +{ + VK_FROM_HANDLE(vk_instance, instance, _instance); + const VkAllocationCallbacks *allocator; + + if (pAllocator) + allocator = pAllocator; + else + allocator = &instance->alloc; + + return wsi_create_wl_surface(allocator, + pCreateInfo, + pSurface); +} + static struct wsi_image * wsi_wl_swapchain_get_wsi_image(struct wsi_swapchain *wsi_chain, uint32_t image_index) @@ -1648,7 +1787,7 @@ wsi_wl_image_init(struct wsi_wl_swapchain *chain, VkResult result; result = wsi_create_image(&chain->base, &chain->base.image_info, - &image->base); + display->fd, &image->base); if (result != VK_SUCCESS) return result; @@ -1745,6 +1884,8 @@ wsi_wl_swapchain_chain_free(struct wsi_wl_swapchain *chain, wsi_swapchain_finish(&chain->base); + vk_free(pAllocator, (void *)chain->drm_modifiers); + vk_free(pAllocator, chain); } @@ -1801,8 +1942,10 @@ wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, wsi_wl_surface->chain = chain; result = wsi_wl_surface_init(wsi_wl_surface, wsi_device); - if (result != VK_SUCCESS) - goto fail; + if (result != VK_SUCCESS) { + vk_free(pAllocator, chain); + return result; + } enum wsi_wl_buffer_type buffer_type; struct wsi_base_image_params *image_params = NULL; @@ -1857,7 +2000,8 @@ wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, } result = wsi_swapchain_init(wsi_device, &chain->base, device, - pCreateInfo, image_params, pAllocator); + pCreateInfo, image_params, pAllocator, + chain->wsi_wl_surface->display->fd); if (result != VK_SUCCESS) { vk_free(pAllocator, chain); return result; @@ -1880,8 +2024,24 @@ wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, } else { chain->shm_format = wl_shm_format_for_vk_format(chain->vk_format, alpha); } + chain->num_drm_modifiers = num_drm_modifiers; - chain->drm_modifiers = drm_modifiers; + if (num_drm_modifiers > 0) { + uint64_t *modifiers; + + modifiers = vk_alloc(pAllocator, sizeof(*modifiers) * num_drm_modifiers, + 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + if (!modifiers) { + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail_modifiers_alloc; + } + + for (uint32_t i = 0; i < num_drm_modifiers; i++) + modifiers[i] = drm_modifiers[i]; + + chain->drm_modifiers = modifiers; + } + chain->fifo_ready = true; for (uint32_t i = 0; i < chain->base.image_count; i++) { @@ -1899,7 +2059,7 @@ wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, fail_image_init: wsi_wl_swapchain_images_free(chain); -fail: +fail_modifiers_alloc: wsi_wl_swapchain_chain_free(chain, pAllocator); return result; diff --git a/src/vulkan/wsi/wsi_common_wayland.h b/src/vulkan/wsi/wsi_common_wayland.h new file mode 100644 index 0000000..effba0e --- /dev/null +++ b/src/vulkan/wsi/wsi_common_wayland.h @@ -0,0 +1,35 @@ +/* + * Copyright © 2015 Intel Corporation + * + * 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. + */ +#ifndef WSI_COMMON_WAYLAND_H +#define WSI_COMMON_WAYLAND_H + +#include "wsi_common.h" + +VkBool32 +wsi_wl_get_presentation_support(struct wsi_device *wsi_device, + struct wl_display *wl_display); + +VkResult wsi_create_wl_surface(const VkAllocationCallbacks *pAllocator, + const VkWaylandSurfaceCreateInfoKHR *pCreateInfo, + VkSurfaceKHR *pSurface); +#endif diff --git a/src/vulkan/wsi/wsi_common_win32.c b/src/vulkan/wsi/wsi_common_win32.c index bef8102..7d16144 100644 --- a/src/vulkan/wsi/wsi_common_win32.c +++ b/src/vulkan/wsi/wsi_common_win32.c @@ -310,7 +310,7 @@ wsi_win32_image_init(VkDevice device_h, { assert(chain->base.use_buffer_blit); VkResult result = wsi_create_image(&chain->base, &chain->base.image_info, - &image->base); + -1, &image->base); if (result != VK_SUCCESS) return result; @@ -454,7 +454,7 @@ wsi_win32_surface_create_swapchain( VkResult result = wsi_swapchain_init(wsi_device, &chain->base, device, create_info, &image_params.base, - allocator); + allocator, -1); if (result != VK_SUCCESS) { vk_free(allocator, chain); return result; diff --git a/src/vulkan/wsi/wsi_common_x11.c b/src/vulkan/wsi/wsi_common_x11.c index a3c4538..9533622 100644 --- a/src/vulkan/wsi/wsi_common_x11.c +++ b/src/vulkan/wsi/wsi_common_x11.c @@ -52,6 +52,7 @@ #include "vk_enum_to_str.h" #include "wsi_common_entrypoints.h" #include "wsi_common_private.h" +#include "wsi_common_x11.h" #include "wsi_common_queue.h" #ifdef HAVE_SYS_SHM_H @@ -285,7 +286,7 @@ wsi_x11_connection_create(struct wsi_device *wsi_dev, ver_cookie = xcb_present_query_version(conn, 1, 2); ver_reply = xcb_present_query_version_reply(conn, ver_cookie, NULL); - has_present_v1_2 = + has_present_v1_2 = ver_reply != NULL && (ver_reply->major_version > 1 || ver_reply->minor_version >= 2); free(ver_reply); } @@ -543,14 +544,12 @@ visual_supported(xcb_visualtype_t *visual) visual->_class == XCB_VISUAL_CLASS_DIRECT_COLOR; } -VKAPI_ATTR VkBool32 VKAPI_CALL -wsi_GetPhysicalDeviceXcbPresentationSupportKHR(VkPhysicalDevice physicalDevice, - uint32_t queueFamilyIndex, - xcb_connection_t *connection, - xcb_visualid_t visual_id) +VkBool32 wsi_get_physical_device_xcb_presentation_support( + struct wsi_device *wsi_device, + uint32_t queueFamilyIndex, + xcb_connection_t *connection, + xcb_visualid_t visual_id) { - VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); - struct wsi_device *wsi_device = pdevice->wsi_device; struct wsi_x11_connection *wsi_conn = wsi_x11_get_connection(wsi_device, connection); @@ -568,6 +567,21 @@ wsi_GetPhysicalDeviceXcbPresentationSupportKHR(VkPhysicalDevice physicalDevice, return true; } +VKAPI_ATTR VkBool32 VKAPI_CALL +wsi_GetPhysicalDeviceXcbPresentationSupportKHR(VkPhysicalDevice physicalDevice, + uint32_t queueFamilyIndex, + xcb_connection_t *connection, + xcb_visualid_t visual_id) +{ + VK_FROM_HANDLE(vk_physical_device, pdevice, physicalDevice); + struct wsi_device *wsi_device = pdevice->wsi_device; + + return wsi_get_physical_device_xcb_presentation_support(wsi_device, + queueFamilyIndex, + connection, + visual_id); +} + VKAPI_ATTR VkBool32 VKAPI_CALL wsi_GetPhysicalDeviceXlibPresentationSupportKHR(VkPhysicalDevice physicalDevice, uint32_t queueFamilyIndex, @@ -876,19 +890,16 @@ x11_surface_get_present_rectangles(VkIcdSurfaceBase *icd_surface, return vk_outarray_status(&out); } -VKAPI_ATTR VkResult VKAPI_CALL -wsi_CreateXcbSurfaceKHR(VkInstance _instance, - const VkXcbSurfaceCreateInfoKHR *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkSurfaceKHR *pSurface) +VkResult wsi_create_xcb_surface(const VkAllocationCallbacks *allocator, + const VkXcbSurfaceCreateInfoKHR *pCreateInfo, + VkSurfaceKHR *pSurface) { - VK_FROM_HANDLE(vk_instance, instance, _instance); VkIcdSurfaceXcb *surface; assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR); - surface = vk_alloc2(&instance->alloc, pAllocator, sizeof *surface, 8, - VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + surface = vk_alloc(allocator, sizeof *surface, 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); if (surface == NULL) return VK_ERROR_OUT_OF_HOST_MEMORY; @@ -901,18 +912,34 @@ wsi_CreateXcbSurfaceKHR(VkInstance _instance, } VKAPI_ATTR VkResult VKAPI_CALL -wsi_CreateXlibSurfaceKHR(VkInstance _instance, - const VkXlibSurfaceCreateInfoKHR *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkSurfaceKHR *pSurface) +wsi_CreateXcbSurfaceKHR(VkInstance _instance, + const VkXcbSurfaceCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkSurfaceKHR *pSurface) { VK_FROM_HANDLE(vk_instance, instance, _instance); + const VkAllocationCallbacks *allocator; + + if (pAllocator) + allocator = pAllocator; + else + allocator = &instance->alloc; + + return wsi_create_xcb_surface(allocator, + pCreateInfo, + pSurface); +} + +VkResult wsi_create_xlib_surface(const VkAllocationCallbacks *allocator, + const VkXlibSurfaceCreateInfoKHR *pCreateInfo, + VkSurfaceKHR *pSurface) +{ VkIcdSurfaceXlib *surface; assert(pCreateInfo->sType == VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR); - surface = vk_alloc2(&instance->alloc, pAllocator, sizeof *surface, 8, - VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); + surface = vk_alloc(allocator, sizeof *surface, 8, + VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); if (surface == NULL) return VK_ERROR_OUT_OF_HOST_MEMORY; @@ -939,6 +966,25 @@ struct x11_image { uint8_t * shmaddr; }; +VKAPI_ATTR VkResult VKAPI_CALL +wsi_CreateXlibSurfaceKHR(VkInstance _instance, + const VkXlibSurfaceCreateInfoKHR *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkSurfaceKHR *pSurface) +{ + VK_FROM_HANDLE(vk_instance, instance, _instance); + const VkAllocationCallbacks *allocator; + + if (pAllocator) + allocator = pAllocator; + else + allocator = &instance->alloc; + + return wsi_create_xlib_surface(allocator, + pCreateInfo, + pSurface); +} + struct x11_swapchain { struct wsi_swapchain base; @@ -1660,6 +1706,7 @@ static VkResult x11_image_init(VkDevice device_h, struct x11_swapchain *chain, const VkSwapchainCreateInfoKHR *pCreateInfo, const VkAllocationCallbacks* pAllocator, + int display_fd, struct x11_image *image) { xcb_void_cookie_t cookie; @@ -1668,7 +1715,7 @@ x11_image_init(VkDevice device_h, struct x11_swapchain *chain, int fence_fd; result = wsi_create_image(&chain->base, &chain->base.image_info, - &image->base); + display_fd, &image->base); if (result != VK_SUCCESS) return result; @@ -2048,8 +2095,19 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, image_params = &drm_image_params.base; } + int display_fd; + if (wsi_device->sw) { + display_fd = -1; + } else { + xcb_screen_iterator_t screen_iter = + xcb_setup_roots_iterator(xcb_get_setup(conn)); + xcb_screen_t *screen = screen_iter.data; + + display_fd = wsi_dri3_open(conn, screen->root, None); + } + result = wsi_swapchain_init(wsi_device, &chain->base, device, pCreateInfo, - image_params, pAllocator); + image_params, pAllocator, display_fd); for (int i = 0; i < ARRAY_SIZE(modifiers); i++) vk_free(pAllocator, modifiers[i]); @@ -2140,11 +2198,16 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, uint32_t image = 0; for (; image < chain->base.image_count; image++) { result = x11_image_init(device, chain, pCreateInfo, pAllocator, - &chain->images[image]); + display_fd, &chain->images[image]); if (result != VK_SUCCESS) goto fail_init_images; } + if (display_fd >= 0) { + close(display_fd); + display_fd = -1; + } + /* Initialize queues for images in our swapchain. Possible queues are: * - Present queue: for images sent to the X server but not yet presented. * - Acquire queue: for images already presented but not yet released by the @@ -2222,6 +2285,9 @@ fail_register: fail_alloc: vk_free(pAllocator, chain); + if (display_fd >= 0) + close(display_fd); + return result; } diff --git a/src/vulkan/wsi/wsi_common_x11.h b/src/vulkan/wsi/wsi_common_x11.h new file mode 100644 index 0000000..e4b1e94 --- /dev/null +++ b/src/vulkan/wsi/wsi_common_x11.h @@ -0,0 +1,41 @@ +/* + * Copyright © 2015 Intel Corporation + * + * 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. + */ +#ifndef WSI_COMMON_X11_H +#define WSI_COMMON_X11_H + +#include "wsi_common.h" + +VkBool32 wsi_get_physical_device_xcb_presentation_support( + struct wsi_device *wsi_device, + uint32_t queueFamilyIndex, + xcb_connection_t* connection, + xcb_visualid_t visual_id); + +VkResult wsi_create_xcb_surface(const VkAllocationCallbacks *pAllocator, + const VkXcbSurfaceCreateInfoKHR *pCreateInfo, + VkSurfaceKHR *pSurface); + +VkResult wsi_create_xlib_surface(const VkAllocationCallbacks *pAllocator, + const VkXlibSurfaceCreateInfoKHR *pCreateInfo, + VkSurfaceKHR *pSurface); +#endif