diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index c9d324892..f826f5500 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -1,5 +1,8 @@ name: docs +permissions: + contents: read + on: push: paths-ignore: diff --git a/.github/workflows/freebsd.yml b/.github/workflows/freebsd.yml index 2c741ffda..fadd66220 100644 --- a/.github/workflows/freebsd.yml +++ b/.github/workflows/freebsd.yml @@ -1,15 +1,18 @@ name: freebsd +permissions: + contents: read + on: [push, pull_request] jobs: freebsd: - runs-on: macos-12 + runs-on: ubuntu-latest steps: - name: 'Checkout' uses: actions/checkout@v4 - name: 'Install prerequisites and build' - uses: vmactions/freebsd-vm@v0 + uses: vmactions/freebsd-vm@v1 with: prepare: | pkg install -y meson pkgconf libdrm libXext libXfixes wayland diff --git a/.github/workflows/ghpages.yml b/.github/workflows/ghpages.yml index 732cdbcd4..28afcd594 100644 --- a/.github/workflows/ghpages.yml +++ b/.github/workflows/ghpages.yml @@ -47,11 +47,11 @@ jobs: - name: 'Upload the artifacts' if: github.ref_name == env.GIT_LATEST_TAG - uses: actions/upload-pages-artifact@v2 + uses: actions/upload-pages-artifact@v3 with: path: "_build/doc/html-out" - name: 'Deploy to GitHub Pages' if: github.ref_name == env.GIT_LATEST_TAG id: deployment - uses: actions/deploy-pages@v2 + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/style.yml b/.github/workflows/style.yml index 4865a7b7f..71b76089c 100644 --- a/.github/workflows/style.yml +++ b/.github/workflows/style.yml @@ -1,5 +1,8 @@ name: style +permissions: + contents: read + on: [push, pull_request] jobs: diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 7cfc156f3..f81a204ab 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -1,5 +1,8 @@ name: ubuntu +permissions: + contents: read + on: [push, pull_request] env: diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index c3324bbe2..df3ce5679 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -1,5 +1,8 @@ name: windows +permissions: + contents: read + on: [push, pull_request] jobs: @@ -9,7 +12,7 @@ jobs: - name: 'Checkout' uses: actions/checkout@v4 - name: 'Setup Python' - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.x' - name: 'Install Meson' @@ -24,6 +27,27 @@ jobs: - name: 'Install' run: meson install -C _build + windows-msvc-debug: + runs-on: windows-2022 + steps: + - name: 'Checkout' + uses: actions/checkout@v4 + - name: 'Setup Python' + uses: actions/setup-python@v5 + with: + python-version: '3.x' + - name: 'Install Meson' + run: pip install meson + - name: 'Enter DevShell' + run: '.github\workflows\EnterDevShell.ps1 ${{ inputs.architecture }}' + shell: pwsh + - name: 'Configure with meson' + run: meson setup _build -D werror=true -D buildtype=debug + - name: 'Build' + run: meson compile -C _build + - name: 'Install' + run: meson install -C _build + windows-mingw: runs-on: windows-2022 env: diff --git a/NEWS b/NEWS index b327aa481..ed5eb1e6d 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,28 @@ -libva NEWS -- summary of user visible changes. 2023-09-14 -Copyright (C) 2009-2023 Intel Corporation +libva NEWS -- summary of user visible changes. 2024-03-12 +Copyright (C) 2009-2024 Intel Corporation + +version 2.21.0 - 12.Mar.2024 +* va: Add allow_content_tools and force_intger_mv to AV1 enc +* va: add VASurfaceAttribAlignmentSize +* va: Re-add drm_state and fd checks to VA_DRM_GetDriverNames +* va: export symbol vaGetLibFunc for Windows +* va: Add PRIME3 defination and correct the value +* va: add driver name map for new intel KMD xe +* va: export symbol vaMapBuffer2 for Windows +* va: add new interface vaMapBuffer2 for map operation optimization +* va: Add VAConfigAttribEncMaxTileRows and VAConfigAttribEncMaxTileCols +* va: fix handling when all wayland backends fail +* va_trace:add return value trace for vaPutSurfaces +* ci: harden permissions for all github workflows +* ci: update to vmactions/freebsd-vm from v0 to v1 +* ci: windows.yml: Add windows-msvc-debug +* meson: create dist archives suitable for building with configure, too +* autogen.sh: successfully detect if the autoreconf program is installed +* build(deps): bump actions/upload-pages-artifact from 2 to 3 +* build(deps): bump actions/deploy-pages from 3 to 4 +* build(deps): bump actions/setup-python from 4 to 5 +* build(deps): bump actions/deploy-pages from 2 to 3 +* win32: Fix debug build break version 2.20.0 - 14.Sep.2023 * va: drop no longer applicable vaGetDriverNames check diff --git a/autogen.sh b/autogen.sh index af7d03c30..aa9997682 100755 --- a/autogen.sh +++ b/autogen.sh @@ -23,6 +23,13 @@ PROJECT="libva" +# for `meson dist` +if test -z "$srcdir"; then + srcdir="$MESON_PROJECT_DIST_ROOT" + test -n "$srcdir" || srcdir="$MESON_DIST_ROOT" + test -n "$srcdir" && NOCONFIGURE=1 +fi + test -n "$srcdir" || srcdir="`dirname \"$0\"`" test -n "$srcdir" || srcdir=. @@ -36,7 +43,7 @@ cd "$srcdir" mkdir -p m4 -AUTORECONF=`which autoreconf` +AUTORECONF=`command -v autoreconf` if test -z $AUTORECONF; then echo "*** No autoreconf found ***" exit 1 diff --git a/configure.ac b/configure.ac index bb8b97a8b..c566063b1 100644 --- a/configure.ac +++ b/configure.ac @@ -27,7 +27,7 @@ # - reset micro version to zero when minor version is incremented # - reset minor version to zero when major version is incremented m4_define([va_api_major_version], [1]) -m4_define([va_api_minor_version], [21]) +m4_define([va_api_minor_version], [22]) m4_define([va_api_micro_version], [0]) m4_define([va_api_version], @@ -75,7 +75,8 @@ m4_define([libva_lt_age], [m4_eval(libva_binary_age - libva_interface_age)]) # libdrm minimun version requirement -m4_define([libdrm_version], [2.4.60]) +# 2.4.75 for drmGetDevices2 +m4_define([libdrm_version], [2.4.75]) # Wayland minimum version number # 1.11.0 for wl_proxy_create_wrapper diff --git a/meson.build b/meson.build index 6acf90676..9e42ab40c 100644 --- a/meson.build +++ b/meson.build @@ -7,7 +7,7 @@ # - reset micro version to zero when VA-API major or minor version is changed project( 'libva', 'c', - version : '2.21.0.1', + version : '2.22.0.1', meson_version : '>= 0.53.0', default_options : [ 'warning_level=1', 'buildtype=debugoptimized' ]) @@ -19,7 +19,7 @@ project( # - reset micro version to zero when minor version is incremented # - reset minor version to zero when major version is incremented va_api_major_version = 1 -va_api_minor_version = 21 +va_api_minor_version = 22 va_api_micro_version = 0 va_api_version = '@0@.@1@.@2@'.format(va_api_major_version, @@ -85,7 +85,7 @@ cc = meson.get_compiler('c') dl_dep = cc.find_library('dl', required : false) WITH_DRM = not get_option('disable_drm') and (host_machine.system() != 'windows') -libdrm_dep = dependency('libdrm', version : '>= 2.4.60', required : (host_machine.system() != 'windows')) +libdrm_dep = dependency('libdrm', version : '>= 2.4.75', required : (host_machine.system() != 'windows')) WITH_X11 = false if get_option('with_x11') != 'no' @@ -157,3 +157,5 @@ doxygen = find_program('doxygen', required: false) if get_option('enable_docs') and doxygen.found() subdir('doc') endif + +meson.add_dist_script('./autogen.sh') diff --git a/va/drm/va_drm_utils.c b/va/drm/va_drm_utils.c index ec550a73b..e6a477fff 100644 --- a/va/drm/va_drm_utils.c +++ b/va/drm/va_drm_utils.c @@ -59,6 +59,7 @@ VA_DRM_GetDriverNames(VADriverContextP ctx, char **drivers, unsigned *num_driver const char * const drm_driver; const char * const va_driver[MAX_NAMES]; } map[] = { + { "xe", { "iHD" } }, { "i915", { "iHD", "i965" } }, // Intel Media and OTC GenX { "pvrsrvkm", { "pvr" } }, // Intel UMG PVR { "radeon", { "r600", "radeonsi" } }, // Mesa Gallium @@ -71,6 +72,9 @@ VA_DRM_GetDriverNames(VADriverContextP ctx, char **drivers, unsigned *num_driver char *drm_driver; unsigned count = 0; + if (!drm_state || drm_state->fd < 0) + return VA_STATUS_ERROR_INVALID_DISPLAY; + drm_driver = va_DRM_GetDrmDriverName(drm_state->fd); if (!drm_driver) return VA_STATUS_ERROR_UNKNOWN; diff --git a/va/libva.def b/va/libva.def index 017343813..18288cb4a 100644 --- a/va/libva.def +++ b/va/libva.def @@ -32,6 +32,7 @@ EXPORTS vaGetDisplayAttributes vaGetImage vaMapBuffer + vaMapBuffer2 vaMaxNumDisplayAttributes vaMaxNumImageFormats vaMaxNumSubpictureFormats @@ -83,3 +84,4 @@ EXPORTS vaStatusStr vaSyncSurface2 vaDisplayIsValid + vaGetLibFunc diff --git a/va/meson.build b/va/meson.build index fa402b0ca..cca645f03 100644 --- a/va/meson.build +++ b/va/meson.build @@ -151,10 +151,11 @@ if WITH_X11 libva_dri_headers = [ 'x11/va_dri2.h', + 'x11/va_dri3.h', 'x11/va_dricommon.h', ] - libva_x11_headers = ['va_x11.h'] + libva_dri_headers + libva_x11_headers = ['va_x11.h'] + libva_dri_headers + ['va_trace.h'] libva_headers_subproject += libva_dri_headers @@ -227,6 +228,7 @@ endif if WITH_WAYLAND libva_wayland_sources = [ 'wayland/va_wayland.c', + 'wayland/va_wayland_linux_dmabuf.c', 'wayland/va_wayland_drm.c', 'wayland/va_wayland_emgd.c', 'drm/va_drm_utils.c', @@ -240,24 +242,31 @@ if WITH_WAYLAND libva_headers_subproject += libva_wayland_headers libva_wayland_headers_priv = [ + 'wayland/va_wayland_linux_dmabuf.h', 'wayland/va_wayland_drm.h', 'wayland/va_wayland_emgd.h', 'wayland/va_wayland_private.h', ] - protocol_files = [ - custom_target( - 'wayland-drm-client-protocol.c', - output : 'wayland-drm-client-protocol.c', - input : 'wayland/wayland-drm.xml', - command : [wl_scanner, 'private-code', '@INPUT@', '@OUTPUT@']), - - custom_target( - 'wayland-drm-client-protocol.h', - output : 'wayland-drm-client-protocol.h', - input : 'wayland/wayland-drm.xml', + # XXX: grab linux-dmabuf-v1.xml from wayland-protocols + protocols = { + 'wayland-drm': 'wayland/wayland-drm.xml', + 'linux-dmabuf-v1': 'wayland/linux-dmabuf-v1.xml', + } + + protocol_files = [] + foreach name, xml : protocols + protocol_files += custom_target( + name + '-client-protocol.c', + output : name + '-client-protocol.c', + input : xml, + command : [wl_scanner, 'private-code', '@INPUT@', '@OUTPUT@']) + protocol_files += custom_target( + name + '-client-protocol.h', + output : name + '-client-protocol.h', + input : xml, command : [wl_scanner, 'client-header', '@INPUT@', '@OUTPUT@']) - ] + endforeach install_headers(libva_wayland_headers, subdir : 'va') diff --git a/va/va.c b/va/va.c index 920b76c50..6d6ed1810 100644 --- a/va/va.c +++ b/va/va.c @@ -1430,14 +1430,43 @@ VAStatus vaMapBuffer( ) { VADriverContextP ctx; - VAStatus va_status; + VAStatus va_status = VA_STATUS_SUCCESS; + + CHECK_DISPLAY(dpy); + ctx = CTX(dpy); + + if (ctx->vtable->vaMapBuffer2) { + va_status = ctx->vtable->vaMapBuffer2(ctx, buf_id, pbuf, VA_MAPBUFFER_FLAG_DEFAULT); + } else if (ctx->vtable->vaMapBuffer) { + va_status = ctx->vtable->vaMapBuffer(ctx, buf_id, pbuf); + } + + VA_TRACE_ALL(va_TraceMapBuffer, dpy, buf_id, pbuf, VA_MAPBUFFER_FLAG_DEFAULT); + VA_TRACE_RET(dpy, va_status); + + return va_status; +} + +VAStatus vaMapBuffer2( + VADisplay dpy, + VABufferID buf_id, /* in */ + void **pbuf, /* out */ + uint32_t flags /*in */ +) +{ + VADriverContextP ctx; + VAStatus va_status = VA_STATUS_SUCCESS; CHECK_DISPLAY(dpy); ctx = CTX(dpy); - va_status = ctx->vtable->vaMapBuffer(ctx, buf_id, pbuf); + if (ctx->vtable->vaMapBuffer2) { + va_status = ctx->vtable->vaMapBuffer2(ctx, buf_id, pbuf, flags); + } else if (ctx->vtable->vaMapBuffer) { + va_status = ctx->vtable->vaMapBuffer(ctx, buf_id, pbuf); + } - VA_TRACE_ALL(va_TraceMapBuffer, dpy, buf_id, pbuf); + VA_TRACE_ALL(va_TraceMapBuffer, dpy, buf_id, pbuf, flags); VA_TRACE_RET(dpy, va_status); return va_status; diff --git a/va/va.h b/va/va.h index 311ff61a1..d349704e8 100644 --- a/va/va.h +++ b/va/va.h @@ -1036,6 +1036,20 @@ typedef enum { * The value returned uses the VAConfigAttribValEncPerBlockControl type. */ VAConfigAttribEncPerBlockControl = 55, + /** + * \brief Maximum number of tile rows. Read-only. + * + * This attribute determines the maximum number of tile + * rows supported for encoding with tile support. + */ + VAConfigAttribEncMaxTileRows = 56, + /** + * \brief Maximum number of tile cols. Read-only. + * + * This attribute determines the maximum number of tile + * columns supported for encoding with tile support. + */ + VAConfigAttribEncMaxTileCols = 57, /**@}*/ VAConfigAttribTypeMax } VAConfigAttribType; @@ -1685,6 +1699,15 @@ typedef enum { * when importing an existing buffer. */ VASurfaceAttribDRMFormatModifiers, + /** \brief width and height log2 aligment in pixels (int, read-only) + * + * For special HW requirement used in some codecs, if + * VASurfaceAttribAlignmentSize is not implemented in the driver, then + * the surface_width and surface_height should keep the original logic + * without any modification, this is an add-on requirement to + * surface_width and surface_height. + */ + VASurfaceAttribAlignmentSize, /** \brief Number of surface attributes. */ VASurfaceAttribCount } VASurfaceAttribType; @@ -1713,6 +1736,20 @@ typedef struct _VASurfaceAttrib { /** \brief User pointer memory type is supported. */ #define VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR 0x00000004 /**@}*/ +/** + * \brief VASurfaceAttribAlignmentStruct structure for + * the VASurfaceAttribAlignmentSize attribute. + */ +typedef union _VASurfaceAttribAlignmentStruct { + struct { + /** \brief log2 width aligment */ + uint32_t log2_width_alignment : 4; + /** \brief log2 height aligment */ + uint32_t log2_height_alignment : 4; + uint32_t reserved : 24; + } bits; + uint32_t value; +} VASurfaceAttribAlignmentStruct; /** * \brief VASurfaceAttribExternalBuffers structure for @@ -3880,6 +3917,28 @@ VAStatus vaMapBuffer( void **pbuf /* out */ ); +/** + * Map data store of the buffer into the client's address space + * this interface could be used to convey the operation hint + * backend driver could use these hint to optimize the implementations + */ + +/** \brief VA_MAPBUFFER_FLAG_DEFAULT is used when there are no flag specified + * same as VA_MAPBUFFER_FLAG_READ | VA_MAPBUFFER_FLAG_WRITE. + */ +#define VA_MAPBUFFER_FLAG_DEFAULT 0 +/** \brief application will read the surface after map */ +#define VA_MAPBUFFER_FLAG_READ 1 +/** \brief application will write the surface after map */ +#define VA_MAPBUFFER_FLAG_WRITE 2 + +VAStatus vaMapBuffer2( + VADisplay dpy, + VABufferID buf_id, /* in */ + void **pbuf, /* out */ + uint32_t flags /* in */ +); + /** * After client making changes to a mapped data store, it needs to * "Unmap" it to let the server know that the data is ready to be diff --git a/va/va_backend.h b/va/va_backend.h index 51e80d058..d62e4ce75 100644 --- a/va/va_backend.h +++ b/va/va_backend.h @@ -504,8 +504,16 @@ struct VADriverVTable { VACopyObject *src, /* in */ VACopyOption option /* in */ ); + + VAStatus(*vaMapBuffer2)( + VADriverContextP ctx, + VABufferID buf_id, /* in */ + void **pbuf, /* out */ + uint32_t flags /* in */ + ); /** \brief Reserved bytes for future use, must be zero */ - unsigned long reserved[54]; + unsigned long reserved[53]; + }; struct VADriverContext { diff --git a/va/va_drmcommon.h b/va/va_drmcommon.h index 0bda45874..4f93f8cf2 100644 --- a/va/va_drmcommon.h +++ b/va/va_drmcommon.h @@ -28,6 +28,7 @@ #define VA_DRM_COMMON_H #include +#include /** \brief DRM authentication type. */ @@ -86,6 +87,11 @@ struct drm_state { * Used with VADRMPRIMESurfaceDescriptor. */ #define VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2 0x40000000 +/** \brief DRM PRIME3 memory type + * + * Used with VADRMPRIME3SurfaceDescriptor. + */ +#define VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_3 0x08000000 /** * \brief External buffer descriptor for a DRM PRIME surface. @@ -158,6 +164,55 @@ typedef struct _VADRMPRIMESurfaceDescriptor { } layers[4]; } VADRMPRIMESurfaceDescriptor; +/** + * \brief External buffer descriptor for a DRM PRIME surface with flags + * + * This structure is an extention for VADRMPRIMESurfaceDescriptor, + * it has the same behavior as if used with VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2. + * + * The field "flags" is added, see "Surface external buffer descriptor flags". + * To use this structure, use VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_3 instead. + */ +typedef struct _VADRMPRIME3SurfaceDescriptor { + /** Pixel format fourcc of the whole surface (VA_FOURCC_*). */ + uint32_t fourcc; + /** Width of the surface in pixels. */ + uint32_t width; + /** Height of the surface in pixels. */ + uint32_t height; + /** Number of distinct DRM objects making up the surface. */ + uint32_t num_objects; + /** Description of each object. */ + struct { + /** DRM PRIME file descriptor for this object. */ + int fd; + /** Total size of this object (may include regions which are + * not part of the surface). */ + uint32_t size; + /** Format modifier applied to this object. */ + uint64_t drm_format_modifier; + } objects[4]; + /** Number of layers making up the surface. */ + uint32_t num_layers; + /** Description of each layer in the surface. */ + struct { + /** DRM format fourcc of this layer (DRM_FOURCC_*). */ + uint32_t drm_format; + /** Number of planes in this layer. */ + uint32_t num_planes; + /** Index in the objects array of the object containing each + * plane. */ + uint32_t object_index[4]; + /** Offset within the object of each plane. */ + uint32_t offset[4]; + /** Pitch of each plane. */ + uint32_t pitch[4]; + } layers[4]; + /** \brief flags. See "Surface external buffer descriptor flags". */ + uint32_t flags; + /** reserved bytes, must be zero */ + uint32_t reserved[VA_PADDING_MEDIUM - 1]; +} VADRMPRIME3SurfaceDescriptor; /** * \brief List of DRM format modifiers. * diff --git a/va/va_enc_av1.h b/va/va_enc_av1.h index e47836b63..d96c3f224 100644 --- a/va/va_enc_av1.h +++ b/va/va_enc_av1.h @@ -656,8 +656,12 @@ typedef struct _VAEncPictureParameterBufferAV1 { * Otherwise disable palette encoding. */ uint32_t palette_mode_enable : 1; + /** \brief Corresponds to AV1 syntax element of the same name. */ + uint32_t allow_screen_content_tools : 1; + /** \brief Corresponds to AV1 syntax element of the same name. */ + uint32_t force_integer_mv : 1; /** \brief Reserved bytes for future use, must be zero. */ - uint32_t reserved : 18; + uint32_t reserved : 16; } bits; uint32_t value; } picture_flags; diff --git a/va/va_str.c b/va/va_str.c index 99df94877..3d96f9b66 100644 --- a/va/va_str.c +++ b/va/va_str.c @@ -149,6 +149,8 @@ const char *vaConfigAttribTypeStr(VAConfigAttribType configAttribType) TOSTR(VAConfigAttribEncAV1Ext1); TOSTR(VAConfigAttribEncAV1Ext2); TOSTR(VAConfigAttribEncPerBlockControl); + TOSTR(VAConfigAttribEncMaxTileRows); + TOSTR(VAConfigAttribEncMaxTileCols); case VAConfigAttribTypeMax: break; } diff --git a/va/va_trace.c b/va/va_trace.c index 7d281db18..365708cff 100644 --- a/va/va_trace.c +++ b/va/va_trace.c @@ -1255,6 +1255,31 @@ static void va_TraceSurfaceAttributes( va_TraceMsg(trace_ctx, "\t\t\t\tlayers[%d].pitch[%d]=0x%d\n", j, k, tmp->layers[j].pitch[k]); } } + } else if (memtype == VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_3) { + VADRMPRIME3SurfaceDescriptor *tmp = (VADRMPRIME3SurfaceDescriptor *) p->value.value.p; + uint32_t j, k; + + va_TraceMsg(trace_ctx, "\t\t--VADRMPRIME3SurfaceDescriptor\n"); + va_TraceMsg(trace_ctx, "\t\t pixel_format=0x%08x\n", tmp->fourcc); + va_TraceMsg(trace_ctx, "\t\t width=%d\n", tmp->width); + va_TraceMsg(trace_ctx, "\t\t height=%d\n", tmp->height); + va_TraceMsg(trace_ctx, "\t\t num_objects=0x%08x\n", tmp->num_objects); + va_TraceMsg(trace_ctx, "\t\t flags=0x%08x\n", tmp->flags); + for (j = 0; j < tmp->num_objects && tmp->num_objects <= 4; j++) { + va_TraceMsg(trace_ctx, "\t\t\tobjects[%d].fd=%d\n", j, tmp->objects[j].fd); + va_TraceMsg(trace_ctx, "\t\t\tobjects[%d].size=%d\n", j, tmp->objects[j].size); + va_TraceMsg(trace_ctx, "\t\t\tobjects[%d].drm_format_modifier=%llx\n", j, tmp->objects[j].drm_format_modifier); + } + va_TraceMsg(trace_ctx, "\t\t num_layers=%d\n", tmp->num_layers); + for (j = 0; j < tmp->num_layers && tmp->num_layers <= 4; j++) { + va_TraceMsg(trace_ctx, "\t\t\tlayers[%d].drm_format=0x%08x\n", j, tmp->layers[j].drm_format); + va_TraceMsg(trace_ctx, "\t\t\tlayers[%d].num_planes=0x%d\n", j, tmp->layers[j].num_planes); + for (k = 0; k < 4; k++) { + va_TraceMsg(trace_ctx, "\t\t\t\tlayers[%d].object_index[%d]=0x%d\n", j, k, tmp->layers[j].object_index[k]); + va_TraceMsg(trace_ctx, "\t\t\t\tlayers[%d].offset[%d]=0x%d\n", j, k, tmp->layers[j].offset[k]); + va_TraceMsg(trace_ctx, "\t\t\t\tlayers[%d].pitch[%d]=0x%d\n", j, k, tmp->layers[j].pitch[k]); + } + } #if defined(_WIN32) } else if (memtype == VA_SURFACE_ATTRIB_MEM_TYPE_NTHANDLE) { va_TraceMsg(trace_ctx, "\t\t--Win32 %d surfaces\n", num_surfaces); @@ -1740,7 +1765,8 @@ static void va_TraceCodedBufferIVFHeader(struct trace_context *trace_ctx, void * void va_TraceMapBuffer( VADisplay dpy, VABufferID buf_id, /* in */ - void **pbuf /* out */ + void **pbuf, /* out */ + uint32_t flags /* in */ ) { VABufferType type; @@ -1761,6 +1787,7 @@ void va_TraceMapBuffer( TRACE_FUNCNAME(idx); va_TraceMsg(trace_ctx, "\tbuf_id=0x%x\n", buf_id); va_TraceMsg(trace_ctx, "\tbuf_type=%s\n", vaBufferTypeStr(type)); + va_TraceMsg(trace_ctx, "\tflags = 0x%x\n", flags); if ((pbuf == NULL) || (*pbuf == NULL)) return; @@ -6334,7 +6361,7 @@ void va_TraceExportSurfaceHandle( va_TraceMsg(trace_ctx, "\tmemType = 0x%08x\n", memType); va_TraceMsg(trace_ctx, "\tflags = 0x%08x\n", flags); - if (memType != VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2) { + if (memType != VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2 && memType != VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_3) { DPY2TRACE_VIRCTX_EXIT(pva_trace); return; } diff --git a/va/va_trace.h b/va/va_trace.h index aeb1884a9..05637afac 100644 --- a/va/va_trace.h +++ b/va/va_trace.h @@ -353,7 +353,8 @@ DLL_HIDDEN void va_TraceMapBuffer( VADisplay dpy, VABufferID buf_id, /* in */ - void **pbuf /* out */ + void **pbuf, /* out */ + uint32_t flags /* in */ ); @@ -474,7 +475,6 @@ void va_TracePutSurface( unsigned int flags /* de-interlacing flags */ ); -DLL_HIDDEN void va_TraceStatus(VADisplay dpy, const char * funcName, VAStatus status); /** \brief va_TraceEvent diff --git a/va/wayland/Makefile.am b/va/wayland/Makefile.am index d1638870a..1f61aa4d2 100644 --- a/va/wayland/Makefile.am +++ b/va/wayland/Makefile.am @@ -29,6 +29,7 @@ AM_CPPFLAGS = \ source_c = \ va_wayland.c \ + va_wayland_linux_dmabuf.c \ va_wayland_drm.c \ va_wayland_emgd.c \ ../drm/va_drm_utils.c \ @@ -40,16 +41,19 @@ source_h = \ $(NULL) source_h_priv = \ + va_wayland_linux_dmabuf.h \ va_wayland_drm.h \ va_wayland_emgd.h \ va_wayland_private.h \ $(NULL) protocol_source_c = \ + linux-dmabuf-v1-client-protocol.c \ wayland-drm-client-protocol.c \ $(NULL) protocol_source_h = \ + linux-dmabuf-v1-client-protocol.h \ wayland-drm-client-protocol.h \ $(NULL) @@ -61,6 +65,7 @@ noinst_HEADERS = $(source_h_priv) # Wayland protocol va_wayland_drm.c: $(protocol_source_h) +va_wayland_linux_dmabuf.c: $(protocol_source_h) %-client-protocol.h : %.xml $(AM_V_GEN)$(WAYLAND_SCANNER) client-header < $< > $@ %-client-protocol.c : %.xml @@ -68,6 +73,7 @@ va_wayland_drm.c: $(protocol_source_h) EXTRA_DIST = \ wayland-drm.xml \ + linux-dmabuf-v1.xml \ $(NULL) BUILT_SOURCES = $(protocol_source_h) $(protocol_source_c) diff --git a/va/wayland/linux-dmabuf-v1.xml b/va/wayland/linux-dmabuf-v1.xml new file mode 100644 index 000000000..38e06f5b6 --- /dev/null +++ b/va/wayland/linux-dmabuf-v1.xml @@ -0,0 +1,585 @@ + + + + + Copyright © 2014, 2015 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. + + + + + Following the interfaces from: + https://www.khronos.org/registry/egl/extensions/EXT/EGL_EXT_image_dma_buf_import.txt + https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_image_dma_buf_import_modifiers.txt + and the Linux DRM sub-system's AddFb2 ioctl. + + This interface offers ways to create generic dmabuf-based wl_buffers. + + Clients can use the get_surface_feedback request to get dmabuf feedback + for a particular surface. If the client wants to retrieve feedback not + tied to a surface, they can use the get_default_feedback request. + + The following are required from clients: + + - Clients must ensure that either all data in the dma-buf is + coherent for all subsequent read access or that coherency is + correctly handled by the underlying kernel-side dma-buf + implementation. + + - Don't make any more attachments after sending the buffer to the + compositor. Making more attachments later increases the risk of + the compositor not being able to use (re-import) an existing + dmabuf-based wl_buffer. + + The underlying graphics stack must ensure the following: + + - The dmabuf file descriptors relayed to the server will stay valid + for the whole lifetime of the wl_buffer. This means the server may + at any time use those fds to import the dmabuf into any kernel + sub-system that might accept it. + + However, when the underlying graphics stack fails to deliver the + promise, because of e.g. a device hot-unplug which raises internal + errors, after the wl_buffer has been successfully created the + compositor must not raise protocol errors to the client when dmabuf + import later fails. + + To create a wl_buffer from one or more dmabufs, a client creates a + zwp_linux_dmabuf_params_v1 object with a zwp_linux_dmabuf_v1.create_params + request. All planes required by the intended format are added with + the 'add' request. Finally, a 'create' or 'create_immed' request is + issued, which has the following outcome depending on the import success. + + The 'create' request, + - on success, triggers a 'created' event which provides the final + wl_buffer to the client. + - on failure, triggers a 'failed' event to convey that the server + cannot use the dmabufs received from the client. + + For the 'create_immed' request, + - on success, the server immediately imports the added dmabufs to + create a wl_buffer. No event is sent from the server in this case. + - on failure, the server can choose to either: + - terminate the client by raising a fatal error. + - mark the wl_buffer as failed, and send a 'failed' event to the + client. If the client uses a failed wl_buffer as an argument to any + request, the behaviour is compositor implementation-defined. + + For all DRM formats and unless specified in another protocol extension, + pre-multiplied alpha is used for pixel values. + + Unless specified otherwise in another protocol extension, implicit + synchronization is used. In other words, compositors and clients must + wait and signal fences implicitly passed via the DMA-BUF's reservation + mechanism. + + + + + Objects created through this interface, especially wl_buffers, will + remain valid. + + + + + + This temporary object is used to collect multiple dmabuf handles into + a single batch to create a wl_buffer. It can only be used once and + should be destroyed after a 'created' or 'failed' event has been + received. + + + + + + + This event advertises one buffer format that the server supports. + All the supported formats are advertised once when the client + binds to this interface. A roundtrip after binding guarantees + that the client has received all supported formats. + + For the definition of the format codes, see the + zwp_linux_buffer_params_v1::create request. + + Starting version 4, the format event is deprecated and must not be + sent by compositors. Instead, use get_default_feedback or + get_surface_feedback. + + + + + + + This event advertises the formats that the server supports, along with + the modifiers supported for each format. All the supported modifiers + for all the supported formats are advertised once when the client + binds to this interface. A roundtrip after binding guarantees that + the client has received all supported format-modifier pairs. + + For legacy support, DRM_FORMAT_MOD_INVALID (that is, modifier_hi == + 0x00ffffff and modifier_lo == 0xffffffff) is allowed in this event. + It indicates that the server can support the format with an implicit + modifier. When a plane has DRM_FORMAT_MOD_INVALID as its modifier, it + is as if no explicit modifier is specified. The effective modifier + will be derived from the dmabuf. + + A compositor that sends valid modifiers and DRM_FORMAT_MOD_INVALID for + a given format supports both explicit modifiers and implicit modifiers. + + For the definition of the format and modifier codes, see the + zwp_linux_buffer_params_v1::create and zwp_linux_buffer_params_v1::add + requests. + + Starting version 4, the modifier event is deprecated and must not be + sent by compositors. Instead, use get_default_feedback or + get_surface_feedback. + + + + + + + + + + + This request creates a new wp_linux_dmabuf_feedback object not bound + to a particular surface. This object will deliver feedback about dmabuf + parameters to use if the client doesn't support per-surface feedback + (see get_surface_feedback). + + + + + + + This request creates a new wp_linux_dmabuf_feedback object for the + specified wl_surface. This object will deliver feedback about dmabuf + parameters to use for buffers attached to this surface. + + If the surface is destroyed before the wp_linux_dmabuf_feedback object, + the feedback object becomes inert. + + + + + + + + + This temporary object is a collection of dmabufs and other + parameters that together form a single logical buffer. The temporary + object may eventually create one wl_buffer unless cancelled by + destroying it before requesting 'create'. + + Single-planar formats only require one dmabuf, however + multi-planar formats may require more than one dmabuf. For all + formats, an 'add' request must be called once per plane (even if the + underlying dmabuf fd is identical). + + You must use consecutive plane indices ('plane_idx' argument for 'add') + from zero to the number of planes used by the drm_fourcc format code. + All planes required by the format must be given exactly once, but can + be given in any order. Each plane index can be set only once. + + + + + + + + + + + + + + + + Cleans up the temporary data sent to the server for dmabuf-based + wl_buffer creation. + + + + + + This request adds one dmabuf to the set in this + zwp_linux_buffer_params_v1. + + The 64-bit unsigned value combined from modifier_hi and modifier_lo + is the dmabuf layout modifier. DRM AddFB2 ioctl calls this the + fb modifier, which is defined in drm_mode.h of Linux UAPI. + This is an opaque token. Drivers use this token to express tiling, + compression, etc. driver-specific modifications to the base format + defined by the DRM fourcc code. + + Starting from version 4, the invalid_format protocol error is sent if + the format + modifier pair was not advertised as supported. + + Starting from version 5, the invalid_format protocol error is sent if + all planes don't use the same modifier. + + This request raises the PLANE_IDX error if plane_idx is too large. + The error PLANE_SET is raised if attempting to set a plane that + was already set. + + + + + + + + + + + + + + + + + + This asks for creation of a wl_buffer from the added dmabuf + buffers. The wl_buffer is not created immediately but returned via + the 'created' event if the dmabuf sharing succeeds. The sharing + may fail at runtime for reasons a client cannot predict, in + which case the 'failed' event is triggered. + + The 'format' argument is a DRM_FORMAT code, as defined by the + libdrm's drm_fourcc.h. The Linux kernel's DRM sub-system is the + authoritative source on how the format codes should work. + + The 'flags' is a bitfield of the flags defined in enum "flags". + 'y_invert' means the that the image needs to be y-flipped. + + Flag 'interlaced' means that the frame in the buffer is not + progressive as usual, but interlaced. An interlaced buffer as + supported here must always contain both top and bottom fields. + The top field always begins on the first pixel row. The temporal + ordering between the two fields is top field first, unless + 'bottom_first' is specified. It is undefined whether 'bottom_first' + is ignored if 'interlaced' is not set. + + This protocol does not convey any information about field rate, + duration, or timing, other than the relative ordering between the + two fields in one buffer. A compositor may have to estimate the + intended field rate from the incoming buffer rate. It is undefined + whether the time of receiving wl_surface.commit with a new buffer + attached, applying the wl_surface state, wl_surface.frame callback + trigger, presentation, or any other point in the compositor cycle + is used to measure the frame or field times. There is no support + for detecting missed or late frames/fields/buffers either, and + there is no support whatsoever for cooperating with interlaced + compositor output. + + The composited image quality resulting from the use of interlaced + buffers is explicitly undefined. A compositor may use elaborate + hardware features or software to deinterlace and create progressive + output frames from a sequence of interlaced input buffers, or it + may produce substandard image quality. However, compositors that + cannot guarantee reasonable image quality in all cases are recommended + to just reject all interlaced buffers. + + Any argument errors, including non-positive width or height, + mismatch between the number of planes and the format, bad + format, bad offset or stride, may be indicated by fatal protocol + errors: INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS, + OUT_OF_BOUNDS. + + Dmabuf import errors in the server that are not obvious client + bugs are returned via the 'failed' event as non-fatal. This + allows attempting dmabuf sharing and falling back in the client + if it fails. + + This request can be sent only once in the object's lifetime, after + which the only legal request is destroy. This object should be + destroyed after issuing a 'create' request. Attempting to use this + object after issuing 'create' raises ALREADY_USED protocol error. + + It is not mandatory to issue 'create'. If a client wants to + cancel the buffer creation, it can just destroy this object. + + + + + + + + + + This event indicates that the attempted buffer creation was + successful. It provides the new wl_buffer referencing the dmabuf(s). + + Upon receiving this event, the client should destroy the + zwp_linux_buffer_params_v1 object. + + + + + + + This event indicates that the attempted buffer creation has + failed. It usually means that one of the dmabuf constraints + has not been fulfilled. + + Upon receiving this event, the client should destroy the + zwp_linux_buffer_params_v1 object. + + + + + + This asks for immediate creation of a wl_buffer by importing the + added dmabufs. + + In case of import success, no event is sent from the server, and the + wl_buffer is ready to be used by the client. + + Upon import failure, either of the following may happen, as seen fit + by the implementation: + - the client is terminated with one of the following fatal protocol + errors: + - INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS, OUT_OF_BOUNDS, + in case of argument errors such as mismatch between the number + of planes and the format, bad format, non-positive width or + height, or bad offset or stride. + - INVALID_WL_BUFFER, in case the cause for failure is unknown or + plaform specific. + - the server creates an invalid wl_buffer, marks it as failed and + sends a 'failed' event to the client. The result of using this + invalid wl_buffer as an argument in any request by the client is + defined by the compositor implementation. + + This takes the same arguments as a 'create' request, and obeys the + same restrictions. + + + + + + + + + + + + This object advertises dmabuf parameters feedback. This includes the + preferred devices and the supported formats/modifiers. + + The parameters are sent once when this object is created and whenever they + change. The done event is always sent once after all parameters have been + sent. When a single parameter changes, all parameters are re-sent by the + compositor. + + Compositors can re-send the parameters when the current client buffer + allocations are sub-optimal. Compositors should not re-send the + parameters if re-allocating the buffers would not result in a more optimal + configuration. In particular, compositors should avoid sending the exact + same parameters multiple times in a row. + + The tranche_target_device and tranche_formats events are grouped by + tranches of preference. For each tranche, a tranche_target_device, one + tranche_flags and one or more tranche_formats events are sent, followed + by a tranche_done event finishing the list. The tranches are sent in + descending order of preference. All formats and modifiers in the same + tranche have the same preference. + + To send parameters, the compositor sends one main_device event, tranches + (each consisting of one tranche_target_device event, one tranche_flags + event, tranche_formats events and then a tranche_done event), then one + done event. + + + + + Using this request a client can tell the server that it is not going to + use the wp_linux_dmabuf_feedback object anymore. + + + + + + This event is sent after all parameters of a wp_linux_dmabuf_feedback + object have been sent. + + This allows changes to the wp_linux_dmabuf_feedback parameters to be + seen as atomic, even if they happen via multiple events. + + + + + + This event provides a file descriptor which can be memory-mapped to + access the format and modifier table. + + The table contains a tightly packed array of consecutive format + + modifier pairs. Each pair is 16 bytes wide. It contains a format as a + 32-bit unsigned integer, followed by 4 bytes of unused padding, and a + modifier as a 64-bit unsigned integer. The native endianness is used. + + The client must map the file descriptor in read-only private mode. + + Compositors are not allowed to mutate the table file contents once this + event has been sent. Instead, compositors must create a new, separate + table file and re-send feedback parameters. Compositors are allowed to + store duplicate format + modifier pairs in the table. + + + + + + + + This event advertises the main device that the server prefers to use + when direct scan-out to the target device isn't possible. The + advertised main device may be different for each + wp_linux_dmabuf_feedback object, and may change over time. + + There is exactly one main device. The compositor must send at least + one preference tranche with tranche_target_device equal to main_device. + + Clients need to create buffers that the main device can import and + read from, otherwise creating the dmabuf wl_buffer will fail (see the + wp_linux_buffer_params.create and create_immed requests for details). + The main device will also likely be kept active by the compositor, + so clients can use it instead of waking up another device for power + savings. + + In general the device is a DRM node. The DRM node type (primary vs. + render) is unspecified. Clients must not rely on the compositor sending + a particular node type. Clients cannot check two devices for equality + by comparing the dev_t value. + + If explicit modifiers are not supported and the client performs buffer + allocations on a different device than the main device, then the client + must force the buffer to have a linear layout. + + + + + + + This event splits tranche_target_device and tranche_formats events in + preference tranches. It is sent after a set of tranche_target_device + and tranche_formats events; it represents the end of a tranche. The + next tranche will have a lower preference. + + + + + + This event advertises the target device that the server prefers to use + for a buffer created given this tranche. The advertised target device + may be different for each preference tranche, and may change over time. + + There is exactly one target device per tranche. + + The target device may be a scan-out device, for example if the + compositor prefers to directly scan-out a buffer created given this + tranche. The target device may be a rendering device, for example if + the compositor prefers to texture from said buffer. + + The client can use this hint to allocate the buffer in a way that makes + it accessible from the target device, ideally directly. The buffer must + still be accessible from the main device, either through direct import + or through a potentially more expensive fallback path. If the buffer + can't be directly imported from the main device then clients must be + prepared for the compositor changing the tranche priority or making + wl_buffer creation fail (see the wp_linux_buffer_params.create and + create_immed requests for details). + + If the device is a DRM node, the DRM node type (primary vs. render) is + unspecified. Clients must not rely on the compositor sending a + particular node type. Clients cannot check two devices for equality by + comparing the dev_t value. + + This event is tied to a preference tranche, see the tranche_done event. + + + + + + + This event advertises the format + modifier combinations that the + compositor supports. + + It carries an array of indices, each referring to a format + modifier + pair in the last received format table (see the format_table event). + Each index is a 16-bit unsigned integer in native endianness. + + For legacy support, DRM_FORMAT_MOD_INVALID is an allowed modifier. + It indicates that the server can support the format with an implicit + modifier. When a buffer has DRM_FORMAT_MOD_INVALID as its modifier, it + is as if no explicit modifier is specified. The effective modifier + will be derived from the dmabuf. + + A compositor that sends valid modifiers and DRM_FORMAT_MOD_INVALID for + a given format supports both explicit modifiers and implicit modifiers. + + Compositors must not send duplicate format + modifier pairs within the + same tranche or across two different tranches with the same target + device and flags. + + This event is tied to a preference tranche, see the tranche_done event. + + For the definition of the format and modifier codes, see the + wp_linux_buffer_params.create request. + + + + + + + + + + + This event sets tranche-specific flags. + + The scanout flag is a hint that direct scan-out may be attempted by the + compositor on the target device if the client appropriately allocates a + buffer. How to allocate a buffer that can be scanned out on the target + device is implementation-defined. + + This event is tied to a preference tranche, see the tranche_done event. + + + + + + diff --git a/va/wayland/va_wayland.c b/va/wayland/va_wayland.c index b3e1f5c8a..759b05517 100644 --- a/va/wayland/va_wayland.c +++ b/va/wayland/va_wayland.c @@ -27,6 +27,7 @@ #include "sysdeps.h" #include #include "va_wayland.h" +#include "va_wayland_linux_dmabuf.h" #include "va_wayland_drm.h" #include "va_wayland_emgd.h" #include "va_wayland_private.h" @@ -90,6 +91,10 @@ struct va_wayland_backend { }; static const struct va_wayland_backend g_backends[] = { + { + va_wayland_linux_dmabuf_create, + va_wayland_linux_dmabuf_destroy + }, { va_wayland_drm_create, va_wayland_drm_destroy @@ -133,12 +138,10 @@ vaGetDisplayWl(struct wl_display *display) for (i = 0; g_backends[i].create != NULL; i++) { if (g_backends[i].create(pDisplayContext)) - break; + return (VADisplay)pDisplayContext; g_backends[i].destroy(pDisplayContext); } - return (VADisplay)pDisplayContext; - error: va_DisplayContextDestroy(pDisplayContext); return NULL; diff --git a/va/wayland/va_wayland_linux_dmabuf.c b/va/wayland/va_wayland_linux_dmabuf.c new file mode 100644 index 000000000..27e357c8a --- /dev/null +++ b/va/wayland/va_wayland_linux_dmabuf.c @@ -0,0 +1,364 @@ +/* + * va_wayland_drm.c - Wayland/linux-dmabuf helpers + * + * Copyright (c) 2024 Simon Ser + * + * 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, sub license, 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 NON-INFRINGEMENT. + * IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS 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 "sysdeps.h" +#include +#include +#include +#include +#include +#include +#include "va_drmcommon.h" +#include "drm/va_drm_utils.h" +#include "va_wayland_linux_dmabuf.h" +#include "va_wayland_private.h" +#include "linux-dmabuf-v1-client-protocol.h" + +typedef struct va_wayland_linux_dmabuf_context { + struct va_wayland_context base; + bool has_linux_dmabuf; + bool default_feedback_done; +} VADisplayContextWaylandLinuxDmabuf; + +static void +feedback_handle_done( + void *data, + struct zwp_linux_dmabuf_feedback_v1 *feedback +) +{ + VADisplayContextP const pDisplayContext = data; + struct va_wayland_linux_dmabuf_context *wl_linux_dmabuf_ctx = pDisplayContext->opaque; + + wl_linux_dmabuf_ctx->default_feedback_done = true; + + zwp_linux_dmabuf_feedback_v1_destroy(feedback); +} + +static void +feedback_handle_format_table( + void *data, + struct zwp_linux_dmabuf_feedback_v1 *feedback, + int fd, + uint32_t size +) +{ + close(fd); +} + +/* XXX: replace with drmGetDeviceFromDevId() */ +static drmDevice * +get_drm_device_from_dev_id(dev_t dev_id) +{ + uint32_t flags = 0; + int devices_len, i, node_type; + drmDevice *match = NULL, *dev; + struct stat statbuf; + + devices_len = drmGetDevices2(flags, NULL, 0); + if (devices_len < 0) { + return NULL; + } + drmDevice **devices = calloc(devices_len, sizeof(*devices)); + if (devices == NULL) { + return NULL; + } + devices_len = drmGetDevices2(flags, devices, devices_len); + if (devices_len < 0) { + free(devices); + return NULL; + } + + for (i = 0; i < devices_len; i++) { + dev = devices[i]; + for (node_type = 0; node_type < DRM_NODE_MAX; node_type++) { + if (!(dev->available_nodes & (1 << node_type))) + continue; + + if (stat(dev->nodes[node_type], &statbuf) != 0) { + va_wayland_error("stat() failed for %s", dev->nodes[node_type]); + continue; + } + + if (statbuf.st_rdev == dev_id) { + match = dev; + break; + } + } + } + + for (i = 0; i < devices_len; i++) { + dev = devices[i]; + if (dev != match) + drmFreeDevice(&dev); + } + free(devices); + + return match; +} + +static void +feedback_handle_main_device( + void *data, + struct zwp_linux_dmabuf_feedback_v1 *feedback, + struct wl_array *device_array +) +{ + dev_t dev_id; + drmDevice *dev; + const char *dev_path; + VADisplayContextP const pDisplayContext = data; + VADriverContextP const ctx = pDisplayContext->pDriverContext; + struct drm_state * const drm_state = ctx->drm_state; + + assert(device_array->size == sizeof(dev_id)); + memcpy(&dev_id, device_array->data, sizeof(dev_id)); + + dev = get_drm_device_from_dev_id(dev_id); + if (!dev) { + va_wayland_error("failed to get DRM device from device ID"); + return; + } + + if (!(dev->available_nodes & (1 << DRM_NODE_RENDER))) + goto end; + + dev_path = dev->nodes[DRM_NODE_RENDER]; + drm_state->fd = open(dev_path, O_RDWR | O_CLOEXEC); + if (drm_state->fd < 0) { + va_wayland_error("failed to open %s", dev_path); + goto end; + } + + drm_state->auth_type = VA_DRM_AUTH_CUSTOM; + +end: + drmFreeDevice(&dev); +} + +static void +feedback_handle_tranche_done( + void *data, + struct zwp_linux_dmabuf_feedback_v1 *feedback +) +{ +} + +static void +feedback_handle_tranche_target_device( + void *data, + struct zwp_linux_dmabuf_feedback_v1 *feedback, + struct wl_array *device_array +) +{ +} + +static void +feedback_handle_tranche_formats( + void *data, + struct zwp_linux_dmabuf_feedback_v1 *feedback, + struct wl_array *indices_array +) +{ +} + +static void +feedback_handle_tranche_flags( + void *data, + struct zwp_linux_dmabuf_feedback_v1 *feedback, + uint32_t flags +) +{ +} + +static const struct zwp_linux_dmabuf_feedback_v1_listener feedback_listener = { + .done = feedback_handle_done, + .format_table = feedback_handle_format_table, + .main_device = feedback_handle_main_device, + .tranche_done = feedback_handle_tranche_done, + .tranche_target_device = feedback_handle_tranche_target_device, + .tranche_formats = feedback_handle_tranche_formats, + .tranche_flags = feedback_handle_tranche_flags, +}; + +static void +registry_handle_global( + void *data, + struct wl_registry *registry, + uint32_t name, + const char *interface, + uint32_t version +) +{ + VADisplayContextP const pDisplayContext = data; + struct va_wayland_linux_dmabuf_context *wl_linux_dmabuf_ctx = pDisplayContext->opaque; + struct zwp_linux_dmabuf_v1 *linux_dmabuf; + struct zwp_linux_dmabuf_feedback_v1 *feedback; + + if (strcmp(interface, zwp_linux_dmabuf_v1_interface.name) == 0 && + version >= 4) { + wl_linux_dmabuf_ctx->has_linux_dmabuf = true; + linux_dmabuf = + wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface, 4); + feedback = zwp_linux_dmabuf_v1_get_default_feedback(linux_dmabuf); + zwp_linux_dmabuf_feedback_v1_add_listener(feedback, &feedback_listener, data); + zwp_linux_dmabuf_v1_destroy(linux_dmabuf); + } +} + +static void +registry_handle_global_remove( + void *data, + struct wl_registry *registry, + uint32_t name +) +{ +} + +static const struct wl_registry_listener registry_listener = { + .global = registry_handle_global, + .global_remove = registry_handle_global_remove, +}; + +static VAStatus +va_DisplayContextGetDriverNames( + VADisplayContextP pDisplayContext, + char **drivers, + unsigned *num_drivers +) +{ + VADriverContextP const ctx = pDisplayContext->pDriverContext; + + return VA_DRM_GetDriverNames(ctx, drivers, num_drivers); +} + +bool +va_wayland_linux_dmabuf_create(VADisplayContextP pDisplayContext) +{ + bool result = false; + VADriverContextP const ctx = pDisplayContext->pDriverContext; + struct VADriverVTableWayland *vtable = ctx->vtable_wayland; + struct va_wayland_linux_dmabuf_context *wl_linux_dmabuf_ctx; + struct drm_state *drm_state; + struct wl_event_queue *queue = NULL; + struct wl_display *display = NULL; + struct wl_registry *registry = NULL; + + wl_linux_dmabuf_ctx = calloc(1, sizeof(*wl_linux_dmabuf_ctx)); + if (!wl_linux_dmabuf_ctx) { + va_wayland_error("could not allocate wl_linux_dmabuf_ctx"); + goto end; + } + wl_linux_dmabuf_ctx->base.destroy = va_wayland_linux_dmabuf_destroy; + pDisplayContext->opaque = wl_linux_dmabuf_ctx; + pDisplayContext->vaGetDriverNames = va_DisplayContextGetDriverNames; + + drm_state = calloc(1, sizeof(*drm_state)); + if (!drm_state) { + va_wayland_error("could not allocate drm_state"); + goto end; + } + drm_state->fd = -1; + drm_state->auth_type = 0; + ctx->drm_state = drm_state; + + vtable->has_prime_sharing = 0; + + /* Use wrapped wl_display with private event queue to prevent + * thread safety issues with applications that e.g. run an event pump + * parallel to libva initialization. + * Using the default queue, events might get lost and crashes occur + * because wl_display_roundtrip is not thread-safe with respect to the + * same queue. + */ + queue = wl_display_create_queue(ctx->native_dpy); + if (!queue) { + va_wayland_error("could not create Wayland event queue"); + goto end; + } + + display = wl_proxy_create_wrapper(ctx->native_dpy); + if (!display) { + va_wayland_error("could not create Wayland proxy wrapper"); + goto end; + } + wl_proxy_set_queue((struct wl_proxy *) display, queue); + + registry = wl_display_get_registry(display); + if (!registry) { + va_wayland_error("could not create wl_registry"); + goto end; + } + wl_registry_add_listener(registry, ®istry_listener, pDisplayContext); + + if (wl_display_roundtrip_queue(ctx->native_dpy, queue) < 0) { + va_wayland_error("failed to roundtrip Wayland queue"); + goto end; + } + + if (!wl_linux_dmabuf_ctx->has_linux_dmabuf) + goto end; + + while (!wl_linux_dmabuf_ctx->default_feedback_done) { + if (wl_display_dispatch_queue(ctx->native_dpy, queue) < 0) { + va_wayland_error("failed to dispatch Wayland queue"); + goto end; + } + } + + if (drm_state->fd < 0) + goto end; + + result = true; + vtable->has_prime_sharing = true; + +end: + if (registry) + wl_registry_destroy(registry); + if (display) + wl_proxy_wrapper_destroy(display); + if (queue) + wl_event_queue_destroy(queue); + return result; +} + +void +va_wayland_linux_dmabuf_destroy(VADisplayContextP pDisplayContext) +{ + VADriverContextP const ctx = pDisplayContext->pDriverContext; + struct drm_state * const drm_state = ctx->drm_state; + struct VADriverVTableWayland *vtable = ctx->vtable_wayland; + + vtable->has_prime_sharing = 0; + + if (drm_state) { + if (drm_state->fd >= 0) { + close(drm_state->fd); + drm_state->fd = -1; + } + free(ctx->drm_state); + ctx->drm_state = NULL; + } +} diff --git a/va/wayland/va_wayland_linux_dmabuf.h b/va/wayland/va_wayland_linux_dmabuf.h new file mode 100644 index 000000000..aeea38bb1 --- /dev/null +++ b/va/wayland/va_wayland_linux_dmabuf.h @@ -0,0 +1,52 @@ +/* + * va_wayland_linux_dmabuf.h - Wayland/linux-dmabuf helpers + * + * Copyright (c) 2024 Simon Ser + * + * 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, sub license, 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 NON-INFRINGEMENT. + * IN NO EVENT SHALL INTEL AND/OR ITS SUPPLIERS 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 VA_WAYLAND_LINUX_DMABUF_H +#define VA_WAYLAND_LINUX_DMABUF_H + +#include +#include "va_wayland.h" +#include "va_backend.h" +#include "va_backend_wayland.h" + +/** + * \brief Initializes Wayland/linux-dmabuf layer. + * + * This is an internal function used to initialize the VA/linux-dmabuf subsystem + * if the application is running on a linux-dmabuf-based server. + * + * @param[in] pDisplayContext the VA display context + * @return true if successful + */ +DLL_HIDDEN +bool +va_wayland_linux_dmabuf_create(VADisplayContextP pDisplayContext); + +DLL_HIDDEN +void +va_wayland_linux_dmabuf_destroy(VADisplayContextP pDisplayContext); + +#endif /* VA_WAYLAND_LINUX_DMABUF_H */ diff --git a/va/win32/va_win32.c b/va/win32/va_win32.c index 7a6a895d3..350ee3a27 100644 --- a/va/win32/va_win32.c +++ b/va/win32/va_win32.c @@ -183,9 +183,9 @@ VADisplay vaGetDisplayWin32( LoadDriverNameFromRegistry(adapter_luid, pWin32Ctx); #ifdef _DEBUG if (pWin32Ctx->registry_driver_available_flag) { - fprintf(stderr, "VA_Win32: Found driver %s in the registry for LUID %ld %ld \n", pWin32Ctx->registry_driver_name, adapter_luid.LowPart, adapter_luid.HighPart); + fprintf(stderr, "VA_Win32: Found driver %s in the registry for LUID %ld %ld \n", pWin32Ctx->registry_driver_name, adapter_luid->LowPart, adapter_luid->HighPart); } else { - fprintf(stderr, "VA_Win32: Couldn't find a driver in the registry for LUID %ld %ld. Using default driver: %s \n", adapter_luid.LowPart, adapter_luid.HighPart, VAAPI_DEFAULT_DRIVER_NAME); + fprintf(stderr, "VA_Win32: Couldn't find a driver in the registry for LUID %ld %ld. Using default driver: %s \n", adapter_luid->LowPart, adapter_luid->HighPart, VAAPI_DEFAULT_DRIVER_NAME); } #endif // _DEBUG } diff --git a/va/x11/va_x11.c b/va/x11/va_x11.c index 242e6e7c3..cd3bf9ee8 100644 --- a/va/x11/va_x11.c +++ b/va/x11/va_x11.c @@ -171,7 +171,7 @@ VAStatus vaPutSurface( ) { VADriverContextP ctx; - + VAStatus vaStatus = VA_STATUS_SUCCESS; CHECK_DISPLAY(dpy); ctx = CTX(dpy); @@ -179,7 +179,9 @@ VAStatus vaPutSurface( destx, desty, destw, desth, cliprects, number_cliprects, flags); - return ctx->vtable->vaPutSurface(ctx, surface, (void *)draw, srcx, srcy, srcw, srch, - destx, desty, destw, desth, - cliprects, number_cliprects, flags); + vaStatus = ctx->vtable->vaPutSurface(ctx, surface, (void *)draw, srcx, srcy, srcw, srch, + destx, desty, destw, desth, + cliprects, number_cliprects, flags); + VA_TRACE_RET(dpy, vaStatus); + return vaStatus; }