diff --git a/recipes-graphics/mesa/mesa-pvr/0001-Add-pvr-dri-driver.patch b/recipes-graphics/mesa/mesa-pvr/0001-Add-pvr-dri-driver.patch new file mode 100644 index 0000000..17f2264 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0001-Add-pvr-dri-driver.patch @@ -0,0 +1,4692 @@ +From 1546e69ae9fec54134bc06146143511b4374bf4a Mon Sep 17 00:00:00 2001 +From: Frank Binns +Date: Tue, 14 Apr 2020 09:47:46 +0100 +Subject: [PATCH 01/67] Add pvr dri driver + +--- + meson.build | 19 +- + meson_options.txt | 2 +- + src/mesa/drivers/dri/meson.build | 5 + + src/mesa/drivers/dri/pvr/dri_support.h | 581 +++++++++++++++ + src/mesa/drivers/dri/pvr/img_drm_fourcc.h | 113 +++ + src/mesa/drivers/dri/pvr/imgpixfmts.h | 307 ++++++++ + src/mesa/drivers/dri/pvr/imgyuv.h | 58 ++ + src/mesa/drivers/dri/pvr/mesa_context.c | 208 ++++++ + src/mesa/drivers/dri/pvr/meson.build | 48 ++ + src/mesa/drivers/dri/pvr/pvrcb.c | 328 +++++++++ + src/mesa/drivers/dri/pvr/pvrcompat.c | 838 ++++++++++++++++++++++ + src/mesa/drivers/dri/pvr/pvrdri.c | 613 ++++++++++++++++ + src/mesa/drivers/dri/pvr/pvrdri.h | 188 +++++ + src/mesa/drivers/dri/pvr/pvrdri_support.h | 206 ++++++ + src/mesa/drivers/dri/pvr/pvrext.c | 704 ++++++++++++++++++ + src/mesa/drivers/dri/pvr/pvrmesa.h | 36 + + src/mesa/drivers/dri/pvr/pvrutil.c | 239 ++++++ + src/meson.build | 1 + + 18 files changed, 4485 insertions(+), 9 deletions(-) + create mode 100644 src/mesa/drivers/dri/pvr/dri_support.h + create mode 100644 src/mesa/drivers/dri/pvr/img_drm_fourcc.h + create mode 100644 src/mesa/drivers/dri/pvr/imgpixfmts.h + create mode 100644 src/mesa/drivers/dri/pvr/imgyuv.h + create mode 100644 src/mesa/drivers/dri/pvr/mesa_context.c + create mode 100644 src/mesa/drivers/dri/pvr/meson.build + create mode 100644 src/mesa/drivers/dri/pvr/pvrcb.c + create mode 100644 src/mesa/drivers/dri/pvr/pvrcompat.c + create mode 100644 src/mesa/drivers/dri/pvr/pvrdri.c + create mode 100644 src/mesa/drivers/dri/pvr/pvrdri.h + create mode 100644 src/mesa/drivers/dri/pvr/pvrdri_support.h + create mode 100644 src/mesa/drivers/dri/pvr/pvrext.c + create mode 100644 src/mesa/drivers/dri/pvr/pvrmesa.h + create mode 100644 src/mesa/drivers/dri/pvr/pvrutil.c + +diff --git a/meson.build b/meson.build +index 155db287796..968b4f5f499 100644 +--- a/meson.build ++++ b/meson.build +@@ -171,11 +171,11 @@ if dri_drivers.contains('auto') + if system_has_kms_drm + # TODO: PPC, Sparc + if ['x86', 'x86_64'].contains(host_machine.cpu_family()) +- dri_drivers = ['i915', 'i965', 'r100', 'r200', 'nouveau'] ++ dri_drivers = ['i915', 'i965', 'r100', 'r200', 'nouveau', 'pvr'] + elif ['arm', 'aarch64'].contains(host_machine.cpu_family()) +- dri_drivers = [] ++ dri_drivers = ['pvr'] + elif ['mips', 'mips64', 'riscv32', 'riscv64'].contains(host_machine.cpu_family()) +- dri_drivers = ['r100', 'r200', 'nouveau'] ++ dri_drivers = ['r100', 'r200', 'nouveau', 'pvr'] + else + error('Unknown architecture @0@. Please pass -Ddri-drivers to set driver options. Patches gladly accepted to fix this.'.format( + host_machine.cpu_family())) +@@ -194,6 +194,7 @@ with_dri_i965 = dri_drivers.contains('i965') + with_dri_r100 = dri_drivers.contains('r100') + with_dri_r200 = dri_drivers.contains('r200') + with_dri_nouveau = dri_drivers.contains('nouveau') ++with_dri_pvr = dri_drivers.contains('pvr') + + with_dri = dri_drivers.length() != 0 + +@@ -1516,14 +1517,16 @@ _drm_amdgpu_ver = '2.4.107' + _drm_radeon_ver = '2.4.71' + _drm_nouveau_ver = '2.4.102' + _drm_intel_ver = '2.4.75' ++_drm_pvr_ver = '2.4.60' + _drm_ver = '2.4.81' + + _libdrm_checks = [ +- ['intel', with_dri_i915 or with_gallium_i915], +- ['amdgpu', (with_amd_vk and not with_platform_windows) or with_gallium_radeonsi], ++ ['intel', with_dri_i915 or with_gallium_i915, true], ++ ['amdgpu', (with_amd_vk and not with_platform_windows) or with_gallium_radeonsi, true], + ['radeon', (with_gallium_radeonsi or with_dri_r100 or with_dri_r200 or +- with_gallium_r300 or with_gallium_r600)], +- ['nouveau', (with_gallium_nouveau or with_dri_nouveau)], ++ with_gallium_r300 or with_gallium_r600), true], ++ ['nouveau', (with_gallium_nouveau or with_dri_nouveau), true], ++ ['pvr', with_dri_pvr, false], + ] + + # VC4 only needs core libdrm support of this version, not a libdrm_vc4 +@@ -1553,7 +1556,7 @@ endif + + # Then get each libdrm module + foreach d : _libdrm_checks +- if d[1] ++ if d[1] and d[2] + set_variable( + 'dep_libdrm_' + d[0], + dependency('libdrm_' + d[0], version : '>=' + _drm_ver) +diff --git a/meson_options.txt b/meson_options.txt +index 29c402c4844..dac791099a1 100644 +--- a/meson_options.txt ++++ b/meson_options.txt +@@ -55,7 +55,7 @@ option( + 'dri-drivers', + type : 'array', + value : ['auto'], +- choices : ['auto', 'i915', 'i965', 'r100', 'r200', 'nouveau'], ++ choices : ['auto', 'i915', 'i965', 'r100', 'r200', 'nouveau', 'pvr'], + description : 'List of dri drivers to build. If this is set to auto all drivers applicable to the target OS/architecture will be built' + ) + option( +diff --git a/src/mesa/drivers/dri/meson.build b/src/mesa/drivers/dri/meson.build +index 239ca962c2a..88a973bb84f 100644 +--- a/src/mesa/drivers/dri/meson.build ++++ b/src/mesa/drivers/dri/meson.build +@@ -48,6 +48,11 @@ if with_dri_nouveau + _dri_drivers += libnouveau_vieux + _dri_link += 'nouveau_vieux_dri.so' + endif ++if with_dri_pvr ++ subdir('pvr') ++ _dri_drivers += libpvr ++ _dri_link += 'pvr_dri.so' ++endif + + if _dri_drivers != [] + libmesa_dri_drivers = shared_library( +diff --git a/src/mesa/drivers/dri/pvr/dri_support.h b/src/mesa/drivers/dri/pvr/dri_support.h +new file mode 100644 +index 00000000000..631410438fd +--- /dev/null ++++ b/src/mesa/drivers/dri/pvr/dri_support.h +@@ -0,0 +1,581 @@ ++/* -*- 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 ++ ++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; ++}; ++ ++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; ++}; ++ ++#endif /* defined(__PVRDRIIFCE_H__) */ +diff --git a/src/mesa/drivers/dri/pvr/img_drm_fourcc.h b/src/mesa/drivers/dri/pvr/img_drm_fourcc.h +new file mode 100644 +index 00000000000..8d570ff8f53 +--- /dev/null ++++ b/src/mesa/drivers/dri/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/mesa/drivers/dri/pvr/imgpixfmts.h b/src/mesa/drivers/dri/pvr/imgpixfmts.h +new file mode 100644 +index 00000000000..da12a0fb5f6 +--- /dev/null ++++ b/src/mesa/drivers/dri/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/mesa/drivers/dri/pvr/imgyuv.h b/src/mesa/drivers/dri/pvr/imgyuv.h +new file mode 100644 +index 00000000000..7ae8fd19ac0 +--- /dev/null ++++ b/src/mesa/drivers/dri/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/mesa/drivers/dri/pvr/mesa_context.c b/src/mesa/drivers/dri/pvr/mesa_context.c +new file mode 100644 +index 00000000000..d36bae5ac54 +--- /dev/null ++++ b/src/mesa/drivers/dri/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/mesa/drivers/dri/pvr/meson.build b/src/mesa/drivers/dri/pvr/meson.build +new file mode 100644 +index 00000000000..59cccf8add4 +--- /dev/null ++++ b/src/mesa/drivers/dri/pvr/meson.build +@@ -0,0 +1,48 @@ ++# 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_pvr = files( ++ 'mesa_context.c', ++ 'pvrcb.c', ++ 'pvrcompat.c', ++ 'pvrdri.c', ++ 'pvrext.c', ++ 'pvrutil.c', ++) ++ ++dep_libpvr = [ ++ dep_libdrm, ++] ++ ++if with_platform_tizen ++ dep_libpvr += dep_dlog ++endif ++ ++libpvr = static_library( ++ 'pvr', ++ [files_pvr, main_dispatch_h], ++ include_directories : [inc_include, inc_src, inc_mapi, inc_mesa, ++ inc_dri_common, inc_util, inc_pvr], ++ c_args : [no_override_init_args], ++ gnu_symbol_visibility : 'hidden', ++ dependencies : [dep_libpvr], ++) +diff --git a/src/mesa/drivers/dri/pvr/pvrcb.c b/src/mesa/drivers/dri/pvr/pvrcb.c +new file mode 100644 +index 00000000000..ea8911c64d5 +--- /dev/null ++++ b/src/mesa/drivers/dri/pvr/pvrcb.c +@@ -0,0 +1,328 @@ ++/* ++ * 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 "utils.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); ++} +diff --git a/src/mesa/drivers/dri/pvr/pvrcompat.c b/src/mesa/drivers/dri/pvr/pvrcompat.c +new file mode 100644 +index 00000000000..23a57dde682 +--- /dev/null ++++ b/src/mesa/drivers/dri/pvr/pvrcompat.c +@@ -0,0 +1,838 @@ ++/* ++ * 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) ++ ++/* 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: ++ /* These versions require version 0 */ ++ return false; ++ default: ++ return false; ++ } ++ ++ /* The "default" case should be associated with the latest version */ ++ switch (uVersion) { ++ default: ++ 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; ++} +diff --git a/src/mesa/drivers/dri/pvr/pvrdri.c b/src/mesa/drivers/dri/pvr/pvrdri.c +new file mode 100644 +index 00000000000..ab941f71567 +--- /dev/null ++++ b/src/mesa/drivers/dri/pvr/pvrdri.c +@@ -0,0 +1,613 @@ ++/* ++ * 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 "utils.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, ++ }; ++ ++ if (!PVRLoaderIsSupported(psDRIScreen)) ++ return NULL; ++ ++ if (!PVRDRICompatInit(&sDRICallbacksV2, 3, 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 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, ++}; ++ ++static const __DRIextension *pvr_driver_extensions[] = { ++ &driCoreExtension.base, ++ &driImageDriverExtension.base, ++ &driDRI2Extension.base, ++ &pvr_vtable.base, ++ NULL ++}; ++ ++const __DRIextension **__driDriverGetExtensions_pvr(void); ++ ++PUBLIC const __DRIextension ** ++__driDriverGetExtensions_pvr(void) ++{ ++ globalDriverAPI = &pvr_driver_api; ++ ++ return pvr_driver_extensions; ++} +diff --git a/src/mesa/drivers/dri/pvr/pvrdri.h b/src/mesa/drivers/dri/pvr/pvrdri.h +new file mode 100644 +index 00000000000..fd465bf7f5c +--- /dev/null ++++ b/src/mesa/drivers/dri/pvr/pvrdri.h +@@ -0,0 +1,188 @@ ++/* ++ * 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); ++ ++#endif /* defined(__PVRDRI_H__) */ +diff --git a/src/mesa/drivers/dri/pvr/pvrdri_support.h b/src/mesa/drivers/dri/pvr/pvrdri_support.h +new file mode 100644 +index 00000000000..58ea3505a4d +--- /dev/null ++++ b/src/mesa/drivers/dri/pvr/pvrdri_support.h +@@ -0,0 +1,206 @@ ++/* ++ * 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); ++ ++#endif /* defined(__PVRDRI_SUPPORT_H__) */ +diff --git a/src/mesa/drivers/dri/pvr/pvrext.c b/src/mesa/drivers/dri/pvr/pvrext.c +new file mode 100644 +index 00000000000..478399618df +--- /dev/null ++++ b/src/mesa/drivers/dri/pvr/pvrext.c +@@ -0,0 +1,704 @@ ++/* ++ * 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 "utils.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 17 ++#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); ++} ++ ++#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, ++#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) ++{ ++ switch (uVersion) { ++ default: ++ 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; ++ } ++} +diff --git a/src/mesa/drivers/dri/pvr/pvrmesa.h b/src/mesa/drivers/dri/pvr/pvrmesa.h +new file mode 100644 +index 00000000000..5e1c9c1b2e6 +--- /dev/null ++++ b/src/mesa/drivers/dri/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/mesa/drivers/dri/pvr/pvrutil.c b/src/mesa/drivers/dri/pvr/pvrutil.c +new file mode 100644 +index 00000000000..945e18cf220 +--- /dev/null ++++ b/src/mesa/drivers/dri/pvr/pvrutil.c +@@ -0,0 +1,239 @@ ++/* ++ * 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 "utils.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)) ++#elif defined(HAVE_TIZEN_PLATFORM) ++#include ++#define err_printf(f, args...) LOGE(f, ##args) ++#define dbg_printf(f, args...) LOGD(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 and Tizen, always print messages; otherwise, only print if ++ * the environment variable LIBGL_DEBUG=verbose. ++ */ ++#if !defined(HAVE_ANDROID_PLATFORM) && !defined(HAVE_TIZEN_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; ++ 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; ++ 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; ++ default: ++ __driUtilMessage("%s: Unknown format: %d", __func__, iFourCC); ++ break; ++ } ++ ++ return 0; ++} +diff --git a/src/meson.build b/src/meson.build +index acc7fe94abb..c3bab27718d 100644 +--- a/src/meson.build ++++ b/src/meson.build +@@ -25,6 +25,7 @@ inc_gallium = include_directories('gallium/include') + inc_gallium_aux = include_directories('gallium/auxiliary') + inc_amd_common = include_directories('amd/common') + inc_amd_common_llvm = include_directories('amd/llvm') ++inc_pvr = include_directories('mesa/main', 'mapi/glapi') + inc_tool = include_directories('tool') + pps_datasources = [] + pps_includes = [] +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0002-Force-Mesa-to-use-the-PVR-driver-for-platform-device.patch b/recipes-graphics/mesa/mesa-pvr/0002-Force-Mesa-to-use-the-PVR-driver-for-platform-device.patch new file mode 100644 index 0000000..fb7b595 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0002-Force-Mesa-to-use-the-PVR-driver-for-platform-device.patch @@ -0,0 +1,34 @@ +From 184d3da84d449bc05511cb857cc843285dde4b63 Mon Sep 17 00:00:00 2001 +From: Frank Binns +Date: Wed, 17 Jun 2015 15:37:18 +0100 +Subject: [PATCH 02/67] Force Mesa to use the PVR driver for platform devices + +For platform devices, Mesa uses the DRM driver name to determine which DRI +driver to load. This doesn't work in the multi-DRM driver model where there +are separate DRM drivers for the display and GPU. This is because we normally +want Mesa to deal with the display driver and the name of this won't match +that of the DRI driver. For the time being, take the easy approach and just +force it to use the PVR DRI driver. +--- + src/loader/loader.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/loader/loader.c b/src/loader/loader.c +index 08eeb61504b..c7e561ef2e4 100644 +--- a/src/loader/loader.c ++++ b/src/loader/loader.c +@@ -436,7 +436,11 @@ loader_get_pci_driver(int fd) + char *driver = NULL; + + if (!loader_get_pci_id_for_fd(fd, &vendor_id, &chip_id)) ++#if 1 ++ return strdup("pvr"); ++#else + return NULL; ++#endif + + for (i = 0; i < ARRAY_SIZE(driver_map); i++) { + if (vendor_id != driver_map[i].vendor_id) +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0003-dri-Add-some-new-DRI-formats-and-fourccs.patch b/recipes-graphics/mesa/mesa-pvr/0003-dri-Add-some-new-DRI-formats-and-fourccs.patch new file mode 100644 index 0000000..c82ec94 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0003-dri-Add-some-new-DRI-formats-and-fourccs.patch @@ -0,0 +1,80 @@ +From fec4f46f7cedb6b3e90bf88c3efc3cd5da0d9131 Mon Sep 17 00:00:00 2001 +From: Frank Binns +Date: Thu, 5 Jun 2014 12:07:01 +0100 +Subject: [PATCH 03/67] dri: Add some new DRI formats and fourccs + +Add ARGB4444 DRI format and fourcc. +Add YVU444_PACK10_IMG DRI format and fourcc. +Add BGR888 DRI format and fourcc. +--- + include/GL/internal/dri_interface.h | 4 ++++ + include/drm-uapi/drm_fourcc.h | 1 + + src/egl/drivers/dri2/egl_dri2.c | 1 + + src/mesa/drivers/dri/common/dri_util.c | 5 +++++ + 4 files changed, 11 insertions(+) + +diff --git a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h +index 66dc0927cb7..510289403d2 100644 +--- a/include/GL/internal/dri_interface.h ++++ b/include/GL/internal/dri_interface.h +@@ -1367,6 +1367,9 @@ struct __DRIdri2ExtensionRec { + #define __DRI_IMAGE_FORMAT_ABGR16161616F 0x1015 + #define __DRI_IMAGE_FORMAT_SXRGB8 0x1016 + #define __DRI_IMAGE_FORMAT_ABGR16161616 0x1017 ++#define __DRI_IMAGE_FORMAT_ARGB4444 0x1018 ++#define __DRI_IMAGE_FORMAT_YVU444_PACK10_IMG 0x1019 ++#define __DRI_IMAGE_FORMAT_BGR888 0x101a + + #define __DRI_IMAGE_USE_SHARE 0x0001 + #define __DRI_IMAGE_USE_SCANOUT 0x0002 +@@ -1397,6 +1400,7 @@ struct __DRIdri2ExtensionRec { + #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. +diff --git a/include/drm-uapi/drm_fourcc.h b/include/drm-uapi/drm_fourcc.h +index cd3ce8a8c60..57657592a38 100644 +--- a/include/drm-uapi/drm_fourcc.h ++++ b/include/drm-uapi/drm_fourcc.h +@@ -344,6 +344,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/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c +index 9e5a55a287c..eee28eb4726 100644 +--- a/src/egl/drivers/dri2/egl_dri2.c ++++ b/src/egl/drivers/dri2/egl_dri2.c +@@ -2652,6 +2652,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: +diff --git a/src/mesa/drivers/dri/common/dri_util.c b/src/mesa/drivers/dri/common/dri_util.c +index e2a11240dea..caed5fa6a68 100644 +--- a/src/mesa/drivers/dri/common/dri_util.c ++++ b/src/mesa/drivers/dri/common/dri_util.c +@@ -904,6 +904,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, +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0004-GL_EXT_sparse_texture-entry-points.patch b/recipes-graphics/mesa/mesa-pvr/0004-GL_EXT_sparse_texture-entry-points.patch new file mode 100644 index 0000000..2dde5ce --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0004-GL_EXT_sparse_texture-entry-points.patch @@ -0,0 +1,104 @@ +From e66cd64b65e86a23807260a9a0c73f1355715314 Mon Sep 17 00:00:00 2001 +From: Frank Binns +Date: Wed, 12 Aug 2015 09:11:51 +0100 +Subject: [PATCH 04/67] GL_EXT_sparse_texture entry points + +--- + src/mapi/glapi/gen/EXT_sparse_texture.xml | 56 +++++++++++++++++++++++ + src/mapi/glapi/gen/es_EXT.xml | 3 ++ + src/mapi/glapi/gen/static_data.py | 2 + + 3 files changed, 61 insertions(+) + create mode 100644 src/mapi/glapi/gen/EXT_sparse_texture.xml + +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 00000000000..48d03e7b9c0 +--- /dev/null ++++ b/src/mapi/glapi/gen/EXT_sparse_texture.xml +@@ -0,0 +1,56 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/src/mapi/glapi/gen/es_EXT.xml b/src/mapi/glapi/gen/es_EXT.xml +index 929b40bbd4a..962170bc58e 100644 +--- a/src/mapi/glapi/gen/es_EXT.xml ++++ b/src/mapi/glapi/gen/es_EXT.xml +@@ -1433,6 +1433,9 @@ + + + ++ ++ ++ + + + +diff --git a/src/mapi/glapi/gen/static_data.py b/src/mapi/glapi/gen/static_data.py +index 6accff1b231..d063930bd81 100644 +--- a/src/mapi/glapi/gen/static_data.py ++++ b/src/mapi/glapi/gen/static_data.py +@@ -1689,6 +1689,8 @@ offsets = { + "VertexAttribs2hvNV": 1653, + "VertexAttribs3hvNV": 1654, + "VertexAttribs4hvNV": 1655, ++ "TexPageCommitmentEXT": 1656, ++ "TexturePageCommitmentEXT" : 1657, + } + + functions = [ +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0005-Add-support-for-various-GLES-extensions.patch b/recipes-graphics/mesa/mesa-pvr/0005-Add-support-for-various-GLES-extensions.patch new file mode 100644 index 0000000..9f3f10c --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0005-Add-support-for-various-GLES-extensions.patch @@ -0,0 +1,106 @@ +From 4a1be491de2ea78be95dc4cf08af4b1da5e16d91 Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Mon, 10 Mar 2014 12:27:03 +0000 +Subject: [PATCH 05/67] Add support for various GLES extensions + +Add support for: + EXT_occlusion_query_boolean + IMG_multisampled_render_to_texture + OES_matrix_palette +--- + src/mapi/glapi/gen/es_EXT.xml | 41 ++++++++++++++++++++++++------- + src/mapi/glapi/gen/static_data.py | 6 +++++ + 2 files changed, 38 insertions(+), 9 deletions(-) + +diff --git a/src/mapi/glapi/gen/es_EXT.xml b/src/mapi/glapi/gen/es_EXT.xml +index 962170bc58e..e586b0ec19b 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 @@ + + + ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + + + +diff --git a/src/mapi/glapi/gen/static_data.py b/src/mapi/glapi/gen/static_data.py +index d063930bd81..79b8f19cb75 100644 +--- a/src/mapi/glapi/gen/static_data.py ++++ b/src/mapi/glapi/gen/static_data.py +@@ -1691,6 +1691,12 @@ offsets = { + "VertexAttribs4hvNV": 1655, + "TexPageCommitmentEXT": 1656, + "TexturePageCommitmentEXT" : 1657, ++ "CurrentPaletteMatrixOES" : 1658, ++ "LoadPaletteFromModelViewMatrixOES" : 1659, ++ "MatrixIndexPointerOES" : 1660, ++ "WeightPointerOES" : 1661, ++ "RenderbufferStorageMultisampleIMG" : 1662, ++ "FramebufferTexture2DMultisampleIMG" : 1663, + } + + functions = [ +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0006-Add-EGL_IMG_cl_image-extension.patch b/recipes-graphics/mesa/mesa-pvr/0006-Add-EGL_IMG_cl_image-extension.patch new file mode 100644 index 0000000..0d11e65 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0006-Add-EGL_IMG_cl_image-extension.patch @@ -0,0 +1,187 @@ +From 7fdeb8bf25be01f122a7cb55dbe2b0e67e4a24a2 Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Tue, 11 Mar 2014 11:50:53 +0000 +Subject: [PATCH 06/67] Add EGL_IMG_cl_image extension + +Add support for the experimental EGL_IMG_cl_image extension to EGL, and +the DRI2 EGL driver. +--- + include/EGL/eglmesaext.h | 5 +++ + include/GL/internal/dri_interface.h | 13 +++++++ + src/egl/drivers/dri2/egl_dri2.c | 60 +++++++++++++++++++++++++---- + src/egl/main/eglapi.c | 1 + + src/egl/main/egldisplay.h | 2 + + 5 files changed, 73 insertions(+), 8 deletions(-) + +diff --git a/include/EGL/eglmesaext.h b/include/EGL/eglmesaext.h +index f0395a8a58c..5d11f3e488e 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 510289403d2..b197092939f 100644 +--- a/include/GL/internal/dri_interface.h ++++ b/include/GL/internal/dri_interface.h +@@ -1831,6 +1831,19 @@ struct __DRIimageExtensionRec { + const unsigned int modifier_count, + unsigned int use, + void *loaderPrivate); ++ ++ /** ++ * 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); + }; + + +diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c +index eee28eb4726..dea5899b3a8 100644 +--- a/src/egl/drivers/dri2/egl_dri2.c ++++ b/src/egl/drivers/dri2/egl_dri2.c +@@ -995,6 +995,10 @@ 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 (dri2_dpy->flush_control) +@@ -2360,17 +2364,13 @@ dri2_get_sync_values_chromium(_EGLDisplay *disp, _EGLSurface *surf, + return dri2_dpy->vtbl->get_sync_values(disp, surf, ust, msc, sbc); + } + +-/** +- * 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 * +@@ -2449,7 +2449,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); +@@ -2916,7 +2958,7 @@ dri2_create_image_dma_buf(_EGLDisplay *disp, _EGLContext *ctx, + &error, + NULL); + } +- dri2_create_image_khr_texture_error(error); ++ dri2_create_image_khr_error(error); + + if (!dri_image) + return EGL_NO_IMAGE_KHR; +@@ -3152,6 +3194,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; +diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c +index 17e36af22e1..6ffcff8b2cc 100644 +--- a/src/egl/main/eglapi.c ++++ b/src/egl/main/eglapi.c +@@ -549,6 +549,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 + } + +diff --git a/src/egl/main/egldisplay.h b/src/egl/main/egldisplay.h +index 4d2afbc712e..5b05dcc1e6d 100644 +--- a/src/egl/main/egldisplay.h ++++ b/src/egl/main/egldisplay.h +@@ -150,6 +150,8 @@ struct _egl_extensions + + EGLBoolean WL_bind_wayland_display; + EGLBoolean WL_create_wayland_buffer_from_image; ++ ++ EGLBoolean IMG_cl_image; + }; + + struct _egl_display +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0007-egl-Be-stricter-when-making-a-context-current-withou.patch b/recipes-graphics/mesa/mesa-pvr/0007-egl-Be-stricter-when-making-a-context-current-withou.patch new file mode 100644 index 0000000..2e33ad4 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0007-egl-Be-stricter-when-making-a-context-current-withou.patch @@ -0,0 +1,51 @@ +From fa57726f60bc6fc6e7094f16300cdc41b44ff4f3 Mon Sep 17 00:00:00 2001 +From: Frank Binns +Date: Wed, 18 Jun 2014 17:10:28 +0100 +Subject: [PATCH 07/67] egl: Be stricter when making a context current without + any surfaces + +The EGL_KHR_surfaceless_context extension spec states for eglMakeCurrent: + "If does not support being bound without read and draw + surfaces, and both and are EGL_NO_SURFACE, an + EGL_BAD_MATCH error is generated." + +Only OpenGLES contexts support this, via the GL_OES_surfaceless_context, +so if EGL_KHR_surfaceless_context is supported and the context isn't an +OpenGLES context then set the EGL error to EGL_BAD_MATCH. + +NOTE: This patch can't be upstreamed as is because we set the error to +EGL_BAD_MATCH if we have an OpenGLES 1.x context but the +GL_OES_surfaceless_context extension spec says: + "This extension is written against the OpenGL ES 2.0 Specification + but can apply to OpenGL ES 1.1 with the GL_OES_framebuffer_object + extension." + +All Mesa OpenGLES drivers support GL_OES_framebuffer_object, but we +don't, so there would never be a reason to check whether or not this +extension is supported. + +In order to upstream this patch the check would need to be changed +to set the error to EGL_BAD_MATCH if EGL_KHR_surfaceless_context is +supported and the context API isn't OpenGLES or the OpenGLES version +is 1.0. +--- + src/egl/main/eglapi.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c +index 6ffcff8b2cc..3cd69b96a0f 100644 +--- a/src/egl/main/eglapi.c ++++ b/src/egl/main/eglapi.c +@@ -888,6 +888,9 @@ eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, + RETURN_EGL_ERROR(disp, EGL_BAD_SURFACE, EGL_FALSE); + if (draw_surf || read_surf) + RETURN_EGL_ERROR(disp, EGL_BAD_MATCH, EGL_FALSE); ++ if (disp->Extensions.KHR_surfaceless_context && context && ++ (context->ClientAPI != EGL_OPENGL_ES_API || context->ClientMajorVersion == 1)) ++ RETURN_EGL_ERROR(disp, EGL_BAD_MATCH, EGL_FALSE); + } + + /* If a native window underlying either draw or read is no longer valid, +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0008-egl-optimise-eglMakeCurrent-for-the-case-where-nothi.patch b/recipes-graphics/mesa/mesa-pvr/0008-egl-optimise-eglMakeCurrent-for-the-case-where-nothi.patch new file mode 100644 index 0000000..5de24ac --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0008-egl-optimise-eglMakeCurrent-for-the-case-where-nothi.patch @@ -0,0 +1,46 @@ +From f556292d5811750d119acea6c7dc0c5ebd3e1af6 Mon Sep 17 00:00:00 2001 +From: Frank Binns +Date: Tue, 15 Sep 2015 14:15:31 +0100 +Subject: [PATCH 08/67] egl: optimise eglMakeCurrent for the case where nothing + has changed + +When an application calls eglMakeCurrent with a context, draw surface and +read surface that match those that are currently bound to the calling +thread don't perform a flush as this is an expensive operation. +--- + src/egl/main/eglapi.c | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c +index 3cd69b96a0f..234449adf64 100644 +--- a/src/egl/main/eglapi.c ++++ b/src/egl/main/eglapi.c +@@ -853,6 +853,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); +@@ -909,7 +910,16 @@ eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, + draw_surf && !draw_surf->ProtectedContent) + RETURN_EGL_ERROR(disp, EGL_BAD_ACCESS, EGL_FALSE); + +- 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))) { ++ ret = disp->Driver->MakeCurrent(disp, draw_surf, read_surf, context); ++ } else { ++ ret = EGL_TRUE; ++ } + + RETURN_EGL_EVAL(disp, ret); + } +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0009-GL_EXT_shader_pixel_local_storage2-entry-points.patch b/recipes-graphics/mesa/mesa-pvr/0009-GL_EXT_shader_pixel_local_storage2-entry-points.patch new file mode 100644 index 0000000..12b7e1f --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0009-GL_EXT_shader_pixel_local_storage2-entry-points.patch @@ -0,0 +1,84 @@ +From 13e925af5ba3bd763eb4c9e5d0781f92981550f6 Mon Sep 17 00:00:00 2001 +From: Rufus Hamade +Date: Thu, 4 Feb 2016 14:09:26 +0000 +Subject: [PATCH 09/67] GL_EXT_shader_pixel_local_storage2 entry points + +--- + .../gen/EXT_shader_pixel_local_storage2.xml | 35 +++++++++++++++++++ + src/mapi/glapi/gen/es_EXT.xml | 3 ++ + src/mapi/glapi/gen/static_data.py | 3 ++ + 3 files changed, 41 insertions(+) + create mode 100644 src/mapi/glapi/gen/EXT_shader_pixel_local_storage2.xml + +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 00000000000..20e186c0f0d +--- /dev/null ++++ b/src/mapi/glapi/gen/EXT_shader_pixel_local_storage2.xml +@@ -0,0 +1,35 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/src/mapi/glapi/gen/es_EXT.xml b/src/mapi/glapi/gen/es_EXT.xml +index e586b0ec19b..a3bfe86a888 100644 +--- a/src/mapi/glapi/gen/es_EXT.xml ++++ b/src/mapi/glapi/gen/es_EXT.xml +@@ -1459,6 +1459,9 @@ + + + ++ ++ ++ + + + +diff --git a/src/mapi/glapi/gen/static_data.py b/src/mapi/glapi/gen/static_data.py +index 79b8f19cb75..99729e21b7f 100644 +--- a/src/mapi/glapi/gen/static_data.py ++++ b/src/mapi/glapi/gen/static_data.py +@@ -1697,6 +1697,9 @@ offsets = { + "WeightPointerOES" : 1661, + "RenderbufferStorageMultisampleIMG" : 1662, + "FramebufferTexture2DMultisampleIMG" : 1663, ++ "ClearPixelLocalStorageuiEXT" : 1664, ++ "FramebufferPixelLocalStorageSizeEXT" : 1665, ++ "GetFramebufferPixelLocalStorageSizeEXT" : 1666, + } + + functions = [ +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0010-GL_IMG_framebuffer_downsample-entry-points.patch b/recipes-graphics/mesa/mesa-pvr/0010-GL_IMG_framebuffer_downsample-entry-points.patch new file mode 100644 index 0000000..edc8ff1 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0010-GL_IMG_framebuffer_downsample-entry-points.patch @@ -0,0 +1,85 @@ +From f43a3258b8f4859ff3e0e3d3d356b319dd6a5435 Mon Sep 17 00:00:00 2001 +From: Rufus Hamade +Date: Thu, 4 Feb 2016 14:09:26 +0000 +Subject: [PATCH 10/67] GL_IMG_framebuffer_downsample entry points + +--- + .../glapi/gen/IMG_framebuffer_downsample.xml | 37 +++++++++++++++++++ + src/mapi/glapi/gen/es_EXT.xml | 3 ++ + src/mapi/glapi/gen/static_data.py | 2 + + 3 files changed, 42 insertions(+) + create mode 100644 src/mapi/glapi/gen/IMG_framebuffer_downsample.xml + +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 00000000000..b5ce77dfb08 +--- /dev/null ++++ b/src/mapi/glapi/gen/IMG_framebuffer_downsample.xml +@@ -0,0 +1,37 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/src/mapi/glapi/gen/es_EXT.xml b/src/mapi/glapi/gen/es_EXT.xml +index a3bfe86a888..b3432820ba6 100644 +--- a/src/mapi/glapi/gen/es_EXT.xml ++++ b/src/mapi/glapi/gen/es_EXT.xml +@@ -1462,6 +1462,9 @@ + + + ++ ++ ++ + + + +diff --git a/src/mapi/glapi/gen/static_data.py b/src/mapi/glapi/gen/static_data.py +index 99729e21b7f..c723cb3fab8 100644 +--- a/src/mapi/glapi/gen/static_data.py ++++ b/src/mapi/glapi/gen/static_data.py +@@ -1700,6 +1700,8 @@ offsets = { + "ClearPixelLocalStorageuiEXT" : 1664, + "FramebufferPixelLocalStorageSizeEXT" : 1665, + "GetFramebufferPixelLocalStorageSizeEXT" : 1666, ++ "FramebufferTexture2DDownsampleIMG" : 1667, ++ "FramebufferTextureLayerDownsampleIMG" : 1668, + } + + functions = [ +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0011-GL_OVR_multiview-entry-points.patch b/recipes-graphics/mesa/mesa-pvr/0011-GL_OVR_multiview-entry-points.patch new file mode 100644 index 0000000..81464a5 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0011-GL_OVR_multiview-entry-points.patch @@ -0,0 +1,53 @@ +From cbc7a7501ea4ceffd55ca389deb55d12ff9ceb3f Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Mon, 11 Jul 2016 12:45:30 +0100 +Subject: [PATCH 11/67] GL_OVR_multiview entry points + +--- + src/mapi/glapi/gen/gl_API.xml | 17 +++++++++++++++++ + src/mapi/glapi/gen/static_data.py | 1 + + 2 files changed, 18 insertions(+) + +diff --git a/src/mapi/glapi/gen/gl_API.xml b/src/mapi/glapi/gen/gl_API.xml +index cf5a0f0a0c0..4e35de0f4ea 100644 +--- a/src/mapi/glapi/gen/gl_API.xml ++++ b/src/mapi/glapi/gen/gl_API.xml +@@ -13125,6 +13125,23 @@ + + + ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + + + +diff --git a/src/mapi/glapi/gen/static_data.py b/src/mapi/glapi/gen/static_data.py +index c723cb3fab8..73625c7fe41 100644 +--- a/src/mapi/glapi/gen/static_data.py ++++ b/src/mapi/glapi/gen/static_data.py +@@ -1702,6 +1702,7 @@ offsets = { + "GetFramebufferPixelLocalStorageSizeEXT" : 1666, + "FramebufferTexture2DDownsampleIMG" : 1667, + "FramebufferTextureLayerDownsampleIMG" : 1668, ++ "FramebufferTextureMultiviewOVR" : 1669, + } + + functions = [ +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0012-Add-OVR_multiview_multisampled_render_to_texture.patch b/recipes-graphics/mesa/mesa-pvr/0012-Add-OVR_multiview_multisampled_render_to_texture.patch new file mode 100644 index 0000000..58cfbaa --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0012-Add-OVR_multiview_multisampled_render_to_texture.patch @@ -0,0 +1,68 @@ +From 91ea37486db99fd403654ebff2a0a8401f7cd600 Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Mon, 11 Jul 2016 13:29:51 +0100 +Subject: [PATCH 12/67] Add OVR_multiview_multisampled_render_to_texture + +--- + ...ltiview_multisampled_render_to_texture.xml | 21 +++++++++++++++++++ + src/mapi/glapi/gen/es_EXT.xml | 3 +++ + src/mapi/glapi/gen/static_data.py | 1 + + 3 files changed, 25 insertions(+) + create mode 100644 src/mapi/glapi/gen/OVR_multiview_multisampled_render_to_texture.xml + +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 00000000000..86bebc728e9 +--- /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/es_EXT.xml b/src/mapi/glapi/gen/es_EXT.xml +index b3432820ba6..fe8f27e1e6f 100644 +--- a/src/mapi/glapi/gen/es_EXT.xml ++++ b/src/mapi/glapi/gen/es_EXT.xml +@@ -1459,6 +1459,9 @@ + + + ++ ++ ++ + + + +diff --git a/src/mapi/glapi/gen/static_data.py b/src/mapi/glapi/gen/static_data.py +index 73625c7fe41..dc6bdc9dcce 100644 +--- a/src/mapi/glapi/gen/static_data.py ++++ b/src/mapi/glapi/gen/static_data.py +@@ -1703,6 +1703,7 @@ offsets = { + "FramebufferTexture2DDownsampleIMG" : 1667, + "FramebufferTextureLayerDownsampleIMG" : 1668, + "FramebufferTextureMultiviewOVR" : 1669, ++ "FramebufferTextureMultisampleMultiviewOVR" : 1670, + } + + functions = [ +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0013-wayland-drm-install-wayland-drm.xml-to-the-configure.patch b/recipes-graphics/mesa/mesa-pvr/0013-wayland-drm-install-wayland-drm.xml-to-the-configure.patch new file mode 100644 index 0000000..bb028d9 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0013-wayland-drm-install-wayland-drm.xml-to-the-configure.patch @@ -0,0 +1,57 @@ +From b38c4118c7a3a060ef1c8b8477200f5a73305397 Mon Sep 17 00:00:00 2001 +From: Frank Binns +Date: Thu, 18 Aug 2016 15:52:28 +0100 +Subject: [PATCH 13/67] wayland-drm: install wayland-drm.xml to the configured + pkgdatadir + +Add a pkg-config file as well so that it can be located without hardcoding the +path. +--- + src/egl/wayland/wayland-drm/meson.build | 15 +++++++++++++++ + src/egl/wayland/wayland-drm/wayland-drm.pc.in | 7 +++++++ + 2 files changed, 22 insertions(+) + create mode 100644 src/egl/wayland/wayland-drm/wayland-drm.pc.in + +diff --git a/src/egl/wayland/wayland-drm/meson.build b/src/egl/wayland/wayland-drm/meson.build +index b4782a013c9..f291ef9f55e 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 00000000000..d08ccdaf6ce +--- /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 +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0014-Enable-buffer-sharing-in-the-kms_swrast-driver.patch b/recipes-graphics/mesa/mesa-pvr/0014-Enable-buffer-sharing-in-the-kms_swrast-driver.patch new file mode 100644 index 0000000..317ad37 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0014-Enable-buffer-sharing-in-the-kms_swrast-driver.patch @@ -0,0 +1,27 @@ +From b80c78b05ebb661e7f088d0a369b0f0d2990afca Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Wed, 26 Oct 2016 16:24:28 +0100 +Subject: [PATCH 14/67] Enable buffer sharing in the kms_swrast driver + +Enable buffer sharing, so that a DRI driver can be loaded by a +Wayland client when kms_swrast is being used by the compositor. +--- + src/gallium/frontends/dri/dri2.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/gallium/frontends/dri/dri2.c b/src/gallium/frontends/dri/dri2.c +index ebc18a73c86..09f4b02e758 100644 +--- a/src/gallium/frontends/dri/dri2.c ++++ b/src/gallium/frontends/dri/dri2.c +@@ -2400,7 +2400,7 @@ dri_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->broken_invalidate = !sPriv->dri2.useInvalidate; + screen->lookup_egl_image = dri2_lookup_egl_image; +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0015-egl-wayland-add-support-for-RGB565-back-buffers.patch b/recipes-graphics/mesa/mesa-pvr/0015-egl-wayland-add-support-for-RGB565-back-buffers.patch new file mode 100644 index 0000000..cba6084 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0015-egl-wayland-add-support-for-RGB565-back-buffers.patch @@ -0,0 +1,46 @@ +From 55a15a019dd792477e39f6225f2b4e50a1359b66 Mon Sep 17 00:00:00 2001 +From: James Glanville +Date: Tue, 28 Feb 2017 16:08:47 +0000 +Subject: [PATCH 15/67] egl/wayland: add support for RGB565 back buffers + +--- + src/egl/drivers/dri2/platform_wayland.c | 13 +++++++++++-- + 1 file changed, 11 insertions(+), 2 deletions(-) + +diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c +index cfff0ade90e..c18edc0de4e 100644 +--- a/src/egl/drivers/dri2/platform_wayland.c ++++ b/src/egl/drivers/dri2/platform_wayland.c +@@ -633,18 +633,27 @@ back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer) + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + __DRIimage *image; +- int name, pitch; ++ int name, pitch, format; + + image = dri2_surf->back->dri_image; + + 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->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; ++ } + } + + static int +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0016-egl-dri3-fix-segfault-in-eglCopyBuffers.patch b/recipes-graphics/mesa/mesa-pvr/0016-egl-dri3-fix-segfault-in-eglCopyBuffers.patch new file mode 100644 index 0000000..106ea5c --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0016-egl-dri3-fix-segfault-in-eglCopyBuffers.patch @@ -0,0 +1,49 @@ +From 03f4f18f9edb4090c6aeca16e6f4de602aea68bf Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Thu, 13 Apr 2017 10:12:40 +0100 +Subject: [PATCH 16/67] egl/dri3: fix segfault in eglCopyBuffers + +The loader_dri3_copy_drawable function expected the drawable to have +a fake front buffer, resulting in a segfault if there wasn't one, +when dri3_fence_reset was called. +If there is no fake front buffer, but there are back buffers, use the +current back buffer. +--- + src/loader/loader_dri3_helper.c | 15 ++++++++++++--- + 1 file changed, 12 insertions(+), 3 deletions(-) + +diff --git a/src/loader/loader_dri3_helper.c b/src/loader/loader_dri3_helper.c +index 6e825f9a898..ff6d1ffc660 100644 +--- a/src/loader/loader_dri3_helper.c ++++ b/src/loader/loader_dri3_helper.c +@@ -863,15 +863,24 @@ loader_dri3_copy_drawable(struct loader_dri3_drawable *draw, + xcb_drawable_t dest, + xcb_drawable_t src) + { ++ struct loader_dri3_buffer *buffer; ++ ++ if (draw->have_fake_front) ++ buffer = dri3_fake_front_buffer(draw); ++ else if (draw->have_back) ++ buffer = dri3_back_buffer(draw); ++ else ++ return; ++ + loader_dri3_flush(draw, __DRI2_FLUSH_DRAWABLE, __DRI2_THROTTLE_COPYSUBBUFFER); + +- dri3_fence_reset(draw->conn, dri3_fake_front_buffer(draw)); ++ dri3_fence_reset(draw->conn, buffer); + dri3_copy_area(draw->conn, + src, dest, + dri3_drawable_gc(draw), + 0, 0, 0, 0, draw->width, draw->height); +- dri3_fence_trigger(draw->conn, dri3_fake_front_buffer(draw)); +- dri3_fence_await(draw->conn, draw, dri3_fake_front_buffer(draw)); ++ dri3_fence_trigger(draw->conn, buffer); ++ dri3_fence_await(draw->conn, draw, buffer); + } + + void +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0017-egl-automatically-call-eglReleaseThread-on-thread-te.patch b/recipes-graphics/mesa/mesa-pvr/0017-egl-automatically-call-eglReleaseThread-on-thread-te.patch new file mode 100644 index 0000000..35b2d51 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0017-egl-automatically-call-eglReleaseThread-on-thread-te.patch @@ -0,0 +1,78 @@ +From d98cd46b5841ecb785a801a977a1b341d98d08c4 Mon Sep 17 00:00:00 2001 +From: Iosif Antochi +Date: Wed, 14 Jun 2017 14:49:55 +0100 +Subject: [PATCH 17/67] egl: automatically call eglReleaseThread on thread + termination + +EGL thread cleanup conformance tests could run out of memory as the contexts +were not freed even though the application requested to have them deleted. +This was caused by the fact that the contexts were still current on their +threads when delete was called and (in order not to block any potential +pending renders) they were just marked for delete. + +Fix this by calling eglReleaseThread on thread termination. This is safe to +do even if this was already called by the application since, according to the +EGL 1.5 spec, eglReleaseThread can be called multiple times without error. + +Fixes: +dEQP-EGL.functional.thread_cleanup.multi_context_* +dEQP-EGL.functional.robustness.create_context.query_robust_access +--- + src/egl/main/eglcurrent.c | 27 ++++++++++++++++++++++++++- + 1 file changed, 26 insertions(+), 1 deletion(-) + +diff --git a/src/egl/main/eglcurrent.c b/src/egl/main/eglcurrent.c +index 11277d3e4c0..c87eac0d007 100644 +--- a/src/egl/main/eglcurrent.c ++++ b/src/egl/main/eglcurrent.c +@@ -44,6 +44,7 @@ static mtx_t _egl_TSDMutex = _MTX_INITIALIZER_NP; + static EGLBoolean _egl_TSDInitialized; + static tss_t _egl_TSD; + static void _eglDestroyThreadInfo(_EGLThreadInfo *t); ++static void _eglDestroyThreadInfoCallback(_EGLThreadInfo *t); + + #ifdef USE_ELF_TLS + static __THREAD_INITIAL_EXEC const _EGLThreadInfo *_egl_TLS; +@@ -86,7 +87,7 @@ static inline EGLBoolean _eglInitTSD() + + /* check again after acquiring lock */ + if (!_egl_TSDInitialized) { +- if (tss_create(&_egl_TSD, (void (*)(void *)) _eglDestroyThreadInfo) != thrd_success) { ++ if (tss_create(&_egl_TSD, (void (*)(void *)) _eglDestroyThreadInfoCallback) != thrd_success) { + mtx_unlock(&_egl_TSDMutex); + return EGL_FALSE; + } +@@ -135,6 +136,30 @@ _eglDestroyThreadInfo(_EGLThreadInfo *t) + } + + ++/** ++ * Delete/free a _EGLThreadInfo object. ++ */ ++static void ++_eglDestroyThreadInfoCallback(_EGLThreadInfo *t) ++{ ++ /* If this callback is called on thread termination then try to also give a ++ * chance to cleanup to the client drivers. If called for module termination ++ * then just release the thread information as calling eglReleaseThread ++ * would result in a deadlock. ++ */ ++ if (_egl_TSDInitialized) { ++ /* The callback handler has replaced the TLS entry, which is passed in as ++ * 't', with NULL. Restore it here so that the release thread finds it in ++ * the TLS entry. ++ */ ++ _eglSetTSD(t); ++ eglReleaseThread(); ++ } else { ++ _eglDestroyThreadInfo(t); ++ } ++} ++ ++ + /** + * Make sure TSD is initialized and return current value. + */ +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0018-egl-add-Tizen-platform-support.patch b/recipes-graphics/mesa/mesa-pvr/0018-egl-add-Tizen-platform-support.patch new file mode 100644 index 0000000..3fa9541 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0018-egl-add-Tizen-platform-support.patch @@ -0,0 +1,1636 @@ +From a2fea4d0fb40d7bdfd2a3860132c37288f3d7864 Mon Sep 17 00:00:00 2001 +From: Frank Binns +Date: Fri, 6 Jan 2017 16:35:00 +0000 +Subject: [PATCH 18/67] egl: add Tizen platform support + +Add a new "tizen" platform to support drm/gbm and Wayland on Tizen. +The platform can be enabled by passing "-Dplatforms=tizen" to Meson. +--- + meson.build | 25 +- + meson_options.txt | 2 +- + src/egl/drivers/dri2/egl_dri2.c | 182 ++++- + src/egl/drivers/dri2/egl_dri2.h | 59 +- + src/egl/drivers/dri2/platform_tizen.c | 980 ++++++++++++++++++++++++++ + src/egl/main/eglapi.c | 7 + + src/egl/main/egldisplay.c | 32 +- + src/egl/main/egldisplay.h | 7 + + src/egl/main/egllog.c | 27 +- + src/egl/meson.build | 7 +- + 10 files changed, 1313 insertions(+), 15 deletions(-) + create mode 100644 src/egl/drivers/dri2/platform_tizen.c + +diff --git a/meson.build b/meson.build +index 968b4f5f499..3d9d345dbf2 100644 +--- a/meson.build ++++ b/meson.build +@@ -358,6 +358,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_tizen = _platforms.contains('tizen') ++ ++if with_platform_tizen and _platforms.length() != 1 ++ error('tizen cannot be enabled at the same time as other platforms') ++endif + + with_glx = get_option('glx') + if with_glx == 'auto' +@@ -910,7 +915,7 @@ else + pre_args += '-DEGL_NO_X11' + gl_pkgconfig_c_flags += '-DEGL_NO_X11' + endif +-if with_gbm and not with_platform_android ++if with_gbm and not with_platform_android and not with_platform_tizen + pre_args += '-DHAVE_DRM_PLATFORM' + endif + +@@ -944,6 +949,15 @@ endif + if with_platform_haiku + pre_args += '-DHAVE_HAIKU_PLATFORM' + endif ++if with_platform_tizen ++ dep_dlog = dependency('dlog') ++ dep_tizen = [ ++ dep_dlog, ++ dependency('libtbm'), ++ dependency('tpl-egl'), ++ ] ++ pre_args += '-DHAVE_TIZEN_PLATFORM' ++endif + + prog_python = import('python').find_installation('python3') + has_mako = run_command( +@@ -1568,7 +1582,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_tizen + ) + if dep_libdrm.found() + pre_args += '-DHAVE_LIBDRM' +@@ -2187,8 +2202,10 @@ if with_egl + lines += 'EGL drivers: ' + ' '.join(egl_drivers) + endif + if with_egl or with_any_vk +- _platforms += 'surfaceless' +- if with_gbm and not with_platform_android ++ if not with_platform_tizen ++ _platforms += 'surfaceless' ++ endif ++ if with_gbm and not with_platform_android and not with_platform_tizen + _platforms += 'drm' + endif + lines += 'EGL/Vulkan/VL platforms: ' + ' '.join(_platforms) +diff --git a/meson_options.txt b/meson_options.txt +index dac791099a1..8230db93c70 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', 'tizen', + ], + description : 'window systems to support. If this is set to `auto`, all platforms applicable will be enabled.' + ) +diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c +index dea5899b3a8..6d34395d65d 100644 +--- a/src/egl/drivers/dri2/egl_dri2.c ++++ b/src/egl/drivers/dri2/egl_dri2.c +@@ -1179,6 +1179,11 @@ dri2_initialize(_EGLDisplay *disp) + case _EGL_PLATFORM_ANDROID: + ret = dri2_initialize_android(disp); + break; ++#ifdef HAVE_TIZEN_PLATFORM ++ case _EGL_PLATFORM_TIZEN: ++ ret = dri2_initialize_tizen(disp); ++ break; ++#endif + default: + unreachable("Callers ensure we cannot get here."); + return EGL_FALSE; +@@ -1253,6 +1258,12 @@ dri2_display_destroy(_EGLDisplay *disp) + case _EGL_PLATFORM_WAYLAND: + dri2_teardown_wayland(dri2_dpy); + break; ++#ifdef HAVE_TIZEN_PLATFORM ++ case _EGL_PLATFORM_TIZEN: ++ if (dri2_dpy->tpl_dpy) ++ tpl_object_unreference((tpl_object_t *) dri2_dpy->tpl_dpy); ++ break; ++#endif + default: + /* TODO: add teardown for other platforms */ + break; +@@ -2293,8 +2304,96 @@ dri2_create_image_khr_renderbuffer(_EGLDisplay *disp, _EGLContext *ctx, + return dri2_create_image_from_dri(disp, dri_image); + } + +-#ifdef HAVE_WAYLAND_PLATFORM ++#ifdef HAVE_TIZEN_PLATFORM ++int ++dri2_fourcc_from_tbm_format(tbm_format format) ++{ ++ switch (format) { ++ case TBM_FORMAT_ARGB8888: ++ return DRM_FORMAT_ARGB8888; ++ case TBM_FORMAT_XRGB8888: ++ return DRM_FORMAT_XRGB8888; ++ case TBM_FORMAT_RGB565: ++ return DRM_FORMAT_RGB565; ++ default: ++ _eglLog(_EGL_DEBUG, "%s: unsupported tbm format %#x", __func__, format); ++ return 0; ++ } ++} + ++static _EGLImage * ++dri2_create_image_wayland_wl_buffer_tizen(_EGLDisplay *disp, _EGLContext *ctx, ++ EGLClientBuffer _buffer, ++ const EGLint *attr_list) ++{ ++ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); ++ __DRIimage *dri_image; ++ _EGLImageAttribs attrs; ++ tbm_surface_h tbm_surf; ++ tbm_bo tbm_buf; ++ tbm_surface_info_s info; ++ int fourcc, fd, pitch, offset; ++ ++ tbm_surf = tpl_display_get_buffer_from_native_pixmap(dri2_dpy->tpl_dpy, ++ (tpl_handle_t) _buffer); ++ if (!tbm_surf) { ++ _eglError(EGL_BAD_PARAMETER, "tpl_display_get_buffer_from_native_pixmap"); ++ return NULL; ++ } ++ ++ if (!_eglParseImageAttribList(&attrs, disp, attr_list)) { ++ _eglError(EGL_BAD_PARAMETER, "dri2_create_image_wayland_wl_buffer_tizen"); ++ return NULL; ++ } ++ ++ if (tbm_surface_get_info(tbm_surf, &info)) { ++ _eglError(EGL_BAD_PARAMETER, "tbm_surface_get_info"); ++ return NULL; ++ } ++ ++ if (info.num_planes > 1) { ++ _eglError(EGL_BAD_PARAMETER, ++ "dri2_create_image_wayland_wl_buffer_tizen (multi-plane format)"); ++ return NULL; ++ } ++ ++ if (attrs.PlaneWL < 0 || attrs.PlaneWL >= info.num_planes) { ++ _eglError(EGL_BAD_PARAMETER, ++ "dri2_create_image_wayland_wl_buffer_tizen (plane out of bounds)"); ++ return NULL; ++ } ++ ++ tbm_buf = tbm_surface_internal_get_bo(tbm_surf, attrs.PlaneWL); ++ if (!tbm_buf) { ++ _eglError(EGL_BAD_PARAMETER, "tbm_surface_internal_get_bo"); ++ return NULL; ++ } ++ ++ fourcc = dri2_fourcc_from_tbm_format(info.format); ++ pitch = info.planes[attrs.PlaneWL].stride; ++ offset = info.planes[attrs.PlaneWL].offset; ++ fd = tbm_bo_export_fd(tbm_buf); ++ ++ dri_image = dri2_dpy->image->createImageFromFds(dri2_dpy->dri_screen, ++ info.width, ++ info.height, ++ fourcc, ++ &fd, ++ 1, ++ &pitch, ++ &offset, ++ tbm_surf); ++ close(fd); ++ if (dri_image == NULL) { ++ _eglError(EGL_BAD_PARAMETER, "createImageFromFds"); ++ return NULL; ++ } ++ ++ return dri2_create_image_from_dri(disp, dri_image); ++} ++#endif ++ ++#ifdef HAVE_WAYLAND_PLATFORM + /* This structure describes how a wl_buffer maps to one or more + * __DRIimages. A wl_drm_buffer stores the wl_drm format code and the + * offsets and strides of the planes in the buffer. This table maps a +@@ -3193,6 +3292,10 @@ dri2_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target, + #ifdef HAVE_WAYLAND_PLATFORM + case EGL_WAYLAND_BUFFER_WL: + return dri2_create_image_wayland_wl_buffer(disp, ctx, buffer, attr_list); ++#endif ++#ifdef HAVE_TIZEN_PLATFORM ++ case EGL_WAYLAND_BUFFER_WL: ++ return dri2_create_image_wayland_wl_buffer_tizen(disp, ctx, buffer, attr_list); + #endif + case EGL_CL_IMAGE_IMG: + return dri2_create_image_img_buffer(disp, ctx, target, buffer, attr_list); +@@ -3214,6 +3317,78 @@ dri2_destroy_image_khr(_EGLDisplay *disp, _EGLImage *image) + return EGL_TRUE; + } + ++#ifdef HAVE_TIZEN_PLATFORM ++ ++static EGLint get_texture_format_from_gbm_format(tbm_format format) ++{ ++ switch (format) { ++ case TBM_FORMAT_ARGB8888: ++ return EGL_TEXTURE_RGBA; ++ default: ++ _eglLog(_EGL_DEBUG, "%s: unsupported tbm format %#x", __func__, format); ++ return 0; ++ } ++} ++ ++static EGLBoolean ++dri2_bind_wayland_display_wl_tizen(_EGLDisplay *disp, struct wl_display *wl_dpy) ++{ ++ (void) disp; ++ (void) wl_dpy; ++ ++ return EGL_TRUE; ++} ++ ++static EGLBoolean ++dri2_unbind_wayland_display_wl_tizen(_EGLDisplay *disp, ++ struct wl_display *wl_dpy) ++{ ++ (void) disp; ++ (void) wl_dpy; ++ ++ return EGL_TRUE; ++} ++ ++static EGLBoolean ++dri2_query_wayland_buffer_wl_tizen(_EGLDisplay *disp, ++ struct wl_resource *buffer_resource, ++ EGLint attribute, EGLint *value) ++{ ++ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); ++ tpl_handle_t pixmap = (tpl_handle_t) buffer_resource; ++ tbm_surface_h tbm_surf; ++ tbm_format format; ++ EGLint tex_format; ++ ++ tbm_surf = tpl_display_get_buffer_from_native_pixmap(dri2_dpy->tpl_dpy, ++ pixmap); ++ if (!tbm_surf) ++ return EGL_FALSE; ++ ++ switch (attribute) { ++ case EGL_TEXTURE_FORMAT: ++ format = tbm_surface_get_format(tbm_surf); ++ tex_format = get_texture_format_from_gbm_format(format); ++ if (!tex_format) ++ return EGL_FALSE; ++ ++ *value = tex_format; ++ break; ++ case EGL_WIDTH: ++ *value = tbm_surface_get_width(tbm_surf); ++ break; ++ case EGL_HEIGHT: ++ *value = tbm_surface_get_height(tbm_surf); ++ break; ++ default: ++ return EGL_FALSE; ++ } ++ ++ return EGL_TRUE; ++} ++ ++#endif ++ + #ifdef HAVE_WAYLAND_PLATFORM + + static void +@@ -3755,6 +3930,11 @@ const _EGLDriver _eglDriver = { + .BindWaylandDisplayWL = dri2_bind_wayland_display_wl, + .UnbindWaylandDisplayWL = dri2_unbind_wayland_display_wl, + .QueryWaylandBufferWL = dri2_query_wayland_buffer_wl, ++#endif ++#ifdef HAVE_TIZEN_PLATFORM ++ .BindWaylandDisplayWL = dri2_bind_wayland_display_wl_tizen, ++ .UnbindWaylandDisplayWL = dri2_unbind_wayland_display_wl_tizen, ++ .QueryWaylandBufferWL = dri2_query_wayland_buffer_wl_tizen, + #endif + .GetSyncValuesCHROMIUM = dri2_get_sync_values_chromium, + .CreateSyncKHR = dri2_create_sync, +diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h +index 6a7eedea112..a8bfe45b1f5 100644 +--- a/src/egl/drivers/dri2/egl_dri2.h ++++ b/src/egl/drivers/dri2/egl_dri2.h +@@ -62,9 +62,9 @@ struct zwp_linux_dmabuf_v1; + #include + #endif + +-#ifdef HAVE_ANDROID_PLATFORM + #define LOG_TAG "EGL-DRI2" + ++#ifdef HAVE_ANDROID_PLATFORM + #include + + #if ANDROID_API_LEVEL >= 26 +@@ -75,6 +75,12 @@ struct zwp_linux_dmabuf_v1; + + #endif /* HAVE_ANDROID_PLATFORM */ + ++#ifdef HAVE_TIZEN_PLATFORM ++#include ++#include ++#include ++#endif ++ + #include "eglconfig.h" + #include "eglcontext.h" + #include "egldevice.h" +@@ -259,6 +265,10 @@ struct dri2_egl_display + + bool is_render_node; + bool is_different_gpu; ++ ++#ifdef HAVE_TIZEN_PLATFORM ++ tpl_display_t *tpl_dpy; ++#endif + }; + + struct dri2_egl_context +@@ -276,6 +286,18 @@ enum wayland_buffer_type { + }; + #endif + ++#define DRI2_SURFACE_NUM_COLOR_BUFFERS 4 ++ ++#ifdef HAVE_TIZEN_PLATFORM ++struct tpl_swap_queue_elem ++{ ++ tbm_surface_h tbm_surf; ++ EGLint *rects; ++ EGLint n_rects_max; ++ EGLint n_rects; ++}; ++#endif ++ + struct dri2_egl_surface + { + _EGLSurface base; +@@ -308,15 +330,33 @@ struct dri2_egl_surface + struct gbm_dri_surface *gbm_surf; + #endif + ++#ifdef HAVE_TIZEN_PLATFORM ++ tpl_surface_t *tpl_surf; ++ bool reset; ++ /* ++ * Protects swap_queue_idx_head, swap_queue_idx_tail and ++ * color_buffers.locked. ++ */ ++ pthread_mutex_t mutex; ++ pthread_cond_t swap_queue_cond; ++ struct tpl_swap_queue_elem swap_queue[DRI2_SURFACE_NUM_COLOR_BUFFERS]; ++ 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_TIZEN_PLATFORM) + struct { ++#if defined(HAVE_WAYLAND_PLATFORM) || defined(HAVE_TIZEN_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 */ +@@ -325,6 +365,9 @@ struct dri2_egl_surface + #endif + #ifdef HAVE_DRM_PLATFORM + struct gbm_bo *bo; ++#endif ++#ifdef HAVE_TIZEN_PLATFORM ++ tbm_surface_h tbm_surf; + #endif + bool locked; + int age; +@@ -525,6 +568,11 @@ dri2_initialize_android(_EGLDisplay *disp) + EGLBoolean + dri2_initialize_surfaceless(_EGLDisplay *disp); + ++#ifdef HAVE_TIZEN_PLATFORM ++EGLBoolean ++dri2_initialize_tizen(_EGLDisplay *disp); ++#endif ++ + EGLBoolean + dri2_initialize_device(_EGLDisplay *disp); + static inline void +@@ -559,6 +607,11 @@ dri2_set_WL_bind_wayland_display(_EGLDisplay *disp) + #endif + } + ++#ifdef HAVE_TIZEN_PLATFORM ++int ++dri2_fourcc_from_tbm_format(tbm_format format); ++#endif ++ + void + dri2_display_destroy(_EGLDisplay *disp); + +diff --git a/src/egl/drivers/dri2/platform_tizen.c b/src/egl/drivers/dri2/platform_tizen.c +new file mode 100644 +index 00000000000..a08bc8c07bf +--- /dev/null ++++ b/src/egl/drivers/dri2/platform_tizen.c +@@ -0,0 +1,980 @@ ++/* ++ * Mesa 3-D graphics library ++ * ++ * Copyright (c) Imagination Technologies Ltd. ++ * Copyright © 2011 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 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 "egl_dri2.h" ++#include "loader.h" ++ ++#define TIZEN_DRM_RENDER_MINOR_START 128 ++#define TIZEN_DRM_RENDER_MINOR_MAX 191 ++ ++#define TIZEN_SWAP_N_RECTS_MIN 32 ++ ++struct rgba_shifts_and_sizes { ++ int shifts[4]; ++ unsigned int sizes[4]; ++}; ++ ++static void *swap_queue_processor_worker(void *data) ++{ ++ struct dri2_egl_surface *dri2_surf = data; ++ ++ pthread_mutex_lock(&dri2_surf->mutex); ++ while (1) { ++ struct tpl_swap_queue_elem *queue_elem; ++ int i; ++ tpl_result_t res; ++ ++ if (dri2_surf->swap_queue_idx_head == dri2_surf->swap_queue_idx_tail) { ++ /* Wait for new swaps to be added to the queue */ ++ pthread_cond_wait(&dri2_surf->swap_queue_cond, &dri2_surf->mutex); ++ continue; ++ } ++ ++ queue_elem = &dri2_surf->swap_queue[dri2_surf->swap_queue_idx_head]; ++ pthread_mutex_unlock(&dri2_surf->mutex); ++ ++ res = tpl_surface_enqueue_buffer_with_damage(dri2_surf->tpl_surf, ++ queue_elem->tbm_surf, ++ queue_elem->n_rects, ++ queue_elem->rects); ++ if (res != TPL_ERROR_NONE) ++ return NULL; ++ ++ pthread_mutex_lock(&dri2_surf->mutex); ++ for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { ++ if (dri2_surf->color_buffers[i].tbm_surf == queue_elem->tbm_surf) { ++ dri2_surf->color_buffers[i].locked = false; ++ break; ++ } ++ } ++ ++ 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, reset_surface_cb ++ * that it may be able to reset the surface or dri2_tizen_destroy_surface ++ * that it may be able to proceed with surface destruction. ++ */ ++ pthread_cond_signal(&dri2_surf->swap_queue_cond); ++ } ++ pthread_mutex_unlock(&dri2_surf->mutex); ++ ++ return NULL; ++} ++ ++static __DRIimage * ++create_image_from_native(struct dri2_egl_surface *dri2_surf, ++ tbm_surface_h tbm_surf, ++ int *width, int *height, ++ void *loaderPrivate) ++{ ++ _EGLSurface *surf = &dri2_surf->base; ++ struct dri2_egl_display *dri2_dpy = dri2_egl_display(surf->Resource.Display); ++ tbm_bo tbm_buf; ++ tbm_surface_info_s info; ++ int fd, fourcc, offset, pitch; ++ __DRIimage *dri_image; ++ ++ tbm_buf = tbm_surface_internal_get_bo(tbm_surf, 0); ++ if (!tbm_buf) { ++ _eglLog(_EGL_DEBUG, "%s: failed to get bo for tbm surface", __func__); ++ return NULL; ++ } ++ ++ if (tbm_surface_get_info(tbm_surf, &info)) { ++ _eglLog(_EGL_DEBUG, "%s: failed to get tbm surface info", __func__); ++ return NULL; ++ } ++ ++ fd = tbm_bo_export_fd(tbm_buf); ++ fourcc = dri2_fourcc_from_tbm_format(info.format); ++ offset = info.planes[0].offset; ++ pitch = info.planes[0].stride; ++ ++ dri_image = dri2_dpy->image->createImageFromFds(dri2_dpy->dri_screen, ++ info.width, ++ info.height, ++ fourcc, ++ &fd, ++ 1, ++ &pitch, ++ &offset, ++ loaderPrivate); ++ close(fd); ++ ++ if (!dri_image) { ++ _eglLog(_EGL_DEBUG, "%s: failed to create dri image from tbm bo", __func__); ++ return NULL; ++ } ++ ++ if (width) ++ *width = info.width; ++ ++ if (height) ++ *height = info.height; ++ ++ return dri_image; ++} ++ ++static int ++get_back_bo(struct dri2_egl_surface *dri2_surf, bool allow_update) ++{ ++ struct dri2_egl_display *dri2_dpy = ++ dri2_egl_display(dri2_surf->base.Resource.Display); ++ tbm_surface_h tbm_surf; ++ tpl_bool_t tpl_surf_valid; ++ int i; ++ ++ if (dri2_surf->base.Type == EGL_PIXMAP_BIT) { ++ _eglLog(_EGL_DEBUG, "%s: can't get back bo for pixmap surface", __func__); ++ return -1; ++ } ++ ++ if (dri2_surf->back && !allow_update) ++ return 0; ++ ++ /* ++ * If the tpl surface is no longer valid, e.g. it has been resized, then ++ * we should get a new back buffer. ++ */ ++ tpl_surf_valid = tpl_surface_validate(dri2_surf->tpl_surf); ++ if (dri2_surf->back && tpl_surf_valid == TPL_TRUE) ++ return 0; ++ ++ tbm_surf = tpl_surface_dequeue_buffer(dri2_surf->tpl_surf); ++ if (!tbm_surf) { ++ _eglLog(_EGL_DEBUG, "%s: surface buffer dequeue failed", __func__); ++ return -1; ++ } ++ ++ pthread_mutex_lock(&dri2_surf->mutex); ++ /* ++ * If the tpl surface is no longer valid, e.g. it has been resized, then the ++ * call to tpl_surface should've resulted in a call to reset_surface_cb, ++ * which sets the dri2_surf reset flag. In this case we need to reset the ++ * color_buffer state. ++ * ++ * Note: we can't rely on the return value of tpl_surface_validate ++ * since the surface may have become invalid between this call and ++ * tpl_surface_dequeue_buffer. ++ */ ++ if (dri2_surf->reset) { ++ /* Wait for any outstanding swaps to complete */ ++ while (dri2_surf->swap_queue_idx_head != dri2_surf->swap_queue_idx_tail) ++ pthread_cond_wait(&dri2_surf->swap_queue_cond, &dri2_surf->mutex); ++ ++ /* Cancel the old back buffer */ ++ if (dri2_surf->back) { ++ tbm_surface_internal_unref(dri2_surf->back->tbm_surf); ++ dri2_surf->back->locked = false; ++ dri2_surf->back = NULL; ++ } ++ ++ /* Reset the color buffers */ ++ for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { ++ assert(!dri2_surf->color_buffers[i].locked); ++ ++ if (dri2_surf->color_buffers[i].dri_image) { ++ dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image); ++ dri2_surf->color_buffers[i].dri_image = NULL; ++ } ++ ++ dri2_surf->color_buffers[i].tbm_surf = NULL; ++ dri2_surf->color_buffers[i].age = 0; ++ } ++ ++ dri2_surf->back = NULL; ++ dri2_surf->current = NULL; ++ dri2_surf->reset = false; ++ } ++ ++ assert(!dri2_surf->back); ++ ++ for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { ++ if (dri2_surf->color_buffers[i].tbm_surf == tbm_surf) { ++ dri2_surf->back = &dri2_surf->color_buffers[i]; ++ assert(!dri2_surf->back->locked); ++ break; ++ } ++ } ++ ++ while (!dri2_surf->back) { ++ int age; ++ ++ /* ++ * Search for a free color buffer. Free the oldest buffer if one ++ * cannot be found. ++ */ ++ for (i = 0, age = -1; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { ++ if (dri2_surf->color_buffers[i].locked) ++ continue; ++ if (!dri2_surf->color_buffers[i].dri_image) { ++ dri2_surf->back = &dri2_surf->color_buffers[i]; ++ break; ++ } ++ ++ if (dri2_surf->color_buffers[i].age > age) { ++ dri2_surf->back = &dri2_surf->color_buffers[i]; ++ age = dri2_surf->color_buffers[i].age; ++ } ++ } ++ ++ if (!dri2_surf->back) { ++ /* ++ * There aren't any available back buffers so wait for ++ * swap_queue_processor_worker to make one available. ++ */ ++ pthread_cond_wait(&dri2_surf->swap_queue_cond, &dri2_surf->mutex); ++ continue; ++ } ++ ++ if (dri2_surf->back->dri_image) ++ dri2_dpy->image->destroyImage(dri2_surf->back->dri_image); ++ ++ dri2_surf->back->dri_image = ++ create_image_from_native(dri2_surf, tbm_surf, ++ &dri2_surf->base.Width, ++ &dri2_surf->base.Height, ++ dri2_surf); ++ if (!dri2_surf->back->dri_image) { ++ dri2_surf->back = NULL; ++ pthread_mutex_unlock(&dri2_surf->mutex); ++ return -1; ++ } ++ } ++ ++ dri2_surf->back->tbm_surf = tbm_surf; ++ dri2_surf->back->locked = true; ++ ++ if (dri2_surf->base.SwapBehavior == EGL_BUFFER_PRESERVED && ++ dri2_surf->current) { ++ _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); ++ } ++ } ++ ++ pthread_mutex_unlock(&dri2_surf->mutex); ++ ++ return 0; ++} ++ ++static int ++get_front_bo(struct dri2_egl_surface *dri2_surf) ++{ ++ struct dri2_egl_display *dri2_dpy = ++ dri2_egl_display(dri2_surf->base.Resource.Display); ++ ++ if (dri2_surf->front) ++ return 0; ++ ++ if (dri2_surf->base.Type == EGL_PIXMAP_BIT) { ++ tbm_surface_h tbm_surf; ++ ++ tbm_surf = tpl_surface_dequeue_buffer(dri2_surf->tpl_surf); ++ if (!tbm_surf) ++ return -1; ++ ++ dri2_surf->front = create_image_from_native(dri2_surf, tbm_surf, ++ &dri2_surf->base.Width, ++ &dri2_surf->base.Height, ++ dri2_surf); ++ } else { ++ dri2_surf->front = dri2_dpy->image->createImage(dri2_dpy->dri_screen, ++ dri2_surf->base.Width, ++ dri2_surf->base.Height, ++ dri2_surf->visual, ++ 0, ++ dri2_surf); ++ } ++ ++ return dri2_surf->front ? 0 : -1; ++} ++ ++static _EGLSurface * ++create_surface(_EGLDisplay *dpy, _EGLConfig *config, EGLint type, ++ const EGLint *attrib_list) ++{ ++ struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); ++ struct dri2_egl_config *dri2_config = dri2_egl_config(config); ++ struct dri2_egl_surface *dri2_surf; ++ const __DRIconfig *dri_config; ++ ++ dri2_surf = calloc(1, sizeof(*dri2_surf)); ++ if (!dri2_surf) { ++ _eglError(EGL_BAD_ALLOC, "DRI2: failed to create surface"); ++ return NULL; ++ } ++ ++ if (!dri2_init_surface(&dri2_surf->base, dpy, type, config, attrib_list, ++ false, 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, "DRI2: failed to create drawable"); ++ goto err_free_surface; ++ } ++ ++ pthread_mutex_init(&dri2_surf->mutex, NULL); ++ pthread_cond_init(&dri2_surf->swap_queue_cond, NULL); ++ ++ return &dri2_surf->base; ++ ++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); ++ ++ pthread_cond_destroy(&dri2_surf->swap_queue_cond); ++ pthread_mutex_destroy(&dri2_surf->mutex); ++ dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable); ++ free(dri2_surf); ++} ++ ++static void ++reset_surface_cb(void *data) ++{ ++ struct dri2_egl_surface *dri2_surf = data; ++ ++ dri2_surf->reset = true; ++} ++ ++static _EGLSurface * ++dri2_tizen_create_window_surface(_EGLDisplay *dpy, _EGLConfig *config, ++ void *native_window, const EGLint *attrib_list) ++{ ++ struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); ++ struct dri2_egl_surface *dri2_surf; ++ _EGLSurface *surf; ++ int width, height; ++ tbm_format format; ++ tpl_result_t res; ++ int err; ++ ++ surf = create_surface(dpy, config, EGL_WINDOW_BIT, attrib_list); ++ if (!surf) ++ return NULL; ++ ++ res = tpl_display_get_native_window_info(dri2_dpy->tpl_dpy, native_window, ++ &width, &height, &format, ++ config->RedSize + ++ config->GreenSize + ++ config->BlueSize + ++ config->AlphaSize, ++ config->AlphaSize); ++ if (res != TPL_ERROR_NONE) { ++ _eglError(EGL_BAD_NATIVE_WINDOW, "DRI2: failed to get window info"); ++ goto err_destroy_surface; ++ } ++ ++ dri2_surf = dri2_egl_surface(surf); ++ dri2_surf->base.Width = width; ++ dri2_surf->base.Height = height; ++ ++ dri2_surf->tpl_surf = tpl_surface_create(dri2_dpy->tpl_dpy, native_window, ++ TPL_SURFACE_TYPE_WINDOW, format); ++ if (!dri2_surf->tpl_surf) { ++ _eglError(EGL_BAD_ALLOC, "DRI2: failed to create TPL window surface"); ++ goto err_destroy_surface; ++ } ++ ++ res = tpl_surface_set_reset_cb(dri2_surf->tpl_surf, dri2_surf, ++ reset_surface_cb); ++ if (res != TPL_ERROR_NONE) { ++ _eglError(EGL_BAD_NATIVE_WINDOW, ++ "DRI2: failed to register TPL window surface reset callback"); ++ goto err_tpl_surface_destroy; ++ } ++ ++ err = pthread_create(&dri2_surf->swap_queue_processor, NULL, ++ swap_queue_processor_worker, dri2_surf); ++ if (err) { ++ _eglError(EGL_BAD_ALLOC, "DRI2: failed to create TPL window thread"); ++ goto err_tpl_surface_destroy; ++ } ++ ++ return surf; ++ ++err_tpl_surface_destroy: ++ tpl_object_unreference((tpl_object_t *) dri2_surf->tpl_surf); ++err_destroy_surface: ++ destroy_surface(surf); ++ return NULL; ++} ++ ++static _EGLSurface * ++dri2_tizen_create_pixmap_surface(_EGLDisplay *dpy, _EGLConfig *config, ++ void *native_pixmap, const EGLint *attrib_list) ++{ ++ struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); ++ struct dri2_egl_surface *dri2_surf; ++ _EGLSurface *surf; ++ int width, height; ++ tbm_format format; ++ tpl_result_t res; ++ ++ surf = create_surface(dpy, config, EGL_PIXMAP_BIT, attrib_list); ++ if (!surf) ++ return NULL; ++ ++ res = tpl_display_get_native_pixmap_info(dri2_dpy->tpl_dpy, native_pixmap, ++ &width, &height, &format); ++ if (res != TPL_ERROR_NONE) { ++ _eglError(EGL_BAD_NATIVE_PIXMAP, "DRI2: failed to get pixmap info"); ++ goto err_destroy_surface; ++ } ++ ++ dri2_surf = dri2_egl_surface(surf); ++ dri2_surf->base.Width = width; ++ dri2_surf->base.Height = height; ++ ++ dri2_surf->tpl_surf = tpl_surface_create(dri2_dpy->tpl_dpy, native_pixmap, ++ TPL_SURFACE_TYPE_PIXMAP, format); ++ if (!dri2_surf->tpl_surf) { ++ _eglError(EGL_BAD_ALLOC, "DRI2: failed to create TPL pixmap surface"); ++ goto err_destroy_surface; ++ } ++ ++ return surf; ++ ++err_destroy_surface: ++ destroy_surface(surf); ++ return NULL; ++} ++ ++static _EGLSurface * ++dri2_tizen_create_pbuffer_surface(_EGLDisplay *dpy, _EGLConfig *config, ++ const EGLint *attrib_list) ++{ ++ struct dri2_egl_surface *dri2_surf; ++ _EGLSurface *surf; ++ ++ surf = create_surface(dpy, config, EGL_PBUFFER_BIT, attrib_list); ++ if (!surf) ++ return NULL; ++ ++ dri2_surf = dri2_egl_surface(surf); ++ ++ if (config->RedSize == 5) ++ dri2_surf->visual = __DRI_IMAGE_FORMAT_RGB565; ++ else if (config->AlphaSize) ++ dri2_surf->visual = __DRI_IMAGE_FORMAT_ARGB8888; ++ else ++ dri2_surf->visual = __DRI_IMAGE_FORMAT_XRGB8888; ++ ++ return surf; ++} ++ ++static EGLBoolean ++dri2_tizen_destroy_surface(_EGLDisplay *dpy, _EGLSurface *surf) ++{ ++ struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); ++ struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); ++ int i; ++ ++ if (dri2_surf->swap_queue_processor) { ++ /* Wait for any outstanding swaps to complete */ ++ 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); ++ pthread_mutex_unlock(&dri2_surf->mutex); ++ ++ pthread_cancel(dri2_surf->swap_queue_processor); ++ pthread_join(dri2_surf->swap_queue_processor, NULL); ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(dri2_surf->swap_queue); i++) ++ free(dri2_surf->swap_queue[i].rects); ++ ++ if (dri2_surf->front) ++ dri2_dpy->image->destroyImage(dri2_surf->front); ++ ++ if (dri2_surf->back) { ++ tbm_surface_internal_unref(dri2_surf->back->tbm_surf); ++ dri2_surf->back->locked = false; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { ++ if (dri2_surf->color_buffers[i].dri_image) ++ dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image); ++ assert(!dri2_surf->color_buffers[i].locked); ++ } ++ ++ if (dri2_surf->tpl_surf) ++ tpl_object_unreference((tpl_object_t *) dri2_surf->tpl_surf); ++ ++ destroy_surface(surf); ++ ++ return EGL_TRUE; ++} ++ ++static EGLBoolean ++dri2_tizen_swap_interval(_EGLDisplay *dpy, _EGLSurface *surf, EGLint interval) ++{ ++ struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); ++ tpl_result_t res; ++ ++ if (interval > surf->Config->MaxSwapInterval) ++ interval = surf->Config->MaxSwapInterval; ++ else if (interval < surf->Config->MinSwapInterval) ++ interval = surf->Config->MinSwapInterval; ++ ++ if (interval == surf->SwapInterval) ++ return EGL_TRUE; ++ ++ res = tpl_surface_set_post_interval(dri2_surf->tpl_surf, interval); ++ if (res == TPL_ERROR_NONE) { ++ surf->SwapInterval = interval; ++ return EGL_TRUE; ++ } ++ ++ return EGL_FALSE; ++} ++ ++static EGLBoolean ++dri2_tizen_swap_buffers_with_damage(_EGLDisplay *dpy, _EGLSurface *draw, ++ const EGLint *rects, EGLint n_rects) ++{ ++ struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); ++ struct tpl_swap_queue_elem *queue_elem; ++ int i; ++ ++ if (dri2_surf->base.Type != EGL_WINDOW_BIT) ++ return EGL_TRUE; ++ ++ for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) { ++ if (draw->SwapBehavior == EGL_BUFFER_PRESERVED) ++ dri2_surf->color_buffers[i].age = 1; ++ else 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, false) < 0) { ++ _eglError(EGL_BAD_ALLOC, "DRI2: failed to get back buffer"); ++ return EGL_FALSE; ++ } ++ ++ dri2_flush_drawable_for_swapbuffers(dpy, draw); ++ ++ pthread_mutex_lock(&dri2_surf->mutex); ++ queue_elem = ++ &dri2_surf->swap_queue[dri2_surf->swap_queue_idx_tail]; ++ ++ queue_elem->tbm_surf = dri2_surf->back->tbm_surf; ++ ++ /* Allocate space for damage rectangles in swap queue element if necessary */ ++ if (queue_elem->n_rects_max < n_rects) { ++ free(queue_elem->rects); ++ ++ if (!queue_elem->n_rects_max) ++ queue_elem->n_rects_max = TIZEN_SWAP_N_RECTS_MIN; ++ ++ while (queue_elem->n_rects_max <= n_rects) ++ queue_elem->n_rects_max *= 2; ++ ++ queue_elem->rects = ++ malloc(sizeof(*queue_elem->rects) * queue_elem->n_rects_max); ++ if (!queue_elem->rects) { ++ _eglError(EGL_BAD_ALLOC, ++ "DRI2: failed to allocate space for damage rects"); ++ queue_elem->n_rects_max = 0; ++ pthread_mutex_unlock(&dri2_surf->mutex); ++ return EGL_FALSE; ++ } ++ } ++ ++ /* Copy damage rectangles into swap queue element */ ++ STATIC_ASSERT(sizeof(*queue_elem->rects) == sizeof(*rects)); ++ memcpy(&queue_elem->rects[0], &rects[0], sizeof(*rects) * n_rects); ++ queue_elem->n_rects = n_rects; ++ ++ dri2_surf->swap_queue_idx_tail++; ++ dri2_surf->swap_queue_idx_tail %= ARRAY_SIZE(dri2_surf->color_buffers); ++ ++ /* Notify swap_queue_processor_worker that there's new work */ ++ pthread_cond_signal(&dri2_surf->swap_queue_cond); ++ pthread_mutex_unlock(&dri2_surf->mutex); ++ ++ dri2_surf->back->age = 1; ++ dri2_surf->current = dri2_surf->back; ++ dri2_surf->back = NULL; ++ ++ return EGL_TRUE; ++} ++ ++static EGLBoolean ++dri2_tizen_swap_buffers(_EGLDisplay *dpy, _EGLSurface *draw) ++{ ++ return dri2_tizen_swap_buffers_with_damage(dpy, draw, NULL, 0); ++} ++ ++static EGLint ++dri2_tizen_query_buffer_age(_EGLDisplay *dpy, _EGLSurface *surface) ++{ ++ struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface); ++ ++ if (get_back_bo(dri2_surf, false) < 0) { ++ _eglError(EGL_BAD_ALLOC, "DRI2: failed to get back buffer"); ++ return -1; ++ } ++ ++ return dri2_surf->back->age; ++} ++ ++ ++static EGLBoolean ++dri2_tizen_query_surface(_EGLDisplay *dpy, _EGLSurface *surf, ++ EGLint attribute, EGLint *value) ++{ ++ struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); ++ struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); ++ ++ switch (attribute) { ++ case EGL_WIDTH: ++ case EGL_HEIGHT: ++ if (dri2_surf->base.Type == EGL_WINDOW_BIT) { ++ tpl_handle_t window; ++ int width, height; ++ tbm_format format; ++ tpl_result_t res; ++ ++ window = tpl_surface_get_native_handle(dri2_surf->tpl_surf); ++ ++ res = tpl_display_get_native_window_info(dri2_dpy->tpl_dpy, window, ++ &width, &height, &format, ++ surf->Config->RedSize + ++ surf->Config->GreenSize + ++ surf->Config->BlueSize + ++ surf->Config->AlphaSize, ++ surf->Config->AlphaSize); ++ if (res == TPL_ERROR_NONE) { ++ surf->Width = width; ++ surf->Height = height; ++ } ++ } ++ break; ++ default: ++ break; ++ } ++ ++ return _eglQuerySurface(dpy, surf, attribute, value); ++} ++ ++ ++static struct dri2_egl_display_vtbl dri2_tizen_display_vtbl = { ++ .create_window_surface = dri2_tizen_create_window_surface, ++ .create_pixmap_surface = dri2_tizen_create_pixmap_surface, ++ .create_pbuffer_surface = dri2_tizen_create_pbuffer_surface, ++ .destroy_surface = dri2_tizen_destroy_surface, ++ .create_image = dri2_create_image_khr, ++ .swap_interval = dri2_tizen_swap_interval, ++ .swap_buffers = dri2_tizen_swap_buffers, ++ .swap_buffers_with_damage = dri2_tizen_swap_buffers_with_damage, ++ .query_buffer_age = dri2_tizen_query_buffer_age, ++ .query_surface = dri2_tizen_query_surface, ++ .get_dri_drawable = dri2_surface_get_dri_drawable, ++}; ++ ++static int ++dri2_tizen_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->front = NULL; ++ buffers->back = NULL; ++ ++ if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) ++ if (get_front_bo(dri2_surf) < 0) ++ return 0; ++ ++ if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) ++ if (get_back_bo(dri2_surf, true) < 0) ++ return 0; ++ ++ if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) { ++ buffers->front = dri2_surf->front; ++ buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT; ++ } ++ ++ if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) { ++ buffers->back = dri2_surf->back->dri_image; ++ buffers->image_mask |= __DRI_IMAGE_BUFFER_BACK; ++ } ++ ++ return 1; ++} ++ ++static void ++dri2_tizen_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate) ++{ ++} ++ ++static const __DRIimageLoaderExtension tizen_image_loader_extension = { ++ .base = { __DRI_IMAGE_LOADER, 1 }, ++ .getBuffers = dri2_tizen_get_buffers, ++ .flushFrontBuffer = dri2_tizen_flush_front_buffer, ++}; ++ ++static const __DRIextension *image_loader_extensions[] = { ++ &tizen_image_loader_extension.base, ++ &image_lookup_extension.base, ++ NULL, ++}; ++ ++static EGLBoolean ++dri2_tizen_add_configs(_EGLDisplay *dpy) ++{ ++ struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy); ++ int count = 0; ++ ++ for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++) { ++ static const struct rgba_shifts_and_sizes pbuffer_sasa[] = { ++ { ++ /* ARGB8888 */ ++ { 16, 8, 0, 24 }, ++ { 8, 8, 8, 8 }, ++ }, ++ { ++ /* RGB888 */ ++ { 16, 8, 0, -1 }, ++ { 8, 8, 8, 0 }, ++ }, ++ { ++ /* RGB565 */ ++ { 11, 5, 0, -1 }, ++ { 5, 6, 5, 0 }, ++ }, ++ }; ++ struct dri2_egl_config *dri2_cfg; ++ int shifts[4]; ++ unsigned int sizes[4]; ++ unsigned int caveat = 0; ++ int surface_type = 0; ++ tpl_bool_t is_slow; ++ EGLint attr_list[] = { ++ EGL_NATIVE_VISUAL_ID, 0, ++ EGL_CONFIG_CAVEAT, EGL_NONE, ++ EGL_NONE, ++ }; ++ tpl_result_t res; ++ ++ dri2_get_shifts_and_sizes(dri2_dpy->core, dri2_dpy->driver_configs[i], ++ shifts, sizes); ++ ++ dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i], ++ __DRI_ATTRIB_BUFFER_SIZE, &depth); ++ ++ dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i], ++ __DRI_ATTRIB_CONFIG_CAVEAT, &caveat); ++ ++ res = tpl_display_query_config(dri2_dpy->tpl_dpy, TPL_SURFACE_TYPE_WINDOW, ++ sizes[0], sizes[1], sizes[2], sizes[3], ++ depth, &attr_list[1], &is_slow); ++ if (res != TPL_ERROR_NONE) ++ continue; ++ surface_type |= EGL_WINDOW_BIT; ++ ++ if (is_slow) ++ caveat |= __DRI_ATTRIB_SLOW_BIT; ++ ++ res = tpl_display_query_config(dri2_dpy->tpl_dpy, TPL_SURFACE_TYPE_PIXMAP, ++ sizes[0], sizes[1], sizes[2], sizes[3], ++ depth, NULL, &is_slow); ++ if (res == TPL_ERROR_NONE) { ++ surface_type |= EGL_PIXMAP_BIT; ++ ++ if (is_slow) ++ caveat |= __DRI_ATTRIB_SLOW_BIT; ++ } ++ ++ for (unsigned j = 0; j < ARRAY_SIZE(pbuffer_sasa); j++) { ++ const struct rgba_shifts_and_sizes *pbuffer_sas = &pbuffer_sasa[j]; ++ ++ if (shifts[0] == pbuffer_sas->shifts[0] && ++ shifts[1] == pbuffer_sas->shifts[1] && ++ shifts[2] == pbuffer_sas->shifts[2] && ++ shifts[3] == pbuffer_sas->shifts[3] && ++ sizes[0] == pbuffer_sas->sizes[0] && ++ sizes[1] == pbuffer_sas->sizes[1] && ++ sizes[2] == pbuffer_sas->sizes[2] && ++ sizes[3] == pbuffer_sas->sizes[3]) { ++ surface_type |= EGL_PBUFFER_BIT; ++ break; ++ } ++ } ++ ++ if (dri2_dpy->image->base.version >= 9 && dri2_dpy->image->blitImage) ++ surface_type |= EGL_SWAP_BEHAVIOR_PRESERVED_BIT; ++ ++ if (caveat & __DRI_ATTRIB_NON_CONFORMANT_CONFIG) ++ attr_list[3] = EGL_NON_CONFORMANT_CONFIG; ++ else if (caveat & __DRI_ATTRIB_SLOW_BIT) ++ attr_list[3] = EGL_SLOW_CONFIG; ++ ++ dri2_cfg = dri2_add_config(dpy, dri2_dpy->driver_configs[i], count + 1, ++ surface_type, &attr_list[0], NULL, NULL); ++ if (dri2_cfg) ++ count++; ++ } ++ ++ return count != 0; ++} ++ ++EGLBoolean ++dri2_initialize_tizen(_EGLDisplay *dpy) ++{ ++ struct dri2_egl_display *dri2_dpy; ++ int i; ++ ++ dri2_dpy = calloc(1, sizeof(*dri2_dpy)); ++ if (!dri2_dpy) ++ return _eglError(EGL_BAD_ALLOC, "DRI2: failed to create display"); ++ ++ dpy->DriverData = (void *) dri2_dpy; ++ dri2_dpy->fd = -1; ++ ++ dri2_dpy->tpl_dpy = ++ tpl_display_create(TPL_BACKEND_UNKNOWN, dpy->PlatformDisplay); ++ if (!dri2_dpy->tpl_dpy) { ++ _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to create tpl display"); ++ goto cleanup; ++ } ++ ++ for (i = TIZEN_DRM_RENDER_MINOR_START; i <= TIZEN_DRM_RENDER_MINOR_MAX; i++) { ++ char *render_path; ++ ++ if (asprintf(&render_path, DRM_RENDER_DEV_NAME, DRM_DIR_NAME, i) < 0) ++ continue; ++ ++ dri2_dpy->fd = loader_open_device(render_path); ++ free(render_path); ++ if (dri2_dpy->fd < 0) ++ continue; ++ ++ dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd); ++ if (dri2_dpy->driver_name) { ++ if (dri2_load_driver_dri3(dpy)) { ++ _EGLDevice *dev = _eglAddDevice(dri2_dpy->fd, false); ++ if (!dev) { ++ dlclose(dri2_dpy->driver); ++ _eglLog(_EGL_WARNING, "DRI2: failed to find EGLDevice"); ++ } else { ++ dri2_dpy->own_device = 1; ++ dpy->Device = dev; ++ break; ++ } ++ } ++ ++ free(dri2_dpy->driver_name); ++ dri2_dpy->driver_name = NULL; ++ } ++ ++ close(dri2_dpy->fd); ++ dri2_dpy->fd = -1; ++ } ++ ++ if (dri2_dpy->fd < 0) { ++ _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to load driver"); ++ goto cleanup; ++ } ++ ++ dri2_dpy->loader_extensions = &image_loader_extensions[0]; ++ ++ if (!dri2_create_screen(dpy)) { ++ _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to create screen"); ++ goto cleanup; ++ } ++ ++ if (!dri2_setup_extensions(dpy)) ++ goto cleanup; ++ ++ dri2_setup_screen(dpy); ++ ++ if (!dri2_tizen_add_configs(dpy)) { ++ _eglError(EGL_NOT_INITIALIZED, "DRI2: failed to add configs"); ++ goto cleanup; ++ } ++ ++ dpy->Extensions.EXT_buffer_age = EGL_TRUE; ++ dpy->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE; ++ dpy->Extensions.KHR_image_base = EGL_TRUE; ++ dpy->Extensions.WL_bind_wayland_display = EGL_TRUE; ++ ++ /* ++ * Fill vtbl last to prevent accidentally calling virtual function during ++ * initialization. ++ */ ++ dri2_dpy->vtbl = &dri2_tizen_display_vtbl; ++ ++ return EGL_TRUE; ++ ++cleanup: ++ dri2_display_destroy(dpy); ++ return EGL_FALSE; ++} +diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c +index 234449adf64..43c7b917909 100644 +--- a/src/egl/main/eglapi.c ++++ b/src/egl/main/eglapi.c +@@ -416,6 +416,13 @@ _eglGetPlatformDisplayCommon(EGLenum platform, void *native_display, + case EGL_PLATFORM_DEVICE_EXT: + disp = _eglGetDeviceDisplay(native_display, attrib_list); + break; ++#ifdef HAVE_TIZEN_PLATFORM ++ case EGL_PLATFORM_GBM_MESA: ++ case EGL_PLATFORM_WAYLAND_EXT: ++ disp = _eglGetTizenDisplay((struct gbm_device*) native_display, ++ attrib_list); ++ break; ++#endif + default: + RETURN_EGL_ERROR(NULL, EGL_BAD_PARAMETER, NULL); + } +diff --git a/src/egl/main/egldisplay.c b/src/egl/main/egldisplay.c +index 765618f0dd0..486ac3b0557 100644 +--- a/src/egl/main/egldisplay.c ++++ b/src/egl/main/egldisplay.c +@@ -77,6 +77,7 @@ static const struct { + { _EGL_PLATFORM_HAIKU, "haiku" }, + { _EGL_PLATFORM_SURFACELESS, "surfaceless" }, + { _EGL_PLATFORM_DEVICE, "device" }, ++ { _EGL_PLATFORM_TIZEN, "tizen" }, + }; + + +@@ -107,6 +108,17 @@ _eglGetNativePlatformFromEnv(void) + } + } + ++#ifdef HAVE_TIZEN_PLATFORM ++ switch (plat) { ++ case _EGL_PLATFORM_DRM: ++ case _EGL_PLATFORM_WAYLAND: ++ plat = _EGL_PLATFORM_TIZEN; ++ break; ++ default: ++ break; ++ } ++#endif ++ + if (plat == _EGL_INVALID_PLATFORM) + _eglLog(_EGL_WARNING, "invalid EGL_PLATFORM given"); + +@@ -120,6 +132,7 @@ _eglGetNativePlatformFromEnv(void) + static _EGLPlatformType + _eglNativePlatformDetectNativeDisplay(void *nativeDisplay) + { ++#ifndef HAVE_TIZEN_PLATFORM + if (nativeDisplay == EGL_DEFAULT_DISPLAY) + return _EGL_INVALID_PLATFORM; + +@@ -141,7 +154,7 @@ _eglNativePlatformDetectNativeDisplay(void *nativeDisplay) + return _EGL_PLATFORM_DRM; + #endif + } +- ++#endif + return _EGL_INVALID_PLATFORM; + } + +@@ -595,6 +608,23 @@ _eglGetAndroidDisplay(void *native_display, + } + #endif /* HAVE_ANDROID_PLATFORM */ + ++#ifdef HAVE_TIZEN_PLATFORM ++_EGLDisplay* ++_eglGetTizenDisplay(void *native_display, ++ const EGLint *attrib_list) ++{ ++ /* EGL_MESA_platform_gbm and EGL_EXT_platform_wayland recognizes no ++ * attributes. */ ++ if (attrib_list != NULL && attrib_list[0] != EGL_NONE) { ++ _eglError(EGL_BAD_ATTRIBUTE, "eglGetPlatformDisplay"); ++ return NULL; ++ } ++ ++ return _eglFindDisplay(_EGL_PLATFORM_TIZEN, native_display, ++ attrib_list); ++} ++#endif /* HAVE_TIZEN_PLATFORM */ ++ + _EGLDisplay* + _eglGetDeviceDisplay(void *native_display, + const EGLAttrib *attrib_list) +diff --git a/src/egl/main/egldisplay.h b/src/egl/main/egldisplay.h +index 5b05dcc1e6d..cbb098331bf 100644 +--- a/src/egl/main/egldisplay.h ++++ b/src/egl/main/egldisplay.h +@@ -52,6 +52,7 @@ enum _egl_platform_type { + _EGL_PLATFORM_HAIKU, + _EGL_PLATFORM_SURFACELESS, + _EGL_PLATFORM_DEVICE, ++ _EGL_PLATFORM_TIZEN, + + _EGL_NUM_PLATFORMS, + _EGL_INVALID_PLATFORM = -1 +@@ -329,6 +330,12 @@ _eglGetAndroidDisplay(void *native_display, + const EGLAttrib *attrib_list); + #endif + ++#ifdef HAVE_TIZEN_PLATFORM ++_EGLDisplay* ++_eglGetTizenDisplay(void *native_display, ++ const EGLint *attrib_list); ++#endif ++ + _EGLDisplay* + _eglGetDeviceDisplay(void *native_display, + const EGLAttrib *attrib_list); +diff --git a/src/egl/main/egllog.c b/src/egl/main/egllog.c +index 6a91952577f..973b7600ab1 100644 +--- a/src/egl/main/egllog.c ++++ b/src/egl/main/egllog.c +@@ -46,15 +46,17 @@ + + #include "egllog.h" + +-#ifdef HAVE_ANDROID_PLATFORM + #define LOG_TAG "EGL-MAIN" ++ ++#ifdef HAVE_ANDROID_PLATFORM + #if ANDROID_API_LEVEL >= 26 + #include + #else + #include + #endif /* use log/log.h start from android 8 major version */ +- +-#endif /* HAVE_ANDROID_PLATFORM */ ++#elif defined(HAVE_TIZEN_PLATFORM) ++#include ++#endif /* HAVE_TIZEN_PLATFORM */ + + #define MAXSTRING 1000 + #define FALLBACK_LOG_LEVEL _EGL_WARNING +@@ -93,9 +95,26 @@ _eglDefaultLogger(EGLint level, const char *msg) + [_EGL_DEBUG] = ANDROID_LOG_DEBUG, + }; + LOG_PRI(egl2alog[level], LOG_TAG, "%s", msg); ++#elif defined(HAVE_TIZEN_PLATFORM) ++ switch (level) { ++ case _EGL_DEBUG: ++ LOGD("%s", msg); ++ break; ++ case _EGL_INFO: ++ LOGI("%s", msg); ++ break; ++ case _EGL_WARNING: ++ LOGW("%s", msg); ++ break; ++ case _EGL_FATAL: ++ LOGF("%s", msg); ++ break; ++ default: ++ break; ++ } + #else + fprintf(stderr, "libEGL %s: %s\n", level_strings[level], msg); +-#endif /* HAVE_ANDROID_PLATFORM */ ++#endif /* HAVE_TIZEN_PLATFORM */ + } + + +diff --git a/src/egl/meson.build b/src/egl/meson.build +index ab8f4e1fdbe..5749ec88f89 100644 +--- a/src/egl/meson.build ++++ b/src/egl/meson.build +@@ -106,7 +106,7 @@ if with_dri2 + endif + deps_for_egl += [dep_x11_xcb, dep_xcb_dri2, dep_xcb_xfixes] + endif +- if with_gbm and not with_platform_android ++ if with_gbm and not with_platform_android and not with_platform_tizen + files_egl += files('drivers/dri2/platform_drm.c') + link_for_egl += libgbm + incs_for_egl += [inc_gbm, include_directories('../gbm/main')] +@@ -141,6 +141,11 @@ elif with_platform_haiku + link_for_egl += libgl + deps_for_egl += cpp.find_library('be') + endif ++if with_platform_tizen ++ files_egl += files('drivers/dri2/platform_tizen.c') ++ incs_for_egl += [inc_loader] ++ deps_for_egl += [dep_tizen, dep_libdrm] ++endif + + if cc.has_function('mincore') + c_args_for_egl += '-DHAVE_MINCORE' +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0019-egl-add-support-for-EGL_TIZEN_image_native_surface.patch b/recipes-graphics/mesa/mesa-pvr/0019-egl-add-support-for-EGL_TIZEN_image_native_surface.patch new file mode 100644 index 0000000..f58ea5f --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0019-egl-add-support-for-EGL_TIZEN_image_native_surface.patch @@ -0,0 +1,231 @@ +From 230a8cb550dc23a46a96b1852720c262bb244665 Mon Sep 17 00:00:00 2001 +From: Eric Engestrom +Date: Mon, 6 Feb 2017 15:54:00 +0000 +Subject: [PATCH 19/67] egl: add support for EGL_TIZEN_image_native_surface + +--- + src/egl/drivers/dri2/egl_dri2.c | 127 ++++++++++++++++++++------ + src/egl/drivers/dri2/platform_tizen.c | 1 + + src/egl/main/eglapi.c | 2 + + src/egl/main/egldisplay.h | 2 + + 4 files changed, 102 insertions(+), 30 deletions(-) + +diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c +index 6d34395d65d..eaa0baed066 100644 +--- a/src/egl/drivers/dri2/egl_dri2.c ++++ b/src/egl/drivers/dri2/egl_dri2.c +@@ -58,6 +58,10 @@ + #include "X11/Xlibint.h" + #endif + ++#ifdef HAVE_TIZEN_PLATFORM ++#include ++#endif ++ + #include "egldefines.h" + #include "egl_dri2.h" + #include "GL/mesa_glinterop.h" +@@ -2311,28 +2315,115 @@ dri2_fourcc_from_tbm_format(tbm_format format) + switch (format) { + case TBM_FORMAT_ARGB8888: + return DRM_FORMAT_ARGB8888; ++ case TBM_FORMAT_ABGR8888: ++ return DRM_FORMAT_ABGR8888; + case TBM_FORMAT_XRGB8888: + return DRM_FORMAT_XRGB8888; ++ case TBM_FORMAT_XBGR8888: ++ return DRM_FORMAT_XBGR8888; ++ case TBM_FORMAT_ARGB4444: ++ return DRM_FORMAT_ARGB4444; ++ case TBM_FORMAT_ARGB1555: ++ return DRM_FORMAT_ARGB1555; + case TBM_FORMAT_RGB565: + return DRM_FORMAT_RGB565; ++ case TBM_FORMAT_YUV420: ++ return DRM_FORMAT_YUV420; ++ case TBM_FORMAT_YVU420: ++ return DRM_FORMAT_YVU420; ++ case TBM_FORMAT_NV12: ++ return DRM_FORMAT_NV12; ++ case TBM_FORMAT_NV21: ++ return DRM_FORMAT_NV21; + default: + _eglLog(_EGL_DEBUG, "%s: unsupported tbm format %#x", __func__, format); + return 0; + } + } + ++static _EGLImage * ++dri2_create_image_tbm_surface(_EGLDisplay *disp, _EGLContext *ctx, ++ tbm_surface_h tbm_surf) ++{ ++ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); ++ __DRIimage *dri_image; ++ tbm_surface_info_s info; ++ int fd[TBM_SURF_PLANE_MAX], pitch[TBM_SURF_PLANE_MAX], offset[TBM_SURF_PLANE_MAX]; ++ int fourcc; ++ int i; ++ ++ if (tbm_surface_get_info(tbm_surf, &info)) { ++ _eglError(EGL_BAD_PARAMETER, "tbm_surface_get_info"); ++ return NULL; ++ } ++ ++ fourcc = dri2_fourcc_from_tbm_format(info.format); ++ if (!fourcc) { ++ _eglError(EGL_BAD_PARAMETER, "dri2_fourcc_from_tbm_format"); ++ return NULL; ++ } ++ ++ for (i = 0; i < info.num_planes; i++) { ++ tbm_bo tbm_buf; ++ ++ tbm_buf = tbm_surface_internal_get_bo(tbm_surf, i); ++ if (!tbm_buf) { ++ _eglError(EGL_BAD_PARAMETER, "tbm_surface_internal_get_bo"); ++ goto fail_close; ++ } ++ ++ pitch[i] = info.planes[i].stride; ++ offset[i] = info.planes[i].offset; ++ fd[i] = tbm_bo_export_fd(tbm_buf); ++ } ++ ++ dri_image = dri2_dpy->image->createImageFromFds(dri2_dpy->dri_screen, ++ info.width, ++ info.height, ++ fourcc, ++ &fd[0], ++ info.num_planes, ++ &pitch[0], ++ &offset[0], ++ tbm_surf); ++ for (i = 0; i < info.num_planes; i++) { ++ close(fd[i]); ++ fd[i] = -1; ++ } ++ ++ if (!dri_image) { ++ _eglError(EGL_BAD_PARAMETER, "createImageFromFds"); ++ return NULL; ++ } ++ ++ return dri2_create_image_from_dri(disp, dri_image); ++ ++fail_close: ++ while (i--) ++ close(fd[i]); ++ ++ return NULL; ++} ++ ++static _EGLImage * ++dri2_create_image_tizen(_EGLDisplay *disp, _EGLContext *ctx, ++ EGLClientBuffer _buffer, ++ const EGLint *attr_list) ++{ ++ tbm_surface_h tbm_surf = (tbm_surface_h)_buffer; ++ ++ return dri2_create_image_tbm_surface(disp, ctx, tbm_surf); ++} ++ + static _EGLImage * + dri2_create_image_wayland_wl_buffer_tizen(_EGLDisplay *disp, _EGLContext *ctx, + EGLClientBuffer _buffer, + const EGLint *attr_list) + { + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); +- __DRIimage *dri_image; + _EGLImageAttribs attrs; + tbm_surface_h tbm_surf; +- tbm_bo tbm_buf; + tbm_surface_info_s info; +- int fourcc, fd, pitch, offset; + + tbm_surf = tpl_display_get_buffer_from_native_pixmap(dri2_dpy->tpl_dpy, + (tpl_handle_t) _buffer); +@@ -2363,33 +2454,7 @@ dri2_create_image_wayland_wl_buffer_tizen(_EGLDisplay *disp, _EGLContext *ctx, + return NULL; + } + +- tbm_buf = tbm_surface_internal_get_bo(tbm_surf, attrs.PlaneWL); +- if (!tbm_buf) { +- _eglError(EGL_BAD_PARAMETER, "tbm_surface_internal_get_bo"); +- return NULL; +- } +- +- fourcc = dri2_fourcc_from_tbm_format(info.format); +- pitch = info.planes[attrs.PlaneWL].stride; +- offset = info.planes[attrs.PlaneWL].offset; +- fd = tbm_bo_export_fd(tbm_buf); +- +- dri_image = dri2_dpy->image->createImageFromFds(dri2_dpy->dri_screen, +- info.width, +- info.height, +- fourcc, +- &fd, +- 1, +- &pitch, +- &offset, +- tbm_surf); +- close(fd); +- if (dri_image == NULL) { +- _eglError(EGL_BAD_PARAMETER, "createImageFromFds"); +- return NULL; +- } +- +- return dri2_create_image_from_dri(disp, dri_image); ++ return dri2_create_image_tbm_surface(disp, ctx, tbm_surf); + } + #endif + +@@ -3296,6 +3361,8 @@ dri2_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target, + #ifdef HAVE_TIZEN_PLATFORM + case EGL_WAYLAND_BUFFER_WL: + return dri2_create_image_wayland_wl_buffer_tizen(disp, ctx, buffer, attr_list); ++ case EGL_NATIVE_SURFACE_TIZEN: ++ return dri2_create_image_tizen(disp, ctx, buffer, attr_list); + #endif + case EGL_CL_IMAGE_IMG: + return dri2_create_image_img_buffer(disp, ctx, target, buffer, attr_list); +diff --git a/src/egl/drivers/dri2/platform_tizen.c b/src/egl/drivers/dri2/platform_tizen.c +index a08bc8c07bf..ad75c115d7e 100644 +--- a/src/egl/drivers/dri2/platform_tizen.c ++++ b/src/egl/drivers/dri2/platform_tizen.c +@@ -965,6 +965,7 @@ dri2_initialize_tizen(_EGLDisplay *dpy) + dpy->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE; + dpy->Extensions.KHR_image_base = EGL_TRUE; + dpy->Extensions.WL_bind_wayland_display = EGL_TRUE; ++ dpy->Extensions.TIZEN_image_native_surface = EGL_TRUE; + + /* + * Fill vtbl last to prevent accidentally calling virtual function during +diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c +index 43c7b917909..e2a7797d73e 100644 +--- a/src/egl/main/eglapi.c ++++ b/src/egl/main/eglapi.c +@@ -553,6 +553,8 @@ _eglCreateExtensionsString(_EGLDisplay *disp) + + _EGL_CHECK_EXTENSION(NV_post_sub_buffer); + ++ _EGL_CHECK_EXTENSION(TIZEN_image_native_surface); ++ + _EGL_CHECK_EXTENSION(WL_bind_wayland_display); + _EGL_CHECK_EXTENSION(WL_create_wayland_buffer_from_image); + +diff --git a/src/egl/main/egldisplay.h b/src/egl/main/egldisplay.h +index cbb098331bf..0a7366b7c07 100644 +--- a/src/egl/main/egldisplay.h ++++ b/src/egl/main/egldisplay.h +@@ -149,6 +149,8 @@ struct _egl_extensions + + EGLBoolean NV_post_sub_buffer; + ++ EGLBoolean TIZEN_image_native_surface; ++ + EGLBoolean WL_bind_wayland_display; + EGLBoolean WL_create_wayland_buffer_from_image; + +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0020-egl-wayland-post-maximum-damage-when-blitting.patch b/recipes-graphics/mesa/mesa-pvr/0020-egl-wayland-post-maximum-damage-when-blitting.patch new file mode 100644 index 0000000..8d610aa --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0020-egl-wayland-post-maximum-damage-when-blitting.patch @@ -0,0 +1,33 @@ +From 54d08798efca8f8929744a238e2b8b2851083317 Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Wed, 8 Nov 2017 15:15:20 +0000 +Subject: [PATCH 20/67] egl/wayland: post maximum damage when blitting + +When blitting, as part of the "is_different_gpu" case when swapping +buffers, the blit is done using the full surface dimensions, ignoring +the damage region. This results in corruption of the non damaged region +on screen. Workaround this by posting maximum damage when blitting. + +A better fix would be to limit the blit to the damaged region, at least +when the number of damage rectangles is 1. +--- + src/egl/drivers/dri2/platform_wayland.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c +index c18edc0de4e..c2e428769fe 100644 +--- a/src/egl/drivers/dri2/platform_wayland.c ++++ b/src/egl/drivers/dri2/platform_wayland.c +@@ -1112,7 +1112,8 @@ 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); + +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0021-egl-wayland-flush-the-drawable-before-blitting.patch b/recipes-graphics/mesa/mesa-pvr/0021-egl-wayland-flush-the-drawable-before-blitting.patch new file mode 100644 index 0000000..a780105 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0021-egl-wayland-flush-the-drawable-before-blitting.patch @@ -0,0 +1,46 @@ +From a6aa5c866c25f7f334afbbcc3835467d50eb8965 Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Wed, 8 Nov 2017 15:26:25 +0000 +Subject: [PATCH 21/67] egl/wayland: flush the drawable before blitting + +Flush the drawable before blitting in the "is_different_gpu" case when +swapping buffers, and pass the flush flag to the blitImage call. The +change brings the code into line with the way the DRI3 GLX code works. + +For the PowerVR driver, the drawable parameters that will be used in +the flush have been obtained previously, including any native fence +associated with the blit source. The blit will result in a new native +fence for the source, and make the one in the drawable parameters +invalid. +--- + src/egl/drivers/dri2/platform_wayland.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c +index c2e428769fe..811d28bd669 100644 +--- a/src/egl/drivers/dri2/platform_wayland.c ++++ b/src/egl/drivers/dri2/platform_wayland.c +@@ -1117,6 +1117,8 @@ dri2_wl_swap_buffers_with_damage(_EGLDisplay *disp, + wl_surface_damage(dri2_surf->wl_surface_wrapper, + 0, 0, INT32_MAX, INT32_MAX); + ++ dri2_flush_drawable_for_swapbuffers(disp, draw); ++ + if (dri2_dpy->is_different_gpu) { + _EGLContext *ctx = _eglGetCurrentContext(); + struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); +@@ -1126,10 +1128,9 @@ 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); + } + +- dri2_flush_drawable_for_swapbuffers(disp, draw); + dri2_dpy->flush->invalidate(dri2_surf->dri_drawable); + + wl_surface_commit(dri2_surf->wl_surface_wrapper); +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0022-egl-tizen-create-an-internal-_EGLImage-for-each-tbm-.patch b/recipes-graphics/mesa/mesa-pvr/0022-egl-tizen-create-an-internal-_EGLImage-for-each-tbm-.patch new file mode 100644 index 0000000..83c9511 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0022-egl-tizen-create-an-internal-_EGLImage-for-each-tbm-.patch @@ -0,0 +1,380 @@ +From 404c0e915de381c2337c79657f80b0aa95c1c995 Mon Sep 17 00:00:00 2001 +From: Frank Binns +Date: Wed, 25 Oct 2017 18:15:00 +0100 +Subject: [PATCH 22/67] egl/tizen: create an internal _EGLImage for each tbm + surface + +Create an internal _EGLImage the first time a tbm surface is seen +by eglCreateImageKHR (with either the EGL_WAYLAND_BUFFER_WL or +EGL_NATIVE_SURFACE_TIZEN target) and return a copy of it to the +caller. This avoids some tbm surfaces being frequently mapped and +then unmapped from the GPU. +--- + src/egl/drivers/dri2/egl_dri2.c | 236 +++++++++++++++++++++++++- + src/egl/drivers/dri2/egl_dri2.h | 12 ++ + src/egl/drivers/dri2/platform_tizen.c | 6 + + 3 files changed, 251 insertions(+), 3 deletions(-) + +diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c +index eaa0baed066..db993f8f059 100644 +--- a/src/egl/drivers/dri2/egl_dri2.c ++++ b/src/egl/drivers/dri2/egl_dri2.c +@@ -1264,6 +1264,10 @@ dri2_display_destroy(_EGLDisplay *disp) + break; + #ifdef HAVE_TIZEN_PLATFORM + case _EGL_PLATFORM_TIZEN: ++ if (dri2_dpy->image_list_mutex_initialized) { ++ pthread_mutex_destroy(&dri2_dpy->image_list_mutex); ++ dri2_dpy->image_list_mutex_initialized = false; ++ } + if (dri2_dpy->tpl_dpy) + tpl_object_unreference((tpl_object_t *) dri2_dpy->tpl_dpy); + break; +@@ -1320,6 +1324,60 @@ dri2_egl_surface_free_local_buffers(struct dri2_egl_surface *dri2_surf) + } + } + ++static void ++dri2_display_release_resources_tizen(_EGLDisplay *disp) ++{ ++#ifdef HAVE_TIZEN_PLATFORM ++ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); ++ _EGLResource *image_elem; ++ ++ /* Destroy _EGLImages in the image_list */ ++ pthread_mutex_lock(&dri2_dpy->image_list_mutex); ++ image_elem = dri2_dpy->image_list; ++ dri2_dpy->image_list = NULL; ++ pthread_mutex_unlock(&dri2_dpy->image_list_mutex); ++ ++ while (image_elem) { ++ _EGLImage *img = (_EGLImage *) image_elem; ++ struct dri2_egl_image *dri2_img = dri2_egl_image(img); ++ ++ image_elem = image_elem->Next; ++ ++ /* ++ * Delete the tbm surface user data (_EGLImage), unless the tbm surface ++ * was destroyed since we started processing the image_list. ++ */ ++ if (dri2_img->tbm_surf) ++ tbm_surface_internal_delete_user_data(dri2_img->tbm_surf, ++ (unsigned long) disp); ++ ++ /* ++ * dri2_orphan_tbm_surf_egl_image won't be able to transfer the ++ * _EGLImage to the orphan_image_list once we have started processing ++ * the image_list so we must destroy it ourselves. ++ */ ++ dri2_dpy->image->destroyImage(dri2_img->dri_image); ++ free(dri2_img); ++ } ++ ++ /* Destroy _EGLimages in the orphan_image_list*/ ++ pthread_mutex_lock(&dri2_dpy->image_list_mutex); ++ image_elem = dri2_dpy->orphan_image_list; ++ dri2_dpy->orphan_image_list = NULL; ++ pthread_mutex_unlock(&dri2_dpy->image_list_mutex); ++ ++ while (image_elem) { ++ _EGLImage *img = (_EGLImage *) image_elem; ++ struct dri2_egl_image *dri2_img = dri2_egl_image(img); ++ ++ image_elem = image_elem->Next; ++ ++ dri2_dpy->image->destroyImage(dri2_img->dri_image); ++ free(dri2_img); ++ } ++#endif ++} ++ + /** + * Called via eglTerminate(), drv->Terminate(). + * +@@ -1332,6 +1390,8 @@ dri2_terminate(_EGLDisplay *disp) + /* Release all non-current Context/Surfaces. */ + _eglReleaseDisplayResources(disp); + ++ dri2_display_release_resources_tizen(disp); ++ + dri2_display_release(disp); + + return EGL_TRUE; +@@ -2309,6 +2369,9 @@ dri2_create_image_khr_renderbuffer(_EGLDisplay *disp, _EGLContext *ctx, + } + + #ifdef HAVE_TIZEN_PLATFORM ++static EGLBoolean ++dri2_destroy_image_khr(_EGLDisplay *disp, _EGLImage *image); ++ + int + dri2_fourcc_from_tbm_format(tbm_format format) + { +@@ -2405,14 +2468,145 @@ fail_close: + return NULL; + } + ++static void ++dri2_orphan_tbm_surf_egl_image(void *user_data) ++{ ++ _EGLImage *img = user_data; ++ struct dri2_egl_image *dri2_img = dri2_egl_image(img); ++ _EGLDisplay *disp = img->Resource.Display; ++ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); ++ ++ /* ++ * Transfer the passed in _EGLImage from the image_list to the ++ * orphan_image_list so that it can be cleaned up at some later ++ * point. This is necessary as the disp->Mutex needs to be held ++ * in order destroy the _EGLImage and this could potentially cause ++ * a deadlock in the event that the tbm surface is destroyed. ++ */ ++ pthread_mutex_lock(&dri2_dpy->image_list_mutex); ++ /* ++ * This may be NULL if called via dri2_terminate or if dri2_terminate is ++ * running in another thread. ++ */ ++ if (dri2_dpy->image_list) { ++ _EGLResource *image_elem; ++ ++ /* Remove the _EGLImage from the image_list */ ++ image_elem = dri2_dpy->image_list; ++ if (image_elem != &img->Resource) { ++ while (image_elem) { ++ if (image_elem->Next == &img->Resource) ++ break; ++ image_elem = image_elem->Next; ++ } ++ image_elem->Next = img->Resource.Next; ++ } else { ++ dri2_dpy->image_list = img->Resource.Next; ++ } ++ ++ /* Add the _EGLImage to the orphan_image_list */ ++ img->Resource.Next = dri2_dpy->orphan_image_list; ++ dri2_dpy->orphan_image_list = &img->Resource; ++ } ++ ++ /* ++ * This function may have been called via tbm_surface_destroy so tbm_surf ++ * may be invalid after this function returns. ++ */ ++ dri2_img->tbm_surf = NULL; ++ pthread_mutex_unlock(&dri2_dpy->image_list_mutex); ++} ++ ++static _EGLImage * ++dri2_get_tbm_surf_egl_image(_EGLDisplay *disp, _EGLContext *ctx, ++ tbm_surface_h tbm_surf) ++{ ++ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); ++ struct dri2_egl_image *dri2_img; ++ _EGLImage *img; ++ int ret; ++ ++ ret = tbm_surface_internal_get_user_data(tbm_surf, (unsigned long) disp, ++ (void **) &img); ++ if (ret) ++ return img; ++ ++ img = dri2_create_image_tbm_surface(disp, ctx, tbm_surf); ++ if (!img) { ++ _eglError(EGL_BAD_PARAMETER, "dri2_create_image_tbm_surface failed"); ++ goto fail_exit; ++ } ++ dri2_img = dri2_egl_image(img); ++ ++ /* Use 'disp' as the 'key' as the _EGLimage is tied to it */ ++ ret = tbm_surface_internal_add_user_data(tbm_surf, (unsigned long) disp, ++ dri2_orphan_tbm_surf_egl_image); ++ if (!ret) { ++ _eglError(EGL_BAD_PARAMETER, "dri2_get_tbm_surf_egl_image"); ++ goto fail_destroy_image; ++ } ++ ++ ret = tbm_surface_internal_set_user_data(tbm_surf, (unsigned long) disp, img); ++ if (!ret) { ++ _eglError(EGL_BAD_PARAMETER, "dri2_get_tbm_surf_egl_image"); ++ goto fail_delete_user_data; ++ } ++ ++ /* ++ * Store the tbm surface so that the user data (_EGLImage) can be destroyed ++ * in dri2_terminate. We don't take a reference on the surface as this would ++ * prevent it from being destroyed until eglTerminate is called. This isn't ++ * an issue since it will be set to NULL, via dri2_orphan_tbm_surf_egl_image, ++ * once the surface is destroyed (although it's actually safe to call tbm ++ * surface functions with stale/NULL pointers). ++ */ ++ dri2_img->tbm_surf = tbm_surf; ++ ++ /* ++ * Add to the list of _EGLImages that are associated with tbm surfaces. ++ * This allows the _EGLImage to be destroyed if the application calls ++ * eglTerminate before the tbm surface is destroyed. ++ */ ++ pthread_mutex_lock(&dri2_dpy->image_list_mutex); ++ img->Resource.Next = dri2_dpy->image_list; ++ dri2_dpy->image_list = &img->Resource; ++ pthread_mutex_unlock(&dri2_dpy->image_list_mutex); ++ ++ return img; ++ ++fail_delete_user_data: ++ tbm_surface_internal_delete_user_data(tbm_surf, (unsigned long) disp); ++fail_destroy_image: ++ dri2_destroy_image_khr(disp, img); ++fail_exit: ++ return NULL; ++} ++ + static _EGLImage * + dri2_create_image_tizen(_EGLDisplay *disp, _EGLContext *ctx, + EGLClientBuffer _buffer, + const EGLint *attr_list) + { +- tbm_surface_h tbm_surf = (tbm_surface_h)_buffer; ++ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); ++ tbm_surface_h tbm_surf = (tbm_surface_h) _buffer; ++ _EGLImage *img; ++ struct dri2_egl_image *dri2_img; ++ __DRIimage *dri_image; ++ ++ img = dri2_get_tbm_surf_egl_image(disp, ctx, tbm_surf); ++ if (!img) { ++ _eglError(EGL_BAD_PARAMETER, "dri2_create_image_tizen"); ++ return NULL; ++ } ++ dri2_img = dri2_egl_image(img); ++ ++ dri_image = dri2_dpy->image->fromPlanar(dri2_img->dri_image, 0, NULL); ++ if (!dri_image) { ++ _eglError(EGL_BAD_PARAMETER, "dri2_create_image_tizen"); ++ return NULL; ++ } + +- return dri2_create_image_tbm_surface(disp, ctx, tbm_surf); ++ return dri2_create_image_from_dri(disp, dri_image); + } + + static _EGLImage * +@@ -2424,6 +2618,9 @@ dri2_create_image_wayland_wl_buffer_tizen(_EGLDisplay *disp, _EGLContext *ctx, + _EGLImageAttribs attrs; + tbm_surface_h tbm_surf; + tbm_surface_info_s info; ++ _EGLImage *img; ++ struct dri2_egl_image *dri2_img; ++ __DRIimage *dri_image; + + tbm_surf = tpl_display_get_buffer_from_native_pixmap(dri2_dpy->tpl_dpy, + (tpl_handle_t) _buffer); +@@ -2454,7 +2651,21 @@ dri2_create_image_wayland_wl_buffer_tizen(_EGLDisplay *disp, _EGLContext *ctx, + return NULL; + } + +- return dri2_create_image_tbm_surface(disp, ctx, tbm_surf); ++ img = dri2_get_tbm_surf_egl_image(disp, ctx, tbm_surf); ++ if (!img) { ++ _eglError(EGL_BAD_PARAMETER, "dri2_create_image_wayland_wl_buffer_tizen"); ++ return NULL; ++ } ++ dri2_img = dri2_egl_image(img); ++ ++ dri_image = ++ dri2_dpy->image->fromPlanar(dri2_img->dri_image, attrs.PlaneWL, NULL); ++ if (!dri_image) { ++ _eglError(EGL_BAD_PARAMETER, "dri2_create_image_wayland_wl_buffer_tizen"); ++ return NULL; ++ } ++ ++ return dri2_create_image_from_dri(disp, dri_image); + } + #endif + +@@ -3377,10 +3588,29 @@ dri2_destroy_image_khr(_EGLDisplay *disp, _EGLImage *image) + { + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + struct dri2_egl_image *dri2_img = dri2_egl_image(image); ++#ifdef HAVE_TIZEN_PLATFORM ++ _EGLResource *image_elem; ++#endif + + dri2_dpy->image->destroyImage(dri2_img->dri_image); + free(dri2_img); + ++#ifdef HAVE_TIZEN_PLATFORM ++ /* Take the opportunity to destroy orphaned tbm surface _EGLImages */ ++ pthread_mutex_lock(&dri2_dpy->image_list_mutex); ++ image_elem = dri2_dpy->orphan_image_list; ++ dri2_dpy->orphan_image_list = NULL; ++ pthread_mutex_unlock(&dri2_dpy->image_list_mutex); ++ ++ while (image_elem) { ++ dri2_img = dri2_egl_image((_EGLImage *) image_elem); ++ image_elem = image_elem->Next; ++ ++ dri2_dpy->image->destroyImage(dri2_img->dri_image); ++ free(dri2_img); ++ } ++#endif ++ + return EGL_TRUE; + } + +diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h +index a8bfe45b1f5..546bc0a0dbc 100644 +--- a/src/egl/drivers/dri2/egl_dri2.h ++++ b/src/egl/drivers/dri2/egl_dri2.h +@@ -268,6 +268,15 @@ struct dri2_egl_display + + #ifdef HAVE_TIZEN_PLATFORM + tpl_display_t *tpl_dpy; ++ /* ++ * The image_list_mutex protects the image_list and orphan_image_list. It ++ * should never be held while calling a libtbm function as this may result ++ * in a deadlock. ++ */ ++ pthread_mutex_t image_list_mutex; ++ bool image_list_mutex_initialized; ++ _EGLResource *image_list; ++ _EGLResource *orphan_image_list; + #endif + }; + +@@ -413,6 +422,9 @@ struct dri2_egl_image + { + _EGLImage base; + __DRIimage *dri_image; ++#ifdef HAVE_TIZEN_PLATFORM ++ tbm_surface_h tbm_surf; ++#endif + }; + + struct dri2_egl_sync { +diff --git a/src/egl/drivers/dri2/platform_tizen.c b/src/egl/drivers/dri2/platform_tizen.c +index ad75c115d7e..49462152beb 100644 +--- a/src/egl/drivers/dri2/platform_tizen.c ++++ b/src/egl/drivers/dri2/platform_tizen.c +@@ -891,6 +891,7 @@ dri2_initialize_tizen(_EGLDisplay *dpy) + { + struct dri2_egl_display *dri2_dpy; + int i; ++ int err; + + dri2_dpy = calloc(1, sizeof(*dri2_dpy)); + if (!dri2_dpy) +@@ -906,6 +907,11 @@ dri2_initialize_tizen(_EGLDisplay *dpy) + goto cleanup; + } + ++ err = pthread_mutex_init(&dri2_dpy->image_list_mutex, NULL); ++ if (err) ++ goto cleanup; ++ dri2_dpy->image_list_mutex_initialized = true; ++ + for (i = TIZEN_DRM_RENDER_MINOR_START; i <= TIZEN_DRM_RENDER_MINOR_MAX; i++) { + char *render_path; + +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0023-dri-use-a-supported-API-in-driCreateNewContext.patch b/recipes-graphics/mesa/mesa-pvr/0023-dri-use-a-supported-API-in-driCreateNewContext.patch new file mode 100644 index 0000000..141b017 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0023-dri-use-a-supported-API-in-driCreateNewContext.patch @@ -0,0 +1,54 @@ +From 1f4a1a21384b00e28b8a9dd2c29f9c261f201c6f Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Thu, 23 Nov 2017 15:50:21 +0000 +Subject: [PATCH 23/67] dri: use a supported API in driCreateNewContext + +Don't assume the screen supports OpenGL when creating a new context, +use an API that the screen supports. +--- + src/mesa/drivers/dri/common/dri_util.c | 14 +++++++++++++- + 1 file changed, 13 insertions(+), 1 deletion(-) + +diff --git a/src/mesa/drivers/dri/common/dri_util.c b/src/mesa/drivers/dri/common/dri_util.c +index caed5fa6a68..6c45eb007fc 100644 +--- a/src/mesa/drivers/dri/common/dri_util.c ++++ b/src/mesa/drivers/dri/common/dri_util.c +@@ -50,6 +50,7 @@ + #include "main/debug_output.h" + #include "main/errors.h" + #include "main/macros.h" ++#include "util/bitscan.h" + + driOptionDescription __dri2ConfigOptions[] = { + DRI_CONF_SECTION_DEBUG +@@ -332,7 +333,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: +@@ -515,7 +520,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); + } + +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0024-gbm-add-gbm_bo_blit.patch b/recipes-graphics/mesa/mesa-pvr/0024-gbm-add-gbm_bo_blit.patch new file mode 100644 index 0000000..82e1c44 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0024-gbm-add-gbm_bo_blit.patch @@ -0,0 +1,224 @@ +From 0751612b949f1c90338a14453ff7fa4be8bfd016 Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Tue, 28 Nov 2017 16:27:38 +0000 +Subject: [PATCH 24/67] gbm: add gbm_bo_blit + +For the GBM DRI backend, gbm_bo_blit is a wrapper around blitImage in +the DRI Image extension. +--- + src/gbm/backends/dri/gbm_dri.c | 33 +++++++++++++++++++++++++++++++++ + src/gbm/main/gbm.c | 31 +++++++++++++++++++++++++++++++ + src/gbm/main/gbm.h | 21 +++++++++++++++++++++ + src/gbm/main/gbm_abi_check.c | 20 +++++++++++++++++++- + src/gbm/main/gbm_backend_abi.h | 10 +++++++++- + 5 files changed, 113 insertions(+), 2 deletions(-) + +diff --git a/src/gbm/backends/dri/gbm_dri.c b/src/gbm/backends/dri/gbm_dri.c +index 96fa9217255..bd8a80cdecf 100644 +--- a/src/gbm/backends/dri/gbm_dri.c ++++ b/src/gbm/backends/dri/gbm_dri.c +@@ -1355,6 +1355,37 @@ 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); ++ assert(dri->context); ++ mtx_unlock(&dri->mutex); ++ ++ /* 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) + { +@@ -1416,6 +1447,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/main/gbm.c b/src/gbm/main/gbm.c +index d81931a7483..e2351d34ad8 100644 +--- a/src/gbm/main/gbm.c ++++ b/src/gbm/main/gbm.c +@@ -758,6 +758,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 3a0fe73faae..7c82cd661a3 100644 +--- a/src/gbm/main/gbm.h ++++ b/src/gbm/main/gbm.h +@@ -246,6 +246,21 @@ enum gbm_bo_flags { + GBM_BO_USE_PROTECTED = (1 << 5), + }; + ++/** ++ * 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); + +@@ -425,6 +440,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 f1137be7baf..02ce23b129e 100644 +--- a/src/gbm/main/gbm_abi_check.c ++++ b/src/gbm/main/gbm_abi_check.c +@@ -101,6 +101,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 + * +@@ -359,8 +374,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 962ee74f003..3abf29faa92 100644 +--- a/src/gbm/main/gbm_backend_abi.h ++++ b/src/gbm/main/gbm_backend_abi.h +@@ -72,7 +72,7 @@ struct gbm_backend_desc; + * Core ABI version: 4 + * ABI version of a buffer object created by a device from the backend: 4 + */ +-#define GBM_BACKEND_ABI_VERSION 0 ++#define GBM_BACKEND_ABI_VERSION 1 + + /** + * GBM device interface corresponding to GBM_BACKEND_ABI_VERSION = 0 +@@ -149,6 +149,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. + * +@@ -161,6 +168,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; + }; + + /** +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0025-gbm-don-t-assert-if-DRI-context-creation-fails.patch b/recipes-graphics/mesa/mesa-pvr/0025-gbm-don-t-assert-if-DRI-context-creation-fails.patch new file mode 100644 index 0000000..cac3a05 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0025-gbm-don-t-assert-if-DRI-context-creation-fails.patch @@ -0,0 +1,44 @@ +From dbe611e4cb6f0dddc05ead03f0341274a6b018c8 Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Fri, 1 Dec 2017 08:31:15 +0000 +Subject: [PATCH 25/67] gbm: don't assert if DRI context creation fails + +If the DRI backend fails to create a DRI context, return an error, +rather than asserting. +--- + src/gbm/backends/dri/gbm_dri.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/src/gbm/backends/dri/gbm_dri.c b/src/gbm/backends/dri/gbm_dri.c +index bd8a80cdecf..2aa9c7c41ad 100644 +--- a/src/gbm/backends/dri/gbm_dri.c ++++ b/src/gbm/backends/dri/gbm_dri.c +@@ -1245,8 +1245,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, +@@ -1374,8 +1377,11 @@ gbm_dri_bo_blit(struct gbm_bo *_dst_bo, struct gbm_bo *_src_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 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, +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0026-egl-wayland-add-pbuffer-support.patch b/recipes-graphics/mesa/mesa-pvr/0026-egl-wayland-add-pbuffer-support.patch new file mode 100644 index 0000000..1bbc6be --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0026-egl-wayland-add-pbuffer-support.patch @@ -0,0 +1,471 @@ +From f16ea577ee06375423198dced8231d04e94536af Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Fri, 17 Mar 2017 16:23:07 +0000 +Subject: [PATCH 26/67] egl/wayland: add pbuffer support + +The pbuffer code is based on that in the Surfaceless platform code. +--- + src/egl/drivers/dri2/egl_dri2.h | 4 + + src/egl/drivers/dri2/platform_wayland.c | 270 ++++++++++++++++++++---- + 2 files changed, 236 insertions(+), 38 deletions(-) + +diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h +index 546bc0a0dbc..f41f32cd234 100644 +--- a/src/egl/drivers/dri2/egl_dri2.h ++++ b/src/egl/drivers/dri2/egl_dri2.h +@@ -405,6 +405,10 @@ struct dri2_egl_surface + __DRIimage *front; + unsigned int visual; + ++#ifdef HAVE_WAYLAND_PLATFORM ++ void *swrast_front; ++#endif ++ + int out_fence_fd; + EGLBoolean enable_out_fence; + +diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c +index 811d28bd669..a096d9500c1 100644 +--- a/src/egl/drivers/dri2/platform_wayland.c ++++ b/src/egl/drivers/dri2/platform_wayland.c +@@ -427,6 +427,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); ++ 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(). + */ +@@ -453,6 +546,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); + +@@ -462,11 +558,14 @@ 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); +- 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); +@@ -628,20 +727,16 @@ 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, format; + +- image = dri2_surf->back->dri_image; +- + 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->flags = 0; +@@ -656,12 +751,28 @@ back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer) + } + } + +-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) ++{ + if (dri2_surf->wl_win && + (dri2_surf->base.Width != dri2_surf->wl_win->width || + dri2_surf->base.Height != dri2_surf->wl_win->height)) { +@@ -703,12 +814,13 @@ 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) + { + if (dri2_surf->back != NULL) + return 0; + +- return update_buffers(dri2_surf); ++ return update_buffers(dri2_dpy, dri2_surf); + } + + static __DRIbuffer * +@@ -718,17 +830,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(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(dri2_dpy, dri2_surf) < 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], +@@ -798,12 +918,30 @@ 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(dri2_surf) < 0) +- return 0; ++ buffers->image_mask = 0; ++ buffers->front = NULL; ++ buffers->back = NULL; ++ ++ if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) ++ { ++ if (update_buffers(dri2_dpy, dri2_surf) < 0) ++ return 0; + +- buffers->image_mask = __DRI_IMAGE_BUFFER_BACK; +- buffers->back = dri2_surf->back->dri_image; ++ buffers->image_mask |= __DRI_IMAGE_BUFFER_BACK; ++ buffers->back = dri2_surf->back->dri_image; ++ } ++ ++ 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; + } +@@ -1054,6 +1192,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"); + +@@ -1068,7 +1209,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) < 0) + return _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers"); + + if (draw->SwapInterval > 0) { +@@ -1153,9 +1294,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) < 0) { + _eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age"); + return -1; + } +@@ -1376,6 +1521,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, + .create_image = dri2_create_image_khr, + .swap_buffers = dri2_wl_swap_buffers, +@@ -1418,7 +1564,7 @@ dri2_wl_add_configs_for_visuals(_EGLDisplay *disp) + continue; + + 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, EGL_WINDOW_BIT | EGL_PBUFFER_BIT, NULL, dri2_wl_visuals[j].rgba_shifts, dri2_wl_visuals[j].rgba_sizes); + if (dri2_conf) { + if (dri2_conf->base.ConfigID == count + 1) + count++; +@@ -1654,6 +1800,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, +@@ -1775,8 +1938,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) +@@ -1846,7 +2025,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; +@@ -1865,7 +2046,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; +@@ -1903,14 +2088,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; +@@ -1928,7 +2119,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 +@@ -1996,6 +2189,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, +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0027-egl-tizen-support-DRI-driver-handling-of-swap-preser.patch b/recipes-graphics/mesa/mesa-pvr/0027-egl-tizen-support-DRI-driver-handling-of-swap-preser.patch new file mode 100644 index 0000000..6885040 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0027-egl-tizen-support-DRI-driver-handling-of-swap-preser.patch @@ -0,0 +1,121 @@ +From 48fe256681d8d7d3892393b102bf0a3ebc697c51 Mon Sep 17 00:00:00 2001 +From: Frank Binns +Date: Mon, 18 Dec 2017 19:22:50 +0000 +Subject: [PATCH 27/67] egl/tizen: support DRI driver handling of swap preserve + +This adds a new flag (__DRI_IMAGE_BUFFER_PREV) to the __DRIimageBufferMask +enum that allows a DRI driver to request the previous back buffer. This +will only be returned if the swap behaviour is EGL_BUFFER_PRESERVED and +should result in the DRI driver preserving the previous content instead of +this being done in the platform code. For hardware that supports it, this +should avoid a blit being performed every frame, although this will still +be necessary under certain conditions, e.g. an empty swap. +--- + include/GL/internal/dri_interface.h | 3 +++ + src/egl/drivers/dri2/platform_tizen.c | 29 +++++++++++++++++++++------ + 2 files changed, 26 insertions(+), 6 deletions(-) + +diff --git a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h +index b197092939f..16cc095ea29 100644 +--- a/include/GL/internal/dri_interface.h ++++ b/include/GL/internal/dri_interface.h +@@ -2073,12 +2073,15 @@ 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" +diff --git a/src/egl/drivers/dri2/platform_tizen.c b/src/egl/drivers/dri2/platform_tizen.c +index 49462152beb..2bc9b3e7c64 100644 +--- a/src/egl/drivers/dri2/platform_tizen.c ++++ b/src/egl/drivers/dri2/platform_tizen.c +@@ -147,7 +147,8 @@ create_image_from_native(struct dri2_egl_surface *dri2_surf, + } + + static int +-get_back_bo(struct dri2_egl_surface *dri2_surf, bool allow_update) ++get_back_bo(struct dri2_egl_surface *dri2_surf, bool allow_update, ++ bool allow_preserve) + { + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); +@@ -277,7 +278,7 @@ get_back_bo(struct dri2_egl_surface *dri2_surf, bool allow_update) + dri2_surf->back->locked = true; + + if (dri2_surf->base.SwapBehavior == EGL_BUFFER_PRESERVED && +- dri2_surf->current) { ++ allow_preserve && dri2_surf->current) { + _EGLContext *ctx = _eglGetCurrentContext(); + struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx); + +@@ -609,7 +610,7 @@ dri2_tizen_swap_buffers_with_damage(_EGLDisplay *dpy, _EGLSurface *draw, + * Make sure we have a back buffer in case we're swapping without ever + * rendering. + */ +- if (get_back_bo(dri2_surf, false) < 0) { ++ if (get_back_bo(dri2_surf, false, true) < 0) { + _eglError(EGL_BAD_ALLOC, "DRI2: failed to get back buffer"); + return EGL_FALSE; + } +@@ -673,7 +674,7 @@ dri2_tizen_query_buffer_age(_EGLDisplay *dpy, _EGLSurface *surface) + { + struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface); + +- if (get_back_bo(dri2_surf, false) < 0) { ++ if (get_back_bo(dri2_surf, false, true) < 0) { + _eglError(EGL_BAD_ALLOC, "DRI2: failed to get back buffer"); + return -1; + } +@@ -748,14 +749,22 @@ dri2_tizen_get_buffers(__DRIdrawable *driDrawable, + buffers->image_mask = 0; + buffers->front = NULL; + buffers->back = NULL; ++ buffers->prev = NULL; + + if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) + if (get_front_bo(dri2_surf) < 0) + return 0; + +- if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) +- if (get_back_bo(dri2_surf, true) < 0) ++ if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) { ++ /* ++ * The DRI driver has requested the previous buffer so it will take care ++ * of preserving the previous content. ++ */ ++ bool allow_preserve = !(buffer_mask & __DRI_IMAGE_BUFFER_PREV); ++ ++ if (get_back_bo(dri2_surf, true, allow_preserve) < 0) + return 0; ++ } + + if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) { + buffers->front = dri2_surf->front; +@@ -767,6 +776,14 @@ dri2_tizen_get_buffers(__DRIdrawable *driDrawable, + buffers->image_mask |= __DRI_IMAGE_BUFFER_BACK; + } + ++ if (buffer_mask & __DRI_IMAGE_BUFFER_PREV) { ++ if (dri2_surf->base.SwapBehavior == EGL_BUFFER_PRESERVED && ++ dri2_surf->current) { ++ buffers->prev = dri2_surf->current->dri_image; ++ buffers->image_mask |= __DRI_IMAGE_BUFFER_PREV; ++ } ++ } ++ + return 1; + } + +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0028-egl-eglBindAPI-workaround-for-dEQP-bug.patch b/recipes-graphics/mesa/mesa-pvr/0028-egl-eglBindAPI-workaround-for-dEQP-bug.patch new file mode 100644 index 0000000..ebdbf20 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0028-egl-eglBindAPI-workaround-for-dEQP-bug.patch @@ -0,0 +1,29 @@ +From 90c87ad050dd7a4deda3ee1609e6cc27ea7dd616 Mon Sep 17 00:00:00 2001 +From: Eric Engestrom +Date: Mon, 25 Sep 2017 15:58:49 +0100 +Subject: [PATCH 28/67] egl: eglBindAPI workaround for dEQP bug + +dEQP relies on eglBindAPI to only return true if the API can +successfully be used to create contexts, which the spec does not +require. +Until dEQP is fixed, just disable GL on non-X11 platforms. +--- + src/egl/main/eglcurrent.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/egl/main/eglcurrent.h b/src/egl/main/eglcurrent.h +index d9a4a90174e..32570970947 100644 +--- a/src/egl/main/eglcurrent.h ++++ b/src/egl/main/eglcurrent.h +@@ -71,7 +71,7 @@ struct _egl_thread_info + static inline EGLBoolean + _eglIsApiValid(EGLenum api) + { +-#ifdef ANDROID ++#ifndef HAVE_X11_PLATFORM + /* OpenGL is not a valid/supported API on Android */ + return api == EGL_OPENGL_ES_API; + #else +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0029-GL_EXT_multi_draw_indirect-entry-points.patch b/recipes-graphics/mesa/mesa-pvr/0029-GL_EXT_multi_draw_indirect-entry-points.patch new file mode 100644 index 0000000..08dee62 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0029-GL_EXT_multi_draw_indirect-entry-points.patch @@ -0,0 +1,56 @@ +From a763c01172ee21a26f4c9dbb6055093f78d06fb2 Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Tue, 30 Jan 2018 10:25:11 +0000 +Subject: [PATCH 29/67] GL_EXT_multi_draw_indirect entry points + +--- + src/mapi/glapi/gen/es_EXT.xml | 19 +++++++++++++++++++ + src/mapi/glapi/gen/static_data.py | 2 ++ + 2 files changed, 21 insertions(+) + +diff --git a/src/mapi/glapi/gen/es_EXT.xml b/src/mapi/glapi/gen/es_EXT.xml +index fe8f27e1e6f..e0d60faa9d2 100644 +--- a/src/mapi/glapi/gen/es_EXT.xml ++++ b/src/mapi/glapi/gen/es_EXT.xml +@@ -1140,6 +1140,25 @@ + + + ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + + + +diff --git a/src/mapi/glapi/gen/static_data.py b/src/mapi/glapi/gen/static_data.py +index dc6bdc9dcce..e231c176264 100644 +--- a/src/mapi/glapi/gen/static_data.py ++++ b/src/mapi/glapi/gen/static_data.py +@@ -1704,6 +1704,8 @@ offsets = { + "FramebufferTextureLayerDownsampleIMG" : 1668, + "FramebufferTextureMultiviewOVR" : 1669, + "FramebufferTextureMultisampleMultiviewOVR" : 1670, ++ "MultiDrawArraysIndirectEXT" : 1671, ++ "MultiDrawElementsIndirectEXT" : 1672, + } + + functions = [ +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0030-dri-add-support-for-YUV-DRI-config.patch b/recipes-graphics/mesa/mesa-pvr/0030-dri-add-support-for-YUV-DRI-config.patch new file mode 100644 index 0000000..95d0ed5 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0030-dri-add-support-for-YUV-DRI-config.patch @@ -0,0 +1,494 @@ +From 389e1a41360160bf56182a87cc52b5df9dc1265d Mon Sep 17 00:00:00 2001 +From: Frank Binns +Date: Fri, 22 Dec 2017 17:17:50 +0000 +Subject: [PATCH 30/67] dri: add support for YUV DRI config + +This is prerequisite for adding support for EGL_EXT_yuv_surface. + +This also adds support for NV12 and NV21 EGL configs. +--- + include/GL/internal/dri_interface.h | 42 ++++++++- + src/gallium/frontends/dri/dri_screen.c | 8 +- + src/gallium/include/pipe/p_format.h | 2 + + src/mesa/drivers/dri/common/utils.c | 88 +++++++++++++++++-- + src/mesa/drivers/dri/common/utils.h | 3 +- + src/mesa/drivers/dri/i915/intel_screen.c | 8 +- + src/mesa/drivers/dri/i965/brw_screen.c | 12 ++- + src/mesa/drivers/dri/nouveau/nouveau_screen.c | 4 +- + src/mesa/drivers/dri/radeon/radeon_screen.c | 4 +- + src/mesa/main/format_info.py | 2 +- + src/mesa/main/formats.c | 9 ++ + src/mesa/main/formats.csv | 2 + + src/mesa/main/formats.h | 7 ++ + src/mesa/main/mtypes.h | 9 ++ + 14 files changed, 181 insertions(+), 19 deletions(-) + +diff --git a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h +index 16cc095ea29..4d5a1874dc2 100644 +--- a/include/GL/internal/dri_interface.h ++++ b/include/GL/internal/dri_interface.h +@@ -826,7 +826,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 +@@ -834,6 +840,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 +@@ -860,6 +867,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. + * +diff --git a/src/gallium/frontends/dri/dri_screen.c b/src/gallium/frontends/dri/dri_screen.c +index b565a1fe8ec..37a0d4add0c 100644 +--- a/src/gallium/frontends/dri/dri_screen.c ++++ b/src/gallium/frontends/dri/dri_screen.c +@@ -324,7 +324,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. */ +@@ -334,7 +336,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/include/pipe/p_format.h b/src/gallium/include/pipe/p_format.h +index 0c93d7df6e2..fd653379b7a 100644 +--- a/src/gallium/include/pipe/p_format.h ++++ b/src/gallium/include/pipe/p_format.h +@@ -513,6 +513,8 @@ enum pipe_format { + PIPE_FORMAT_R4G4B4X4_UNORM, + PIPE_FORMAT_B10G10R10X2_SNORM, + PIPE_FORMAT_R5G6B5_SRGB, ++ PIPE_FORMAT_YUV420_2PLANE, ++ PIPE_FORMAT_YVU420_2PLANE, + + PIPE_FORMAT_COUNT + }; +diff --git a/src/mesa/drivers/dri/common/utils.c b/src/mesa/drivers/dri/common/utils.c +index a3f2bc57f46..d268dc41fbb 100644 +--- a/src/mesa/drivers/dri/common/utils.c ++++ b/src/mesa/drivers/dri/common/utils.c +@@ -163,6 +163,21 @@ driGetRendererString( char * buffer, const char * hardware_name, + * 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. +@@ -175,7 +190,8 @@ driCreateConfigs(mesa_format format, + 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]; +@@ -214,6 +230,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; +@@ -227,6 +246,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; + +@@ -279,6 +303,33 @@ 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; + default: + fprintf(stderr, "[%s:%u] Unknown framebuffer type %s (%d).\n", + __func__, __LINE__, +@@ -334,8 +385,12 @@ driCreateConfigs(mesa_format format, + modes->greenShift = shifts[1]; + modes->blueShift = shifts[2]; + modes->alphaShift = shifts[3]; +- modes->rgbBits = modes->redBits + modes->greenBits +- + modes->blueBits + modes->alphaBits; ++ ++ if (is_yuv) ++ modes->rgbBits = 8; ++ else ++ modes->rgbBits = modes->redBits + modes->greenBits ++ + modes->blueBits + modes->alphaBits; + + modes->accumRedBits = 16 * j; + modes->accumGreenBits = 16 * j; +@@ -345,6 +400,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; +@@ -357,6 +414,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; + } + } + } +@@ -436,10 +500,14 @@ driGetConfigAttribIndex(const __DRIconfig *config, + break; + __ATTRIB(__DRI_ATTRIB_SAMPLES, samples); + case __DRI_ATTRIB_RENDER_TYPE: +- /* no support for color index mode */ +- *value = __DRI_ATTRIB_RGBA_BIT; +- if (config->modes.floatMode) +- *value |= __DRI_ATTRIB_FLOAT_BIT; ++ /* no support for color index mode */ ++ 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; + case __DRI_ATTRIB_CONFIG_CAVEAT: + if (config->modes.accumRedBits != 0) +@@ -505,6 +573,12 @@ driGetConfigAttribIndex(const __DRIconfig *config, + __ATTRIB(__DRI_ATTRIB_GREEN_SHIFT, greenShift); + __ATTRIB(__DRI_ATTRIB_BLUE_SHIFT, blueShift); + __ATTRIB(__DRI_ATTRIB_ALPHA_SHIFT, alphaShift); ++ __ATTRIB(__DRI_ATTRIB_YUV_ORDER, YUVOrder); ++ __ATTRIB(__DRI_ATTRIB_YUV_NUMBER_OF_PLANES, YUVNumberOfPlanes); ++ __ATTRIB(__DRI_ATTRIB_YUV_SUBSAMPLE, YUVSubsample); ++ __ATTRIB(__DRI_ATTRIB_YUV_DEPTH_RANGE, YUVDepthRange); ++ __ATTRIB(__DRI_ATTRIB_YUV_CSC_STANDARD, YUVCSCStandard); ++ __ATTRIB(__DRI_ATTRIB_YUV_PLANE_BPP, YUVPlaneBPP); + default: + /* XXX log an error or smth */ + return GL_FALSE; +diff --git a/src/mesa/drivers/dri/common/utils.h b/src/mesa/drivers/dri/common/utils.h +index 7be0465c261..ebd98d9dc33 100644 +--- a/src/mesa/drivers/dri/common/utils.h ++++ b/src/mesa/drivers/dri/common/utils.h +@@ -45,7 +45,8 @@ driCreateConfigs(mesa_format format, + 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_standards); + + __DRIconfig **driConcatConfigs(__DRIconfig **a, + __DRIconfig **b); +diff --git a/src/mesa/drivers/dri/i915/intel_screen.c b/src/mesa/drivers/dri/i915/intel_screen.c +index 6135357c2a0..a94c6de0a06 100644 +--- a/src/mesa/drivers/dri/i915/intel_screen.c ++++ b/src/mesa/drivers/dri/i915/intel_screen.c +@@ -1083,7 +1083,9 @@ intel_screen_make_configs(__DRIscreen *dri_screen) + num_depth_stencil_bits, + back_buffer_modes, 2, + singlesample_samples, 1, +- false, false); ++ false, false, ++ __DRI_ATTRIB_YUV_DEPTH_RANGE_NONE, ++ __DRI_ATTRIB_YUV_CSC_STANDARD_NONE); + configs = driConcatConfigs(configs, new_configs); + } + +@@ -1105,7 +1107,9 @@ intel_screen_make_configs(__DRIscreen *dri_screen) + depth_bits, stencil_bits, 1, + back_buffer_modes, 1, + singlesample_samples, 1, +- true, false); ++ true, false, ++ __DRI_ATTRIB_YUV_DEPTH_RANGE_NONE, ++ __DRI_ATTRIB_YUV_CSC_STANDARD_NONE); + configs = driConcatConfigs(configs, new_configs); + } + +diff --git a/src/mesa/drivers/dri/i965/brw_screen.c b/src/mesa/drivers/dri/i965/brw_screen.c +index 56811110567..c450bae1054 100644 +--- a/src/mesa/drivers/dri/i965/brw_screen.c ++++ b/src/mesa/drivers/dri/i965/brw_screen.c +@@ -2292,7 +2292,9 @@ brw_screen_make_configs(__DRIscreen *dri_screen) + num_depth_stencil_bits, + back_buffer_modes, 2, + singlesample_samples, 1, +- false, false); ++ false, false, ++ __DRI_ATTRIB_YUV_DEPTH_RANGE_NONE, ++ __DRI_ATTRIB_YUV_CSC_STANDARD_NONE); + configs = driConcatConfigs(configs, new_configs); + } + +@@ -2325,7 +2327,9 @@ brw_screen_make_configs(__DRIscreen *dri_screen) + depth_bits, stencil_bits, 1, + back_buffer_modes, 1, + singlesample_samples, 1, +- true, false); ++ true, false, ++ __DRI_ATTRIB_YUV_DEPTH_RANGE_NONE, ++ __DRI_ATTRIB_YUV_CSC_STANDARD_NONE); + configs = driConcatConfigs(configs, new_configs); + } + +@@ -2390,7 +2394,9 @@ brw_screen_make_configs(__DRIscreen *dri_screen) + back_buffer_modes, 1, + multisample_samples, + num_msaa_modes, +- false, false); ++ false, false, ++ __DRI_ATTRIB_YUV_DEPTH_RANGE_NONE, ++ __DRI_ATTRIB_YUV_CSC_STANDARD_NONE); + configs = driConcatConfigs(configs, new_configs); + } + +diff --git a/src/mesa/drivers/dri/nouveau/nouveau_screen.c b/src/mesa/drivers/dri/nouveau/nouveau_screen.c +index c92efcd7b20..fc87d5eb395 100644 +--- a/src/mesa/drivers/dri/nouveau/nouveau_screen.c ++++ b/src/mesa/drivers/dri/nouveau/nouveau_screen.c +@@ -79,7 +79,9 @@ nouveau_get_configs(uint32_t chipset) + ARRAY_SIZE(back_buffer_modes), + msaa_samples, + ARRAY_SIZE(msaa_samples), +- GL_TRUE, chipset < 0x10); ++ GL_TRUE, chipset < 0x10, ++ __DRI_ATTRIB_YUV_DEPTH_RANGE_NONE, ++ __DRI_ATTRIB_YUV_CSC_STANDARD_NONE); + assert(config); + + configs = driConcatConfigs(configs, config); +diff --git a/src/mesa/drivers/dri/radeon/radeon_screen.c b/src/mesa/drivers/dri/radeon/radeon_screen.c +index 3764a5d6538..f7628555b8f 100644 +--- a/src/mesa/drivers/dri/radeon/radeon_screen.c ++++ b/src/mesa/drivers/dri/radeon/radeon_screen.c +@@ -838,7 +838,9 @@ __DRIconfig **radeonInitScreen2(__DRIscreen *psp) + ARRAY_SIZE(back_buffer_modes), + msaa_samples_array, + ARRAY_SIZE(msaa_samples_array), +- GL_TRUE, GL_FALSE); ++ GL_TRUE, GL_FALSE, ++ __DRI_ATTRIB_YUV_DEPTH_RANGE_NONE, ++ __DRI_ATTRIB_YUV_CSC_STANDARD_NONE); + configs = driConcatConfigs(configs, new_configs); + } + +diff --git a/src/mesa/main/format_info.py b/src/mesa/main/format_info.py +index edc0324e60b..d58403ea85e 100644 +--- a/src/mesa/main/format_info.py ++++ b/src/mesa/main/format_info.py +@@ -29,7 +29,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']: + 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 9cd026f7507..f81caeceff4 100644 +--- a/src/mesa/main/formats.c ++++ b/src/mesa/main/formats.c +@@ -1452,6 +1452,15 @@ _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: ++ 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 21cdea26e08..b2d476577e0 100644 +--- a/src/mesa/main/formats.csv ++++ b/src/mesa/main/formats.csv +@@ -92,6 +92,8 @@ 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_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 508c9c342d2..0e778d64467 100644 +--- a/src/mesa/main/formats.h ++++ b/src/mesa/main/formats.h +@@ -617,6 +617,13 @@ 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 HAVE_MESA_FORMAT_YUV420_2PLANE ++#define MESA_FORMAT_YUV420_2PLANE PIPE_FORMAT_YUV420_2PLANE ++ ++#define HAVE_MESA_FORMAT_YVU420_2PLANE ++#define MESA_FORMAT_YVU420_2PLANE PIPE_FORMAT_YVU420_2PLANE ++ + #define MESA_FORMAT_COUNT PIPE_FORMAT_COUNT + + /* Packed to array format adapters */ +diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h +index 32528a5f16b..8f77d4c58dd 100644 +--- a/src/mesa/main/mtypes.h ++++ b/src/mesa/main/mtypes.h +@@ -158,6 +158,7 @@ _mesa_varying_slot_in_fs(gl_varying_slot slot) + */ + struct gl_config + { ++ GLboolean rgbMode; + GLboolean floatMode; + GLuint doubleBufferMode; + GLuint stereoMode; +@@ -179,6 +180,14 @@ struct gl_config + + /* EXT_framebuffer_sRGB */ + GLint sRGBCapable; ++ ++ /* EXT_yuv_surface */ ++ GLint YUVOrder; ++ GLint YUVNumberOfPlanes; ++ GLint YUVSubsample; ++ GLint YUVDepthRange; ++ GLint YUVCSCStandard; ++ GLint YUVPlaneBPP; + }; + + +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0031-egl-add-support-for-EXT_yuv_surface.patch b/recipes-graphics/mesa/mesa-pvr/0031-egl-add-support-for-EXT_yuv_surface.patch new file mode 100644 index 0000000..96c004d --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0031-egl-add-support-for-EXT_yuv_surface.patch @@ -0,0 +1,541 @@ +From 4e65ae659b775259b4f703eb563feffc623c17b7 Mon Sep 17 00:00:00 2001 +From: Frank Binns +Date: Wed, 20 Dec 2017 17:41:38 +0000 +Subject: [PATCH 31/67] egl: add support for EXT_yuv_surface + +This implements EXT_yuv_surface but doesn't expose it for any platform. +--- + include/GL/internal/dri_interface.h | 1 + + src/egl/drivers/dri2/egl_dri2.c | 83 +++++++++ + src/egl/main/eglapi.c | 1 + + src/egl/main/eglconfig.c | 255 +++++++++++++++++++++++++++- + src/egl/main/eglconfig.h | 12 ++ + src/egl/main/egldisplay.h | 1 + + 6 files changed, 348 insertions(+), 5 deletions(-) + +diff --git a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h +index 4d5a1874dc2..62517e4004a 100644 +--- a/include/GL/internal/dri_interface.h ++++ b/include/GL/internal/dri_interface.h +@@ -1154,6 +1154,7 @@ enum dri_loader_cap { + */ + DRI_LOADER_CAP_RGBA_ORDERING, + DRI_LOADER_CAP_FP16, ++ DRI_LOADER_CAP_YUV_SURFACE_IMG = 0x7001, + }; + + struct __DRIdri2LoaderExtensionRec { +diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c +index db993f8f059..ee3bcda4d12 100644 +--- a/src/egl/drivers/dri2/egl_dri2.c ++++ b/src/egl/drivers/dri2/egl_dri2.c +@@ -306,6 +306,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 * +@@ -432,6 +433,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; +@@ -536,6 +539,73 @@ dri2_add_config(_EGLDisplay *disp, const __DRIconfig *dri_config, int id, + 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) +@@ -583,6 +653,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; + +@@ -1014,6 +1095,8 @@ dri2_setup_screen(_EGLDisplay *disp) + disp->Extensions.EXT_protected_surface = + dri2_renderer_query_integer(dri2_dpy, + __DRI2_RENDERER_HAS_PROTECTED_CONTENT); ++ ++ disp->Extensions.EXT_yuv_surface = EGL_TRUE; + } + + void +diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c +index e2a7797d73e..6d7f62c6851 100644 +--- a/src/egl/main/eglapi.c ++++ b/src/egl/main/eglapi.c +@@ -512,6 +512,7 @@ _eglCreateExtensionsString(_EGLDisplay *disp) + _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); + +diff --git a/src/egl/main/eglconfig.c b/src/egl/main/eglconfig.c +index 17d8f3555d4..5e56948ab72 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 1f2a4008f12..d4a748970b5 100644 +--- a/src/egl/main/eglconfig.h ++++ b/src/egl/main/eglconfig.h +@@ -89,6 +89,12 @@ struct _egl_config + EGLint FramebufferTargetAndroid; + EGLint RecordableAndroid; + EGLint ComponentType; ++ EGLint YUVOrderEXT; ++ EGLint YUVNumberOfPlanesEXT; ++ EGLint YUVSubsampleEXT; ++ EGLint YUVDepthRangeEXT; ++ EGLint YUVCSCStandardEXT; ++ EGLint YUVPlaneBPPEXT; + }; + + +@@ -139,6 +145,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/egldisplay.h b/src/egl/main/egldisplay.h +index 0a7366b7c07..020529c57e2 100644 +--- a/src/egl/main/egldisplay.h ++++ b/src/egl/main/egldisplay.h +@@ -112,6 +112,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 +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0032-dri-add-missing-__DRI_IMAGE_COMPONENTS-define-for-EG.patch b/recipes-graphics/mesa/mesa-pvr/0032-dri-add-missing-__DRI_IMAGE_COMPONENTS-define-for-EG.patch new file mode 100644 index 0000000..7f836c6 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0032-dri-add-missing-__DRI_IMAGE_COMPONENTS-define-for-EG.patch @@ -0,0 +1,35 @@ +From 5a22280c13e98932ad45fa6a131217abdffd16b4 Mon Sep 17 00:00:00 2001 +From: Frank Binns +Date: Fri, 2 Feb 2018 16:59:52 +0000 +Subject: [PATCH 32/67] dri: add missing __DRI_IMAGE_COMPONENTS define for + EGL_TEXTURE_EXTERNAL_WL + +The __DRI_IMAGE_COMPONENTS defines have been re-ordered, to make it +less likely that new defines will be added with the same values as +existing ones. +--- + include/GL/internal/dri_interface.h | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h +index 62517e4004a..6490f6e80e2 100644 +--- a/include/GL/internal/dri_interface.h ++++ b/include/GL/internal/dri_interface.h +@@ -1461,11 +1461,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 + + + /** +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0033-egl-wayland-expose-EXT_yuv_surface-support.patch b/recipes-graphics/mesa/mesa-pvr/0033-egl-wayland-expose-EXT_yuv_surface-support.patch new file mode 100644 index 0000000..e7f0fba --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0033-egl-wayland-expose-EXT_yuv_surface-support.patch @@ -0,0 +1,74 @@ +From 3d47285da42c76fe36ae67c62e8d0a0d76d18da0 Mon Sep 17 00:00:00 2001 +From: Frank Binns +Date: Thu, 11 Jan 2018 09:38:47 +0000 +Subject: [PATCH 33/67] egl/wayland: expose EXT_yuv_surface support + +This adds support for YUYV configs. +--- + src/egl/drivers/dri2/egl_dri2.c | 1 + + src/egl/drivers/dri2/platform_wayland.c | 15 ++++++++++++++- + 2 files changed, 15 insertions(+), 1 deletion(-) + +diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c +index ee3bcda4d12..d511d73f2ed 100644 +--- a/src/egl/drivers/dri2/egl_dri2.c ++++ b/src/egl/drivers/dri2/egl_dri2.c +@@ -2769,6 +2769,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 * +diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c +index a096d9500c1..72456d5d748 100644 +--- a/src/egl/drivers/dri2/platform_wayland.c ++++ b/src/egl/drivers/dri2/platform_wayland.c +@@ -135,6 +135,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_assert(ARRAY_SIZE(dri2_wl_visuals) <= EGL_DRI2_MAX_FORMATS, +@@ -958,6 +965,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; + default: + return 0; +@@ -1552,6 +1560,7 @@ dri2_wl_add_configs_for_visuals(_EGLDisplay *disp) + 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++) { +@@ -1563,8 +1572,12 @@ dri2_wl_add_configs_for_visuals(_EGLDisplay *disp) + if (!BITSET_TEST(dri2_dpy->formats, j)) + continue; + ++ surface_type = EGL_WINDOW_BIT; ++ if (dri2_wl_visuals[j].wl_drm_format != WL_DRM_FORMAT_YUYV) ++ surface_type |= EGL_PBUFFER_BIT; ++ + dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i], +- count + 1, EGL_WINDOW_BIT | EGL_PBUFFER_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++; +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0034-egl-tizen-expose-EXT_yuv_surface-support.patch b/recipes-graphics/mesa/mesa-pvr/0034-egl-tizen-expose-EXT_yuv_surface-support.patch new file mode 100644 index 0000000..f15e499 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0034-egl-tizen-expose-EXT_yuv_surface-support.patch @@ -0,0 +1,357 @@ +From 40c0d03cfb2751279b24890d0f752fade968862e Mon Sep 17 00:00:00 2001 +From: Frank Binns +Date: Tue, 13 Feb 2018 14:47:48 +0000 +Subject: [PATCH 34/67] egl/tizen: expose EXT_yuv_surface support + +This adds support for NV12 and NV21 configs. +--- + src/egl/drivers/dri2/platform_tizen.c | 278 ++++++++++++++++++-------- + 1 file changed, 200 insertions(+), 78 deletions(-) + +diff --git a/src/egl/drivers/dri2/platform_tizen.c b/src/egl/drivers/dri2/platform_tizen.c +index 2bc9b3e7c64..b6478a1875b 100644 +--- a/src/egl/drivers/dri2/platform_tizen.c ++++ b/src/egl/drivers/dri2/platform_tizen.c +@@ -100,37 +100,93 @@ create_image_from_native(struct dri2_egl_surface *dri2_surf, + { + _EGLSurface *surf = &dri2_surf->base; + struct dri2_egl_display *dri2_dpy = dri2_egl_display(surf->Resource.Display); ++ struct dri2_egl_config *dri2_conf = dri2_egl_config(surf->Config); ++ const __DRIconfig *config = ++ dri2_get_dri_config(dri2_conf, surf->Type, surf->GLColorspace); + tbm_bo tbm_buf; + tbm_surface_info_s info; +- int fd, fourcc, offset, pitch; ++ int fd[TBM_SURF_PLANE_MAX]; ++ int offset[TBM_SURF_PLANE_MAX]; ++ int pitch[TBM_SURF_PLANE_MAX]; ++ int fourcc; + __DRIimage *dri_image; +- +- tbm_buf = tbm_surface_internal_get_bo(tbm_surf, 0); +- if (!tbm_buf) { +- _eglLog(_EGL_DEBUG, "%s: failed to get bo for tbm surface", __func__); +- return NULL; +- } ++ enum __DRIYUVColorSpace color_space; ++ enum __DRISampleRange sample_range; ++ unsigned csc_standard; ++ unsigned depth_range; ++ unsigned create_error; + + if (tbm_surface_get_info(tbm_surf, &info)) { + _eglLog(_EGL_DEBUG, "%s: failed to get tbm surface info", __func__); + return NULL; + } + +- fd = tbm_bo_export_fd(tbm_buf); + fourcc = dri2_fourcc_from_tbm_format(info.format); +- offset = info.planes[0].offset; +- pitch = info.planes[0].stride; +- +- dri_image = dri2_dpy->image->createImageFromFds(dri2_dpy->dri_screen, +- info.width, +- info.height, +- fourcc, +- &fd, +- 1, +- &pitch, +- &offset, +- loaderPrivate); +- close(fd); ++ ++ for (unsigned i = 0; i < info.num_planes; i++) { ++ int index = tbm_surface_internal_get_plane_bo_idx(tbm_surf, i); ++ ++ tbm_buf = tbm_surface_internal_get_bo(tbm_surf, index); ++ if (!tbm_buf) { ++ while (i--) ++ close(fd[i]); ++ _eglLog(_EGL_DEBUG, "%s: failed to get bo %d for tbm surface", ++ __func__, i); ++ return NULL; ++ } ++ ++ fd[i] = tbm_bo_export_fd(tbm_buf); ++ offset[i] = info.planes[i].offset; ++ pitch[i] = info.planes[i].stride; ++ } ++ ++ dri2_dpy->core->getConfigAttrib(config, ++ __DRI_ATTRIB_YUV_CSC_STANDARD, &csc_standard); ++ switch (csc_standard) { ++ case __DRI_ATTRIB_YUV_CSC_STANDARD_601_BIT: ++ color_space = __DRI_YUV_COLOR_SPACE_ITU_REC601; ++ break; ++ case __DRI_ATTRIB_YUV_CSC_STANDARD_709_BIT: ++ color_space = __DRI_YUV_COLOR_SPACE_ITU_REC709; ++ break; ++ case __DRI_ATTRIB_YUV_CSC_STANDARD_2020_BIT: ++ color_space = __DRI_YUV_COLOR_SPACE_ITU_REC2020; ++ break; ++ default: ++ color_space = __DRI_YUV_COLOR_SPACE_UNDEFINED; ++ break; ++ } ++ ++ dri2_dpy->core->getConfigAttrib(config, ++ __DRI_ATTRIB_YUV_DEPTH_RANGE, &depth_range); ++ switch (depth_range) { ++ case __DRI_ATTRIB_YUV_DEPTH_RANGE_LIMITED_BIT: ++ sample_range = __DRI_YUV_NARROW_RANGE; ++ break; ++ case __DRI_ATTRIB_YUV_DEPTH_RANGE_FULL_BIT: ++ sample_range = __DRI_YUV_FULL_RANGE; ++ break; ++ default: ++ sample_range = __DRI_YUV_RANGE_UNDEFINED; ++ break; ++ } ++ ++ dri_image = dri2_dpy->image->createImageFromDmaBufs(dri2_dpy->dri_screen, ++ info.width, ++ info.height, ++ fourcc, ++ fd, ++ info.num_planes, ++ pitch, ++ offset, ++ color_space, ++ sample_range, ++ __DRI_YUV_CHROMA_SITING_UNDEFINED, ++ __DRI_YUV_CHROMA_SITING_UNDEFINED, ++ &create_error, ++ loaderPrivate); ++ for (unsigned i = 0; i < info.num_planes; i++) ++ close(fd[i]); + + if (!dri_image) { + _eglLog(_EGL_DEBUG, "%s: failed to create dri image from tbm bo", __func__); +@@ -792,10 +848,22 @@ dri2_tizen_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate) + { + } + ++static unsigned ++dri2_tizen_get_capability(void *loaderPrivate, enum dri_loader_cap cap) ++{ ++ switch (cap) { ++ case DRI_LOADER_CAP_YUV_SURFACE_IMG: ++ return 1; ++ default: ++ return 0; ++ } ++} ++ + static const __DRIimageLoaderExtension tizen_image_loader_extension = { +- .base = { __DRI_IMAGE_LOADER, 1 }, ++ .base = { __DRI_IMAGE_LOADER, 2 }, + .getBuffers = dri2_tizen_get_buffers, + .flushFrontBuffer = dri2_tizen_flush_front_buffer, ++ .getCapability = dri2_tizen_get_capability, + }; + + static const __DRIextension *image_loader_extensions[] = { +@@ -804,6 +872,41 @@ static const __DRIextension *image_loader_extensions[] = { + NULL, + }; + ++static EGLBoolean ++derive_yuv_native_visual_from_config(struct dri2_egl_display *dri2_dpy, ++ const __DRIconfig *dri_config, ++ int *native_visual) ++{ ++ unsigned order, subsample, num_planes, plane_bpp; ++ ++ 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 ((plane_bpp & __DRI_ATTRIB_YUV_PLANE_BPP_8_BIT) == 0) ++ return EGL_FALSE; ++ ++ if (num_planes != 2) ++ return EGL_FALSE; ++ ++ if (subsample & __DRI_ATTRIB_YUV_SUBSAMPLE_4_2_0_BIT) { ++ if (order & __DRI_ATTRIB_YUV_ORDER_YUV_BIT) { ++ *native_visual = TBM_FORMAT_NV12; ++ return EGL_TRUE; ++ } else if (order & __DRI_ATTRIB_YUV_ORDER_YVU_BIT) { ++ *native_visual = TBM_FORMAT_NV21; ++ return EGL_TRUE; ++ } ++ } ++ ++ return EGL_FALSE; ++} ++ + static EGLBoolean + dri2_tizen_add_configs(_EGLDisplay *dpy) + { +@@ -811,83 +914,102 @@ dri2_tizen_add_configs(_EGLDisplay *dpy) + int count = 0; + + for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++) { +- static const struct rgba_shifts_and_sizes pbuffer_sasa[] = { +- { +- /* ARGB8888 */ +- { 16, 8, 0, 24 }, +- { 8, 8, 8, 8 }, +- }, +- { +- /* RGB888 */ +- { 16, 8, 0, -1 }, +- { 8, 8, 8, 0 }, +- }, +- { +- /* RGB565 */ +- { 11, 5, 0, -1 }, +- { 5, 6, 5, 0 }, +- }, +- }; + struct dri2_egl_config *dri2_cfg; +- int shifts[4]; +- unsigned int sizes[4]; ++ unsigned int render_type; + unsigned int caveat = 0; + int surface_type = 0; +- tpl_bool_t is_slow; + EGLint attr_list[] = { + EGL_NATIVE_VISUAL_ID, 0, + EGL_CONFIG_CAVEAT, EGL_NONE, + EGL_NONE, + }; +- tpl_result_t res; +- +- dri2_get_shifts_and_sizes(dri2_dpy->core, dri2_dpy->driver_configs[i], +- shifts, sizes); + + dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i], +- __DRI_ATTRIB_BUFFER_SIZE, &depth); ++ __DRI_ATTRIB_CONFIG_CAVEAT, &caveat); + + dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i], +- __DRI_ATTRIB_CONFIG_CAVEAT, &caveat); ++ __DRI_ATTRIB_RENDER_TYPE, &render_type); ++ ++ if (render_type & __DRI_ATTRIB_RGBA_BIT) { ++ static const struct rgba_shifts_and_sizes pbuffer_sasa[] = { ++ { ++ /* ARGB8888 */ ++ { 16, 8, 0, 24 }, ++ { 8, 8, 8, 8 }, ++ }, ++ { ++ /* RGB888 */ ++ { 16, 8, 0, -1 }, ++ { 8, 8, 8, 0 }, ++ }, ++ { ++ /* RGB565 */ ++ { 11, 5, 0, -1 }, ++ { 5, 6, 5, 0 }, ++ }, ++ }; ++ int shifts[4]; ++ unsigned int sizes[4]; ++ unsigned int depth; ++ tpl_bool_t is_slow; ++ tpl_result_t res; + +- res = tpl_display_query_config(dri2_dpy->tpl_dpy, TPL_SURFACE_TYPE_WINDOW, +- sizes[0], sizes[1], sizes[2], sizes[3], +- depth, &attr_list[1], &is_slow); +- if (res != TPL_ERROR_NONE) +- continue; +- surface_type |= EGL_WINDOW_BIT; ++ dri2_get_shifts_and_sizes(dri2_dpy->core, dri2_dpy->driver_configs[i], ++ shifts, sizes); + +- if (is_slow) +- caveat |= __DRI_ATTRIB_SLOW_BIT; ++ dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i], ++ __DRI_ATTRIB_BUFFER_SIZE, &depth); ++ ++ res = tpl_display_query_config(dri2_dpy->tpl_dpy, ++ TPL_SURFACE_TYPE_WINDOW, ++ sizes[0], sizes[1], sizes[2], sizes[3], ++ depth, &attr_list[1], &is_slow); ++ if (res != TPL_ERROR_NONE) ++ continue; + +- res = tpl_display_query_config(dri2_dpy->tpl_dpy, TPL_SURFACE_TYPE_PIXMAP, +- sizes[0], sizes[1], sizes[2], sizes[3], +- depth, NULL, &is_slow); +- if (res == TPL_ERROR_NONE) { +- surface_type |= EGL_PIXMAP_BIT; ++ surface_type |= EGL_WINDOW_BIT; + + if (is_slow) + caveat |= __DRI_ATTRIB_SLOW_BIT; +- } + +- for (unsigned j = 0; j < ARRAY_SIZE(pbuffer_sasa); j++) { +- const struct rgba_shifts_and_sizes *pbuffer_sas = &pbuffer_sasa[j]; +- +- if (shifts[0] == pbuffer_sas->shifts[0] && +- shifts[1] == pbuffer_sas->shifts[1] && +- shifts[2] == pbuffer_sas->shifts[2] && +- shifts[3] == pbuffer_sas->shifts[3] && +- sizes[0] == pbuffer_sas->sizes[0] && +- sizes[1] == pbuffer_sas->sizes[1] && +- sizes[2] == pbuffer_sas->sizes[2] && +- sizes[3] == pbuffer_sas->sizes[3]) { +- surface_type |= EGL_PBUFFER_BIT; +- break; ++ res = tpl_display_query_config(dri2_dpy->tpl_dpy, ++ TPL_SURFACE_TYPE_PIXMAP, ++ sizes[0], sizes[1], sizes[2], sizes[3], ++ depth, NULL, &is_slow); ++ if (res == TPL_ERROR_NONE) { ++ surface_type |= EGL_PIXMAP_BIT; ++ ++ if (is_slow) ++ caveat |= __DRI_ATTRIB_SLOW_BIT; + } +- } + +- if (dri2_dpy->image->base.version >= 9 && dri2_dpy->image->blitImage) +- surface_type |= EGL_SWAP_BEHAVIOR_PRESERVED_BIT; ++ for (unsigned j = 0; j < ARRAY_SIZE(pbuffer_sasa); j++) { ++ const struct rgba_shifts_and_sizes *pbuffer_sas = &pbuffer_sasa[j]; ++ ++ if (shifts[0] == pbuffer_sas->shifts[0] && ++ shifts[1] == pbuffer_sas->shifts[1] && ++ shifts[2] == pbuffer_sas->shifts[2] && ++ shifts[3] == pbuffer_sas->shifts[3] && ++ sizes[0] == pbuffer_sas->sizes[0] && ++ sizes[1] == pbuffer_sas->sizes[1] && ++ sizes[2] == pbuffer_sas->sizes[2] && ++ sizes[3] == pbuffer_sas->sizes[3]) { ++ surface_type |= EGL_PBUFFER_BIT; ++ break; ++ } ++ ++ } ++ ++ if (dri2_dpy->image->base.version >= 9 && dri2_dpy->image->blitImage) ++ surface_type |= EGL_SWAP_BEHAVIOR_PRESERVED_BIT; ++ } else if (render_type & __DRI_ATTRIB_YUV_BIT) { ++ if (!derive_yuv_native_visual_from_config(dri2_dpy, ++ dri2_dpy->driver_configs[i], ++ &attr_list[1])) ++ continue; ++ surface_type = EGL_WINDOW_BIT; ++ caveat = 0; ++ } + + if (caveat & __DRI_ATTRIB_NON_CONFORMANT_CONFIG) + attr_list[3] = EGL_NON_CONFORMANT_CONFIG; +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0035-gbm-add-some-new-GBM-formats.patch b/recipes-graphics/mesa/mesa-pvr/0035-gbm-add-some-new-GBM-formats.patch new file mode 100644 index 0000000..9e41da2 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0035-gbm-add-some-new-GBM-formats.patch @@ -0,0 +1,69 @@ +From 5bd42e648dc9068392641436b70fc28a00689c8e Mon Sep 17 00:00:00 2001 +From: Silvestrs Timofejevs +Date: Thu, 30 Aug 2018 13:48:53 +0100 +Subject: [PATCH 35/67] gbm: add some new GBM formats + +GBM_FORMAT_ARGB4444 +GBM_FORMAT_BGR888 +GBM_FORMAT_YUYV +GBM_FORMAT_YVU444_PACK10_IMG +--- + src/gbm/backends/dri/gbm_dri.c | 16 ++++++++++++++++ + src/gbm/main/gbm.h | 2 ++ + 2 files changed, 18 insertions(+) + +diff --git a/src/gbm/backends/dri/gbm_dri.c b/src/gbm/backends/dri/gbm_dri.c +index 2aa9c7c41ad..5acb15b516f 100644 +--- a/src/gbm/backends/dri/gbm_dri.c ++++ b/src/gbm/backends/dri/gbm_dri.c +@@ -514,11 +514,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 }, +@@ -571,6 +581,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 +diff --git a/src/gbm/main/gbm.h b/src/gbm/main/gbm.h +index 7c82cd661a3..81308ab9745 100644 +--- a/src/gbm/main/gbm.h ++++ b/src/gbm/main/gbm.h +@@ -167,6 +167,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 +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0036-egl-add-null-platform.patch b/recipes-graphics/mesa/mesa-pvr/0036-egl-add-null-platform.patch new file mode 100644 index 0000000..f43dd4c --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0036-egl-add-null-platform.patch @@ -0,0 +1,1491 @@ +From def26b8534e4f8e150e5775dd1f7d2d955580c05 Mon Sep 17 00:00:00 2001 +From: Frank Binns +Date: Sun, 5 Jun 2016 12:04:40 +0100 +Subject: [PATCH 36/67] egl: add "null" platform + +--- + meson.build | 25 +- + meson_options.txt | 2 +- + src/egl/drivers/dri2/egl_dri2.c | 11 +- + src/egl/drivers/dri2/egl_dri2.h | 57 +- + src/egl/drivers/dri2/platform_null.c | 1179 ++++++++++++++++++++++++++ + src/egl/main/eglapi.c | 5 +- + src/egl/main/egldisplay.c | 1 + + src/egl/main/egldisplay.h | 1 + + src/egl/meson.build | 5 + + 9 files changed, 1277 insertions(+), 9 deletions(-) + create mode 100644 src/egl/drivers/dri2/platform_null.c + +diff --git a/meson.build b/meson.build +index 3d9d345dbf2..2018562a1ec 100644 +--- a/meson.build ++++ b/meson.build +@@ -340,7 +340,7 @@ endif + _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()) +@@ -359,6 +359,7 @@ with_platform_wayland = _platforms.contains('wayland') + with_platform_haiku = _platforms.contains('haiku') + with_platform_windows = _platforms.contains('windows') + with_platform_tizen = _platforms.contains('tizen') ++with_platform_null = _platforms.contains('null') + + if with_platform_tizen and _platforms.length() != 1 + error('tizen cannot be enabled at the same time as other platforms') +@@ -958,6 +959,26 @@ if with_platform_tizen + ] + pre_args += '-DHAVE_TIZEN_PLATFORM' + endif ++if with_platform_null ++ pre_args += '-DHAVE_NULL_PLATFORM' ++endif ++if with_platform_android ++ dep_android = [ ++ dependency('cutils'), ++ dependency('hardware'), ++ dependency('sync'), ++ ] ++ if with_gallium ++ dep_android += dependency('backtrace') ++ endif ++ if get_option('platform-sdk-version') >= 26 ++ dep_android += dependency('nativewindow') ++ endif ++ pre_args += '-DHAVE_ANDROID_PLATFORM' ++endif ++if with_platform_haiku ++ pre_args += '-DHAVE_HAIKU_PLATFORM' ++endif + + prog_python = import('python').find_installation('python3') + has_mako = run_command( +@@ -1583,7 +1604,7 @@ 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 or +- with_platform_tizen ++ with_platform_tizen or with_platform_null + ) + if dep_libdrm.found() + pre_args += '-DHAVE_LIBDRM' +diff --git a/meson_options.txt b/meson_options.txt +index 8230db93c70..d90a25f97ff 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', 'tizen', ++ 'auto', 'x11', 'wayland', 'haiku', 'android', 'windows', 'tizen', 'null', + ], + description : 'window systems to support. If this is set to `auto`, all platforms applicable will be enabled.' + ) +diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c +index d511d73f2ed..2f8414e0c60 100644 +--- a/src/egl/drivers/dri2/egl_dri2.c ++++ b/src/egl/drivers/dri2/egl_dri2.c +@@ -1253,6 +1253,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); +@@ -1318,8 +1321,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. +@@ -1355,11 +1356,17 @@ dri2_display_destroy(_EGLDisplay *disp) + tpl_object_unreference((tpl_object_t *) dri2_dpy->tpl_dpy); + break; + #endif ++ case _EGL_PLATFORM_NULL: ++ dri2_teardown_null(dri2_dpy); ++ break; + default: + /* TODO: add teardown for other platforms */ + 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. +diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h +index f41f32cd234..eb2127e3fe6 100644 +--- a/src/egl/drivers/dri2/egl_dri2.h ++++ b/src/egl/drivers/dri2/egl_dri2.h +@@ -81,6 +81,10 @@ struct zwp_linux_dmabuf_v1; + #include + #endif + ++#ifdef HAVE_NULL_PLATFORM ++#include ++#endif ++ + #include "eglconfig.h" + #include "eglcontext.h" + #include "egldevice.h" +@@ -99,6 +103,22 @@ struct zwp_linux_dmabuf_v1; + + struct wl_buffer; + ++#ifdef HAVE_NULL_PLATFORM ++struct display_output { ++ bool in_use; ++ 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; ++}; ++#endif ++ + struct dri2_egl_display_vtbl { + /* mandatory on Wayland, unused otherwise */ + int (*authenticate)(_EGLDisplay *disp, uint32_t id); +@@ -257,6 +277,11 @@ struct dri2_egl_display + char *device_name; + #endif + ++#ifdef HAVE_NULL_PLATFORM ++ bool atomic_enabled; ++ struct display_output output; ++#endif ++ + #ifdef HAVE_ANDROID_PLATFORM + const gralloc_module_t *gralloc; + /* gralloc vendor usage bit for front rendering */ +@@ -332,7 +357,10 @@ struct dri2_egl_surface + struct wl_display *wl_dpy_wrapper; + struct wl_drm *wl_drm_wrapper; + struct wl_callback *throttle_callback; +- int format; ++#endif ++ ++#if defined(HAVE_WAYLAND_PLATFORM) || defined(HAVE_NULL_PLATFORM) ++ int format; + #endif + + #ifdef HAVE_DRM_PLATFORM +@@ -358,9 +386,10 @@ struct dri2_egl_surface + __DRIbuffer *local_buffers[__DRI_BUFFER_COUNT]; + + #if defined(HAVE_WAYLAND_PLATFORM) || defined(HAVE_DRM_PLATFORM) || \ +- defined(HAVE_TIZEN_PLATFORM) ++ defined(HAVE_TIZEN_PLATFORM) || defined(HAVE_NULL_PLATFORM) + struct { +-#if defined(HAVE_WAYLAND_PLATFORM) || defined(HAVE_TIZEN_PLATFORM) ++#if defined(HAVE_WAYLAND_PLATFORM) || defined(HAVE_TIZEN_PLATFORM) || \ ++ defined(HAVE_NULL_PLATFORM) + __DRIimage *dri_image; + #endif + #ifdef HAVE_WAYLAND_PLATFORM +@@ -377,6 +406,9 @@ struct dri2_egl_surface + #endif + #ifdef HAVE_TIZEN_PLATFORM + tbm_surface_h tbm_surf; ++#endif ++#ifdef HAVE_NULL_PLATFORM ++ uint32_t fb_id; + #endif + bool locked; + int age; +@@ -409,6 +441,10 @@ struct dri2_egl_surface + void *swrast_front; + #endif + ++#ifdef HAVE_NULL_PLATFORM ++ uint32_t front_fb_id; ++#endif ++ + int out_fence_fd; + EGLBoolean enable_out_fence; + +@@ -589,6 +625,21 @@ EGLBoolean + dri2_initialize_tizen(_EGLDisplay *disp); + #endif + ++#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_null.c b/src/egl/drivers/dri2/platform_null.c +new file mode 100644 +index 00000000000..fb03ecc36fd +--- /dev/null ++++ b/src/egl/drivers/dri2/platform_null.c +@@ -0,0 +1,1179 @@ ++/* ++ * 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 "egl_dri2.h" ++#include "loader.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; ++}; ++ ++#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, \ ++ } ++ ++/* ++ * 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]; ++} 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 }, ++ }, ++ { ++ .drm_format = DRM_FORMAT_ARGB8888, ++ .dri_image_format = __DRI_IMAGE_FORMAT_ARGB8888, ++ .rgba_shifts = { 16, 8, 0, 24 }, ++ .rgba_sizes = { 8, 8, 8, 8 }, ++ }, ++ { ++ .drm_format = DRM_FORMAT_RGB565, ++ .dri_image_format = __DRI_IMAGE_FORMAT_RGB565, ++ .rgba_shifts = { 11, 5, 0, -1 }, ++ .rgba_sizes = { 5, 6, 5, 0 }, ++ }, ++}; ++ ++ ++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 ++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 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 void ++flip_handler(int fd, unsigned int sequence, unsigned int tv_sec, ++ unsigned int tv_usec, void *user_data) ++{ ++ bool *plocked = user_data; ++ ++ if (plocked) ++ *plocked = false; ++} ++ ++static bool ++flip_process(int fd) ++{ ++ static drmEventContext evctx = ++ {.version = 2, .page_flip_handler = flip_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) ++ return false; ++ ++ drmHandleEvent(fd, &evctx); ++ ++ return true; ++} ++ ++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; ++ ++ 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 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), ++ }; ++ 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; ++ ++ /* ++ * Don't block - like drmModePageFlip, drmModeAtomicCommit will return ++ * -EBUSY if the commit can't be queued in the kernel. ++ */ ++ flags |= DRM_MODE_ATOMIC_NONBLOCK; ++ ++ return drmModeAtomicCommit(fd, output->atomic_state, flags, flip_data); ++} ++ ++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 bool ++display_output_init(int fd, struct display_output *output, bool use_atomic) ++{ ++ 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]; ++ ++ /* Record the display supported 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); ++ } ++ 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) ++{ ++ if (output->atomic_state) ++ return display_output_atomic_flip(fd, output, fb_id, flags, flip_data); ++ ++ return drmModePageFlip(fd, output->crtc_id, fb_id, flags, flip_data); ++} ++ ++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 bool ++add_fb_for_dri_image(struct dri2_egl_display *dri2_dpy, __DRIimage *image, ++ uint32_t *fb_id_out) ++{ ++ uint32_t handles[4] = {0}; ++ uint32_t pitches[4] = {0}; ++ uint32_t offsets[4] = {0}; ++ int handle, stride, width, height, format; ++ int format_idx; ++ ++ dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HANDLE, &handle); ++ dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride); ++ 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); ++ ++ handles[0] = (uint32_t) handle; ++ pitches[0] = (uint32_t) stride; ++ ++ format_idx = format_idx_get_from_dri_image_format(format); ++ assert(format_idx != -1); ++ ++ return !drmModeAddFB2(dri2_dpy->fd, width, height, ++ dri2_null_formats[format_idx].drm_format, ++ handles, pitches, offsets, fb_id_out, 0); ++} ++ ++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 = dri2_dpy->image->createImage(dri2_dpy->dri_screen, ++ dri2_surf->base.Width, ++ dri2_surf->base.Height, ++ dri2_surf->format, ++ use, ++ NULL); ++ if (!dri2_surf->front) ++ return false; ++ ++ if (dri2_surf->base.Type == EGL_WINDOW_BIT) { ++ if (!add_fb_for_dri_image(dri2_dpy, dri2_surf->front, ++ &dri2_surf->front_fb_id)) { ++ dri2_dpy->image->destroyImage(dri2_surf->front); ++ dri2_surf->front = 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); ++ ++ if (!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; ++ } ++ } ++ if (!dri2_surf->back) ++ return false; ++ } ++ ++ if (!dri2_surf->back->dri_image) { ++ dri2_surf->back->dri_image = ++ dri2_dpy->image->createImage(dri2_dpy->dri_screen, ++ dri2_surf->base.Width, ++ dri2_surf->base.Height, ++ dri2_surf->format, ++ __DRI_IMAGE_USE_SCANOUT, ++ NULL); ++ if (!dri2_surf->back->dri_image) ++ return false; ++ } ++ ++ if (!dri2_surf->back->fb_id) { ++ if (!add_fb_for_dri_image(dri2_dpy, dri2_surf->back->dri_image, ++ &dri2_surf->back->fb_id)) { ++ return false; ++ } ++ } ++ ++ dri2_surf->back->locked = 1; ++ ++ return true; ++} ++ ++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 dri2_egl_config *dri2_config = dri2_egl_config(config); ++ struct dri2_egl_surface *dri2_surf; ++ const __DRIconfig *dri_config; ++ _EGLSurface *surf; ++ int format_idx; ++ ++ 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, false, 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; ++ } ++ ++ 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; ++ ++ 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; ++ ++ 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, &dri2_dpy->output, ++ dri2_surf->front_fb_id); ++ if (err) { ++ _eglError(EGL_BAD_NATIVE_WINDOW, "window set mode"); ++ goto err_destroy_surface; ++ } ++ ++ dri2_dpy->output.in_use = true; ++ ++ 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 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->current) ++ flip_process(dri2_dpy->fd); ++ ++ if (dri2_surf->front) ++ dri2_dpy->image->destroyImage(dri2_surf->front); ++ ++ if (dri2_surf->front_fb_id) ++ drmModeRmFB(dri2_dpy->fd, dri2_surf->front_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, 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); ++ bool *plocked = NULL; ++ uint32_t flags; ++ int err; ++ ++ if (dri2_surf->base.Type != EGL_WINDOW_BIT) ++ 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); ++ ++ if (dri2_surf->current) { ++ /* Wait for the previous flip to happen so the next one can be queued */ ++ if (!flip_process(dri2_dpy->fd)) { ++ _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_null_swap_buffers process"); ++ return EGL_FALSE; ++ } ++ ++ plocked = &dri2_surf->current->locked; ++ } ++ ++ flags = DRM_MODE_PAGE_FLIP_EVENT; ++ if (draw->SwapInterval == 0) ++ flags |= DRM_MODE_PAGE_FLIP_ASYNC; ++ ++ do { ++ err = display_output_flip(dri2_dpy->fd, &dri2_dpy->output, ++ dri2_surf->back->fb_id, flags, plocked); ++ } while (err == -EBUSY); ++ ++ if (err) { ++ _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_null_swap_buffers flip"); ++ dri2_surf->back->locked = false; ++ dri2_surf->back = NULL; ++ return EGL_FALSE; ++ } ++ ++ dri2_surf->back->age = 1; ++ dri2_surf->current = dri2_surf->back; ++ 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 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_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; ++ } ++ ++ if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) { ++ buffers->image_mask |= __DRI_IMAGE_BUFFER_BACK; ++ buffers->back = dri2_surf->back->dri_image; ++ } ++ ++ return 1; ++} ++ ++static void ++dri2_null_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate) ++{ ++ (void) driDrawable; ++ (void) loaderPrivate; ++} ++ ++static const __DRIimageLoaderExtension image_loader_extension = { ++ .base = { __DRI_IMAGE_LOADER, 1 }, ++ ++ .getBuffers = dri2_null_image_get_buffers, ++ .flushFrontBuffer = dri2_null_flush_front_buffer, ++}; ++ ++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_probe_device(_EGLDisplay *disp) ++{ ++ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); ++ ++ dri2_dpy->fd = -1; ++ ++ for (unsigned i = 0; i <= NULL_CARD_MINOR_MAX; i++) { ++ char *card_path; ++ ++ if (asprintf(&card_path, DRM_DEV_NAME, DRM_DIR_NAME, i) < 0) ++ continue; ++ ++ dri2_dpy->fd = loader_open_device(card_path); ++ free(card_path); ++ if (dri2_dpy->fd < 0) ++ continue; ++ ++ if (dri2_null_device_is_kms(dri2_dpy->fd)) { ++ dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd); ++ if (dri2_dpy->driver_name) { ++ 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; ++ } ++ } ++ ++ close(dri2_dpy->fd); ++ dri2_dpy->fd = -1; ++ } ++ ++ 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; ++ int format_idx; ++ ++ format_idx = format_idx_get_from_config(dri2_dpy, ++ dri2_dpy->driver_configs[i]); ++ 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, ++ EGL_WINDOW_BIT | EGL_PBUFFER_BIT, ++ NULL, NULL, NULL); ++ if (dri2_conf) ++ count++; ++ } ++ ++ return count != 0; ++} ++ ++EGLBoolean ++dri2_initialize_null(_EGLDisplay *disp) ++{ ++ struct dri2_egl_display *dri2_dpy; ++ 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; ++ ++ if (!dri2_null_probe_device(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, 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, 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_setup_swap_interval(disp, 1); ++ ++ err = drmGetCap(dri2_dpy->fd, DRM_CAP_ASYNC_PAGE_FLIP, &value); ++ if (err || value == 0) ++ dri2_dpy->min_swap_interval = 1; ++ ++ if (dri2_dpy->image->base.version < NULL_IMAGE_EXTENSION_VERSION_MIN) { ++ _eglError(EGL_NOT_INITIALIZED, "image extension version too old"); ++ goto cleanup; ++ } ++ ++ if (!display_output_init(dri2_dpy->fd, &dri2_dpy->output, ++ dri2_dpy->atomic_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, 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); ++ } ++} +diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c +index 6d7f62c6851..e4f2c43b4ef 100644 +--- a/src/egl/main/eglapi.c ++++ b/src/egl/main/eglapi.c +@@ -989,7 +989,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/egldisplay.c b/src/egl/main/egldisplay.c +index 486ac3b0557..395f38156d7 100644 +--- a/src/egl/main/egldisplay.c ++++ b/src/egl/main/egldisplay.c +@@ -78,6 +78,7 @@ static const struct { + { _EGL_PLATFORM_SURFACELESS, "surfaceless" }, + { _EGL_PLATFORM_DEVICE, "device" }, + { _EGL_PLATFORM_TIZEN, "tizen" }, ++ { _EGL_PLATFORM_NULL, "null" }, + }; + + +diff --git a/src/egl/main/egldisplay.h b/src/egl/main/egldisplay.h +index 020529c57e2..8489af9dde2 100644 +--- a/src/egl/main/egldisplay.h ++++ b/src/egl/main/egldisplay.h +@@ -53,6 +53,7 @@ enum _egl_platform_type { + _EGL_PLATFORM_SURFACELESS, + _EGL_PLATFORM_DEVICE, + _EGL_PLATFORM_TIZEN, ++ _EGL_PLATFORM_NULL, + + _EGL_NUM_PLATFORMS, + _EGL_INVALID_PLATFORM = -1 +diff --git a/src/egl/meson.build b/src/egl/meson.build +index 5749ec88f89..daa6a3a04f0 100644 +--- a/src/egl/meson.build ++++ b/src/egl/meson.build +@@ -146,6 +146,11 @@ if with_platform_tizen + incs_for_egl += [inc_loader] + deps_for_egl += [dep_tizen, dep_libdrm] + endif ++if with_platform_null ++ 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' +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0037-egl-add-config-debug-printout.patch b/recipes-graphics/mesa/mesa-pvr/0037-egl-add-config-debug-printout.patch new file mode 100644 index 0000000..9523d41 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0037-egl-add-config-debug-printout.patch @@ -0,0 +1,509 @@ +From 02065d490a68d542be56c2ea23346b3fa19928cb Mon Sep 17 00:00:00 2001 +From: Silvestrs Timofejevs +Date: Mon, 24 Sep 2018 14:14:25 +0100 +Subject: [PATCH 37/67] egl: add config debug printout + +Feature to print out EGL returned configs for debug purposes. + +'eglChooseConfig' and 'eglGetConfigs' debug information printout is +enabled when the log level equals '_EGL_DEBUG'. The configs are +printed, and if any of them are "chosen" they are marked with their +index in the chosen configs array. +--- + src/egl/main/eglconfig.c | 20 ++- + src/egl/main/eglconfigdebug.c | 321 ++++++++++++++++++++++++++++++++++ + src/egl/main/eglconfigdebug.h | 55 ++++++ + src/egl/main/egllog.c | 9 + + src/egl/main/egllog.h | 4 + + src/egl/meson.build | 2 + + 6 files changed, 407 insertions(+), 4 deletions(-) + create mode 100644 src/egl/main/eglconfigdebug.c + create mode 100644 src/egl/main/eglconfigdebug.h + +diff --git a/src/egl/main/eglconfig.c b/src/egl/main/eglconfig.c +index 5e56948ab72..ea4b3c15f3f 100644 +--- a/src/egl/main/eglconfig.c ++++ b/src/egl/main/eglconfig.c +@@ -40,6 +40,7 @@ + #include "util/macros.h" + + #include "eglconfig.h" ++#include "eglconfigdebug.h" + #include "egldisplay.h" + #include "eglcurrent.h" + #include "egllog.h" +@@ -1039,14 +1040,21 @@ _eglChooseConfig(_EGLDisplay *disp, const EGLint *attrib_list, + EGLConfig *configs, EGLint config_size, EGLint *num_configs) + { + _EGLConfig criteria; ++ EGLBoolean result; + + if (!_eglParseConfigAttribList(&criteria, disp, attrib_list)) + return _eglError(EGL_BAD_ATTRIBUTE, "eglChooseConfig"); + +- return _eglFilterConfigArray(disp->Configs, +- configs, config_size, num_configs, +- _eglFallbackMatch, _eglFallbackCompare, +- (void *) &criteria); ++ result = _eglFilterConfigArray(disp->Configs, ++ configs, config_size, num_configs, ++ _eglFallbackMatch, _eglFallbackCompare, ++ (void *) &criteria); ++ ++ if (result && (_eglGetLogLevel() == _EGL_DEBUG)) ++ eglPrintConfigDebug(disp, configs, *num_configs, ++ EGL_CONFIG_DEBUG_CHOOSE); ++ ++ return result; + } + + +@@ -1096,5 +1104,9 @@ _eglGetConfigs(_EGLDisplay *disp, EGLConfig *configs, + *num_config = _eglFlattenArray(disp->Configs, (void *) configs, + sizeof(configs[0]), config_size, _eglFlattenConfig); + ++ if (_eglGetLogLevel() == _EGL_DEBUG) ++ eglPrintConfigDebug(disp, configs, *num_config, ++ EGL_CONFIG_DEBUG_GET); ++ + return EGL_TRUE; + } +diff --git a/src/egl/main/eglconfigdebug.c b/src/egl/main/eglconfigdebug.c +new file mode 100644 +index 00000000000..92ac41a5614 +--- /dev/null ++++ b/src/egl/main/eglconfigdebug.c +@@ -0,0 +1,321 @@ ++/* ++ * Copyright 2017 Imagination Technologies. ++ * All Rights Reserved. ++ * ++ * Based on eglinfo, which has copyright: ++ * Copyright (C) 2005 Brian Paul All Rights Reserved. ++ * ++ * 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 ++ * BRIAN PAUL 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 "eglarray.h" ++#include "eglconfig.h" ++#include "eglconfigdebug.h" ++#include "egldisplay.h" ++#include "egllog.h" ++#include "egltypedefs.h" ++ ++/* Max debug message length */ ++#define CONFIG_DEBUG_MSG_MAX 1000 ++ ++/* ++ * These are X visual types, so if you're running eglinfo under ++ * something not X, they probably don't make sense. ++ */ ++static const char *const vnames[] = { "SG", "GS", "SC", "PC", "TC", "DC" }; ++ ++struct _printAttributes { ++ EGLint id, size, level; ++ EGLint red, green, blue, alpha; ++ EGLint depth, stencil; ++ EGLint renderable, surfaces; ++ EGLint vid, vtype, caveat, bindRgb, bindRgba; ++ EGLint samples, sampleBuffers; ++ char surfString[100]; ++ EGLint colorBufferType; ++ EGLint numPlanes, subsample, order; ++}; ++ ++static void ++_printHeaderFormat(void) ++{ ++ /* ++ * EGL configuration output legend: ++ * ++ * chosen --------------- eglChooseConfig returned config priority, ++ * only relevant when eglChooseConfig is called. ++ * id ------------------- EGL_CONFIG_ID ++ * bfsz ----------------- EGL_BUFFER_SIZE ++ * lvl ------------------ EGL_LEVEL ++ * ++ * color size ++ * r -------------------- EGL_RED_SIZE ++ * g -------------------- EGL_GREEN_SIZE ++ * b -------------------- EGL_BLUE_SIZE ++ * a -------------------- EGL_ALPHA_SIZE ++ * dpth ----------------- EGL_DEPTH_SIZE ++ * stcl ----------------- EGL_STENCIL_SIZE ++ * ++ * multisample ++ * ns ------------------- EGL_SAMPLES ++ * b -------------------- EGL_SAMPLE_BUFFERS ++ * visid ---------------- EGL_NATIVE_VISUAL_ID/EGL_NATIVE_VISUAL_TYPE ++ * caveat --------------- EGL_CONFIG_CAVEAT ++ * bind ----------------- EGL_BIND_TO_TEXTURE_RGB/EGL_BIND_TO_TEXTURE_RGBA ++ * ++ * renderable ++ * gl, es, es2, es3, vg - EGL_RENDERABLE_TYPE ++ * ++ * supported ++ * surfaces ------------- EGL_SURFACE_TYPE ++ * colbuf --------------- EGL_COLOR_BUFFER_TYPE ++ * ++ * yuv ++ * p -------------------- EGL_YUV_NUMBER_OF_PLANES_EXT ++ * sub ------------------ EGL_YUV_SUBSAMPLE_EXT ++ * ord ------------------ EGL_YUV_ORDER_EXT ++ */ ++ _eglLog(_EGL_DEBUG, "---------------"); ++ _eglLog(_EGL_DEBUG, "Configurations:"); ++ _eglLog(_EGL_DEBUG, "cho bf lv color size dp st ms vis cav bi renderable supported" ++ " col yuv "); ++ _eglLog(_EGL_DEBUG, "sen id sz l r g b a th cl ns b id eat nd gl es es2 es3 vg surfaces" ++ " buf p sub ord"); ++ _eglLog(_EGL_DEBUG, "---------------"); ++} ++ ++static void ++_snprintfStrcat(char *const msg, const int maxSize, const char *fmt, ...) ++{ ++ int maxAllowed; ++ va_list args; ++ ++ maxAllowed = maxSize - strlen(msg); ++ ++ va_start(args, fmt); ++ (void) vsnprintf(&msg[strlen(msg)], maxAllowed, fmt, args); ++ va_end(args); ++} ++ ++static inline const char *_enumToString(EGLint constant) ++{ ++ switch (constant) { ++ case EGL_YUV_SUBSAMPLE_4_2_0_EXT: return "420"; ++ case EGL_YUV_SUBSAMPLE_4_2_2_EXT: return "422"; ++ case EGL_YUV_SUBSAMPLE_4_4_4_EXT: return "444"; ++ case EGL_YUV_ORDER_AYUV_EXT: return "AYUV"; ++ case EGL_YUV_ORDER_UYVY_EXT: return "UYVY"; ++ case EGL_YUV_ORDER_VYUY_EXT: return "VYUY"; ++ case EGL_YUV_ORDER_YUYV_EXT: return "YUYV"; ++ case EGL_YUV_ORDER_YVYU_EXT: return "YVYU"; ++ case EGL_YUV_ORDER_YUV_EXT: return "YUV"; ++ case EGL_YUV_ORDER_YVU_EXT: return "YVU"; ++ case EGL_LUMINANCE_BUFFER: return "lum"; ++ case EGL_YUV_BUFFER_EXT: return "yuv"; ++ case EGL_RGB_BUFFER: return "rgb"; ++ default: return "?"; ++ } ++} ++ ++static void ++_eglGetConfigAttrs(_EGLDisplay *const dpy, _EGLConfig *const conf, ++ struct _printAttributes *const attr) ++{ ++ EGLBoolean success = EGL_TRUE; ++ ++ success &= _eglGetConfigAttrib(dpy, conf, EGL_CONFIG_ID, &attr->id); ++ success &= _eglGetConfigAttrib(dpy, conf, EGL_BUFFER_SIZE, &attr->size); ++ success &= _eglGetConfigAttrib(dpy, conf, EGL_LEVEL, &attr->level); ++ ++ success &= _eglGetConfigAttrib(dpy, conf, EGL_RED_SIZE, &attr->red); ++ success &= _eglGetConfigAttrib(dpy, conf, EGL_GREEN_SIZE, &attr->green); ++ success &= _eglGetConfigAttrib(dpy, conf, EGL_BLUE_SIZE, &attr->blue); ++ success &= _eglGetConfigAttrib(dpy, conf, EGL_ALPHA_SIZE, &attr->alpha); ++ success &= _eglGetConfigAttrib(dpy, conf, EGL_DEPTH_SIZE, &attr->depth); ++ success &= _eglGetConfigAttrib(dpy, conf, EGL_STENCIL_SIZE, &attr->stencil); ++ success &= _eglGetConfigAttrib(dpy, conf, EGL_NATIVE_VISUAL_ID, &attr->vid); ++ success &= _eglGetConfigAttrib(dpy, conf, EGL_NATIVE_VISUAL_TYPE, &attr->vtype); ++ ++ success &= _eglGetConfigAttrib(dpy, conf, EGL_CONFIG_CAVEAT, &attr->caveat); ++ success &= _eglGetConfigAttrib(dpy, conf, EGL_BIND_TO_TEXTURE_RGB, &attr->bindRgb); ++ success &= _eglGetConfigAttrib(dpy, conf, EGL_BIND_TO_TEXTURE_RGBA, &attr->bindRgba); ++ success &= _eglGetConfigAttrib(dpy, conf, EGL_RENDERABLE_TYPE, &attr->renderable); ++ success &= _eglGetConfigAttrib(dpy, conf, EGL_SURFACE_TYPE, &attr->surfaces); ++ ++ success &= _eglGetConfigAttrib(dpy, conf, EGL_SAMPLES, &attr->samples); ++ success &= _eglGetConfigAttrib(dpy, conf, EGL_SAMPLE_BUFFERS, &attr->sampleBuffers); ++ success &= _eglGetConfigAttrib(dpy, conf, EGL_COLOR_BUFFER_TYPE, &attr->colorBufferType); ++ ++ if (conf->Display->Extensions.EXT_yuv_surface) { ++ success &= _eglGetConfigAttrib(dpy, conf, EGL_YUV_NUMBER_OF_PLANES_EXT, ++ &attr->numPlanes); ++ success &= _eglGetConfigAttrib(dpy, conf, EGL_YUV_SUBSAMPLE_EXT, &attr->subsample); ++ success &= _eglGetConfigAttrib(dpy, conf, EGL_YUV_ORDER_EXT, &attr->order); ++ } ++ ++ if (!success) ++ _eglLog(_EGL_DEBUG, "%s: config tainted, could not obtain all attributes", ++ __func__); ++} ++ ++static void ++_eglPrintConfig(_EGLDisplay *const dpy, _EGLConfig *const conf, ++ char *const printMsg, const int maxMsgSize) ++{ ++ struct _printAttributes attr = { 0 }; ++ ++ _eglGetConfigAttrs(dpy, conf, &attr); ++ ++ if (attr.surfaces & EGL_WINDOW_BIT) ++ strcat(attr.surfString, "win,"); ++ if (attr.surfaces & EGL_PBUFFER_BIT) ++ strcat(attr.surfString, "pb,"); ++ if (attr.surfaces & EGL_PIXMAP_BIT) ++ strcat(attr.surfString, "pix,"); ++ if (attr.surfaces & EGL_STREAM_BIT_KHR) ++ strcat(attr.surfString, "str,"); ++ if (attr.surfaces & EGL_SWAP_BEHAVIOR_PRESERVED_BIT) ++ strcat(attr.surfString, "prsv,"); ++ if (strlen(attr.surfString) > 0) ++ attr.surfString[strlen(attr.surfString) - 1] = 0; ++ ++ _snprintfStrcat(printMsg, maxMsgSize, ++ "0x%03x %2d %2d %2d %2d %2d %2d %2d %2d %2d%2d 0x%08x%2s ", ++ attr.id, attr.size, attr.level, ++ attr.red, attr.green, attr.blue, attr.alpha, ++ attr.depth, attr.stencil, ++ attr.samples, attr.sampleBuffers, attr.vid, ++ attr.vtype < 6 ? vnames[attr.vtype] : "--"); ++ ++ _snprintfStrcat(printMsg, maxMsgSize, ++ "%c %c %c %c %c %c %c %15s", ++ (attr.caveat != EGL_NONE) ? 'y' : ' ', ++ (attr.bindRgba) ? 'a' : (attr.bindRgb) ? 'y' : ' ', ++ (attr.renderable & EGL_OPENGL_BIT) ? 'y' : ' ', ++ (attr.renderable & EGL_OPENGL_ES_BIT) ? 'y' : ' ', ++ (attr.renderable & EGL_OPENGL_ES2_BIT) ? 'y' : ' ', ++ (attr.renderable & EGL_OPENGL_ES3_BIT) ? 'y' : ' ', ++ (attr.renderable & EGL_OPENVG_BIT) ? 'y' : ' ', ++ attr.surfString); ++ ++ _snprintfStrcat(printMsg, maxMsgSize, " %3.3s", ++ _enumToString(attr.colorBufferType)); ++ ++ if (attr.colorBufferType == EGL_YUV_BUFFER_EXT) ++ _snprintfStrcat(printMsg, maxMsgSize, " %1.1d %3.3s %4.4s", attr.numPlanes, ++ _enumToString(attr.subsample), _enumToString(attr.order)); ++ ++ _eglLog(_EGL_DEBUG, printMsg); ++} ++ ++static void ++_eglMarkChosenConfig(_EGLConfig *const config, ++ _EGLConfig *const *const chosenConfigs, ++ const EGLint numConfigs, char *const printMsg, ++ const int maxMsgSize) ++{ ++ const char padding[] = " "; ++ ++ if (chosenConfigs == NULL) { ++ _snprintfStrcat(printMsg, maxMsgSize, "%s ", &padding[0]); ++ return; ++ } ++ ++ /* Find a match, "mark" and return */ ++ for (EGLint i = 0; i < numConfigs; i++) { ++ if (config == chosenConfigs[i]) { ++ _snprintfStrcat(printMsg, maxMsgSize, "%*d ", strlen(padding), i); ++ return; ++ } ++ } ++ ++ _snprintfStrcat(printMsg, maxMsgSize, "%s ", &padding[0]); ++} ++ ++static void ++_eglPrintConfigs(_EGLDisplay *const dpy, ++ EGLConfig *const configs, const EGLint numConfigs, ++ const enum EGL_CONFIG_DEBUG_OPTION printOption) ++{ ++ const int maxMsgSize = CONFIG_DEBUG_MSG_MAX; ++ EGLint numConfigsToPrint; ++ _EGLConfig **configsToPrint; ++ _EGLConfig **chosenConfigs; ++ char *printMsg; ++ ++ printMsg = malloc(maxMsgSize); ++ if (!printMsg) { ++ _eglLog(_EGL_DEBUG, "%s: failed to allocate the print message", __func__); ++ return; ++ } ++ ++ /* ++ * If the printout request came from the 'eglChooseConfig', all ++ * configs are printed, and the "chosen" configs are marked. ++ */ ++ if (printOption == EGL_CONFIG_DEBUG_CHOOSE) { ++ configsToPrint = (_EGLConfig **) dpy->Configs->Elements; ++ numConfigsToPrint = dpy->Configs->Size; ++ chosenConfigs = (_EGLConfig **) configs; ++ } else { ++ assert(printOption == EGL_CONFIG_DEBUG_GET); ++ configsToPrint = (_EGLConfig **) configs; ++ numConfigsToPrint = numConfigs; ++ chosenConfigs = NULL; ++ } ++ ++ _printHeaderFormat(); ++ for (EGLint i = 0; i < numConfigsToPrint; i++) { ++ _EGLConfig *configToPrint = configsToPrint[i]; ++ ++ /* "clear" message */ ++ printMsg[0] = '\0'; ++ ++ _eglMarkChosenConfig(configToPrint, chosenConfigs, numConfigs, ++ printMsg, maxMsgSize); ++ ++ _eglPrintConfig(dpy, configToPrint, printMsg, maxMsgSize); ++ } ++ ++ free(printMsg); ++} ++ ++void eglPrintConfigDebug(_EGLDisplay *const dpy, ++ EGLConfig *const configs, const EGLint numConfigs, ++ const enum EGL_CONFIG_DEBUG_OPTION printOption) ++{ ++ if (!numConfigs || !configs) { ++ _eglLog(_EGL_DEBUG, "%s: nothing to print", __func__); ++ return; ++ } ++ ++ switch (printOption) { ++ case EGL_CONFIG_DEBUG_CHOOSE: ++ case EGL_CONFIG_DEBUG_GET: ++ _eglPrintConfigs(dpy, configs, numConfigs, printOption); ++ break; ++ default: ++ _eglLog(_EGL_DEBUG, "%s: bad debug option", __func__); ++ break; ++ } ++} +diff --git a/src/egl/main/eglconfigdebug.h b/src/egl/main/eglconfigdebug.h +new file mode 100644 +index 00000000000..562aefff9de +--- /dev/null ++++ b/src/egl/main/eglconfigdebug.h +@@ -0,0 +1,55 @@ ++/************************************************************************** ++ * Copyright 2017 Imagination Technologies. ++ * All Rights Reserved. ++ * ++ * 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 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 EGLCONFIGDEBUG_INCLUDED ++#define EGLCONFIGDEBUG_INCLUDED ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++#include "egltypedefs.h" ++ ++/** ++ * Config printout options. ++ */ ++enum EGL_CONFIG_DEBUG_OPTION { ++ EGL_CONFIG_DEBUG_CHOOSE, ++ EGL_CONFIG_DEBUG_GET, ++}; ++ ++/** ++ * Print the list of configs and the associated attributes. ++ */ ++void eglPrintConfigDebug(_EGLDisplay *const dpy, ++ EGLConfig *const configs, const EGLint numConfigs, ++ const enum EGL_CONFIG_DEBUG_OPTION printOption); ++ ++#ifdef __cplusplus ++} ++#endif ++ ++#endif /* EGLCONFIGDEBUG_INCLUDED */ +diff --git a/src/egl/main/egllog.c b/src/egl/main/egllog.c +index 973b7600ab1..7a9032f9bbb 100644 +--- a/src/egl/main/egllog.c ++++ b/src/egl/main/egllog.c +@@ -153,6 +153,15 @@ _eglInitLogger(void) + } + } + ++/** ++ * Return the log level. ++ */ ++EGLint ++_eglGetLogLevel(void) ++{ ++ return logging.level; ++} ++ + + /** + * Log a message with message logger. +diff --git a/src/egl/main/egllog.h b/src/egl/main/egllog.h +index 2a06a34684a..a1cf9770ed8 100644 +--- a/src/egl/main/egllog.h ++++ b/src/egl/main/egllog.h +@@ -44,6 +44,10 @@ extern "C" { + #define _EGL_DEBUG 3 /* useful info for debugging */ + + ++extern EGLint ++_eglGetLogLevel(void); ++ ++ + extern void + _eglLog(EGLint level, const char *fmtStr, ...); + +diff --git a/src/egl/meson.build b/src/egl/meson.build +index daa6a3a04f0..384bb98ebb3 100644 +--- a/src/egl/meson.build ++++ b/src/egl/meson.build +@@ -31,6 +31,8 @@ files_egl = files( + 'main/eglapi.c', + 'main/eglarray.c', + 'main/eglarray.h', ++ 'main/eglconfigdebug.c', ++ 'main/eglconfigdebug.h', + 'main/eglconfig.c', + 'main/eglconfig.h', + 'main/eglcontext.c', +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0038-egl-add-support-for-EXT_image_gl_colorspace.patch b/recipes-graphics/mesa/mesa-pvr/0038-egl-add-support-for-EXT_image_gl_colorspace.patch new file mode 100644 index 0000000..750fd0c --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0038-egl-add-support-for-EXT_image_gl_colorspace.patch @@ -0,0 +1,217 @@ +From d1d64a3c11fbab083d6225857554ac1c9ad645b6 Mon Sep 17 00:00:00 2001 +From: Frank Binns +Date: Tue, 29 Jan 2019 14:36:25 +0000 +Subject: [PATCH 38/67] egl: add support for EXT_image_gl_colorspace + +--- + src/egl/drivers/dri2/egl_dri2.c | 57 +++++++++++++++++++++++++++++++-- + src/egl/main/eglapi.c | 1 + + src/egl/main/egldisplay.h | 1 + + src/egl/main/eglimage.c | 14 ++++++++ + src/egl/main/eglimage.h | 3 ++ + 5 files changed, 74 insertions(+), 2 deletions(-) + +diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c +index 2f8414e0c60..6b26ff979ae 100644 +--- a/src/egl/drivers/dri2/egl_dri2.c ++++ b/src/egl/drivers/dri2/egl_dri2.c +@@ -1084,6 +1084,9 @@ dri2_setup_screen(_EGLDisplay *disp) + 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) +@@ -2724,6 +2727,11 @@ dri2_create_image_wayland_wl_buffer_tizen(_EGLDisplay *disp, _EGLContext *ctx, + return NULL; + } + ++ if (attrs.GLColorspace != EGL_GL_COLORSPACE_DEFAULT_EXT) { ++ _eglError(EGL_BAD_MATCH, "unsupported colorspace"); ++ return NULL; ++ } ++ + if (tbm_surface_get_info(tbm_surf, &info)) { + _eglError(EGL_BAD_PARAMETER, "tbm_surface_get_info"); + return NULL; +@@ -2799,6 +2807,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) { +@@ -2862,6 +2875,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) { +@@ -3007,6 +3025,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; +@@ -3189,6 +3212,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) +@@ -3334,6 +3374,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; +@@ -3359,6 +3400,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; +@@ -3403,7 +3456,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, +@@ -3415,7 +3468,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, +diff --git a/src/egl/main/eglapi.c b/src/egl/main/eglapi.c +index e4f2c43b4ef..2d3931dfd26 100644 +--- a/src/egl/main/eglapi.c ++++ b/src/egl/main/eglapi.c +@@ -508,6 +508,7 @@ _eglCreateExtensionsString(_EGLDisplay *disp) + _EGL_CHECK_EXTENSION(EXT_create_context_robustness); + _EGL_CHECK_EXTENSION(EXT_image_dma_buf_import); + _EGL_CHECK_EXTENSION(EXT_image_dma_buf_import_modifiers); ++ _EGL_CHECK_EXTENSION(EXT_image_gl_colorspace); + _EGL_CHECK_EXTENSION(EXT_protected_surface); + _EGL_CHECK_EXTENSION(EXT_surface_CTA861_3_metadata); + _EGL_CHECK_EXTENSION(EXT_surface_SMPTE2086_metadata); +diff --git a/src/egl/main/egldisplay.h b/src/egl/main/egldisplay.h +index 8489af9dde2..6e5b29fe1ac 100644 +--- a/src/egl/main/egldisplay.h ++++ b/src/egl/main/egldisplay.h +@@ -108,6 +108,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_surface; + EGLBoolean EXT_surface_CTA861_3_metadata; +diff --git a/src/egl/main/eglimage.c b/src/egl/main/eglimage.c +index 64bf7f2bfe9..73d4e85b82e 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; +@@ -285,6 +297,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 9837f05dad1..fc02d7a265c 100644 +--- a/src/egl/main/eglimage.h ++++ b/src/egl/main/eglimage.h +@@ -80,6 +80,9 @@ struct _egl_image_attribs + struct _egl_image_attrib_int DMABufChromaHorizontalSiting; + struct _egl_image_attrib_int DMABufChromaVerticalSiting; + ++ /* EGL_EXT_image_gl_colorspace */ ++ EGLint GLColorspace; ++ + /* EGL_EXT_protected_surface */ + EGLBoolean ProtectedContent; + }; +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0039-meson-force-C-2011-for-thread_local.patch b/recipes-graphics/mesa/mesa-pvr/0039-meson-force-C-2011-for-thread_local.patch new file mode 100644 index 0000000..07639ee --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0039-meson-force-C-2011-for-thread_local.patch @@ -0,0 +1,35 @@ +From c8a6405eaf4c9693f32381fa7aa6d292e7f95716 Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Mon, 24 Jun 2019 09:35:39 +0100 +Subject: [PATCH 39/67] meson: force C++ 2011 for "thread_local" + +For some combinations of Meson and the GNU C++ compiler, Meson does +not add '-std=c++11' to the command line arguments, resulting in +compilation errors, due to the use of the "thread_local" keyword (a +C++ 2011 feature). If the C++ compiler doesn't understand the +"thread_local" keyword by default, add '-std=c++11' to the compiler +command line arguments. +--- + meson.build | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/meson.build b/meson.build +index 2018562a1ec..21d93d372c2 100644 +--- a/meson.build ++++ b/meson.build +@@ -32,6 +32,12 @@ project( + 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' +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0040-dri2-add-support-for-swap-intervals-other-than-1.patch b/recipes-graphics/mesa/mesa-pvr/0040-dri2-add-support-for-swap-intervals-other-than-1.patch new file mode 100644 index 0000000..8bb3734 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0040-dri2-add-support-for-swap-intervals-other-than-1.patch @@ -0,0 +1,785 @@ +From dbb0d023abb9e4bfed70144514595f0477840f3e Mon Sep 17 00:00:00 2001 +From: Luigi Santivetti +Date: Wed, 19 Jun 2019 16:36:06 +0100 +Subject: [PATCH 40/67] dri2: add support for swap intervals other than 1 + +Before this change, the swap interval was fixed at 1, with page flips +scheduled on the next vblank. This change allows any swap interval +between 0 and 10 to be set. + +An additional thread is created, so as not to rely on the application +polling for previously scheduled drm events (be it a flip or a vblank). +Instead, each call to swap buffers made by the application will be +queued, and consumed asynchronously by the additional thread. This +ensures that drm events will be handled as soon as possible, +regardless of the timing of subsequent calls to swap buffers. + +Change-Id: If7c0495df7ddfaa08583a14f820c46e1b97da788 +Signed-off-by: Luigi Santivetti +--- + src/egl/drivers/dri2/egl_dri2.h | 34 +- + src/egl/drivers/dri2/platform_null.c | 541 +++++++++++++++++++++++---- + 2 files changed, 497 insertions(+), 78 deletions(-) + +diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h +index eb2127e3fe6..64d60ed66e4 100644 +--- a/src/egl/drivers/dri2/egl_dri2.h ++++ b/src/egl/drivers/dri2/egl_dri2.h +@@ -332,6 +332,23 @@ struct tpl_swap_queue_elem + }; + #endif + ++#ifdef HAVE_NULL_PLATFORM ++struct swap_queue_elem ++{ ++ uint32_t swap_interval; ++ uint32_t back_id; ++ uint32_t fb_id; ++}; ++ ++enum { ++ SWAP_IDLE, ++ SWAP_FLIP, ++ SWAP_VBLANK, ++ SWAP_POLL, ++ SWAP_ERROR, ++}; ++#endif ++ + struct dri2_egl_surface + { + _EGLSurface base; +@@ -370,13 +387,18 @@ struct dri2_egl_surface + #ifdef HAVE_TIZEN_PLATFORM + tpl_surface_t *tpl_surf; + bool reset; ++ struct tpl_swap_queue_elem swap_queue[DRI2_SURFACE_NUM_COLOR_BUFFERS]; ++#endif ++#if defined(HAVE_TIZEN_PLATFORM) || 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; +- struct tpl_swap_queue_elem swap_queue[DRI2_SURFACE_NUM_COLOR_BUFFERS]; ++#if defined(HAVE_NULL_PLATFORM) ++ pthread_cond_t swap_unlock_buffer_cond; ++#endif + int swap_queue_idx_head; + int swap_queue_idx_tail; + pthread_t swap_queue_processor; +@@ -412,7 +434,7 @@ struct dri2_egl_surface + #endif + bool locked; + int age; +- } color_buffers[4], *back, *current; ++ } color_buffers[DRI2_SURFACE_NUM_COLOR_BUFFERS], *back, *current; + #endif + + #ifdef HAVE_ANDROID_PLATFORM +@@ -442,7 +464,13 @@ struct dri2_egl_surface + #endif + + #ifdef HAVE_NULL_PLATFORM +- uint32_t front_fb_id; ++ uint32_t front_fb_id; ++ 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 cond_init_unlock_buffer; + #endif + + int out_fence_fd; +diff --git a/src/egl/drivers/dri2/platform_null.c b/src/egl/drivers/dri2/platform_null.c +index fb03ecc36fd..5b7c1ec426c 100644 +--- a/src/egl/drivers/dri2/platform_null.c ++++ b/src/egl/drivers/dri2/platform_null.c +@@ -31,6 +31,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -58,6 +59,17 @@ struct object_property { + 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, \ +@@ -176,36 +188,6 @@ property_id_get_for_name(drmModePropertyRes **prop_res, const char *prop_name) + return 0; + } + +-static void +-flip_handler(int fd, unsigned int sequence, unsigned int tv_sec, +- unsigned int tv_usec, void *user_data) +-{ +- bool *plocked = user_data; +- +- if (plocked) +- *plocked = false; +-} +- +-static bool +-flip_process(int fd) +-{ +- static drmEventContext evctx = +- {.version = 2, .page_flip_handler = flip_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) +- return false; +- +- drmHandleEvent(fd, &evctx); +- +- return true; +-} +- + static drmModePropertyRes ** + object_get_property_resources(int fd, uint32_t object_id, uint32_t object_type) + { +@@ -495,6 +477,113 @@ display_output_atomic_modeset(int fd, struct display_output *output, uint32_t fb + 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; ++ ++ 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 ++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 + display_output_init(int fd, struct display_output *output, bool use_atomic) + { +@@ -571,10 +660,46 @@ static int + display_output_flip(int fd, struct display_output *output, uint32_t fb_id, + uint32_t flags, void *flip_data) + { +- if (output->atomic_state) +- return display_output_atomic_flip(fd, output, fb_id, flags, 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; + +- return drmModePageFlip(fd, output->crtc_id, fb_id, flags, flip_data); ++ *current_vblank_out = vblank.reply.sequence; ++ ++ return 0; + } + + static int +@@ -587,6 +712,213 @@ display_output_modeset(int fd, struct display_output *output, uint32_t fb_id) + &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, 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, 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, &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); ++ 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) +@@ -651,15 +983,18 @@ get_back_bo(struct dri2_egl_surface *dri2_surf) + struct dri2_egl_display *dri2_dpy = + dri2_egl_display(dri2_surf->base.Resource.Display); + +- if (!dri2_surf->back) { ++ 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) +- return false; ++ pthread_cond_wait(&dri2_surf->swap_unlock_buffer_cond, &dri2_surf->mutex); + } + + if (!dri2_surf->back->dri_image) { +@@ -671,19 +1006,23 @@ get_back_bo(struct dri2_egl_surface *dri2_surf) + __DRI_IMAGE_USE_SCANOUT, + NULL); + if (!dri2_surf->back->dri_image) +- return false; ++ 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)) { +- return false; +- } ++ &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 _EGLSurface * +@@ -770,6 +1109,26 @@ dri2_null_create_window_surface(_EGLDisplay *disp, _EGLConfig *config, + 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; +@@ -783,6 +1142,14 @@ dri2_null_create_window_surface(_EGLDisplay *disp, _EGLConfig *config, + } + + 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; + +@@ -808,8 +1175,27 @@ dri2_null_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf) + /* If there's a current surface then a page flip has been performed, so make + * sure we process the flip event. + */ +- if (dri2_surf->current) +- flip_process(dri2_dpy->fd); ++ if (dri2_surf->swap_queue_processor) { ++ pthread_mutex_lock(&dri2_surf->mutex); ++ ++ /* Wait for any outstanding swaps to complete */ ++ 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); ++ 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) + dri2_dpy->image->destroyImage(dri2_surf->front); +@@ -837,9 +1223,7 @@ 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); +- bool *plocked = NULL; +- uint32_t flags; +- int err; ++ uint32_t back_id; + + if (dri2_surf->base.Type != EGL_WINDOW_BIT) + return EGL_TRUE; +@@ -858,34 +1242,13 @@ dri2_null_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw) + dri2_flush_drawable_for_swapbuffers(disp, draw); + dri2_dpy->flush->invalidate(dri2_surf->dri_drawable); + +- if (dri2_surf->current) { +- /* Wait for the previous flip to happen so the next one can be queued */ +- if (!flip_process(dri2_dpy->fd)) { +- _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_null_swap_buffers process"); +- return EGL_FALSE; +- } ++ back_id = get_back_buffer_id(dri2_surf); ++ assert(dri2_surf->back == &dri2_surf->color_buffers[back_id]); + +- plocked = &dri2_surf->current->locked; +- } +- +- flags = DRM_MODE_PAGE_FLIP_EVENT; +- if (draw->SwapInterval == 0) +- flags |= DRM_MODE_PAGE_FLIP_ASYNC; +- +- do { +- err = display_output_flip(dri2_dpy->fd, &dri2_dpy->output, +- dri2_surf->back->fb_id, flags, plocked); +- } while (err == -EBUSY); +- +- if (err) { +- _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_null_swap_buffers flip"); +- dri2_surf->back->locked = false; +- dri2_surf->back = NULL; +- return EGL_FALSE; +- } ++ 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->current = dri2_surf->back; + dri2_surf->back = NULL; + + return EGL_TRUE; +@@ -904,11 +1267,20 @@ dri2_null_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surface) + return dri2_surf->back->age; + } + ++static EGLBoolean ++dri2_null_swap_interval(_EGLDisplay *dpy, _EGLSurface *draw, EGLint interval) ++{ ++ _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, +@@ -1062,12 +1434,35 @@ dri2_null_add_configs_for_formats(_EGLDisplay *disp) + + 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, DRM_CAP_ASYNC_PAGE_FLIP, &value); ++ if (err || value == 0) ++ dri2_dpy->min_swap_interval = 1; ++ ++ /** ++ * drm/atomic: Reject FLIP_ASYNC unconditionally ++ * upstream f2cbda2dba11de868759cae9c0d2bab5b8411406 ++ * ++ * Only allow swap interval 0 for legacy DRM/KMS and let ++ * the app be aware that swap interval is clamped to 1. ++ */ ++ if (dri2_dpy->atomic_enabled) ++ dri2_dpy->min_swap_interval = 1; ++} + + EGLBoolean + dri2_initialize_null(_EGLDisplay *disp) + { + struct dri2_egl_display *dri2_dpy; +- uint64_t value; + int err; + + dri2_dpy = calloc(1, sizeof(*dri2_dpy)); +@@ -1114,11 +1509,7 @@ dri2_initialize_null(_EGLDisplay *disp) + } + + dri2_setup_screen(disp); +- dri2_setup_swap_interval(disp, 1); +- +- err = drmGetCap(dri2_dpy->fd, DRM_CAP_ASYNC_PAGE_FLIP, &value); +- if (err || value == 0) +- dri2_dpy->min_swap_interval = 1; ++ 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"); +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0041-null_platform-add-support-for-explicit-synchronisati.patch b/recipes-graphics/mesa/mesa-pvr/0041-null_platform-add-support-for-explicit-synchronisati.patch new file mode 100644 index 0000000..6a3b649 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0041-null_platform-add-support-for-explicit-synchronisati.patch @@ -0,0 +1,214 @@ +From d286d05d0d84c913c8bfcbe8f693083caf3bcc77 Mon Sep 17 00:00:00 2001 +From: Silvestrs Timofejevs +Date: Mon, 2 Sep 2019 09:32:01 +0100 +Subject: [PATCH 41/67] null_platform: add support for explicit synchronisation + +This change adds support for the 'in' fence, the 'out' fence will +potentially be added in subsequent optimisation changes. + +Explicit synchronisation KMS 'in' and 'out' properties have been first +added in Linux kernel 4.10 as an additional feature to the atomic mode +setting. + +9626014258a5957ff120b3987ee72decdbe0c798 - 'in' property +beaf5af48034c9e2ebb8b2b1fb12dc4d8aeba99e - 'out' property + +Unlike many other features - it doesn't have an in kernel capability +flag, so the support for it can be tested in the following way: +KMS creates an additional set of properties when the version of kernel +is new enough to support it ('in' and 'out' fence properties). When +the user-space requests all the properties from the kernel via +drmModeObjectGetProperties it is possible to determine whether the +required property is supported by the kernel or not. + +The explicit synchronisation is used when available, otherwise the +implicit sync model is used instead. If explicit synchronisation is +available but 'in' fence failed to attach in KMS, the system falls +back to the implicit synchronisation model. + +egl_dri2.c already creates the GPU 'out' fence that is then used by +the null_platform as KMS 'in' fence. null_platform takes owenership of +this fence fd during the swap buffers operation, at which point the +fence fd is no longer available to be used outside of null_platform. + +EGL_LOG_LEVEL=debug should give some useful information in case of +explicit synchronisation failure. As mentioned above, this failure +will result in implicit synchronisation being used instead. + +Change-Id: Ib9c4a0bc3ea1b21192ee37909d7580d6b7b366ec +--- + src/egl/drivers/dri2/egl_dri2.h | 2 + + src/egl/drivers/dri2/platform_null.c | 77 +++++++++++++++++++++++++++- + 2 files changed, 77 insertions(+), 2 deletions(-) + +diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h +index 64d60ed66e4..eb6e4551087 100644 +--- a/src/egl/drivers/dri2/egl_dri2.h ++++ b/src/egl/drivers/dri2/egl_dri2.h +@@ -106,6 +106,7 @@ 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; +@@ -338,6 +339,7 @@ struct swap_queue_elem + uint32_t swap_interval; + uint32_t back_id; + uint32_t fb_id; ++ int kms_in_fence_fd; + }; + + enum { +diff --git a/src/egl/drivers/dri2/platform_null.c b/src/egl/drivers/dri2/platform_null.c +index 5b7c1ec426c..d36dc0ced2a 100644 +--- a/src/egl/drivers/dri2/platform_null.c ++++ b/src/egl/drivers/dri2/platform_null.c +@@ -401,6 +401,9 @@ display_output_atomic_init(int fd, struct display_output *output) + 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; +@@ -418,6 +421,53 @@ err_free_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) +@@ -425,6 +475,8 @@ display_output_atomic_flip(int fd, struct display_output *output, uint32_t fb_id + 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 */ +@@ -435,13 +487,19 @@ display_output_atomic_flip(int fd, struct display_output *output, uint32_t fb_id + 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; + +- return drmModeAtomicCommit(fd, output->atomic_state, flags, flip_data); ++ err = drmModeAtomicCommit(fd, output->atomic_state, flags, flip_data); ++ ++ atomic_relinquish_in_fence_fd(dri2_surf, swap_data); ++ ++ return err; + } + + static int +@@ -489,6 +547,8 @@ swap_enqueue_data(struct dri2_egl_surface *dri2_surf, uint32_t back_id, + 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); + +@@ -1025,11 +1085,21 @@ err_unlock: + 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 _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; +@@ -1043,7 +1113,8 @@ create_surface(_EGLDisplay *disp, _EGLConfig *config, EGLint type, + } + surf = &dri2_surf->base; + +- if (!dri2_init_surface(surf, disp, type, config, attrib_list, false, NULL)) ++ 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, +@@ -1066,6 +1137,8 @@ create_surface(_EGLDisplay *disp, _EGLConfig *config, EGLint type, + + dri2_surf->format = dri2_null_formats[format_idx].dri_image_format; + ++ surface_swap_queue_init(dri2_surf); ++ + return surf; + + err_free_surface: +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0042-egl-null-add-support-for-DRM-image-format-modifiers.patch b/recipes-graphics/mesa/mesa-pvr/0042-egl-null-add-support-for-DRM-image-format-modifiers.patch new file mode 100644 index 0000000..fbd970c --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0042-egl-null-add-support-for-DRM-image-format-modifiers.patch @@ -0,0 +1,401 @@ +From 4f9ca104c16a6eb1af770e2447adb4413fb41cb7 Mon Sep 17 00:00:00 2001 +From: Luigi Santivetti +Date: Thu, 26 Sep 2019 13:32:15 +0100 +Subject: [PATCH 42/68] egl/null: add support for DRM image format modifiers + +This change introduces support for image modifiers to platform_null. In +order for it to create an image with modifiers, it relies on libdrm to +iterate all formats with associated modifiers supported by the display +for the primary drm plane in use. + +drmModeFormatModifierBlobIterNext() is added to the DRM api in a different +change and it is not upstream at present. + +Internal notes: + [1] IN_FORMATS blobs are available since kernel 4.14: + - db1689aa61bd1efb5ce9b896e7aa860a85b7f1b6 + - https://patchwork.freedesktop.org/patch/168543 + + [2] the dri image->base.version threshold is 14. + - Unlike for platform_wayland, where no details were found regarding + why it's using 15 + - dri_interface.h makes createImageWithModifiers available since + version 14 + - dri/gbm_dri.c as an example checks for minimum version 14. + +Change-Id: I0f7b030f6e1943690692674bf18daabfc153208a +Signed-off-by: Luigi Santivetti +--- + meson.build | 5 + + src/egl/drivers/dri2/egl_dri2.h | 3 + + src/egl/drivers/dri2/platform_null.c | 221 +++++++++++++++++++++++---- + 3 files changed, 203 insertions(+), 26 deletions(-) + +diff --git a/meson.build b/meson.build +index 21d93d372c2..ca89b8ac20d 100644 +--- a/meson.build ++++ b/meson.build +@@ -1581,6 +1581,11 @@ if with_gallium_etnaviv + _drm_ver = '2.4.89' + endif + ++# platform_null relies on DRM format-modifier iterators available since 2.4.108 ++if with_platform_null ++ _drm_ver = '2.4.108' ++endif ++ + # Loop over the enables versions and get the highest libdrm requirement for all + # active drivers. + _drm_blame = '' +diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h +index eb6e4551087..32ad720b343 100644 +--- a/src/egl/drivers/dri2/egl_dri2.h ++++ b/src/egl/drivers/dri2/egl_dri2.h +@@ -117,6 +117,8 @@ struct display_output { + uint32_t mode_blob_id; + unsigned formats; + drmModeAtomicReq *atomic_state; ++ uint32_t in_formats_id; ++ struct u_vector modifiers; + }; + #endif + +@@ -280,6 +282,7 @@ struct dri2_egl_display + + #ifdef HAVE_NULL_PLATFORM + bool atomic_enabled; ++ bool in_formats_enabled; + struct display_output output; + #endif + +diff --git a/src/egl/drivers/dri2/platform_null.c b/src/egl/drivers/dri2/platform_null.c +index d36dc0ced2a..2c79199da26 100644 +--- a/src/egl/drivers/dri2/platform_null.c ++++ b/src/egl/drivers/dri2/platform_null.c +@@ -40,6 +40,7 @@ + #include + #include + #include ++#include + #include + + #include "egl_dri2.h" +@@ -156,6 +157,18 @@ format_idx_get_from_drm_format(uint32_t drm_format) + 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, +@@ -645,7 +658,66 @@ drm_event_process(int fd) + } + + static bool +-display_output_init(int fd, struct display_output *output, bool use_atomic) ++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; +@@ -674,16 +746,34 @@ display_output_init(int fd, struct display_output *output, bool use_atomic) + goto err_free_plane; + output->mode = connector->modes[mode_idx]; + +- /* Record the display supported formats */ +- for (unsigned i = 0; i < plane->count_formats; i++) { +- int format_idx; ++ assert(in_formats_enabled_out && !(*in_formats_enabled_out)); + +- format_idx = format_idx_get_from_drm_format(plane->formats[i]); +- if (format_idx == -1) +- continue; ++ /* 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); + +- output->formats |= (1 << format_idx); ++ 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; + +@@ -983,10 +1073,12 @@ static bool + add_fb_for_dri_image(struct dri2_egl_display *dri2_dpy, __DRIimage *image, + uint32_t *fb_id_out) + { ++ uint64_t modifiers[4] = {0}; + uint32_t handles[4] = {0}; + uint32_t pitches[4] = {0}; + uint32_t offsets[4] = {0}; +- int handle, stride, width, height, format; ++ uint32_t flags = 0; ++ int handle, stride, width, height, format, l_mod, h_mod; + int format_idx; + + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HANDLE, &handle); +@@ -1001,9 +1093,47 @@ add_fb_for_dri_image(struct dri2_egl_display *dri2_dpy, __DRIimage *image, + format_idx = format_idx_get_from_dri_image_format(format); + assert(format_idx != -1); + +- return !drmModeAddFB2(dri2_dpy->fd, width, height, +- dri2_null_formats[format_idx].drm_format, +- handles, pitches, offsets, fb_id_out, 0); ++ 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); ++ ++ modifiers[0] = combine_u32_into_u64((uint32_t) h_mod, (uint32_t) l_mod); ++ flags |= DRM_MODE_FB_MODIFIERS; ++ } ++ ++ return !drmModeAddFB2WithModifiers(dri2_dpy->fd, 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 +@@ -1016,12 +1146,7 @@ get_front_bo(struct dri2_egl_surface *dri2_surf) + if (dri2_surf->base.Type == EGL_WINDOW_BIT) + use |= __DRI_IMAGE_USE_SCANOUT; + +- dri2_surf->front = dri2_dpy->image->createImage(dri2_dpy->dri_screen, +- dri2_surf->base.Width, +- dri2_surf->base.Height, +- dri2_surf->format, +- use, +- NULL); ++ dri2_surf->front = create_image(dri2_surf, use); + if (!dri2_surf->front) + return false; + +@@ -1058,13 +1183,8 @@ get_back_bo(struct dri2_egl_surface *dri2_surf) + } + + if (!dri2_surf->back->dri_image) { +- dri2_surf->back->dri_image = +- dri2_dpy->image->createImage(dri2_dpy->dri_screen, +- dri2_surf->base.Width, +- dri2_surf->base.Height, +- dri2_surf->format, +- __DRI_IMAGE_USE_SCANOUT, +- NULL); ++ dri2_surf->back->dri_image = create_image(dri2_surf, ++ __DRI_IMAGE_USE_SCANOUT); + if (!dri2_surf->back->dri_image) + goto err_unlock; + } +@@ -1094,6 +1214,30 @@ static void surface_swap_queue_init(struct dri2_egl_surface *dri2_surf) + 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) +@@ -1105,6 +1249,7 @@ create_surface(_EGLDisplay *disp, _EGLConfig *config, EGLint type, + const __DRIconfig *dri_config; + _EGLSurface *surf; + int format_idx; ++ bool ret; + + dri2_surf = calloc(1, sizeof(*dri2_surf)); + if (!dri2_surf) { +@@ -1137,6 +1282,15 @@ create_surface(_EGLDisplay *disp, _EGLConfig *config, EGLint type, + + 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, ++ 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; +@@ -1536,6 +1690,8 @@ 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)); +@@ -1589,8 +1745,19 @@ dri2_initialize_null(_EGLDisplay *disp) + 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, &dri2_dpy->output, +- dri2_dpy->atomic_enabled)) { ++ dri2_dpy->atomic_enabled, ++ prefer_in_formats, ++ &dri2_dpy->in_formats_enabled)) { + _eglError(EGL_NOT_INITIALIZED, "failed to create output"); + goto cleanup; + } +@@ -1640,4 +1807,6 @@ dri2_teardown_null(struct dri2_egl_display *dri2_dpy) + drmModeFreeProperty(dri2_dpy->output.connector_prop_res[i]); + free(dri2_dpy->output.connector_prop_res); + } ++ ++ u_vector_finish(&dri2_dpy->output.modifiers); + } +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0043-egl-query-the-supported-ES2-context-version.patch b/recipes-graphics/mesa/mesa-pvr/0043-egl-query-the-supported-ES2-context-version.patch new file mode 100644 index 0000000..6f2d9b4 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0043-egl-query-the-supported-ES2-context-version.patch @@ -0,0 +1,203 @@ +From 1e6466e541e1fc67198be3eeb090e3af22bd6d19 Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Mon, 10 Feb 2020 09:23:03 +0000 +Subject: [PATCH 43/67] egl: query the supported ES2 context version + +For OpenGL ES contexts, the EGL specification states that querying +EGL_CONTEXT_CLIENT_VERSION with eglQueryContext may return a version +that differs from that specified at context creation time. For example, +if an OpenGL ES2 context is specified at context creation time, an +OpenGL ES3 context may be created, and so "3" should be returned +when EGL_CONTEXT_CLIENT_VERSION is queried. + +A new EGL driver API function has been added, +QueryContextClientVersion, that is called when the context client +version is queried, allowing EGL drivers to override the default +value (i.e. the version specified at context creation time). If the +function returns zero, the default is used. + +For DRI drivers, QueryContextClientVersion returns zero for all API +contexts other than OpenGL ES2. For OpenGL ES2, the supported context +client version is queried via the Query Renderer driver extension, using +integer query __DRI2_RENDERER_OPENGL_ES2_CONTEXT_CLIENT_VERSION_IMG. If +the query isn't supported, or the query returns zero, zero is returned +to the caller. + +IMG NOTE: In order to avoid potential name and value clashes, "_IMG" +has been added to the end of the new query name, this should be removed +if an attempt is made to push this patch upstream. The value of the new +query should be adjusted to be the next one in sequence, rather than the +large value it currently has. +--- + include/GL/internal/dri_interface.h | 2 ++ + src/egl/drivers/dri2/egl_dri2.c | 21 +++++++++++++++++++++ + src/egl/drivers/haiku/egl_haiku.cpp | 9 +++++++++ + src/egl/main/eglapi.c | 2 +- + src/egl/main/eglcontext.c | 16 ++++++++++++++-- + src/egl/main/eglcontext.h | 3 ++- + src/egl/main/egldriver.h | 1 + + 7 files changed, 50 insertions(+), 4 deletions(-) + +diff --git a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h +index 6490f6e80e2..9c7bcac4cae 100644 +--- a/include/GL/internal/dri_interface.h ++++ b/include/GL/internal/dri_interface.h +@@ -2052,6 +2052,8 @@ typedef struct __DRIDriverVtableExtensionRec { + + #define __DRI2_RENDERER_HAS_PROTECTED_CONTENT 0x000e + ++#define __DRI2_RENDERER_OPENGL_ES2_CONTEXT_CLIENT_VERSION_IMG 0x7001 ++ + typedef struct __DRI2rendererQueryExtensionRec __DRI2rendererQueryExtension; + struct __DRI2rendererQueryExtensionRec { + __DRIextension base; +diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c +index 6b26ff979ae..c4a49cae592 100644 +--- a/src/egl/drivers/dri2/egl_dri2.c ++++ b/src/egl/drivers/dri2/egl_dri2.c +@@ -2055,6 +2055,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) + { +@@ -4336,6 +4356,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/haiku/egl_haiku.cpp b/src/egl/drivers/haiku/egl_haiku.cpp +index 18c73c9cd8b..2690a82eb75 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 2d3931dfd26..1cbff9656e4 100644 +--- a/src/egl/main/eglapi.c ++++ b/src/egl/main/eglapi.c +@@ -948,7 +948,7 @@ eglQueryContext(EGLDisplay dpy, EGLContext ctx, + + _EGL_CHECK_CONTEXT(disp, context, EGL_FALSE); + +- ret = _eglQueryContext(context, attribute, value); ++ ret = _eglQueryContext(disp, context, attribute, value); + + RETURN_EGL_EVAL(disp, ret); + } +diff --git a/src/egl/main/eglcontext.c b/src/egl/main/eglcontext.c +index 15de7c99496..7274d246194 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" +@@ -670,8 +671,19 @@ _eglQueryContextRenderBuffer(_EGLContext *ctx) + } + + ++static EGLint ++_eglQueryContextClientVersion(_EGLDisplay *disp, _EGLContext *ctx) ++{ ++ EGLint version; ++ ++ version = disp->Driver->QueryContextClientVersion(disp, ctx); ++ ++ return (version) ? version : ctx->ClientMajorVersion; ++} ++ + EGLBoolean +-_eglQueryContext(_EGLContext *c, EGLint attribute, EGLint *value) ++_eglQueryContext(_EGLDisplay *disp, _EGLContext *c, ++ EGLint attribute, EGLint *value) + { + if (!value) + return _eglError(EGL_BAD_PARAMETER, "eglQueryContext"); +@@ -688,7 +700,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(disp, c); + break; + case EGL_CONTEXT_CLIENT_TYPE: + *value = c->ClientAPI; +diff --git a/src/egl/main/eglcontext.h b/src/egl/main/eglcontext.h +index 06029e81251..d890217852d 100644 +--- a/src/egl/main/eglcontext.h ++++ b/src/egl/main/eglcontext.h +@@ -74,7 +74,8 @@ _eglInitContext(_EGLContext *ctx, _EGLDisplay *disp, + + + extern EGLBoolean +-_eglQueryContext(_EGLContext *ctx, EGLint attribute, EGLint *value); ++_eglQueryContext(_EGLDisplay *disp, _EGLContext *ctx, ++ EGLint attribute, EGLint *value); + + + extern EGLBoolean +diff --git a/src/egl/main/egldriver.h b/src/egl/main/egldriver.h +index 12f9a0aab86..92af8bd16d5 100644 +--- a/src/egl/main/egldriver.h ++++ b/src/egl/main/egldriver.h +@@ -97,6 +97,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, +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0044-meson-allow-libGL-to-be-built-without-GLX.patch b/recipes-graphics/mesa/mesa-pvr/0044-meson-allow-libGL-to-be-built-without-GLX.patch new file mode 100644 index 0000000..fc079b6 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0044-meson-allow-libGL-to-be-built-without-GLX.patch @@ -0,0 +1,144 @@ +From 64e6997ded5825f10125313ea15e3164bdad769b Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Thu, 11 Jun 2020 12:29:51 +0100 +Subject: [PATCH 44/67] meson: allow libGL to be built without GLX + +If Meson is run with option "glx" set to "null", build the +OpenGL library without GLX. + +The "eglBindAPI workaround for dEQP bug" change to eglcurrent.h +(commit 2d46c91040aeb8ebad486214159c34417fbc87db) has been +modified to use a new EGL_WITH_OPENGL define, which indicates +whether OpneGL is present or not. This allows EGL to be used +with OpenGL on platforms other than X11. +--- + meson.build | 8 ++++++-- + meson_options.txt | 2 +- + src/egl/main/eglcurrent.h | 7 +++---- + src/glx/meson.build | 20 ++++++++++++++++---- + src/meson.build | 2 +- + 5 files changed, 27 insertions(+), 12 deletions(-) + +diff --git a/meson.build b/meson.build +index 21d93d372c2..8db1699729a 100644 +--- a/meson.build ++++ b/meson.build +@@ -485,6 +485,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 ++ + # Android uses emutls for versions <= P/28. For USE_ELF_TLS we need ELF TLS. + use_elf_tls = false + if (not ['freebsd', 'openbsd', 'haiku'].contains(host_machine.system()) and +@@ -502,7 +506,7 @@ if (not ['freebsd', 'openbsd', 'haiku'].contains(host_machine.system()) and + 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 == 'gallium-xlib' +@@ -564,7 +568,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 +diff --git a/meson_options.txt b/meson_options.txt +index d90a25f97ff..d36e714ea4c 100644 +--- a/meson_options.txt ++++ b/meson_options.txt +@@ -290,7 +290,7 @@ option( + 'glx', + type : 'combo', + value : 'auto', +- choices : ['auto', 'disabled', 'dri', 'xlib', 'gallium-xlib'], ++ choices : ['auto', 'disabled', 'dri', 'xlib', 'gallium-xlib', 'null'], + description : 'Build support for GLX platform' + ) + option( +diff --git a/src/egl/main/eglcurrent.h b/src/egl/main/eglcurrent.h +index 32570970947..dcc418afd6f 100644 +--- a/src/egl/main/eglcurrent.h ++++ b/src/egl/main/eglcurrent.h +@@ -71,11 +71,10 @@ struct _egl_thread_info + static inline EGLBoolean + _eglIsApiValid(EGLenum api) + { +-#ifndef HAVE_X11_PLATFORM +- /* 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/glx/meson.build b/src/glx/meson.build +index 8f642d5e14b..605a9717e37 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, + ], +-) ++ ) ++ ++ 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/meson.build b/src/meson.build +index c3bab27718d..f6eede56648 100644 +--- a/src/meson.build ++++ b/src/meson.build +@@ -110,7 +110,7 @@ subdir('loader') + if with_platform_haiku + subdir('hgl') + endif +-if with_glx == 'dri' ++if with_glx == 'dri' or with_glx == 'null' + subdir('glx') + endif + if with_gbm +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0045-egl-wayland-process-non-resized-window-movement.patch b/recipes-graphics/mesa/mesa-pvr/0045-egl-wayland-process-non-resized-window-movement.patch new file mode 100644 index 0000000..a20ca77 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0045-egl-wayland-process-non-resized-window-movement.patch @@ -0,0 +1,38 @@ +From 394d340dda351452571ec8861d6768c52d338251 Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Tue, 25 Aug 2020 14:12:32 +0100 +Subject: [PATCH 45/67] egl/wayland: process non-resized window movement + +The dx and dy parameters to the wl_egl_window_resize function were +not being processed unless the window width or height were being +changed. +--- + src/egl/drivers/dri2/platform_wayland.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c +index 72456d5d748..06272d4081e 100644 +--- a/src/egl/drivers/dri2/platform_wayland.c ++++ b/src/egl/drivers/dri2/platform_wayland.c +@@ -266,6 +266,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; +@@ -786,8 +789,6 @@ update_buffers(struct dri2_egl_display *dri2_dpy, + + 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->wl_win && +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0046-Separate-EXT_framebuffer_object-from-ARB-version.patch b/recipes-graphics/mesa/mesa-pvr/0046-Separate-EXT_framebuffer_object-from-ARB-version.patch new file mode 100644 index 0000000..f0cfb1e --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0046-Separate-EXT_framebuffer_object-from-ARB-version.patch @@ -0,0 +1,539 @@ +From ed4671544a6add01e87e94c04df59a600403dd21 Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Mon, 10 Mar 2014 13:43:45 +0000 +Subject: [PATCH 46/67] Separate EXT_framebuffer_object from ARB version + +This patch separates the EXT_framebuffer_object entry points from the ARB +equivalents. + +Probably not all this separation is necessary; it looks like only + BindRenderbuffer + BindFramebuffer + GetFramebufferAttachmentParameteriv +take advantage of the split. + +Next time this patch is implemented, see if it can be trimmed down to +just the above functions, as it may be more upstreamable. + +We may need to implement the EXT restrictions if we want to upstream. +--- + src/mapi/glapi/gen/EXT_framebuffer_object.xml | 30 +++---- + src/mapi/glapi/gen/static_data.py | 15 ++++ + src/mesa/main/fbobject.c | 83 +++++++++++++++++++ + src/mesa/main/fbobject.h | 54 ++++++++++++ + src/mesa/main/genmipmap.c | 6 ++ + src/mesa/main/genmipmap.h | 3 + + 6 files changed, 176 insertions(+), 15 deletions(-) + +diff --git a/src/mapi/glapi/gen/EXT_framebuffer_object.xml b/src/mapi/glapi/gen/EXT_framebuffer_object.xml +index 6c0e54af1c9..957b6a3a632 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 @@ + + + +- ++ + + + + +- ++ + + + + +- ++ + + + + + + +- ++ + + + + + +- ++ + + + +@@ -115,22 +115,22 @@ + + + +- ++ + + + + +- ++ + + + + +- ++ + + + + +- ++ + + + +@@ -138,7 +138,7 @@ + + + +- ++ + + + +@@ -146,7 +146,7 @@ + + + +- ++ + + + +@@ -155,21 +155,21 @@ + + + +- ++ + + + + + + +- ++ + + + + + + +- ++ + + + +diff --git a/src/mapi/glapi/gen/static_data.py b/src/mapi/glapi/gen/static_data.py +index e231c176264..974f366d7b4 100644 +--- a/src/mapi/glapi/gen/static_data.py ++++ b/src/mapi/glapi/gen/static_data.py +@@ -1706,6 +1706,21 @@ offsets = { + "FramebufferTextureMultisampleMultiviewOVR" : 1670, + "MultiDrawArraysIndirectEXT" : 1671, + "MultiDrawElementsIndirectEXT" : 1672, ++ "IsRenderbufferEXT" : 1673, ++ "DeleteRenderbuffersEXT" : 1674, ++ "GenRenderbuffersEXT" : 1675, ++ "RenderbufferStorageEXT" : 1676, ++ "GetRenderbufferParameterivEXT" : 1677, ++ "IsFramebufferEXT" : 1678, ++ "DeleteFramebuffersEXT" : 1679, ++ "GenFramebuffersEXT" : 1680, ++ "CheckFramebufferStatusEXT" : 1681, ++ "FramebufferTexture1DEXT" : 1682, ++ "FramebufferTexture2DEXT" : 1683, ++ "FramebufferTexture3DEXT" : 1684, ++ "FramebufferRenderbufferEXT" : 1685, ++ "GetFramebufferAttachmentParameterivEXT" : 1686, ++ "GenerateMipmapEXT" : 1687, + } + + functions = [ +diff --git a/src/mesa/main/fbobject.c b/src/mesa/main/fbobject.c +index 49893165250..885aa442911 100644 +--- a/src/mesa/main/fbobject.c ++++ b/src/mesa/main/fbobject.c +@@ -1995,6 +1995,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) +@@ -2722,6 +2727,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) + { +@@ -2752,6 +2763,11 @@ _mesa_EGLImageTargetRenderbufferStorageOES(GLenum target, GLeglImageOES image) + ctx->Driver.EGLImageTargetRenderbufferStorage(ctx, rb, image); + } + ++void GLAPIENTRY ++_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers) ++{ ++ _mesa_GenRenderbuffers(n, renderbuffers); ++} + + /** + * Helper function for _mesa_GetRenderbufferParameteriv() and +@@ -2784,6 +2800,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, +@@ -2985,6 +3007,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, +@@ -3018,6 +3045,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 +@@ -3253,6 +3285,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. +@@ -3299,6 +3336,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) +@@ -3338,6 +3380,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) +@@ -3950,6 +3997,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, +@@ -3990,6 +4043,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, +@@ -4100,6 +4159,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, +@@ -4353,6 +4421,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, +@@ -4754,6 +4831,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/fbobject.h b/src/mesa/main/fbobject.h +index 2a32c158e68..98271d76f50 100644 +--- a/src/mesa/main/fbobject.h ++++ b/src/mesa/main/fbobject.h +@@ -145,6 +145,9 @@ _mesa_bind_framebuffers(struct gl_context *ctx, + extern GLboolean GLAPIENTRY + _mesa_IsRenderbuffer(GLuint renderbuffer); + ++extern GLboolean GLAPIENTRY ++_mesa_IsRenderbufferEXT(GLuint renderbuffer); ++ + extern void GLAPIENTRY + _mesa_BindRenderbuffer(GLenum target, GLuint renderbuffer); + +@@ -157,12 +160,18 @@ _mesa_DeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers); + void GLAPIENTRY + _mesa_GenRenderbuffers_no_error(GLsizei n, GLuint *renderbuffers); + ++extern void GLAPIENTRY ++_mesa_DeleteRenderbuffersEXT(GLsizei n, const GLuint *renderbuffers); ++ + extern void GLAPIENTRY + _mesa_GenRenderbuffers(GLsizei n, GLuint *renderbuffers); + + void GLAPIENTRY + _mesa_CreateRenderbuffers_no_error(GLsizei n, GLuint *renderbuffers); + ++extern void GLAPIENTRY ++_mesa_GenRenderbuffersEXT(GLsizei n, GLuint *renderbuffers); ++ + extern void GLAPIENTRY + _mesa_CreateRenderbuffers(GLsizei n, GLuint *renderbuffers); + +@@ -170,6 +179,10 @@ extern void GLAPIENTRY + _mesa_RenderbufferStorage(GLenum target, GLenum internalformat, + GLsizei width, GLsizei height); + ++extern void GLAPIENTRY ++_mesa_RenderbufferStorageEXT(GLenum target, GLenum internalformat, ++ GLsizei width, GLsizei height); ++ + extern void GLAPIENTRY + _mesa_RenderbufferStorageMultisample(GLenum target, GLsizei samples, + GLenum internalformat, +@@ -213,6 +226,10 @@ extern void GLAPIENTRY + _mesa_GetRenderbufferParameteriv(GLenum target, GLenum pname, + GLint *params); + ++extern void GLAPIENTRY ++_mesa_GetRenderbufferParameterivEXT(GLenum target, GLenum pname, ++ GLint *params); ++ + void GLAPIENTRY + _mesa_GetNamedRenderbufferParameteriv(GLuint renderbuffer, GLenum pname, + GLint *params); +@@ -220,6 +237,9 @@ _mesa_GetNamedRenderbufferParameteriv(GLuint renderbuffer, GLenum pname, + extern GLboolean GLAPIENTRY + _mesa_IsFramebuffer(GLuint framebuffer); + ++extern GLboolean GLAPIENTRY ++_mesa_IsFramebufferEXT(GLuint framebuffer); ++ + extern void GLAPIENTRY + _mesa_BindFramebuffer(GLenum target, GLuint framebuffer); + +@@ -229,9 +249,15 @@ _mesa_BindFramebufferEXT(GLenum target, GLuint framebuffer); + extern void GLAPIENTRY + _mesa_DeleteFramebuffers(GLsizei n, const GLuint *framebuffers); + ++extern void GLAPIENTRY ++_mesa_DeleteFramebuffersEXT(GLsizei n, const GLuint *framebuffers); ++ + extern void GLAPIENTRY + _mesa_GenFramebuffers(GLsizei n, GLuint *framebuffers); + ++extern void GLAPIENTRY ++_mesa_GenFramebuffersEXT(GLsizei n, GLuint *framebuffers); ++ + extern void GLAPIENTRY + _mesa_CreateFramebuffers(GLsizei n, GLuint *framebuffers); + +@@ -241,6 +267,9 @@ _mesa_CheckFramebufferStatus_no_error(GLenum target); + extern GLenum GLAPIENTRY + _mesa_CheckFramebufferStatus(GLenum target); + ++extern GLenum GLAPIENTRY ++_mesa_CheckFramebufferStatusEXT(GLenum target); ++ + extern GLenum GLAPIENTRY + _mesa_CheckNamedFramebufferStatus(GLuint framebuffer, GLenum target); + +@@ -259,6 +288,11 @@ extern void GLAPIENTRY + _mesa_FramebufferTexture2D_no_error(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, + GLint level); ++ ++extern void GLAPIENTRY ++_mesa_FramebufferTexture1DEXT(GLenum target, GLenum attachment, ++ GLenum textarget, GLuint texture, GLint level); ++ + extern void GLAPIENTRY + _mesa_FramebufferTexture2D(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, GLint level); +@@ -272,6 +306,11 @@ extern void GLAPIENTRY + _mesa_FramebufferTexture3D_no_error(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, + GLint level, GLint layer); ++ ++extern void GLAPIENTRY ++_mesa_FramebufferTexture2DEXT(GLenum target, GLenum attachment, ++ GLenum textarget, GLuint texture, GLint level); ++ + extern void GLAPIENTRY + _mesa_FramebufferTexture3D(GLenum target, GLenum attachment, + GLenum textarget, GLuint texture, +@@ -281,6 +320,12 @@ extern void GLAPIENTRY + _mesa_FramebufferTextureLayer_no_error(GLenum target, GLenum attachment, + GLuint texture, GLint level, + GLint layer); ++ ++extern void GLAPIENTRY ++_mesa_FramebufferTexture3DEXT(GLenum target, GLenum attachment, ++ GLenum textarget, GLuint texture, ++ GLint level, GLint zoffset); ++ + extern void GLAPIENTRY + _mesa_FramebufferTextureLayer(GLenum target, GLenum attachment, + GLuint texture, GLint level, GLint layer); +@@ -342,6 +387,11 @@ _mesa_NamedFramebufferRenderbuffer_no_error(GLuint framebuffer, + GLenum renderbuffertarget, + GLuint renderbuffer); + ++extern void GLAPIENTRY ++_mesa_FramebufferRenderbufferEXT(GLenum target, GLenum attachment, ++ GLenum renderbuffertarget, ++ GLuint renderbuffer); ++ + extern void GLAPIENTRY + _mesa_NamedFramebufferRenderbuffer(GLuint framebuffer, GLenum attachment, + GLenum renderbuffertarget, +@@ -390,6 +440,10 @@ _mesa_InvalidateSubFramebuffer_no_error(GLenum target, GLsizei numAttachments, + const GLenum *attachments, GLint x, + GLint y, GLsizei width, GLsizei height); + ++extern void GLAPIENTRY ++_mesa_GetFramebufferAttachmentParameterivEXT(GLenum target, GLenum attachment, ++ GLenum pname, GLint *params); ++ + extern void GLAPIENTRY + _mesa_InvalidateSubFramebuffer(GLenum target, GLsizei numAttachments, + const GLenum *attachments, GLint x, GLint y, +diff --git a/src/mesa/main/genmipmap.c b/src/mesa/main/genmipmap.c +index 36727bb7060..8d262e53852 100644 +--- a/src/mesa/main/genmipmap.c ++++ b/src/mesa/main/genmipmap.c +@@ -267,3 +267,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/genmipmap.h b/src/mesa/main/genmipmap.h +index c661f2184c7..ff3b45a4417 100644 +--- a/src/mesa/main/genmipmap.h ++++ b/src/mesa/main/genmipmap.h +@@ -44,6 +44,9 @@ _mesa_GenerateMipmap(GLenum target); + void GLAPIENTRY + _mesa_GenerateTextureMipmap_no_error(GLuint texture); + ++extern void GLAPIENTRY ++_mesa_GenerateMipmapEXT(GLenum target); ++ + extern void GLAPIENTRY + _mesa_GenerateTextureMipmap(GLuint texture); + +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0047-egl-null-add-support-for-async-flip-with-front-buffe.patch b/recipes-graphics/mesa/mesa-pvr/0047-egl-null-add-support-for-async-flip-with-front-buffe.patch new file mode 100644 index 0000000..58832ed --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0047-egl-null-add-support-for-async-flip-with-front-buffe.patch @@ -0,0 +1,321 @@ +From f775167cbe3f324468f8f355be13bd6efa7d4567 Mon Sep 17 00:00:00 2001 +From: Luigi Santivetti +Date: Mon, 21 Oct 2019 09:21:52 +0100 +Subject: [PATCH 47/67] egl/null: add support for async flip with front buffer + rendering + +This change enables the application to render into the buffer being +scanned out if the display driver doesn't support +DRM_CAP_ASYNC_PAGE_FLIP. + +The egl display now tracks the DRM async flip capabilities, allowing +platform_null to always return the buffer on screen to the application +when the swap interval is set to 0, but the DRM driver doesn't support +async flip. + +platform_null can be in several alternative states by the time +eglSwapInterval() is called, following is a summary of them. + + 1. platform_null was initialised and it has already flipped. In this + case, return to the client API a reference to the buffer on screen + + 2. platform_null was initialised but no back buffer was requested yet + from the client API. In this case, return a reference to the front + buffer + + 3. platform_null was initialised and the client API has already got + a back buffer, but no flip was scheduled. In this case, make sure + to flip and return the buffer on the screen + +Note that this change also refactors the color buffers and front +buffer code. Platform null after this change has a dedicated struct +for storing front buffer DRI data and framebuffer id. + +Also be noted that min_swap_interval is no longer clamped to 1 when +DRM_CAP_ASYNC_PAGE_FLIP isn't supported. This is because, +if min_swap_interval is automatically promoted to 1, Mesa EGL will de +facto prevent the application from requesting any swap interval less +than 1. + +Change-Id: I3930cfcdb30bfb5358166911bcf84a78bdb4548d +Signed-off-by: Luigi Santivetti +--- + src/egl/drivers/dri2/egl_dri2.h | 8 +- + src/egl/drivers/dri2/platform_null.c | 153 +++++++++++++++++++++------ + 2 files changed, 129 insertions(+), 32 deletions(-) + +diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h +index 0f683d76e18..13b808bff80 100644 +--- a/src/egl/drivers/dri2/egl_dri2.h ++++ b/src/egl/drivers/dri2/egl_dri2.h +@@ -282,6 +282,7 @@ struct dri2_egl_display + #ifdef HAVE_NULL_PLATFORM + bool atomic_enabled; + bool in_formats_enabled; ++ bool async_flip_enabled; + struct display_output output; + #endif + +@@ -442,8 +443,12 @@ struct dri2_egl_surface + #endif + bool locked; + int age; ++#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 + struct ANativeWindow *window; +@@ -472,12 +477,13 @@ struct dri2_egl_surface + #endif + + #ifdef HAVE_NULL_PLATFORM +- uint32_t front_fb_id; + 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 + +diff --git a/src/egl/drivers/dri2/platform_null.c b/src/egl/drivers/dri2/platform_null.c +index 48a586b6f38..33cf576f147 100644 +--- a/src/egl/drivers/dri2/platform_null.c ++++ b/src/egl/drivers/dri2/platform_null.c +@@ -601,6 +601,15 @@ swap_dequeue_data_finish(struct dri2_egl_surface *dri2_surf) + 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) +@@ -1118,15 +1127,15 @@ get_front_bo(struct dri2_egl_surface *dri2_surf) + if (dri2_surf->base.Type == EGL_WINDOW_BIT) + use |= __DRI_IMAGE_USE_SCANOUT; + +- dri2_surf->front = create_image(dri2_surf, use); +- if (!dri2_surf->front) ++ 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, +- &dri2_surf->front_fb_id)) { +- dri2_dpy->image->destroyImage(dri2_surf->front); +- dri2_surf->front = NULL; ++ 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; + } + } +@@ -1330,7 +1339,7 @@ dri2_null_create_window_surface(_EGLDisplay *disp, _EGLConfig *config, + } + + err = display_output_modeset(dri2_dpy->fd, &dri2_dpy->output, +- dri2_surf->front_fb_id); ++ dri2_surf->front_buffer.fb_id); + if (err) { + _eglError(EGL_BAD_NATIVE_WINDOW, "window set mode"); + goto err_destroy_surface; +@@ -1360,6 +1369,60 @@ dri2_null_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *config, + 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) + { +@@ -1371,14 +1434,7 @@ dri2_null_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf) + * sure we process the flip event. + */ + if (dri2_surf->swap_queue_processor) { +- pthread_mutex_lock(&dri2_surf->mutex); +- +- /* Wait for any outstanding swaps to complete */ +- 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); ++ swap_drain_queue_data(dri2_surf); + pthread_cancel(dri2_surf->swap_queue_processor); + pthread_join(dri2_surf->swap_queue_processor, NULL); + } +@@ -1392,11 +1448,11 @@ dri2_null_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf) + if (dri2_surf->mutex_init) + pthread_mutex_destroy(&dri2_surf->mutex); + +- if (dri2_surf->front) +- dri2_dpy->image->destroyImage(dri2_surf->front); ++ if (dri2_surf->front_buffer.dri_image) ++ dri2_dpy->image->destroyImage(dri2_surf->front_buffer.dri_image); + +- if (dri2_surf->front_fb_id) +- drmModeRmFB(dri2_dpy->fd, dri2_surf->front_fb_id); ++ if (dri2_surf->front_buffer.fb_id) ++ drmModeRmFB(dri2_dpy->fd, 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) +@@ -1423,6 +1479,16 @@ dri2_null_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw) + 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++; +@@ -1465,6 +1531,22 @@ dri2_null_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surface) + 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; +@@ -1502,7 +1584,7 @@ dri2_null_image_get_buffers(__DRIdrawable *driDrawable, unsigned int format, + + if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) { + buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT; +- buffers->front = dri2_surf->front; ++ buffers->front = dri2_surf->front_buffer.dri_image; + } + + if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) { +@@ -1640,18 +1722,27 @@ dri2_null_setup_swap_interval(_EGLDisplay *disp) + dri2_setup_swap_interval(disp, swap_max_interval); + + err = drmGetCap(dri2_dpy->fd, DRM_CAP_ASYNC_PAGE_FLIP, &value); +- if (err || value == 0) +- dri2_dpy->min_swap_interval = 1; ++ if (err || value == 0) { + +- /** +- * drm/atomic: Reject FLIP_ASYNC unconditionally +- * upstream f2cbda2dba11de868759cae9c0d2bab5b8411406 +- * +- * Only allow swap interval 0 for legacy DRM/KMS and let +- * the app be aware that swap interval is clamped to 1. +- */ +- if (dri2_dpy->atomic_enabled) +- dri2_dpy->min_swap_interval = 1; ++ /* 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 +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0048-gbm-add-pbuffer-support.patch b/recipes-graphics/mesa/mesa-pvr/0048-gbm-add-pbuffer-support.patch new file mode 100644 index 0000000..5dd9e69 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0048-gbm-add-pbuffer-support.patch @@ -0,0 +1,229 @@ +From 4d19dc5cc9be4f3f25ed8befbfcda70c047065d3 Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Fri, 21 Aug 2020 12:13:28 +0100 +Subject: [PATCH 48/67] gbm: add pbuffer support + +The EGL backend GLX provider for XWayland may get the EGL configs it +uses to generate the GLX ones from GBM. That platform doesn't support +pbuffers. When the client tries to match GLX configs with the DRI ones, +a mismatch in the pbuffer attributes will result in the GLX config +being rejected. + +Although support for creating pbuffers has been added, this isn't +required when using the EGL backend GLX provider, as indirect GLX +isn't supported. +--- + src/egl/drivers/dri2/egl_dri2.h | 3 + + src/egl/drivers/dri2/platform_drm.c | 110 +++++++++++++++++++++++++--- + 2 files changed, 103 insertions(+), 10 deletions(-) + +diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h +index 13b808bff80..141df1b1732 100644 +--- a/src/egl/drivers/dri2/egl_dri2.h ++++ b/src/egl/drivers/dri2/egl_dri2.h +@@ -471,6 +471,9 @@ 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; +diff --git a/src/egl/drivers/dri2/platform_drm.c b/src/egl/drivers/dri2/platform_drm.c +index 2b329437f88..258e8b6593e 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; +@@ -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, +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0049-egl-null-expose-EXT_yuv_surface-support.patch b/recipes-graphics/mesa/mesa-pvr/0049-egl-null-expose-EXT_yuv_surface-support.patch new file mode 100644 index 0000000..b8978cd --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0049-egl-null-expose-EXT_yuv_surface-support.patch @@ -0,0 +1,347 @@ +From b0ea3289c16d31d840af71876187cf30b2b32e9a Mon Sep 17 00:00:00 2001 +From: Luigi Santivetti +Date: Thu, 2 Sep 2021 22:47:54 +0100 +Subject: [PATCH 49/68] egl/null: expose EXT_yuv_surface support + +--- + include/GL/internal/dri_interface.h | 2 + + src/egl/drivers/dri2/platform_null.c | 177 ++++++++++++++++++++++++--- + src/mesa/drivers/dri/pvr/pvrutil.c | 8 ++ + 3 files changed, 173 insertions(+), 14 deletions(-) + +diff --git a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h +index 9c7bcac4cae..888a117d56e 100644 +--- a/include/GL/internal/dri_interface.h ++++ b/include/GL/internal/dri_interface.h +@@ -1411,6 +1411,8 @@ struct __DRIdri2ExtensionRec { + #define __DRI_IMAGE_FORMAT_ARGB4444 0x1018 + #define __DRI_IMAGE_FORMAT_YVU444_PACK10_IMG 0x1019 + #define __DRI_IMAGE_FORMAT_BGR888 0x101a ++#define __DRI_IMAGE_FORMAT_NV12 0x101b ++#define __DRI_IMAGE_FORMAT_NV21 0x101c + + #define __DRI_IMAGE_USE_SHARE 0x0001 + #define __DRI_IMAGE_USE_SCANOUT 0x0002 +diff --git a/src/egl/drivers/dri2/platform_null.c b/src/egl/drivers/dri2/platform_null.c +index f2c481c256b..d1e576af5ce 100644 +--- a/src/egl/drivers/dri2/platform_null.c ++++ b/src/egl/drivers/dri2/platform_null.c +@@ -79,6 +79,35 @@ uint32_t get_back_buffer_id(struct dri2_egl_surface *dri2_surf) + .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, ++ }, ++}; ++ + /* + * The index of entries in this table is used as a bitmask in + * dri2_dpy->formats, which tracks the formats supported by the display. +@@ -88,24 +117,49 @@ static const struct dri2_null_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], + }, + }; + +@@ -137,6 +191,36 @@ format_idx_get_from_config(struct dri2_egl_display *dri2_dpy, + 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) + { +@@ -1082,23 +1166,21 @@ static bool + add_fb_for_dri_image(struct dri2_egl_display *dri2_dpy, __DRIimage *image, + uint32_t *fb_id_out) + { +- uint64_t modifiers[4] = {0}; ++ 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 handle, stride, width, height, format, l_mod, h_mod; + int format_idx; ++ int num_planes; + +- dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HANDLE, &handle); +- dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride); + 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); + +- handles[0] = (uint32_t) handle; +- pitches[0] = (uint32_t) stride; +- + format_idx = format_idx_get_from_dri_image_format(format); + assert(format_idx != -1); + +@@ -1106,10 +1188,44 @@ add_fb_for_dri_image(struct dri2_egl_display *dri2_dpy, __DRIimage *image, + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_MODIFIER_UPPER, &h_mod); + dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_MODIFIER_LOWER, &l_mod); + +- modifiers[0] = combine_u32_into_u64((uint32_t) h_mod, (uint32_t) 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, width, height, + dri2_null_formats[format_idx].drm_format, + handles, pitches, offsets, modifiers, +@@ -1256,6 +1372,7 @@ create_surface(_EGLDisplay *disp, _EGLConfig *config, EGLint type, + 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; +@@ -1286,7 +1403,14 @@ create_surface(_EGLDisplay *disp, _EGLConfig *config, EGLint type, + goto err_free_surface; + } + +- format_idx = format_idx_get_from_config(dri2_dpy, dri_config); ++ 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; +@@ -1627,6 +1751,17 @@ dri2_null_image_get_buffers(__DRIdrawable *driDrawable, unsigned int format, + 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) + { +@@ -1635,10 +1770,11 @@ dri2_null_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate) + } + + static const __DRIimageLoaderExtension image_loader_extension = { +- .base = { __DRI_IMAGE_LOADER, 1 }, ++ .base = { __DRI_IMAGE_LOADER, 2 }, + + .getBuffers = dri2_null_image_get_buffers, + .flushFrontBuffer = dri2_null_flush_front_buffer, ++ .getCapability = dri2_null_get_capability, + }; + + static const __DRIextension *image_loader_extensions[] = { +@@ -1720,10 +1856,24 @@ dri2_null_add_configs_for_formats(_EGLDisplay *disp) + + 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; + +- format_idx = format_idx_get_from_config(dri2_dpy, +- dri2_dpy->driver_configs[i]); ++ 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; + +@@ -1735,8 +1885,7 @@ dri2_null_add_configs_for_formats(_EGLDisplay *disp) + + dri2_conf = dri2_add_config(disp, + dri2_dpy->driver_configs[i], count + 1, +- EGL_WINDOW_BIT | EGL_PBUFFER_BIT, +- NULL, NULL, NULL); ++ surface_type, NULL, NULL, NULL); + if (dri2_conf) + count++; + } +diff --git a/src/mesa/drivers/dri/pvr/pvrutil.c b/src/mesa/drivers/dri/pvr/pvrutil.c +index 945e18cf220..d107a5dafad 100644 +--- a/src/mesa/drivers/dri/pvr/pvrutil.c ++++ b/src/mesa/drivers/dri/pvr/pvrutil.c +@@ -174,6 +174,10 @@ PVRDRIFormatToFourCC(int dri_format) + return DRM_FORMAT_YVU444_PACK10_IMG; + case __DRI_IMAGE_FORMAT_BGR888: + return DRM_FORMAT_BGR888; ++ case __DRI_IMAGE_FORMAT_NV12: ++ return DRM_FORMAT_NV12; ++ case __DRI_IMAGE_FORMAT_NV21: ++ return DRM_FORMAT_NV21; + default: + __driUtilMessage("%s: Unknown format: %d", __func__, dri_format); + break; +@@ -230,6 +234,10 @@ PVRDRIFourCCToDRIFormat(int iFourCC) + return __DRI_IMAGE_FORMAT_YVU444_PACK10_IMG; + case DRM_FORMAT_BGR888: + return __DRI_IMAGE_FORMAT_BGR888; ++ case DRM_FORMAT_NV12: ++ return __DRI_IMAGE_FORMAT_NV12; ++ case DRM_FORMAT_NV21: ++ return __DRI_IMAGE_FORMAT_NV21; + default: + __driUtilMessage("%s: Unknown format: %d", __func__, iFourCC); + break; +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0050-dri-preserve-the-original-FD-for-driver-use.patch b/recipes-graphics/mesa/mesa-pvr/0050-dri-preserve-the-original-FD-for-driver-use.patch new file mode 100644 index 0000000..cbe368f --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0050-dri-preserve-the-original-FD-for-driver-use.patch @@ -0,0 +1,433 @@ +From db015d5fd0ded075e759677c047c581151bb1b52 Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Tue, 9 Mar 2021 17:15:30 +0000 +Subject: [PATCH 50/67] dri: preserve the original FD for driver use. + +If an application uses a different GPU from the default, allow the +file descriptor (FD) for that original GPU/display to be preserved +for use by drivers. Drivers may wish to use the original FD to +allocate shared surfaces, to ensure the surface properties are +compatible with the original GPU/display (e.g. for X11 or Wayland). + +This feature is only available on platforms that choose to support +it, by implementing the new getDisplayFD function in the DRI image, +and DRI2 loader extensions. + +If the feature is available, drivers can obtain the original FD +by calling the getDisplayFD function in the relevant loader extension. +Drivers should check the FD is valid before use (i.e. not -1). If +the FD is valid, it may be equal to the current GPU FD if a different +GPU is not being used. The FD is owned by the platform, not the +driver, and the platform is responsible for closing it. + +The feature is currently supported by the Wayland, and DRI3 based +X11 EGL and GLX platforms. +--- + include/GL/internal/dri_interface.h | 26 +++++++++++++++++-- + src/egl/drivers/dri2/egl_dri2.c | 10 +++++++ + src/egl/drivers/dri2/egl_dri2.h | 1 + + src/egl/drivers/dri2/platform_wayland.c | 31 ++++++++++++++++++++-- + src/egl/drivers/dri2/platform_x11.c | 3 +++ + src/egl/drivers/dri2/platform_x11_dri3.c | 27 ++++++++++++++++++- + src/glx/dri3_glx.c | 33 ++++++++++++++++++++++-- + src/glx/dri3_priv.h | 1 + + 8 files changed, 125 insertions(+), 7 deletions(-) + +diff --git a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h +index 888a117d56e..2fb440feb50 100644 +--- a/include/GL/internal/dri_interface.h ++++ b/include/GL/internal/dri_interface.h +@@ -1146,7 +1146,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, +@@ -1227,6 +1227,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); + }; + + /** +@@ -2131,7 +2142,7 @@ struct __DRIimageList { + }; + + #define __DRI_IMAGE_LOADER "DRI_IMAGE_LOADER" +-#define __DRI_IMAGE_LOADER_VERSION 4 ++#define __DRI_IMAGE_LOADER_VERSION 5 + + struct __DRIimageLoaderExtensionRec { + __DRIextension base; +@@ -2199,6 +2210,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/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c +index c4a49cae592..1df53ef011c 100644 +--- a/src/egl/drivers/dri2/egl_dri2.c ++++ b/src/egl/drivers/dri2/egl_dri2.c +@@ -1367,6 +1367,16 @@ dri2_display_destroy(_EGLDisplay *disp) + break; + } + ++ switch (disp->Platform) { ++ 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); + +diff --git a/src/egl/drivers/dri2/egl_dri2.h b/src/egl/drivers/dri2/egl_dri2.h +index 141df1b1732..af03caee623 100644 +--- a/src/egl/drivers/dri2/egl_dri2.h ++++ b/src/egl/drivers/dri2/egl_dri2.h +@@ -230,6 +230,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). */ +diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c +index 06272d4081e..b393e058770 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 +@@ -973,21 +974,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 +@@ -1640,12 +1652,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 (disp->PlatformDisplay == NULL) { + dri2_dpy->wl_dpy = wl_display_connect(NULL); +@@ -1690,8 +1704,20 @@ dri2_initialize_wayland_drm(_EGLDisplay *disp) + (roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated)) + 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"); +@@ -2236,6 +2262,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 (disp->PlatformDisplay == NULL) { + dri2_dpy->wl_dpy = wl_display_connect(NULL); +diff --git a/src/egl/drivers/dri2/platform_x11.c b/src/egl/drivers/dri2/platform_x11.c +index 5ffdf132184..5cf3ce2a369 100644 +--- a/src/egl/drivers/dri2/platform_x11.c ++++ b/src/egl/drivers/dri2/platform_x11.c +@@ -1277,6 +1277,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; + +@@ -1364,6 +1365,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; + +@@ -1472,6 +1474,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 e117105fcb6..0babf9f867e 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" +@@ -414,11 +415,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 +@@ -537,6 +548,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); +@@ -616,12 +628,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/glx/dri3_glx.c b/src/glx/dri3_glx.c +index db1b079663f..1ed6b60ffe8 100644 +--- a/src/glx/dri3_glx.c ++++ b/src/glx/dri3_glx.c +@@ -77,6 +77,7 @@ + #include "dri3_priv.h" + #include "loader.h" + #include "dri2.h" ++#include "util/os_file.h" + + static struct dri3_drawable * + loader_drawable_to_dri3_drawable(struct loader_dri3_drawable *draw) { +@@ -529,6 +530,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) + { +@@ -548,11 +557,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 = { +@@ -618,6 +628,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); + } +@@ -842,8 +856,9 @@ 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; + + psc = calloc(1, sizeof *psc); + if (psc == NULL) +@@ -851,6 +866,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); +@@ -871,12 +887,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) { + 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) { +@@ -1049,6 +1076,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 c0e833c16ef..b3dccf28c06 100644 +--- a/src/glx/dri3_priv.h ++++ b/src/glx/dri3_priv.h +@@ -107,6 +107,7 @@ struct dri3_screen { + + void *driver; + int fd; ++ int fd_dpy; + bool is_different_gpu; + + /* fd for display GPU in case of prime */ +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0051-egl-wayland-a-linear-buffer-is-not-needed-with-DRM-f.patch b/recipes-graphics/mesa/mesa-pvr/0051-egl-wayland-a-linear-buffer-is-not-needed-with-DRM-f.patch new file mode 100644 index 0000000..7f1d8d0 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0051-egl-wayland-a-linear-buffer-is-not-needed-with-DRM-f.patch @@ -0,0 +1,56 @@ +From 627ec429d684c57bdee45a21354009810fc03186 Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Wed, 28 Apr 2021 10:57:15 +0100 +Subject: [PATCH 51/67] egl/wayland: a linear buffer is not needed with DRM + format modifiers + +If the compositor supports DRM format modifiers, there is no +need for an additional linear buffer, as the client can allocate +buffers with attributes known to the compositor. +--- + src/egl/drivers/dri2/platform_wayland.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/src/egl/drivers/dri2/platform_wayland.c b/src/egl/drivers/dri2/platform_wayland.c +index b393e058770..60683fa6c1a 100644 +--- a/src/egl/drivers/dri2/platform_wayland.c ++++ b/src/egl/drivers/dri2/platform_wayland.c +@@ -695,7 +695,7 @@ get_back_bo(struct dri2_egl_surface *dri2_surf) + use_flags |= __DRI_IMAGE_USE_PROTECTED; + } + +- if (dri2_dpy->is_different_gpu && ++ if (dri2_dpy->is_different_gpu && !num_modifiers && + dri2_surf->back->linear_copy == NULL) { + /* The LINEAR modifier should be a perfect alias of the LINEAR use + * flag; try the new interface first before the old, then fall back. */ +@@ -811,7 +811,7 @@ update_buffers(struct dri2_egl_display *dri2_dpy, + dri2_surf->color_buffers[i].wl_buffer) { + 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; +@@ -1247,7 +1247,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; +@@ -1281,7 +1281,7 @@ dri2_wl_swap_buffers_with_damage(_EGLDisplay *disp, + + dri2_flush_drawable_for_swapbuffers(disp, draw); + +- 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, +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0052-dri3-a-linear-buffer-is-not-needed-with-DRM-format-m.patch b/recipes-graphics/mesa/mesa-pvr/0052-dri3-a-linear-buffer-is-not-needed-with-DRM-format-m.patch new file mode 100644 index 0000000..5585d62 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0052-dri3-a-linear-buffer-is-not-needed-with-DRM-format-m.patch @@ -0,0 +1,303 @@ +From e57b9a1b34a733f88af51b1395eebe647006939d Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Wed, 28 Apr 2021 16:33:42 +0100 +Subject: [PATCH 52/67] dri3: a linear buffer is not needed with DRM format + modifiers + +If the X Server supports DRM format modifiers, there is no need +for an additional linear buffer, as the client can allocate buffers +with attributes known to the Server. +--- + src/egl/drivers/dri2/platform_x11_dri3.c | 7 +- + src/glx/dri3_glx.c | 137 +++++++++++++++-------- + src/loader/loader_dri3_helper.c | 15 +++ + src/loader/loader_dri3_helper.h | 4 + + 4 files changed, 113 insertions(+), 50 deletions(-) + +diff --git a/src/egl/drivers/dri2/platform_x11_dri3.c b/src/egl/drivers/dri2/platform_x11_dri3.c +index 0babf9f867e..94205a495a6 100644 +--- a/src/egl/drivers/dri2/platform_x11_dri3.c ++++ b/src/egl/drivers/dri2/platform_x11_dri3.c +@@ -143,6 +143,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) { +@@ -150,6 +151,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; +@@ -174,7 +179,7 @@ dri3_create_surface(_EGLDisplay *disp, EGLint type, _EGLConfig *conf, + + if (loader_dri3_drawable_init(dri2_dpy->conn, drawable, + dri2_dpy->dri_screen, +- dri2_dpy->is_different_gpu, ++ is_incompat_gpu, + dri2_dpy->multibuffers_available, + dri_config, + &dri2_dpy->loader_dri3_ext, +diff --git a/src/glx/dri3_glx.c b/src/glx/dri3_glx.c +index 1ed6b60ffe8..025ad0128ec 100644 +--- a/src/glx/dri3_glx.c ++++ b/src/glx/dri3_glx.c +@@ -354,6 +354,21 @@ dri3_destroy_drawable(__GLXDRIdrawable *base) + free(pdraw); + } + ++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, struct glx_config *config_base) +@@ -361,11 +376,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) +@@ -376,14 +389,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), +@@ -737,13 +742,14 @@ static const struct glx_context_vtable dri3_context_vtable = { + .interop_export_object = dri3_interop_export_object + }; + +-/** 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; +@@ -774,16 +780,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 */ +@@ -817,6 +813,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) + { +@@ -859,6 +882,8 @@ dri3_create_screen(int screen, struct glx_display * priv) + 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) +@@ -890,8 +915,8 @@ dri3_create_screen(int screen, struct glx_display * priv) + 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; + } +@@ -933,27 +958,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, +@@ -965,7 +969,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"); +diff --git a/src/loader/loader_dri3_helper.c b/src/loader/loader_dri3_helper.c +index ff6d1ffc660..5c0379ab5de 100644 +--- a/src/loader/loader_dri3_helper.c ++++ b/src/loader/loader_dri3_helper.c +@@ -2288,3 +2288,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 028e25dc070..5790f5444f5 100644 +--- a/src/loader/loader_dri3_helper.h ++++ b/src/loader/loader_dri3_helper.h +@@ -287,4 +287,8 @@ loader_dri3_swapbuffer_barrier(struct loader_dri3_drawable *draw); + + void + loader_dri3_close_screen(__DRIscreen *dri_screen); ++ ++bool ++loader_dri3_has_modifiers(bool multiplanes_available, ++ const __DRIimageExtension *image); + #endif +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0053-egl-drm-add-support-for-DRI_PRIME-GPU-selection.patch b/recipes-graphics/mesa/mesa-pvr/0053-egl-drm-add-support-for-DRI_PRIME-GPU-selection.patch new file mode 100644 index 0000000..f097cd4 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0053-egl-drm-add-support-for-DRI_PRIME-GPU-selection.patch @@ -0,0 +1,267 @@ +From 8de0535741ce8d126da4d9b0b0eb8c46dd4810b5 Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Thu, 20 May 2021 14:43:29 +0100 +Subject: [PATCH 53/67] egl/drm: add support for DRI_PRIME GPU selection + +Add support for selecting the GPU to be used for rendering using +the DRI_PRIME environment variable. If a different GPU is selected, +a duplicate of the file descriptor for the original GPU/display is +preserved, which can be obtained by calling the getDisplayFD +function in the image loader extension. + +For server side Wayland, the ability to support PRIME is +determined by checking for the PRIME import and export +capabilities on the driver file descriptor, which may no +longer support them if a different GPU from the default has +been selected. It may be that the driver can still support +PRIME; for example, by making use of the original (default) +file descriptor. The driver can indicate it supports PRIME +via the getCapabilities function in the DRI Image extension. +--- + include/GL/internal/dri_interface.h | 2 ++ + src/egl/drivers/dri2/egl_dri2.c | 10 ++++++++ + src/egl/drivers/dri2/platform_drm.c | 19 ++++++++++----- + src/gbm/backends/dri/gbm_dri.c | 38 +++++++++++++++++++++++++---- + src/gbm/backends/dri/gbm_driint.h | 8 ++++++ + 5 files changed, 66 insertions(+), 11 deletions(-) + +diff --git a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h +index 2fb440feb50..080d191b0a3 100644 +--- a/include/GL/internal/dri_interface.h ++++ b/include/GL/internal/dri_interface.h +@@ -1548,6 +1548,8 @@ enum __DRIChromaSiting { + */ + /*@{*/ + #define __DRI_IMAGE_CAP_GLOBAL_NAMES 1 ++#define __DRI_IMAGE_CAP_PRIME_IMPORT 0x2000 ++#define __DRI_IMAGE_CAP_PRIME_EXPORT 0x4000 + /*@}*/ + + /** +diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c +index 1df53ef011c..ec4ac602a84 100644 +--- a/src/egl/drivers/dri2/egl_dri2.c ++++ b/src/egl/drivers/dri2/egl_dri2.c +@@ -1368,6 +1368,7 @@ dri2_display_destroy(_EGLDisplay *disp) + } + + switch (disp->Platform) { ++ case _EGL_PLATFORM_DRM: + case _EGL_PLATFORM_WAYLAND: + case _EGL_PLATFORM_X11: + if (dri2_dpy->fd_dpy >= 0 && dri2_dpy->fd_dpy != dri2_dpy->fd) +@@ -3943,6 +3944,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, +diff --git a/src/egl/drivers/dri2/platform_drm.c b/src/egl/drivers/dri2/platform_drm.c +index 258e8b6593e..f160ad1175e 100644 +--- a/src/egl/drivers/dri2/platform_drm.c ++++ b/src/egl/drivers/dri2/platform_drm.c +@@ -595,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 +@@ -782,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; +@@ -789,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; + } +@@ -810,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"; +@@ -872,7 +879,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/gbm/backends/dri/gbm_dri.c b/src/gbm/backends/dri/gbm_dri.c +index 5acb15b516f..c1586f42e46 100644 +--- a/src/gbm/backends/dri/gbm_dri.c ++++ b/src/gbm/backends/dri/gbm_dri.c +@@ -51,6 +51,7 @@ + #include "loader.h" + #include "util/debug.h" + #include "util/macros.h" ++#include "util/os_file.h" + + /* For importing wl_buffer */ + #if HAVE_WAYLAND_PLATFORM +@@ -141,6 +142,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, +@@ -220,20 +229,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 = { +@@ -398,12 +409,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); + } +@@ -470,8 +481,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; + +@@ -1424,6 +1447,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); + } + +@@ -1445,6 +1471,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; +diff --git a/src/gbm/backends/dri/gbm_driint.h b/src/gbm/backends/dri/gbm_driint.h +index 9e77ba5887c..e33a96edb0b 100644 +--- a/src/gbm/backends/dri/gbm_driint.h ++++ b/src/gbm/backends/dri/gbm_driint.h +@@ -61,6 +61,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 */ +@@ -191,4 +193,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 +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0054-egl-null-add-support-for-DRI_PRIME-GPU-selection.patch b/recipes-graphics/mesa/mesa-pvr/0054-egl-null-add-support-for-DRI_PRIME-GPU-selection.patch new file mode 100644 index 0000000..2c0d670 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0054-egl-null-add-support-for-DRI_PRIME-GPU-selection.patch @@ -0,0 +1,304 @@ +From f1f625dbcb4e0cc062369729b1da3d7fc65969e8 Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Thu, 20 May 2021 20:16:18 +0100 +Subject: [PATCH 54/67] egl/null: add support for DRI_PRIME GPU selection + +Add support for selecting the GPU to be used for rendering using +the DRI_PRIME environment variable. If a different GPU is selected, +a duplicate of the file descriptor for the original GPU/display is +preserved, which can be obtained by calling the getDisplayFD +function in the image loader extension. + +This change includes code, in function dri2_null_try_device, to +skip display devices that are not supported by the PVR driver. +This is to prevent failure on PC based test systems, that often +include display hardware that is incompatible with the driver. +This code would not be needed for systems that don't use the PVR +driver, or on production systems that use the PVR driver. +--- + src/egl/drivers/dri2/egl_dri2.c | 1 + + src/egl/drivers/dri2/platform_null.c | 133 +++++++++++++++++++-------- + 2 files changed, 98 insertions(+), 36 deletions(-) + +diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c +index ec4ac602a84..56b5175db6e 100644 +--- a/src/egl/drivers/dri2/egl_dri2.c ++++ b/src/egl/drivers/dri2/egl_dri2.c +@@ -1369,6 +1369,7 @@ dri2_display_destroy(_EGLDisplay *disp) + + 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) +diff --git a/src/egl/drivers/dri2/platform_null.c b/src/egl/drivers/dri2/platform_null.c +index db6f1147670..af77ea4dd89 100644 +--- a/src/egl/drivers/dri2/platform_null.c ++++ b/src/egl/drivers/dri2/platform_null.c +@@ -44,6 +44,7 @@ + + #include "egl_dri2.h" + #include "loader.h" ++#include "util/os_file.h" + + #define NULL_CARD_MINOR_MAX 63U + +@@ -953,7 +954,7 @@ swap_idle_get_target_frame(struct dri2_egl_surface *dri2_surf, + * 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, current_vblank_out); ++ err = display_get_vblank_sequence(dri2_dpy->fd_dpy, current_vblank_out); + if (err) + return err; + +@@ -1003,7 +1004,7 @@ swap_vblank_state_transition(struct dri2_egl_surface *dri2_surf, + uint32_t flags = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT; + int err; + +- err = display_request_vblank(dri2_dpy->fd, target_frame, ++ err = display_request_vblank(dri2_dpy->fd_dpy, target_frame, + flags, dri2_surf); + if (err) { + dri2_surf->swap_state = SWAP_ERROR; +@@ -1029,7 +1030,7 @@ swap_flip_state_transition(struct dri2_egl_surface *dri2_surf) + flags |= DRM_MODE_PAGE_FLIP_ASYNC; + } + +- err = display_output_flip(dri2_dpy->fd, &dri2_dpy->output, ++ 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; +@@ -1049,7 +1050,7 @@ swap_poll_state_transition(struct dri2_egl_surface *dri2_surf) + int err; + + /* dri2_surf->swap_state is being set inside the handler */ +- err = drm_event_process(dri2_dpy->fd); ++ err = drm_event_process(dri2_dpy->fd_dpy); + if (err) { + dri2_surf->swap_state = SWAP_ERROR; + return err; +@@ -1201,7 +1202,7 @@ add_fb_for_dri_image(struct dri2_egl_display *dri2_dpy, __DRIimage *image, + handles[i] = (uint32_t) handle; + } + +- return !drmModeAddFB2WithModifiers(dri2_dpy->fd, width, height, ++ return !drmModeAddFB2WithModifiers(dri2_dpy->fd_dpy, width, height, + dri2_null_formats[format_idx].drm_format, + handles, pitches, offsets, modifiers, + fb_id_out, flags); +@@ -1459,7 +1460,7 @@ dri2_null_create_window_surface(_EGLDisplay *disp, _EGLConfig *config, + goto err_destroy_surface; + } + +- err = display_output_modeset(dri2_dpy->fd, &dri2_dpy->output, ++ 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"); +@@ -1573,11 +1574,11 @@ dri2_null_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf) + dri2_dpy->image->destroyImage(dri2_surf->front_buffer.dri_image); + + if (dri2_surf->front_buffer.fb_id) +- drmModeRmFB(dri2_dpy->fd, 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, 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); + } +@@ -1734,12 +1735,22 @@ dri2_null_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate) + (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, 2 }, ++ .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[] = { +@@ -1768,12 +1779,74 @@ dri2_null_device_is_kms(int fd) + return is_kms; + } + ++static bool ++dri2_null_try_device(_EGLDisplay *disp) ++{ ++ struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); ++ ++ if (!dri2_null_device_is_kms(dri2_dpy->fd_dpy)) ++ return false; ++ ++#if 1 ++ /* Skip devices not supported by the pvr driver */ ++ { ++ char *driver_name = loader_get_driver_for_fd(dri2_dpy->fd_dpy); ++ bool skip = !driver_name || !!strcmp(driver_name, "pvr"); ++ ++ 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) + { + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); + + dri2_dpy->fd = -1; ++ dri2_dpy->fd_dpy = -1; + + for (unsigned i = 0; i <= NULL_CARD_MINOR_MAX; i++) { + char *card_path; +@@ -1781,32 +1854,20 @@ dri2_null_probe_device(_EGLDisplay *disp) + if (asprintf(&card_path, DRM_DEV_NAME, DRM_DIR_NAME, i) < 0) + continue; + +- dri2_dpy->fd = loader_open_device(card_path); ++ dri2_dpy->fd_dpy = loader_open_device(card_path); + free(card_path); +- if (dri2_dpy->fd < 0) ++ if (dri2_dpy->fd_dpy < 0) + continue; + +- if (dri2_null_device_is_kms(dri2_dpy->fd)) { +- dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd); +- if (dri2_dpy->driver_name) { +- 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; +- } +- } ++ 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); + +- close(dri2_dpy->fd); ++ dri2_dpy->fd_dpy = -1; + dri2_dpy->fd = -1; + } + +@@ -1867,7 +1928,7 @@ dri2_null_setup_swap_interval(_EGLDisplay *disp) + + dri2_setup_swap_interval(disp, swap_max_interval); + +- err = drmGetCap(dri2_dpy->fd, DRM_CAP_ASYNC_PAGE_FLIP, &value); ++ 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 +@@ -1914,7 +1975,7 @@ dri2_initialize_null(_EGLDisplay *disp) + * modesetting if not. If this succeeds then universal planes will also have + * been enabled. + */ +- err = drmSetClientCap(dri2_dpy->fd, DRM_CLIENT_CAP_ATOMIC, 1); ++ err = drmSetClientCap(dri2_dpy->fd_dpy, DRM_CLIENT_CAP_ATOMIC, 1); + dri2_dpy->atomic_enabled = !err; + + if (!dri2_dpy->atomic_enabled) { +@@ -1922,7 +1983,7 @@ dri2_initialize_null(_EGLDisplay *disp) + * Enable universal planes so that we can get the pixel formats for the + * primary plane + */ +- err = drmSetClientCap(dri2_dpy->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1); ++ 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; +@@ -1955,7 +2016,7 @@ dri2_initialize_null(_EGLDisplay *disp) + prefer_in_formats = dri2_dpy->image->base.version >= 14 && + dri2_dpy->image->createImageWithModifiers; + +- if (!display_output_init(dri2_dpy->fd, &dri2_dpy->output, ++ if (!display_output_init(dri2_dpy->fd_dpy, &dri2_dpy->output, + dri2_dpy->atomic_enabled, + prefer_in_formats, + &dri2_dpy->in_formats_enabled)) { +@@ -1990,7 +2051,7 @@ dri2_teardown_null(struct dri2_egl_display *dri2_dpy) + drmModeFreeFormats(dri2_dpy->output.in_formats); + + if (dri2_dpy->output.mode_blob_id) +- drmModeDestroyPropertyBlob(dri2_dpy->fd, 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++) +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0055-egl-null-introduce-NULL_DRM_DISPLAY.patch b/recipes-graphics/mesa/mesa-pvr/0055-egl-null-introduce-NULL_DRM_DISPLAY.patch new file mode 100644 index 0000000..a9fc930 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0055-egl-null-introduce-NULL_DRM_DISPLAY.patch @@ -0,0 +1,120 @@ +From 693fff6d87abfcae887afde7f80f402b7ff5c0ab Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Mon, 28 Jun 2021 16:36:15 +0100 +Subject: [PATCH 55/67] egl/null: introduce NULL_DRM_DISPLAY + +Introduce the NULL_DRM_DISPLAY environment variable, which allows +a particular DRM display to be selected, rather than the first +suitable DRM device found. + +To select a particular display, NULL_DRM_DISPLAY should be set to +the card number (i.e. minor number) of the DRM device representing +the display. For example, NULL_DRM_DISPLAY=2 will select +/dev/dri/card2. +--- + src/egl/drivers/dri2/platform_null.c | 65 ++++++++++++++++++++-------- + 1 file changed, 46 insertions(+), 19 deletions(-) + +diff --git a/src/egl/drivers/dri2/platform_null.c b/src/egl/drivers/dri2/platform_null.c +index af77ea4dd89..529cc7a2a2f 100644 +--- a/src/egl/drivers/dri2/platform_null.c ++++ b/src/egl/drivers/dri2/platform_null.c +@@ -1784,6 +1784,8 @@ 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; + +@@ -1841,34 +1843,56 @@ dri2_null_try_device(_EGLDisplay *disp) + } + + static bool +-dri2_null_probe_device(_EGLDisplay *disp) ++dri2_null_probe_device(_EGLDisplay *disp, unsigned minor) + { + struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); ++ char *card_path; + +- dri2_dpy->fd = -1; +- dri2_dpy->fd_dpy = -1; ++ if (asprintf(&card_path, DRM_DEV_NAME, DRM_DIR_NAME, minor) < 0) ++ goto cleanup; + +- for (unsigned i = 0; i <= NULL_CARD_MINOR_MAX; i++) { +- char *card_path; ++ dri2_dpy->fd_dpy = loader_open_device(card_path); ++ free(card_path); ++ if (dri2_dpy->fd_dpy < 0) ++ goto cleanup; + +- if (asprintf(&card_path, DRM_DEV_NAME, DRM_DIR_NAME, i) < 0) +- continue; ++ if (dri2_null_try_device(disp)) ++ return true; + +- dri2_dpy->fd_dpy = loader_open_device(card_path); +- free(card_path); +- if (dri2_dpy->fd_dpy < 0) +- continue; ++ close(dri2_dpy->fd_dpy); + +- if (dri2_null_try_device(disp)) +- return true; ++ if (dri2_dpy->fd >= 0 && dri2_dpy->fd != dri2_dpy->fd_dpy) ++ close(dri2_dpy->fd); + +- close(dri2_dpy->fd_dpy); ++cleanup: ++ dri2_dpy->fd_dpy = -1; ++ dri2_dpy->fd = -1; + +- if (dri2_dpy->fd >= 0 && dri2_dpy->fd != dri2_dpy->fd_dpy) +- close(dri2_dpy->fd); ++ 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); + +- dri2_dpy->fd_dpy = -1; +- dri2_dpy->fd = -1; ++ 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; +@@ -1965,7 +1989,10 @@ dri2_initialize_null(_EGLDisplay *disp) + + disp->DriverData = (void *) dri2_dpy; + +- if (!dri2_null_probe_device(disp)) { ++ 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; + } +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0056-vulkan-wsi-check-the-DRI3-and-Present-XCB-reply-poin.patch b/recipes-graphics/mesa/mesa-pvr/0056-vulkan-wsi-check-the-DRI3-and-Present-XCB-reply-poin.patch new file mode 100644 index 0000000..2481e92 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0056-vulkan-wsi-check-the-DRI3-and-Present-XCB-reply-poin.patch @@ -0,0 +1,37 @@ +From a422756b7d73b48d3d10d15066a61e9332370719 Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Mon, 21 Jun 2021 17:05:17 +0100 +Subject: [PATCH 56/67] vulkan/wsi: check the DRI3 and Present XCB reply + pointers + +Check that the DRI3 and Present version replies are not NULL +before accessing the version fields. +--- + src/vulkan/wsi/wsi_common_x11.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/src/vulkan/wsi/wsi_common_x11.c b/src/vulkan/wsi/wsi_common_x11.c +index 9dce78eddeb..9eb624df640 100644 +--- a/src/vulkan/wsi/wsi_common_x11.c ++++ b/src/vulkan/wsi/wsi_common_x11.c +@@ -216,7 +216,7 @@ wsi_x11_connection_create(struct wsi_device *wsi_dev, + + ver_cookie = xcb_dri3_query_version(conn, 1, 2); + ver_reply = xcb_dri3_query_version_reply(conn, ver_cookie, NULL); +- has_dri3_v1_2 = ++ has_dri3_v1_2 = ver_reply != NULL && + (ver_reply->major_version > 1 || ver_reply->minor_version >= 2); + free(ver_reply); + } +@@ -230,7 +230,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); + } +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0057-vulkan-wsi-Allow-host-visible-memory-to-be-requested.patch b/recipes-graphics/mesa/mesa-pvr/0057-vulkan-wsi-Allow-host-visible-memory-to-be-requested.patch new file mode 100644 index 0000000..a65524a --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0057-vulkan-wsi-Allow-host-visible-memory-to-be-requested.patch @@ -0,0 +1,143 @@ +From b900d4998b95a8bdfb01600f81635ff76810cfe6 Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Tue, 16 Feb 2021 20:17:32 +0000 +Subject: [PATCH 57/67] vulkan/wsi: Allow host visible memory to be requested + +Allow host visible memory to be explicitly requested when allocating +native images. + +For a software driver on X11, we need to be able to map the memory on +the host, in order to present the contents to the X Server. +--- + src/vulkan/wsi/wsi_common_display.c | 2 +- + src/vulkan/wsi/wsi_common_drm.c | 17 +++++++++++++---- + src/vulkan/wsi/wsi_common_private.h | 1 + + src/vulkan/wsi/wsi_common_wayland.c | 3 ++- + src/vulkan/wsi/wsi_common_x11.c | 1 + + 5 files changed, 18 insertions(+), 6 deletions(-) + +diff --git a/src/vulkan/wsi/wsi_common_display.c b/src/vulkan/wsi/wsi_common_display.c +index aa07cada107..71a84e54079 100644 +--- a/src/vulkan/wsi/wsi_common_display.c ++++ b/src/vulkan/wsi/wsi_common_display.c +@@ -1031,7 +1031,7 @@ wsi_display_image_init(VkDevice device_h, + return VK_ERROR_DEVICE_LOST; + + VkResult result = wsi_create_native_image(&chain->base, create_info, +- 0, NULL, NULL, ++ 0, NULL, NULL, false, + &image->base); + if (result != VK_SUCCESS) + return result; +diff --git a/src/vulkan/wsi/wsi_common_drm.c b/src/vulkan/wsi/wsi_common_drm.c +index 70d934aef13..aabb761908c 100644 +--- a/src/vulkan/wsi/wsi_common_drm.c ++++ b/src/vulkan/wsi/wsi_common_drm.c +@@ -66,6 +66,7 @@ wsi_device_matches_drm_fd(const struct wsi_device *wsi, int drm_fd) + static uint32_t + select_memory_type(const struct wsi_device *wsi, + bool want_device_local, ++ bool want_host_visible, + uint32_t type_bits) + { + assert(type_bits); +@@ -74,8 +75,10 @@ select_memory_type(const struct wsi_device *wsi, + for (uint32_t i = 0; i < wsi->memory_props.memoryTypeCount; i++) { + const VkMemoryType type = wsi->memory_props.memoryTypes[i]; + bool local = type.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; ++ bool host = type.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT; + +- if ((type_bits & (1 << i)) && local == want_device_local) ++ if ((type_bits & (1 << i)) && local == want_device_local && ++ (!want_host_visible || host)) + return i; + all_local &= local; + } +@@ -83,6 +86,8 @@ select_memory_type(const struct wsi_device *wsi, + /* ignore want_device_local when all memory types are device-local */ + if (all_local) { + assert(!want_device_local); ++ /* currently, host visibility is only needed with device local */ ++ assert(!want_host_visible); + return ffs(type_bits) - 1; + } + +@@ -107,6 +112,7 @@ wsi_create_native_image(const struct wsi_swapchain *chain, + uint32_t num_modifier_lists, + const uint32_t *num_modifiers, + const uint64_t *const *modifiers, ++ bool host_visible, + struct wsi_image *image) + { + const struct wsi_device *wsi = chain->wsi; +@@ -317,7 +323,8 @@ wsi_create_native_image(const struct wsi_swapchain *chain, + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = &memory_dedicated_info, + .allocationSize = reqs.size, +- .memoryTypeIndex = select_memory_type(wsi, true, reqs.memoryTypeBits), ++ .memoryTypeIndex = select_memory_type(wsi, true, host_visible, ++ reqs.memoryTypeBits), + }; + result = wsi->AllocateMemory(chain->device, &memory_info, + &chain->alloc, &image->memory); +@@ -488,7 +495,8 @@ wsi_create_prime_image(const struct wsi_swapchain *chain, + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = &prime_memory_dedicated_info, + .allocationSize = linear_size, +- .memoryTypeIndex = select_memory_type(wsi, false, reqs.memoryTypeBits), ++ .memoryTypeIndex = select_memory_type(wsi, false, false, ++ reqs.memoryTypeBits), + }; + result = wsi->AllocateMemory(chain->device, &prime_memory_info, + &chain->alloc, &image->prime.memory); +@@ -542,7 +550,8 @@ wsi_create_prime_image(const struct wsi_swapchain *chain, + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = &memory_dedicated_info, + .allocationSize = reqs.size, +- .memoryTypeIndex = select_memory_type(wsi, true, reqs.memoryTypeBits), ++ .memoryTypeIndex = select_memory_type(wsi, true, false, ++ reqs.memoryTypeBits), + }; + result = wsi->AllocateMemory(chain->device, &memory_info, + &chain->alloc, &image->memory); +diff --git a/src/vulkan/wsi/wsi_common_private.h b/src/vulkan/wsi/wsi_common_private.h +index 1fe8211f9cb..5ad087b32e0 100644 +--- a/src/vulkan/wsi/wsi_common_private.h ++++ b/src/vulkan/wsi/wsi_common_private.h +@@ -94,6 +94,7 @@ wsi_create_native_image(const struct wsi_swapchain *chain, + uint32_t num_modifier_lists, + const uint32_t *num_modifiers, + const uint64_t *const *modifiers, ++ bool host_visible, + struct wsi_image *image); + + VkResult +diff --git a/src/vulkan/wsi/wsi_common_wayland.c b/src/vulkan/wsi/wsi_common_wayland.c +index 40f5338314f..983833e880b 100644 +--- a/src/vulkan/wsi/wsi_common_wayland.c ++++ b/src/vulkan/wsi/wsi_common_wayland.c +@@ -1074,7 +1074,8 @@ wsi_wl_image_init(struct wsi_wl_swapchain *chain, + result = wsi_create_native_image(&chain->base, pCreateInfo, + chain->num_drm_modifiers > 0 ? 1 : 0, + &chain->num_drm_modifiers, +- &chain->drm_modifiers, &image->base); ++ &chain->drm_modifiers, false, ++ &image->base); + + if (result != VK_SUCCESS) + return result; +diff --git a/src/vulkan/wsi/wsi_common_x11.c b/src/vulkan/wsi/wsi_common_x11.c +index 9eb624df640..eb639d6c265 100644 +--- a/src/vulkan/wsi/wsi_common_x11.c ++++ b/src/vulkan/wsi/wsi_common_x11.c +@@ -1315,6 +1315,7 @@ x11_image_init(VkDevice device_h, struct x11_swapchain *chain, + } else { + result = wsi_create_native_image(&chain->base, pCreateInfo, + num_tranches, num_modifiers, modifiers, ++ chain->base.wsi->sw, + &image->base); + } + if (result < 0) +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0058-vulkan-wsi-make-the-display-FD-available.patch b/recipes-graphics/mesa/mesa-pvr/0058-vulkan-wsi-make-the-display-FD-available.patch new file mode 100644 index 0000000..484e14b --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0058-vulkan-wsi-make-the-display-FD-available.patch @@ -0,0 +1,419 @@ +From afcfb076e89365ff1f33c658a6a615d2108d97f5 Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Thu, 17 Jun 2021 17:17:07 +0100 +Subject: [PATCH 58/67] vulkan/wsi: make the display FD available + +Pass the display FD to the Vulkan image create and memory +allocation functions when allocating swapchain images. +--- + src/vulkan/wsi/wsi_common.h | 14 +++ + src/vulkan/wsi/wsi_common_display.c | 2 +- + src/vulkan/wsi/wsi_common_drm.c | 22 ++++- + src/vulkan/wsi/wsi_common_private.h | 2 + + src/vulkan/wsi/wsi_common_wayland.c | 127 ++++++++++++++++++++++------ + src/vulkan/wsi/wsi_common_x11.c | 42 ++++++--- + 6 files changed, 169 insertions(+), 40 deletions(-) + +diff --git a/src/vulkan/wsi/wsi_common.h b/src/vulkan/wsi/wsi_common.h +index d5367db3a94..c2563c677e6 100644 +--- a/src/vulkan/wsi/wsi_common.h ++++ b/src/vulkan/wsi/wsi_common.h +@@ -37,6 +37,8 @@ + #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 +@@ -75,6 +77,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_fence { + VkDevice device; + const struct wsi_device *wsi_device; +diff --git a/src/vulkan/wsi/wsi_common_display.c b/src/vulkan/wsi/wsi_common_display.c +index 71a84e54079..f135b4e38de 100644 +--- a/src/vulkan/wsi/wsi_common_display.c ++++ b/src/vulkan/wsi/wsi_common_display.c +@@ -1032,7 +1032,7 @@ wsi_display_image_init(VkDevice device_h, + + VkResult result = wsi_create_native_image(&chain->base, create_info, + 0, NULL, NULL, false, +- &image->base); ++ wsi->fd, &image->base); + if (result != VK_SUCCESS) + return result; + +diff --git a/src/vulkan/wsi/wsi_common_drm.c b/src/vulkan/wsi/wsi_common_drm.c +index aabb761908c..6201891ca80 100644 +--- a/src/vulkan/wsi/wsi_common_drm.c ++++ b/src/vulkan/wsi/wsi_common_drm.c +@@ -113,6 +113,7 @@ wsi_create_native_image(const struct wsi_swapchain *chain, + const uint32_t *num_modifiers, + const uint64_t *const *modifiers, + bool host_visible, ++ int display_fd, + struct wsi_image *image) + { + const struct wsi_device *wsi = chain->wsi; +@@ -170,6 +171,12 @@ wsi_create_native_image(const struct wsi_swapchain *chain, + __vk_append_struct(&image_info, &image_format_list); + } + ++ struct wsi_image_create_info2 image_wsi_info2 = { ++ .sType = VK_STRUCTURE_TYPE_WSI_IMAGE_CREATE_INFO2_MESA, ++ .display_fd = display_fd, ++ }; ++ __vk_append_struct(&image_info, &image_wsi_info2); ++ + VkImageDrmFormatModifierListCreateInfoEXT image_modifier_list; + + uint32_t image_modifier_count = 0, modifier_prop_count = 0; +@@ -308,9 +315,14 @@ wsi_create_native_image(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 = { +@@ -440,6 +452,7 @@ VkResult + wsi_create_prime_image(const struct wsi_swapchain *chain, + const VkSwapchainCreateInfoKHR *pCreateInfo, + bool use_modifier, ++ int display_fd, + struct wsi_image *image) + { + const struct wsi_device *wsi = chain->wsi; +@@ -480,9 +493,14 @@ wsi_create_prime_image(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 prime_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 prime_memory_dedicated_info = { +diff --git a/src/vulkan/wsi/wsi_common_private.h b/src/vulkan/wsi/wsi_common_private.h +index 5ad087b32e0..e46328156dc 100644 +--- a/src/vulkan/wsi/wsi_common_private.h ++++ b/src/vulkan/wsi/wsi_common_private.h +@@ -95,12 +95,14 @@ wsi_create_native_image(const struct wsi_swapchain *chain, + const uint32_t *num_modifiers, + const uint64_t *const *modifiers, + bool host_visible, ++ int display_fd, + struct wsi_image *image); + + VkResult + wsi_create_prime_image(const struct wsi_swapchain *chain, + const VkSwapchainCreateInfoKHR *pCreateInfo, + bool use_modifier, ++ int display_fd, + struct wsi_image *image); + + void +diff --git a/src/vulkan/wsi/wsi_common_wayland.c b/src/vulkan/wsi/wsi_common_wayland.c +index 983833e880b..1109d3f07b6 100644 +--- a/src/vulkan/wsi/wsi_common_wayland.c ++++ b/src/vulkan/wsi/wsi_common_wayland.c +@@ -32,6 +32,8 @@ + #include + #include + #include ++#include ++#include + + #include "drm-uapi/drm_fourcc.h" + +@@ -82,6 +84,9 @@ struct wsi_wl_display { + + struct wsi_wayland *wsi_wl; + ++ int fd; ++ bool authenticated; ++ + /* Points to formats in wsi_wl_display_drm or wsi_wl_display_dmabuf */ + struct u_vector * formats; + +@@ -261,10 +266,52 @@ wsi_wl_display_add_wl_shm_format(struct wsi_wl_display *display, + } + } + ++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 uint32_t +@@ -346,6 +393,9 @@ 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 +@@ -487,6 +537,9 @@ wsi_wl_display_finish(struct wsi_wl_display *display) + 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 +@@ -501,6 +554,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; + + if (get_format_list) { + if (!u_vector_init(&display->swrast.formats, sizeof(VkFormat), 8) || +@@ -542,41 +596,60 @@ wsi_wl_display_init(struct wsi_wayland *wsi_wl, + /* Round-trip to get wl_drms and zwp_linux_dmabuf_v1 globals */ + wl_display_roundtrip_queue(display->wl_display, display->queue); + ++ if (!display->drm.wl_drm && !display->dmabuf.wl_dmabuf && !display->swrast.wl_shm) { ++ result = VK_ERROR_SURFACE_LOST_KHR; ++ goto fail_registry; ++ } ++ + /* Round-trip again to get formats, modifiers and capabilities */ +- if (display->drm.wl_drm || display->dmabuf.wl_dmabuf || display->swrast.wl_shm) +- wl_display_roundtrip_queue(display->wl_display, display->queue); ++ wl_display_roundtrip_queue(display->wl_display, display->queue); + +- 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. +- */ +- VkFormat *first_fmt = u_vector_head(display->formats); +- VkFormat *iter_fmt; +- u_vector_foreach(iter_fmt, display->formats) { +- if (*iter_fmt == VK_FORMAT_B8G8R8A8_UNORM) { +- *iter_fmt = *first_fmt; +- *first_fmt = VK_FORMAT_B8G8R8A8_UNORM; +- break; +- } +- } ++ if (display->fd == -1) { ++ result = VK_ERROR_SURFACE_LOST_KHR; ++ goto fail_registry; + } + +- /* Prefer the linux-dmabuf protocol if available */ +- if (display->sw) +- display->formats = &display->swrast.formats; +- else if (display->dmabuf.wl_dmabuf) { +- display->formats = &display->dmabuf.formats; +- } else if (display->drm.wl_drm && +- (display->drm.capabilities & WL_DRM_CAPABILITY_PRIME)) { +- /* We need prime support for wl_drm */ +- display->formats = &display->drm.formats; +- } ++ wl_display_roundtrip_queue(display->wl_display, display->queue); + +- if (!display->formats) { ++ if (!display->authenticated) { + result = VK_ERROR_SURFACE_LOST_KHR; + goto fail_registry; + } + ++ if (get_format_list) { ++ /* Prefer the linux-dmabuf protocol if available */ ++ if (display->sw) ++ display->formats = &display->swrast.formats; ++ else if(display->dmabuf.wl_dmabuf && ++ u_vector_length(&display->dmabuf.formats)) { ++ display->formats = &display->dmabuf.formats; ++ } else if (display->drm.wl_drm && ++ display->drm.capabilities & WL_DRM_CAPABILITY_PRIME) { ++ display->formats = &display->drm.formats; ++ } ++ ++ if (!display->formats) { ++ result = VK_ERROR_SURFACE_LOST_KHR; ++ goto fail_registry; ++ } ++ ++ 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. ++ */ ++ VkFormat *first_fmt = u_vector_tail(display->formats); ++ VkFormat *iter_fmt; ++ u_vector_foreach(iter_fmt, display->formats) { ++ if (*iter_fmt == VK_FORMAT_B8G8R8A8_UNORM) { ++ *iter_fmt = *first_fmt; ++ *first_fmt = VK_FORMAT_B8G8R8A8_UNORM; ++ break; ++ } ++ } ++ } ++ } ++ + /* We don't need this anymore */ + wl_registry_destroy(registry); + +@@ -1075,7 +1148,7 @@ wsi_wl_image_init(struct wsi_wl_swapchain *chain, + chain->num_drm_modifiers > 0 ? 1 : 0, + &chain->num_drm_modifiers, + &chain->drm_modifiers, false, +- &image->base); ++ display->fd, &image->base); + + if (result != VK_SUCCESS) + return result; +diff --git a/src/vulkan/wsi/wsi_common_x11.c b/src/vulkan/wsi/wsi_common_x11.c +index eb639d6c265..ba64e260932 100644 +--- a/src/vulkan/wsi/wsi_common_x11.c ++++ b/src/vulkan/wsi/wsi_common_x11.c +@@ -1303,7 +1303,8 @@ x11_image_init(VkDevice device_h, struct x11_swapchain *chain, + const VkAllocationCallbacks* pAllocator, + const uint64_t *const *modifiers, + const uint32_t *num_modifiers, +- int num_tranches, struct x11_image *image) ++ int num_tranches, int display_fd, ++ struct x11_image *image) + { + xcb_void_cookie_t cookie; + VkResult result; +@@ -1311,11 +1312,12 @@ x11_image_init(VkDevice device_h, struct x11_swapchain *chain, + + if (chain->base.use_prime_blit) { + bool use_modifier = num_tranches > 0; +- result = wsi_create_prime_image(&chain->base, pCreateInfo, use_modifier, &image->base); ++ result = wsi_create_prime_image(&chain->base, pCreateInfo, use_modifier, ++ display_fd, &image->base); + } else { + result = wsi_create_native_image(&chain->base, pCreateInfo, + num_tranches, num_modifiers, modifiers, +- chain->base.wsi->sw, ++ chain->base.wsi->sw, display_fd, + &image->base); + } + if (result < 0) +@@ -1687,14 +1689,34 @@ x11_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, + modifiers, num_modifiers, &num_tranches, + pAllocator); + ++ + uint32_t image = 0; +- for (; image < chain->base.image_count; image++) { +- result = x11_image_init(device, chain, pCreateInfo, pAllocator, +- (const uint64_t *const *)modifiers, +- num_modifiers, num_tranches, +- &chain->images[image]); +- if (result != VK_SUCCESS) +- goto fail_init_images; ++ { ++ int display_fd = -1; ++ ++ if (!wsi_device->sw) { ++ 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); ++ } ++ ++ for (; image < chain->base.image_count; image++) { ++ result = x11_image_init(device, chain, pCreateInfo, pAllocator, ++ (const uint64_t *const *)modifiers, ++ num_modifiers, num_tranches, ++ display_fd, &chain->images[image]); ++ if (result != VK_SUCCESS) { ++ if (display_fd >= 0) ++ close(display_fd); ++ ++ goto fail_init_images; ++ } ++ } ++ ++ if (display_fd >= 0) ++ close(display_fd); + } + + if ((chain->base.present_mode == VK_PRESENT_MODE_FIFO_KHR || +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0059-pvr-wsi-add-PowerVR-Vulkan-WSI-library.patch b/recipes-graphics/mesa/mesa-pvr/0059-pvr-wsi-add-PowerVR-Vulkan-WSI-library.patch new file mode 100644 index 0000000..79085fa --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0059-pvr-wsi-add-PowerVR-Vulkan-WSI-library.patch @@ -0,0 +1,1343 @@ +From 650cbfe1007a3f9dd4ef8a3bbe829bbfed4ab1cc Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Thu, 18 Mar 2021 13:44:57 +0000 +Subject: [PATCH 59/67] pvr/wsi: add PowerVR Vulkan WSI library + +PowerVR Vulkan will load the WSI library, libpvr_mesa_wsi.so, +and lookup the symbol pvr_mesa_wsi_sym_addr, which is a used to +lookup all other symbols required by Vulkan from the library. +The function is used by Vulkan to lookup the library initialisation +function, pvr_mesa_wsi_init. That function is passed the address +of another lookup function, pvr_vk_mesa_wsi_sym_addr, which is used +by the WSI library to lookup symbols in Vulkan. + +The interface between PVR Vulkan and the WSI library is defined in +pvr_mesa_wsi_interface.h. Most of the functions defined on the WSI +side are wrappers around Mesa WSI functions. +--- + meson.build | 1 + + meson_options.txt | 2 +- + src/meson.build | 3 + + src/pvr/meson.build | 23 ++ + src/pvr/wsi/meson.build | 75 ++++++ + src/pvr/wsi/pvr_mesa_wsi_interface.h | 306 ++++++++++++++++++++++++ + src/pvr/wsi/pvr_wsi.c | 333 +++++++++++++++++++++++++++ + src/pvr/wsi/pvr_wsi.h | 78 +++++++ + src/pvr/wsi/pvr_wsi_display.c | 293 +++++++++++++++++++++++ + src/pvr/wsi/pvr_wsi_wayland.c | 45 ++++ + src/pvr/wsi/pvr_wsi_x11.c | 62 +++++ + 11 files changed, 1220 insertions(+), 1 deletion(-) + 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 + +diff --git a/meson.build b/meson.build +index 8db1699729a..9341e5500fc 100644 +--- a/meson.build ++++ b/meson.build +@@ -296,6 +296,7 @@ with_swrast_vk = _vulkan_drivers.contains('swrast') + with_virtio_vk = _vulkan_drivers.contains('virtio-experimental') + with_freedreno_kgsl = get_option('freedreno-kgsl') + with_broadcom_vk = _vulkan_drivers.contains('broadcom') ++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 +diff --git a/meson_options.txt b/meson_options.txt +index d36e714ea4c..e0c25a5b15b 100644 +--- a/meson_options.txt ++++ b/meson_options.txt +@@ -194,7 +194,7 @@ option( + 'vulkan-drivers', + type : 'array', + value : ['auto'], +- choices : ['auto', 'amd', 'broadcom', 'freedreno', 'intel', 'panfrost', 'swrast', 'virtio-experimental'], ++ choices : ['auto', 'amd', 'broadcom', 'freedreno', 'intel', 'panfrost', 'swrast', 'virtio-experimental', 'pvr'], + 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( +diff --git a/src/meson.build b/src/meson.build +index f6eede56648..36fec262020 100644 +--- a/src/meson.build ++++ b/src/meson.build +@@ -90,6 +90,9 @@ endif + if with_gallium_panfrost or with_gallium_lima or with_panfrost_vk + subdir('panfrost') + endif ++if with_pvr_vk ++ subdir('pvr') ++endif + if with_gallium_virgl or with_virtio_vk + subdir('virtio') + endif +diff --git a/src/pvr/meson.build b/src/pvr/meson.build +new file mode 100644 +index 00000000000..09a6986a4c9 +--- /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 00000000000..57c7623c4bb +--- /dev/null ++++ b/src/pvr/wsi/meson.build +@@ -0,0 +1,75 @@ ++# 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 = vulkan_wsi_args ++ ++pvr_wsi_depends = [ dep_libdrm, idep_vulkan_util, idep_xmlconfig ] ++ ++pvr_wsi_includes = [ ++ inc_include, ++ inc_src, ++ inc_vulkan_util, ++ inc_vulkan_wsi ++] ++ ++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 ++ ++libvulkan_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 00000000000..b4b1bcb0c9d +--- /dev/null ++++ b/src/pvr/wsi/pvr_mesa_wsi_interface.h +@@ -0,0 +1,306 @@ ++/*************************************************************************/ /*! ++@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. ++ */ ++ ++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); ++ ++/* ++ * Functions defined in the PowerVR DDK for use by Mesa. ++ * All functions have a "pvr_vk_mesa_wsi" prefix. ++ */ ++VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL ++pvr_vk_mesa_wsi_sym_addr(VkPhysicalDevice physicalDevice, ++ const char *name); ++ ++#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 00000000000..a1fcdfd6164 +--- /dev/null ++++ b/src/pvr/wsi/pvr_wsi.c +@@ -0,0 +1,333 @@ ++/* ++ * 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" ++ ++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; ++ ++ result = wsi_device_init(&mwsi->wsi, ++ physicalDevice, ++ pvr_vk_mesa_wsi_sym_addr, ++ alloc, ++ fd, NULL, sw); ++ 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); ++} ++ ++/* ++ * 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 }, ++ }; ++ 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 00000000000..142358db3de +--- /dev/null ++++ b/src/pvr/wsi/pvr_wsi.h +@@ -0,0 +1,78 @@ ++/* ++ * 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(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 *); ++}; ++ ++struct pvr_mesa_wsi ++{ ++ struct wsi_device wsi; ++ struct pvr_vk_mesa_wsi_sym_tab symtab; ++ VkPhysicalDevice physicalDevice; ++}; ++ ++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 00000000000..65a1c99507c +--- /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 wsi_fence *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 wsi_fence *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 00000000000..5b052667ac9 +--- /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 00000000000..0a69e92ac9e +--- /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); ++} +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0060-vulkan-wsi-Disable-use-of-VK_EXT_pci_bus_info.patch b/recipes-graphics/mesa/mesa-pvr/0060-vulkan-wsi-Disable-use-of-VK_EXT_pci_bus_info.patch new file mode 100644 index 0000000..9e5b3d6 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0060-vulkan-wsi-Disable-use-of-VK_EXT_pci_bus_info.patch @@ -0,0 +1,76 @@ +From 83953c9325e4cc9adb23ad7654a02ddabdd3fd99 Mon Sep 17 00:00:00 2001 +From: brendan King +Date: Fri, 30 Jul 2021 15:34:13 +0100 +Subject: [PATCH 60/67] vulkan/wsi: Disable use of VK_EXT_pci_bus_info + +The VK_EXT_pci_bus_info related code has been wrapped in +VULKAN_WSI_USE_PCI_BUS_INFO, effectively disabling it. + +Not all platforms support the VK_EXT_pci_bus_info extension. +A better fix might be to pass another parameter to wsi_device_init, +to indicate that the device is a PCI one. +--- + src/vulkan/wsi/wsi_common.c | 4 ++++ + src/vulkan/wsi/wsi_common.h | 2 ++ + src/vulkan/wsi/wsi_common_drm.c | 4 ++++ + 3 files changed, 10 insertions(+) + +diff --git a/src/vulkan/wsi/wsi_common.c b/src/vulkan/wsi/wsi_common.c +index b1360edb911..66d6683a7c1 100644 +--- a/src/vulkan/wsi/wsi_common.c ++++ b/src/vulkan/wsi/wsi_common.c +@@ -56,11 +56,15 @@ wsi_device_init(struct wsi_device *wsi, + WSI_GET_CB(GetPhysicalDeviceQueueFamilyProperties); + #undef WSI_GET_CB + ++#if defined(VULKAN_WSI_USE_PCI_BUS_INFO) + wsi->pci_bus_info.sType = + VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PCI_BUS_INFO_PROPERTIES_EXT; ++#endif + VkPhysicalDeviceProperties2 pdp2 = { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, ++#if defined(VULKAN_WSI_USE_PCI_BUS_INFO) + .pNext = &wsi->pci_bus_info, ++#endif + }; + GetPhysicalDeviceProperties2(pdevice, &pdp2); + +diff --git a/src/vulkan/wsi/wsi_common.h b/src/vulkan/wsi/wsi_common.h +index c2563c677e6..4a733665d2c 100644 +--- a/src/vulkan/wsi/wsi_common.h ++++ b/src/vulkan/wsi/wsi_common.h +@@ -112,7 +112,9 @@ struct wsi_device { + VkPhysicalDeviceMemoryProperties memory_props; + uint32_t queue_family_count; + ++#if defined(VULKAN_WSI_USE_PCI_BUS_INFO) + VkPhysicalDevicePCIBusInfoPropertiesEXT pci_bus_info; ++#endif + + bool supports_modifiers; + uint32_t maxImageDimension2D; +diff --git a/src/vulkan/wsi/wsi_common_drm.c b/src/vulkan/wsi/wsi_common_drm.c +index 6201891ca80..49a78cf4c62 100644 +--- a/src/vulkan/wsi/wsi_common_drm.c ++++ b/src/vulkan/wsi/wsi_common_drm.c +@@ -45,6 +45,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: +@@ -57,6 +58,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); + +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0061-vulkan-wsi-default-to-force_bgra8_unorm_first-true.patch b/recipes-graphics/mesa/mesa-pvr/0061-vulkan-wsi-default-to-force_bgra8_unorm_first-true.patch new file mode 100644 index 0000000..881d6fb --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0061-vulkan-wsi-default-to-force_bgra8_unorm_first-true.patch @@ -0,0 +1,34 @@ +From 10a0d4ec4f9d468c792f5e675d924fa7a8f97373 Mon Sep 17 00:00:00 2001 +From: brendan King +Date: Mon, 2 Aug 2021 16:29:36 +0100 +Subject: [PATCH 61/67] vulkan/wsi: default to force_bgra8_unorm_first true + +If VULKAN_WSI_BGRA8_SNORM_FIRST is not defined, default to +force_bgra8_unorm_first true. + +This brings Mesa WSI into line with IMG WSI with regards to the +VK_FORMAT_B8G8R8A8_UNORM and VK_FORMAT_B8G8R8A8_SRGB formats. +With this change, the IMG Vulkan unit test, vkbonjour, will default +to VK_FORMAT_B8G8R8A8_UNORM rather than VK_FORMAT_B8G8R8A8_SRGB. +--- + src/vulkan/wsi/wsi_common.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/vulkan/wsi/wsi_common.c b/src/vulkan/wsi/wsi_common.c +index 66d6683a7c1..1ffca6fecfb 100644 +--- a/src/vulkan/wsi/wsi_common.c ++++ b/src/vulkan/wsi/wsi_common.c +@@ -158,6 +158,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) || \ +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0062-vulkan-wsi-enable-additional-formats-for-Wayland.patch b/recipes-graphics/mesa/mesa-pvr/0062-vulkan-wsi-enable-additional-formats-for-Wayland.patch new file mode 100644 index 0000000..4290a33 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0062-vulkan-wsi-enable-additional-formats-for-Wayland.patch @@ -0,0 +1,64 @@ +From 7e8bb12d48651796da6d8f3df1b388551d3b5510 Mon Sep 17 00:00:00 2001 +From: brendan King +Date: Mon, 2 Aug 2021 11:21:16 +0100 +Subject: [PATCH 62/67] vulkan/wsi: enable additional formats for Wayland + +Add VK_FORMAT_R5G6B5_UNORM_PACK16. + +This is for compatibility with IMG WSI. +--- + src/vulkan/wsi/wsi_common_wayland.c | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/src/vulkan/wsi/wsi_common_wayland.c b/src/vulkan/wsi/wsi_common_wayland.c +index 1109d3f07b6..e520aa9af00 100644 +--- a/src/vulkan/wsi/wsi_common_wayland.c ++++ b/src/vulkan/wsi/wsi_common_wayland.c +@@ -68,6 +68,7 @@ struct wsi_wl_display_dmabuf { + struct { + struct u_vector argb8888; + struct u_vector xrgb8888; ++ struct u_vector rgb565; + } modifiers; + }; + +@@ -441,6 +442,9 @@ dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf, + case WL_DRM_FORMAT_XRGB8888: + modifiers = &display->dmabuf.modifiers.xrgb8888; + break; ++ case WL_DRM_FORMAT_RGB565: ++ modifiers = &display->dmabuf.modifiers.rgb565; ++ break; + default: + return; /* Unsupported format */ + } +@@ -527,6 +531,7 @@ wsi_wl_display_finish(struct wsi_wl_display *display) + u_vector_finish(&display->dmabuf.formats); + u_vector_finish(&display->dmabuf.modifiers.argb8888); + u_vector_finish(&display->dmabuf.modifiers.xrgb8888); ++ u_vector_finish(&display->dmabuf.modifiers.rgb565); + if (display->swrast.wl_shm) + wl_shm_destroy(display->swrast.wl_shm); + if (display->drm.wl_drm) +@@ -563,6 +568,8 @@ wsi_wl_display_init(struct wsi_wayland *wsi_wl, + !u_vector_init(&display->dmabuf.modifiers.argb8888, + sizeof(uint64_t), 32) || + !u_vector_init(&display->dmabuf.modifiers.xrgb8888, ++ sizeof(uint64_t), 32) || ++ !u_vector_init(&display->dmabuf.modifiers.rgb565, + sizeof(uint64_t), 32)) { + result = VK_ERROR_OUT_OF_HOST_MEMORY; + goto fail; +@@ -1356,6 +1363,9 @@ wsi_wl_surface_create_swapchain(VkIcdSurfaceBase *icd_surface, + case WL_DRM_FORMAT_XRGB8888: + modifiers = &chain->display->dmabuf.modifiers.xrgb8888; + break; ++ case WL_DRM_FORMAT_RGB565: ++ modifiers = &chain->display->dmabuf.modifiers.rgb565; ++ break; + default: + modifiers = NULL; + break; +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0063-vulkan-wsi-enable-additional-formats-for-Display.patch b/recipes-graphics/mesa/mesa-pvr/0063-vulkan-wsi-enable-additional-formats-for-Display.patch new file mode 100644 index 0000000..f880359 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0063-vulkan-wsi-enable-additional-formats-for-Display.patch @@ -0,0 +1,27 @@ +From c2b91fcb7c88bfec23077ae31c0035684249ea1b Mon Sep 17 00:00:00 2001 +From: brendan King +Date: Tue, 3 Aug 2021 15:44:57 +0100 +Subject: [PATCH 63/67] vulkan/wsi: enable additional formats for Display + +Add VK_FORMAT_R5G6B5_UNORM_PACK16. + +This is for compatibility with IMG WSI. +--- + src/vulkan/wsi/wsi_common_display.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/vulkan/wsi/wsi_common_display.c b/src/vulkan/wsi/wsi_common_display.c +index f135b4e38de..298c78809c3 100644 +--- a/src/vulkan/wsi/wsi_common_display.c ++++ b/src/vulkan/wsi/wsi_common_display.c +@@ -900,6 +900,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 +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0064-mesa-main-dri-add-YUV420_3PLANE-and-YVU420_3PLANE.patch b/recipes-graphics/mesa/mesa-pvr/0064-mesa-main-dri-add-YUV420_3PLANE-and-YVU420_3PLANE.patch new file mode 100644 index 0000000..39e08c0 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0064-mesa-main-dri-add-YUV420_3PLANE-and-YVU420_3PLANE.patch @@ -0,0 +1,183 @@ +From 85762f3538a21a99bf1b71d87345ebe51f9de453 Mon Sep 17 00:00:00 2001 +From: Luigi Santivetti +Date: Thu, 12 Aug 2021 00:55:46 +0100 +Subject: [PATCH 64/67] mesa/main: dri: add YUV420_3PLANE and YVU420_3PLANE + +--- + include/GL/internal/dri_interface.h | 2 ++ + src/gallium/include/pipe/p_format.h | 3 +++ + src/mesa/drivers/dri/common/utils.c | 18 ++++++++++++++++++ + src/mesa/drivers/dri/pvr/dri_support.h | 2 ++ + src/mesa/drivers/dri/pvr/pvrutil.c | 13 +++++++++++++ + src/mesa/main/format_info.py | 2 +- + src/mesa/main/formats.c | 2 ++ + src/mesa/main/formats.csv | 2 ++ + src/mesa/main/formats.h | 6 ++++++ + 9 files changed, 49 insertions(+), 1 deletion(-) + +diff --git a/include/GL/internal/dri_interface.h b/include/GL/internal/dri_interface.h +index 080d191b0a3..7d9a1bd9ba6 100644 +--- a/include/GL/internal/dri_interface.h ++++ b/include/GL/internal/dri_interface.h +@@ -1424,6 +1424,8 @@ struct __DRIdri2ExtensionRec { + #define __DRI_IMAGE_FORMAT_BGR888 0x101a + #define __DRI_IMAGE_FORMAT_NV12 0x101b + #define __DRI_IMAGE_FORMAT_NV21 0x101c ++#define __DRI_IMAGE_FORMAT_YU12 0x101d ++#define __DRI_IMAGE_FORMAT_YV12 0x101e + + #define __DRI_IMAGE_USE_SHARE 0x0001 + #define __DRI_IMAGE_USE_SCANOUT 0x0002 +diff --git a/src/gallium/include/pipe/p_format.h b/src/gallium/include/pipe/p_format.h +index fd653379b7a..970f07598d5 100644 +--- a/src/gallium/include/pipe/p_format.h ++++ b/src/gallium/include/pipe/p_format.h +@@ -516,6 +516,9 @@ enum pipe_format { + PIPE_FORMAT_YUV420_2PLANE, + PIPE_FORMAT_YVU420_2PLANE, + ++ PIPE_FORMAT_YUV420_3PLANE, ++ PIPE_FORMAT_YVU420_3PLANE, ++ + PIPE_FORMAT_COUNT + }; + +diff --git a/src/mesa/drivers/dri/common/utils.c b/src/mesa/drivers/dri/common/utils.c +index d268dc41fbb..df5f8cbfdc0 100644 +--- a/src/mesa/drivers/dri/common/utils.c ++++ b/src/mesa/drivers/dri/common/utils.c +@@ -330,6 +330,24 @@ driCreateConfigs(mesa_format format, + 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; + default: + fprintf(stderr, "[%s:%u] Unknown framebuffer type %s (%d).\n", + __func__, __LINE__, +diff --git a/src/mesa/drivers/dri/pvr/dri_support.h b/src/mesa/drivers/dri/pvr/dri_support.h +index ab0b9dd9a23..a4999dc36bf 100644 +--- a/src/mesa/drivers/dri/pvr/dri_support.h ++++ b/src/mesa/drivers/dri/pvr/dri_support.h +@@ -189,6 +189,8 @@ typedef enum + #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 + + /* The blit flags match their DRI counterparts */ + #define PVRDRI_BLIT_FLAG_FLUSH 0x0001 +diff --git a/src/mesa/drivers/dri/pvr/pvrutil.c b/src/mesa/drivers/dri/pvr/pvrutil.c +index d107a5dafad..ee11ac55914 100644 +--- a/src/mesa/drivers/dri/pvr/pvrutil.c ++++ b/src/mesa/drivers/dri/pvr/pvrutil.c +@@ -118,6 +118,10 @@ PVRDRIMesaFormatToMesaFormat(int pvrdri_mesa_format) + 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; + default: + __driUtilMessage("%s: Unknown format: %d", __func__, pvrdri_mesa_format); + break; +@@ -178,6 +182,11 @@ PVRDRIFormatToFourCC(int dri_format) + 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; ++ + default: + __driUtilMessage("%s: Unknown format: %d", __func__, dri_format); + break; +@@ -238,6 +247,10 @@ PVRDRIFourCCToDRIFormat(int iFourCC) + 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; + default: + __driUtilMessage("%s: Unknown format: %d", __func__, iFourCC); + break; +diff --git a/src/mesa/main/format_info.py b/src/mesa/main/format_info.py +index d58403ea85e..bc18db74f17 100644 +--- a/src/mesa/main/format_info.py ++++ b/src/mesa/main/format_info.py +@@ -29,7 +29,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', 'MESA_FORMAT_YUV420_2PLANE', 'MESA_FORMAT_YVU420_2PLANE']: ++ 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']: + 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 f81caeceff4..d7b0d0a07c9 100644 +--- a/src/mesa/main/formats.c ++++ b/src/mesa/main/formats.c +@@ -1455,6 +1455,8 @@ _mesa_format_matches_format_and_type(mesa_format mformat, + 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: +diff --git a/src/mesa/main/formats.csv b/src/mesa/main/formats.csv +index b2d476577e0..825443b10ce 100644 +--- a/src/mesa/main/formats.csv ++++ b/src/mesa/main/formats.csv +@@ -94,6 +94,8 @@ MESA_FORMAT_YCBCR , other , 1, 1, 1, x16 , , , + 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_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 0e778d64467..1ab03d2be7e 100644 +--- a/src/mesa/main/formats.h ++++ b/src/mesa/main/formats.h +@@ -624,6 +624,12 @@ typedef enum pipe_format mesa_format; + #define HAVE_MESA_FORMAT_YVU420_2PLANE + #define MESA_FORMAT_YVU420_2PLANE PIPE_FORMAT_YVU420_2PLANE + ++#define HAVE_MESA_FORMAT_YUV420_3PLANE ++#define MESA_FORMAT_YUV420_3PLANE PIPE_FORMAT_YUV420_3PLANE ++ ++#define HAVE_MESA_FORMAT_YVU420_3PLANE ++#define MESA_FORMAT_YVU420_3PLANE PIPE_FORMAT_YVU420_3PLANE ++ + #define MESA_FORMAT_COUNT PIPE_FORMAT_COUNT + + /* Packed to array format adapters */ +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0065-egl-null-add-support-for-YU12-and-YV12.patch b/recipes-graphics/mesa/mesa-pvr/0065-egl-null-add-support-for-YU12-and-YV12.patch new file mode 100644 index 0000000..63c6e2b --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0065-egl-null-add-support-for-YU12-and-YV12.patch @@ -0,0 +1,58 @@ +From 89f34a04c15c8657cb77bbbc94fb9b9d0ac76980 Mon Sep 17 00:00:00 2001 +From: Luigi Santivetti +Date: Mon, 23 Aug 2021 09:18:37 +0100 +Subject: [PATCH 65/67] egl/null: add support for YU12 and YV12 + +--- + src/egl/drivers/dri2/platform_null.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/src/egl/drivers/dri2/platform_null.c b/src/egl/drivers/dri2/platform_null.c +index 529cc7a2a2f..2e86d6533de 100644 +--- a/src/egl/drivers/dri2/platform_null.c ++++ b/src/egl/drivers/dri2/platform_null.c +@@ -106,6 +106,20 @@ static const struct dri2_null_yuv_attrib { + .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, ++ }, + }; + + /* +@@ -161,6 +175,20 @@ static const struct dri2_null_format { + .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], ++ }, + }; + + +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0066-mesa-partially-revert-pbuffer-attribute-removal.patch b/recipes-graphics/mesa/mesa-pvr/0066-mesa-partially-revert-pbuffer-attribute-removal.patch new file mode 100644 index 0000000..049e2f4 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0066-mesa-partially-revert-pbuffer-attribute-removal.patch @@ -0,0 +1,59 @@ +From 28e4349702566ba34dad4c214c64bfd702177c8a Mon Sep 17 00:00:00 2001 +From: brendan King +Date: Thu, 16 Sep 2021 17:46:28 +0100 +Subject: [PATCH 66/67] mesa: partially revert pbuffer attribute removal + +This partially reverts commit 5ffd1ebe6b3c8c7dd316dd47fac088044222e6ef +("mesa: Remove misc pbuffer attributes from struct gl_config"). + +The IMG PowerVR driver sets meaningful values for the maximum +pbuffer width, height and pixels. +--- + src/mesa/drivers/dri/common/utils.c | 7 ++++--- + src/mesa/main/mtypes.h | 5 +++++ + 2 files changed, 9 insertions(+), 3 deletions(-) + +diff --git a/src/mesa/drivers/dri/common/utils.c b/src/mesa/drivers/dri/common/utils.c +index df5f8cbfdc0..28debe4e013 100644 +--- a/src/mesa/drivers/dri/common/utils.c ++++ b/src/mesa/drivers/dri/common/utils.c +@@ -480,6 +480,7 @@ __DRIconfig **driConcatConfigs(__DRIconfig **a, + return all; + } + ++/* careful, lack of trailing semicolon */ + #define __ATTRIB(attrib, field) case attrib: *value = config->modes.field; break + + /** +@@ -555,9 +556,9 @@ driGetConfigAttribIndex(const __DRIconfig *config, + __ATTRIB(__DRI_ATTRIB_GREEN_MASK, greenMask); + __ATTRIB(__DRI_ATTRIB_BLUE_MASK, blueMask); + __ATTRIB(__DRI_ATTRIB_ALPHA_MASK, alphaMask); +- case __DRI_ATTRIB_MAX_PBUFFER_WIDTH: +- case __DRI_ATTRIB_MAX_PBUFFER_HEIGHT: +- case __DRI_ATTRIB_MAX_PBUFFER_PIXELS: ++ __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_WIDTH, maxPbufferWidth); ++ __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_HEIGHT, maxPbufferHeight); ++ __ATTRIB(__DRI_ATTRIB_MAX_PBUFFER_PIXELS, maxPbufferPixels); + case __DRI_ATTRIB_OPTIMAL_PBUFFER_WIDTH: + case __DRI_ATTRIB_OPTIMAL_PBUFFER_HEIGHT: + case __DRI_ATTRIB_VISUAL_SELECT_GROUP: +diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h +index 8f77d4c58dd..e37c61d23d0 100644 +--- a/src/mesa/main/mtypes.h ++++ b/src/mesa/main/mtypes.h +@@ -175,6 +175,11 @@ struct gl_config + /* ARB_multisample / SGIS_multisample */ + GLuint samples; + ++ /* GLX 1.3 */ ++ GLint maxPbufferWidth; ++ GLint maxPbufferHeight; ++ GLint maxPbufferPixels; ++ + /* OML_swap_method */ + GLint swapMethod; + +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0067-egl_dri2-set-pbuffer-config-attribs-to-0-for-non-pbu.patch b/recipes-graphics/mesa/mesa-pvr/0067-egl_dri2-set-pbuffer-config-attribs-to-0-for-non-pbu.patch new file mode 100644 index 0000000..1fdc179 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0067-egl_dri2-set-pbuffer-config-attribs-to-0-for-non-pbu.patch @@ -0,0 +1,66 @@ +From 9bb8868ebab2d041c24c76487b6419a8039a5ce7 Mon Sep 17 00:00:00 2001 +From: Frank Binns +Date: Wed, 4 Jun 2014 13:43:03 +0100 +Subject: [PATCH 67/67] egl_dri2: set pbuffer config attribs to 0 for + non-pbuffer configs + +If the EGL_PBUFFER_BIT isn't set in the surface type, don't set the +EGL_MAX_PBUFFER_WIDTH, EGL_MAX_PBUFFER_HEIGHT and +EGL_MAX_PBUFFER_PIXELS attributes to non-zero values when adding an +EGL config. If the EGL_PBUFFER_BIT is set, don't override non-zero +values from the DRI config. +--- + src/egl/drivers/dri2/egl_dri2.c | 20 ++++++++++++++++++-- + 1 file changed, 18 insertions(+), 2 deletions(-) + +diff --git a/src/egl/drivers/dri2/egl_dri2.c b/src/egl/drivers/dri2/egl_dri2.c +index 56b5175db6e..1b10c2e7362 100644 +--- a/src/egl/drivers/dri2/egl_dri2.c ++++ b/src/egl/drivers/dri2/egl_dri2.c +@@ -407,6 +407,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 }; +@@ -530,11 +531,17 @@ 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; +@@ -614,6 +621,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]); +-- +2.25.1 + diff --git a/recipes-graphics/mesa/mesa-pvr/0068-GL_ARB_geometry_shader4-entry-points.patch b/recipes-graphics/mesa/mesa-pvr/0068-GL_ARB_geometry_shader4-entry-points.patch new file mode 100644 index 0000000..e14a244 --- /dev/null +++ b/recipes-graphics/mesa/mesa-pvr/0068-GL_ARB_geometry_shader4-entry-points.patch @@ -0,0 +1,146 @@ +From f9c028d508bac22d7c78b0232c625e27d13340a7 Mon Sep 17 00:00:00 2001 +From: Brendan King +Date: Thu, 11 Nov 2021 12:09:38 +0000 +Subject: [PATCH 68/68] GL_ARB_geometry_shader4 entry points. + +--- + src/mapi/glapi/gen/ARB_geometry_shader4.xml | 97 +++++++++++++++++++++ + src/mapi/glapi/gen/gl_API.xml | 2 +- + src/mapi/glapi/gen/static_data.py | 4 + + 3 files changed, 102 insertions(+), 1 deletion(-) + create mode 100644 src/mapi/glapi/gen/ARB_geometry_shader4.xml + +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 00000000000..d92dc577b17 +--- /dev/null ++++ b/src/mapi/glapi/gen/ARB_geometry_shader4.xml +@@ -0,0 +1,97 @@ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ +diff --git a/src/mapi/glapi/gen/gl_API.xml b/src/mapi/glapi/gen/gl_API.xml +index 4e35de0f4ea..d5a5e7f5386 100644 +--- a/src/mapi/glapi/gen/gl_API.xml ++++ b/src/mapi/glapi/gen/gl_API.xml +@@ -8064,7 +8064,7 @@ + + + +- ++ + + + +diff --git a/src/mapi/glapi/gen/static_data.py b/src/mapi/glapi/gen/static_data.py +index 974f366d7b4..833ad73dd6a 100644 +--- a/src/mapi/glapi/gen/static_data.py ++++ b/src/mapi/glapi/gen/static_data.py +@@ -1721,6 +1721,10 @@ offsets = { + "FramebufferRenderbufferEXT" : 1685, + "GetFramebufferAttachmentParameterivEXT" : 1686, + "GenerateMipmapEXT" : 1687, ++ "ProgramParameteriARB" : 1688, ++ "FramebufferTextureARB" : 1689, ++ "FramebufferTextureLayerARB" : 1690, ++ "FramebufferTextureFaceARB" : 1691, + } + + functions = [ +-- +2.25.1 +