Path: blob/21.2-virgl/src/egl/drivers/dri2/platform_wayland.c
4570 views
/*1* Copyright Ā© 2011-2012 Intel Corporation2* Copyright Ā© 2012 Collabora, Ltd.3*4* Permission is hereby granted, free of charge, to any person obtaining a5* copy of this software and associated documentation files (the "Software"),6* to deal in the Software without restriction, including without limitation7* the rights to use, copy, modify, merge, publish, distribute, sublicense,8* and/or sell copies of the Software, and to permit persons to whom the9* Software is furnished to do so, subject to the following conditions:10*11* The above copyright notice and this permission notice (including the next12* paragraph) shall be included in all copies or substantial portions of the13* Software.14*15* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,16* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF17* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND18* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT19* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,20* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,21* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER22* DEALINGS IN THE SOFTWARE.23*24* Authors:25* Kristian HĆøgsberg <[email protected]>26* Benjamin Franzke <[email protected]>27*/2829#include <stdint.h>30#include <stdlib.h>31#include <string.h>32#include <limits.h>33#include <dlfcn.h>34#include <errno.h>35#include <unistd.h>36#include <fcntl.h>37#include <xf86drm.h>38#include "drm-uapi/drm_fourcc.h"39#include <sys/mman.h>4041#include "egl_dri2.h"42#include "loader_dri_helper.h"43#include "loader.h"44#include "util/u_vector.h"45#include "util/anon_file.h"46#include "eglglobals.h"4748#include <wayland-egl-backend.h>49#include <wayland-client.h>50#include "wayland-drm-client-protocol.h"51#include "linux-dmabuf-unstable-v1-client-protocol.h"5253/*54* The index of entries in this table is used as a bitmask in55* dri2_dpy->formats, which tracks the formats supported by our server.56*/57static const struct dri2_wl_visual {58const char *format_name;59uint32_t wl_drm_format;60uint32_t wl_shm_format;61int dri_image_format;62/* alt_dri_image_format is a substitute wl_buffer format to use for a63* wl-server unsupported dri_image_format, ie. some other dri_image_format in64* the table, of the same precision but with different channel ordering, or65* __DRI_IMAGE_FORMAT_NONE if an alternate format is not needed or supported.66* The code checks if alt_dri_image_format can be used as a fallback for a67* dri_image_format for a given wl-server implementation.68*/69int alt_dri_image_format;70int bpp;71int rgba_shifts[4];72unsigned int rgba_sizes[4];73} dri2_wl_visuals[] = {74{75"ABGR16F",76WL_DRM_FORMAT_ABGR16F, WL_SHM_FORMAT_ABGR16161616F,77__DRI_IMAGE_FORMAT_ABGR16161616F, 0, 64,78{ 0, 16, 32, 48 },79{ 16, 16, 16, 16 },80},81{82"XBGR16F",83WL_DRM_FORMAT_XBGR16F, WL_SHM_FORMAT_XBGR16161616F,84__DRI_IMAGE_FORMAT_XBGR16161616F, 0, 64,85{ 0, 16, 32, -1 },86{ 16, 16, 16, 0 },87},88{89"XRGB2101010",90WL_DRM_FORMAT_XRGB2101010, WL_SHM_FORMAT_XRGB2101010,91__DRI_IMAGE_FORMAT_XRGB2101010, __DRI_IMAGE_FORMAT_XBGR2101010, 32,92{ 20, 10, 0, -1 },93{ 10, 10, 10, 0 },94},95{96"ARGB2101010",97WL_DRM_FORMAT_ARGB2101010, WL_SHM_FORMAT_ARGB2101010,98__DRI_IMAGE_FORMAT_ARGB2101010, __DRI_IMAGE_FORMAT_ABGR2101010, 32,99{ 20, 10, 0, 30 },100{ 10, 10, 10, 2 },101},102{103"XBGR2101010",104WL_DRM_FORMAT_XBGR2101010, WL_SHM_FORMAT_XBGR2101010,105__DRI_IMAGE_FORMAT_XBGR2101010, __DRI_IMAGE_FORMAT_XRGB2101010, 32,106{ 0, 10, 20, -1 },107{ 10, 10, 10, 0 },108},109{110"ABGR2101010",111WL_DRM_FORMAT_ABGR2101010, WL_SHM_FORMAT_ABGR2101010,112__DRI_IMAGE_FORMAT_ABGR2101010, __DRI_IMAGE_FORMAT_ARGB2101010, 32,113{ 0, 10, 20, 30 },114{ 10, 10, 10, 2 },115},116{117"XRGB8888",118WL_DRM_FORMAT_XRGB8888, WL_SHM_FORMAT_XRGB8888,119__DRI_IMAGE_FORMAT_XRGB8888, __DRI_IMAGE_FORMAT_NONE, 32,120{ 16, 8, 0, -1 },121{ 8, 8, 8, 0 },122},123{124"ARGB8888",125WL_DRM_FORMAT_ARGB8888, WL_SHM_FORMAT_ARGB8888,126__DRI_IMAGE_FORMAT_ARGB8888, __DRI_IMAGE_FORMAT_NONE, 32,127{ 16, 8, 0, 24 },128{ 8, 8, 8, 8 },129},130{131"RGB565",132WL_DRM_FORMAT_RGB565, WL_SHM_FORMAT_RGB565,133__DRI_IMAGE_FORMAT_RGB565, __DRI_IMAGE_FORMAT_NONE, 16,134{ 11, 5, 0, -1 },135{ 5, 6, 5, 0 },136},137};138139static_assert(ARRAY_SIZE(dri2_wl_visuals) <= EGL_DRI2_MAX_FORMATS,140"dri2_egl_display::formats is not large enough for "141"the formats in dri2_wl_visuals");142143static int144dri2_wl_visual_idx_from_config(struct dri2_egl_display *dri2_dpy,145const __DRIconfig *config)146{147int shifts[4];148unsigned int sizes[4];149150dri2_get_shifts_and_sizes(dri2_dpy->core, config, shifts, sizes);151152for (unsigned int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {153const struct dri2_wl_visual *wl_visual = &dri2_wl_visuals[i];154155if (shifts[0] == wl_visual->rgba_shifts[0] &&156shifts[1] == wl_visual->rgba_shifts[1] &&157shifts[2] == wl_visual->rgba_shifts[2] &&158shifts[3] == wl_visual->rgba_shifts[3] &&159sizes[0] == wl_visual->rgba_sizes[0] &&160sizes[1] == wl_visual->rgba_sizes[1] &&161sizes[2] == wl_visual->rgba_sizes[2] &&162sizes[3] == wl_visual->rgba_sizes[3]) {163return i;164}165}166167return -1;168}169170static int171dri2_wl_visual_idx_from_fourcc(uint32_t fourcc)172{173for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {174/* wl_drm format codes overlap with DRIImage FourCC codes for all formats175* we support. */176if (dri2_wl_visuals[i].wl_drm_format == fourcc)177return i;178}179180return -1;181}182183static int184dri2_wl_visual_idx_from_dri_image_format(uint32_t dri_image_format)185{186for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {187if (dri2_wl_visuals[i].dri_image_format == dri_image_format)188return i;189}190191return -1;192}193194static int195dri2_wl_visual_idx_from_shm_format(uint32_t shm_format)196{197for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {198if (dri2_wl_visuals[i].wl_shm_format == shm_format)199return i;200}201202return -1;203}204205bool206dri2_wl_is_format_supported(void* user_data, uint32_t format)207{208_EGLDisplay *disp = (_EGLDisplay *) user_data;209struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);210int j = dri2_wl_visual_idx_from_fourcc(format);211212if (j == -1)213return false;214215for (int i = 0; dri2_dpy->driver_configs[i]; i++)216if (j == dri2_wl_visual_idx_from_config(dri2_dpy,217dri2_dpy->driver_configs[i]))218return true;219220return false;221}222223static int224roundtrip(struct dri2_egl_display *dri2_dpy)225{226return wl_display_roundtrip_queue(dri2_dpy->wl_dpy, dri2_dpy->wl_queue);227}228229static void230wl_buffer_release(void *data, struct wl_buffer *buffer)231{232struct dri2_egl_surface *dri2_surf = data;233int i;234235for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); ++i)236if (dri2_surf->color_buffers[i].wl_buffer == buffer)237break;238239assert (i < ARRAY_SIZE(dri2_surf->color_buffers));240241if (dri2_surf->color_buffers[i].wl_release) {242wl_buffer_destroy(buffer);243dri2_surf->color_buffers[i].wl_release = false;244dri2_surf->color_buffers[i].wl_buffer = NULL;245}246247dri2_surf->color_buffers[i].locked = false;248}249250static const struct wl_buffer_listener wl_buffer_listener = {251.release = wl_buffer_release252};253254static void255resize_callback(struct wl_egl_window *wl_win, void *data)256{257struct dri2_egl_surface *dri2_surf = data;258struct dri2_egl_display *dri2_dpy =259dri2_egl_display(dri2_surf->base.Resource.Display);260261if (dri2_surf->base.Width == wl_win->width &&262dri2_surf->base.Height == wl_win->height)263return;264265/* Update the surface size as soon as native window is resized; from user266* pov, this makes the effect that resize is done immediately after native267* window resize, without requiring to wait until the first draw.268*269* A more detailed and lengthy explanation can be found at270* https://lists.freedesktop.org/archives/mesa-dev/2018-June/196474.html271*/272if (!dri2_surf->back) {273dri2_surf->base.Width = wl_win->width;274dri2_surf->base.Height = wl_win->height;275}276dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);277}278279static void280destroy_window_callback(void *data)281{282struct dri2_egl_surface *dri2_surf = data;283dri2_surf->wl_win = NULL;284}285286static struct wl_surface *287get_wl_surface_proxy(struct wl_egl_window *window)288{289/* Version 3 of wl_egl_window introduced a version field at the same290* location where a pointer to wl_surface was stored. Thus, if291* window->version is dereferenceable, we've been given an older version of292* wl_egl_window, and window->version points to wl_surface */293if (_eglPointerIsDereferencable((void *)(window->version))) {294return wl_proxy_create_wrapper((void *)(window->version));295}296return wl_proxy_create_wrapper(window->surface);297}298299/**300* Called via eglCreateWindowSurface(), drv->CreateWindowSurface().301*/302static _EGLSurface *303dri2_wl_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,304void *native_window, const EGLint *attrib_list)305{306struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);307struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);308struct wl_egl_window *window = native_window;309struct dri2_egl_surface *dri2_surf;310int visual_idx;311const __DRIconfig *config;312313if (!window) {314_eglError(EGL_BAD_NATIVE_WINDOW, "dri2_create_surface");315return NULL;316}317318if (window->driver_private) {319_eglError(EGL_BAD_ALLOC, "dri2_create_surface");320return NULL;321}322323dri2_surf = calloc(1, sizeof *dri2_surf);324if (!dri2_surf) {325_eglError(EGL_BAD_ALLOC, "dri2_create_surface");326return NULL;327}328329if (!dri2_init_surface(&dri2_surf->base, disp, EGL_WINDOW_BIT, conf,330attrib_list, false, native_window))331goto cleanup_surf;332333config = dri2_get_dri_config(dri2_conf, EGL_WINDOW_BIT,334dri2_surf->base.GLColorspace);335336if (!config) {337_eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration");338goto cleanup_surf;339}340341dri2_surf->base.Width = window->width;342dri2_surf->base.Height = window->height;343344visual_idx = dri2_wl_visual_idx_from_config(dri2_dpy, config);345assert(visual_idx != -1);346347if (dri2_dpy->wl_dmabuf || dri2_dpy->wl_drm) {348dri2_surf->format = dri2_wl_visuals[visual_idx].wl_drm_format;349} else {350assert(dri2_dpy->wl_shm);351dri2_surf->format = dri2_wl_visuals[visual_idx].wl_shm_format;352}353354dri2_surf->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);355if (!dri2_surf->wl_queue) {356_eglError(EGL_BAD_ALLOC, "dri2_create_surface");357goto cleanup_surf;358}359360if (dri2_dpy->wl_drm) {361dri2_surf->wl_drm_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_drm);362if (!dri2_surf->wl_drm_wrapper) {363_eglError(EGL_BAD_ALLOC, "dri2_create_surface");364goto cleanup_queue;365}366wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_drm_wrapper,367dri2_surf->wl_queue);368}369370dri2_surf->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);371if (!dri2_surf->wl_dpy_wrapper) {372_eglError(EGL_BAD_ALLOC, "dri2_create_surface");373goto cleanup_drm;374}375wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_dpy_wrapper,376dri2_surf->wl_queue);377378dri2_surf->wl_surface_wrapper = get_wl_surface_proxy(window);379if (!dri2_surf->wl_surface_wrapper) {380_eglError(EGL_BAD_ALLOC, "dri2_create_surface");381goto cleanup_dpy_wrapper;382}383wl_proxy_set_queue((struct wl_proxy *)dri2_surf->wl_surface_wrapper,384dri2_surf->wl_queue);385386dri2_surf->wl_win = window;387dri2_surf->wl_win->driver_private = dri2_surf;388dri2_surf->wl_win->destroy_window_callback = destroy_window_callback;389if (dri2_dpy->flush)390dri2_surf->wl_win->resize_callback = resize_callback;391392if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf))393goto cleanup_surf_wrapper;394395dri2_surf->base.SwapInterval = dri2_dpy->default_swap_interval;396397return &dri2_surf->base;398399cleanup_surf_wrapper:400wl_proxy_wrapper_destroy(dri2_surf->wl_surface_wrapper);401cleanup_dpy_wrapper:402wl_proxy_wrapper_destroy(dri2_surf->wl_dpy_wrapper);403cleanup_drm:404if (dri2_surf->wl_drm_wrapper)405wl_proxy_wrapper_destroy(dri2_surf->wl_drm_wrapper);406cleanup_queue:407wl_event_queue_destroy(dri2_surf->wl_queue);408cleanup_surf:409free(dri2_surf);410411return NULL;412}413414static _EGLSurface *415dri2_wl_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf,416void *native_window, const EGLint *attrib_list)417{418/* From the EGL_EXT_platform_wayland spec, version 3:419*420* It is not valid to call eglCreatePlatformPixmapSurfaceEXT with a <dpy>421* that belongs to Wayland. Any such call fails and generates422* EGL_BAD_PARAMETER.423*/424_eglError(EGL_BAD_PARAMETER, "cannot create EGL pixmap surfaces on "425"Wayland");426return NULL;427}428429/**430* Called via eglDestroySurface(), drv->DestroySurface().431*/432static EGLBoolean433dri2_wl_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)434{435struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);436struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);437438dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);439440for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {441if (dri2_surf->color_buffers[i].wl_buffer)442wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);443if (dri2_surf->color_buffers[i].dri_image)444dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);445if (dri2_surf->color_buffers[i].linear_copy)446dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);447if (dri2_surf->color_buffers[i].data)448munmap(dri2_surf->color_buffers[i].data,449dri2_surf->color_buffers[i].data_size);450}451452if (dri2_dpy->dri2)453dri2_egl_surface_free_local_buffers(dri2_surf);454455if (dri2_surf->throttle_callback)456wl_callback_destroy(dri2_surf->throttle_callback);457458if (dri2_surf->wl_win) {459dri2_surf->wl_win->driver_private = NULL;460dri2_surf->wl_win->resize_callback = NULL;461dri2_surf->wl_win->destroy_window_callback = NULL;462}463464wl_proxy_wrapper_destroy(dri2_surf->wl_surface_wrapper);465wl_proxy_wrapper_destroy(dri2_surf->wl_dpy_wrapper);466if (dri2_surf->wl_drm_wrapper)467wl_proxy_wrapper_destroy(dri2_surf->wl_drm_wrapper);468wl_event_queue_destroy(dri2_surf->wl_queue);469470dri2_fini_surface(surf);471free(surf);472473return EGL_TRUE;474}475476static void477dri2_wl_release_buffers(struct dri2_egl_surface *dri2_surf)478{479struct dri2_egl_display *dri2_dpy =480dri2_egl_display(dri2_surf->base.Resource.Display);481482for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {483if (dri2_surf->color_buffers[i].wl_buffer) {484if (dri2_surf->color_buffers[i].locked) {485dri2_surf->color_buffers[i].wl_release = true;486} else {487wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);488dri2_surf->color_buffers[i].wl_buffer = NULL;489}490}491if (dri2_surf->color_buffers[i].dri_image)492dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);493if (dri2_surf->color_buffers[i].linear_copy)494dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);495if (dri2_surf->color_buffers[i].data)496munmap(dri2_surf->color_buffers[i].data,497dri2_surf->color_buffers[i].data_size);498499dri2_surf->color_buffers[i].dri_image = NULL;500dri2_surf->color_buffers[i].linear_copy = NULL;501dri2_surf->color_buffers[i].data = NULL;502}503504if (dri2_dpy->dri2)505dri2_egl_surface_free_local_buffers(dri2_surf);506}507508static int509get_back_bo(struct dri2_egl_surface *dri2_surf)510{511struct dri2_egl_display *dri2_dpy =512dri2_egl_display(dri2_surf->base.Resource.Display);513int use_flags;514int visual_idx;515unsigned int dri_image_format;516unsigned int linear_dri_image_format;517uint64_t *modifiers;518int num_modifiers;519520visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format);521assert(visual_idx != -1);522dri_image_format = dri2_wl_visuals[visual_idx].dri_image_format;523linear_dri_image_format = dri_image_format;524modifiers = u_vector_tail(&dri2_dpy->wl_modifiers[visual_idx]);525num_modifiers = u_vector_length(&dri2_dpy->wl_modifiers[visual_idx]);526527if (num_modifiers == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) {528/* For the purposes of this function, an INVALID modifier on its own529* means the modifiers aren't supported.530*/531num_modifiers = 0;532}533534/* Substitute dri image format if server does not support original format */535if (!BITSET_TEST(dri2_dpy->formats, visual_idx))536linear_dri_image_format = dri2_wl_visuals[visual_idx].alt_dri_image_format;537538/* These asserts hold, as long as dri2_wl_visuals[] is self-consistent and539* the PRIME substitution logic in dri2_wl_add_configs_for_visuals() is free540* of bugs.541*/542assert(linear_dri_image_format != __DRI_IMAGE_FORMAT_NONE);543assert(BITSET_TEST(dri2_dpy->formats,544dri2_wl_visual_idx_from_dri_image_format(linear_dri_image_format)));545546/* There might be a buffer release already queued that wasn't processed */547wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_surf->wl_queue);548549while (dri2_surf->back == NULL) {550for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {551/* Get an unlocked buffer, preferably one with a dri_buffer552* already allocated. */553if (dri2_surf->color_buffers[i].locked)554continue;555if (dri2_surf->back == NULL)556dri2_surf->back = &dri2_surf->color_buffers[i];557else if (dri2_surf->back->dri_image == NULL)558dri2_surf->back = &dri2_surf->color_buffers[i];559}560561if (dri2_surf->back)562break;563564/* If we don't have a buffer, then block on the server to release one for565* us, and try again. wl_display_dispatch_queue will process any pending566* events, however not all servers flush on issuing a buffer release567* event. So, we spam the server with roundtrips as they always cause a568* client flush.569*/570if (wl_display_roundtrip_queue(dri2_dpy->wl_dpy,571dri2_surf->wl_queue) < 0)572return -1;573}574575if (dri2_surf->back == NULL)576return -1;577578use_flags = __DRI_IMAGE_USE_SHARE | __DRI_IMAGE_USE_BACKBUFFER;579580if (dri2_surf->base.ProtectedContent) {581/* Protected buffers can't be read from another GPU */582if (dri2_dpy->is_different_gpu)583return -1;584use_flags |= __DRI_IMAGE_USE_PROTECTED;585}586587if (dri2_dpy->is_different_gpu &&588dri2_surf->back->linear_copy == NULL) {589/* The LINEAR modifier should be a perfect alias of the LINEAR use590* flag; try the new interface first before the old, then fall back. */591uint64_t linear_mod = DRM_FORMAT_MOD_LINEAR;592593dri2_surf->back->linear_copy =594loader_dri_create_image(dri2_dpy->dri_screen, dri2_dpy->image,595dri2_surf->base.Width,596dri2_surf->base.Height,597linear_dri_image_format,598use_flags | __DRI_IMAGE_USE_LINEAR,599&linear_mod, 1, NULL);600601if (dri2_surf->back->linear_copy == NULL)602return -1;603}604605if (dri2_surf->back->dri_image == NULL) {606/* If our DRIImage implementation does not support607* createImageWithModifiers, then fall back to the old createImage,608* and hope it allocates an image which is acceptable to the winsys.609*/610dri2_surf->back->dri_image =611loader_dri_create_image(dri2_dpy->dri_screen, dri2_dpy->image,612dri2_surf->base.Width,613dri2_surf->base.Height,614dri_image_format,615dri2_dpy->is_different_gpu ? 0 : use_flags,616modifiers, num_modifiers, NULL);617618dri2_surf->back->age = 0;619}620if (dri2_surf->back->dri_image == NULL)621return -1;622623dri2_surf->back->locked = true;624625return 0;626}627628629static void630back_bo_to_dri_buffer(struct dri2_egl_surface *dri2_surf, __DRIbuffer *buffer)631{632struct dri2_egl_display *dri2_dpy =633dri2_egl_display(dri2_surf->base.Resource.Display);634__DRIimage *image;635int name, pitch;636637image = dri2_surf->back->dri_image;638639dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);640dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &pitch);641642buffer->attachment = __DRI_BUFFER_BACK_LEFT;643buffer->name = name;644buffer->pitch = pitch;645buffer->cpp = 4;646buffer->flags = 0;647}648649static int650update_buffers(struct dri2_egl_surface *dri2_surf)651{652struct dri2_egl_display *dri2_dpy =653dri2_egl_display(dri2_surf->base.Resource.Display);654655if (dri2_surf->wl_win &&656(dri2_surf->base.Width != dri2_surf->wl_win->width ||657dri2_surf->base.Height != dri2_surf->wl_win->height)) {658659dri2_surf->base.Width = dri2_surf->wl_win->width;660dri2_surf->base.Height = dri2_surf->wl_win->height;661dri2_surf->dx = dri2_surf->wl_win->dx;662dri2_surf->dy = dri2_surf->wl_win->dy;663}664665if (dri2_surf->wl_win &&666(dri2_surf->base.Width != dri2_surf->wl_win->attached_width ||667dri2_surf->base.Height != dri2_surf->wl_win->attached_height)) {668dri2_wl_release_buffers(dri2_surf);669}670671if (get_back_bo(dri2_surf) < 0) {672_eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");673return -1;674}675676/* If we have an extra unlocked buffer at this point, we had to do triple677* buffering for a while, but now can go back to just double buffering.678* That means we can free any unlocked buffer now. */679for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {680if (!dri2_surf->color_buffers[i].locked &&681dri2_surf->color_buffers[i].wl_buffer) {682wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);683dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].dri_image);684if (dri2_dpy->is_different_gpu)685dri2_dpy->image->destroyImage(dri2_surf->color_buffers[i].linear_copy);686dri2_surf->color_buffers[i].wl_buffer = NULL;687dri2_surf->color_buffers[i].dri_image = NULL;688dri2_surf->color_buffers[i].linear_copy = NULL;689}690}691692return 0;693}694695static int696update_buffers_if_needed(struct dri2_egl_surface *dri2_surf)697{698if (dri2_surf->back != NULL)699return 0;700701return update_buffers(dri2_surf);702}703704static __DRIbuffer *705dri2_wl_get_buffers_with_format(__DRIdrawable * driDrawable,706int *width, int *height,707unsigned int *attachments, int count,708int *out_count, void *loaderPrivate)709{710struct dri2_egl_surface *dri2_surf = loaderPrivate;711int i, j;712713if (update_buffers(dri2_surf) < 0)714return NULL;715716for (i = 0, j = 0; i < 2 * count; i += 2, j++) {717__DRIbuffer *local;718719switch (attachments[i]) {720case __DRI_BUFFER_BACK_LEFT:721back_bo_to_dri_buffer(dri2_surf, &dri2_surf->buffers[j]);722break;723default:724local = dri2_egl_surface_alloc_local_buffer(dri2_surf, attachments[i],725attachments[i + 1]);726727if (!local) {728_eglError(EGL_BAD_ALLOC, "failed to allocate local buffer");729return NULL;730}731dri2_surf->buffers[j] = *local;732break;733}734}735736*out_count = j;737if (j == 0)738return NULL;739740*width = dri2_surf->base.Width;741*height = dri2_surf->base.Height;742743return dri2_surf->buffers;744}745746static __DRIbuffer *747dri2_wl_get_buffers(__DRIdrawable * driDrawable,748int *width, int *height,749unsigned int *attachments, int count,750int *out_count, void *loaderPrivate)751{752struct dri2_egl_surface *dri2_surf = loaderPrivate;753unsigned int *attachments_with_format;754__DRIbuffer *buffer;755int visual_idx = dri2_wl_visual_idx_from_fourcc(dri2_surf->format);756757if (visual_idx == -1)758return NULL;759760attachments_with_format = calloc(count, 2 * sizeof(unsigned int));761if (!attachments_with_format) {762*out_count = 0;763return NULL;764}765766for (int i = 0; i < count; ++i) {767attachments_with_format[2*i] = attachments[i];768attachments_with_format[2*i + 1] = dri2_wl_visuals[visual_idx].bpp;769}770771buffer =772dri2_wl_get_buffers_with_format(driDrawable,773width, height,774attachments_with_format, count,775out_count, loaderPrivate);776777free(attachments_with_format);778779return buffer;780}781782static int783image_get_buffers(__DRIdrawable *driDrawable,784unsigned int format,785uint32_t *stamp,786void *loaderPrivate,787uint32_t buffer_mask,788struct __DRIimageList *buffers)789{790struct dri2_egl_surface *dri2_surf = loaderPrivate;791792if (update_buffers(dri2_surf) < 0)793return 0;794795buffers->image_mask = __DRI_IMAGE_BUFFER_BACK;796buffers->back = dri2_surf->back->dri_image;797798return 1;799}800801static void802dri2_wl_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)803{804(void) driDrawable;805(void) loaderPrivate;806}807808static unsigned809dri2_wl_get_capability(void *loaderPrivate, enum dri_loader_cap cap)810{811switch (cap) {812case DRI_LOADER_CAP_FP16:813return 1;814default:815return 0;816}817}818819static const __DRIdri2LoaderExtension dri2_loader_extension = {820.base = { __DRI_DRI2_LOADER, 4 },821822.getBuffers = dri2_wl_get_buffers,823.flushFrontBuffer = dri2_wl_flush_front_buffer,824.getBuffersWithFormat = dri2_wl_get_buffers_with_format,825.getCapability = dri2_wl_get_capability,826};827828static const __DRIimageLoaderExtension image_loader_extension = {829.base = { __DRI_IMAGE_LOADER, 2 },830831.getBuffers = image_get_buffers,832.flushFrontBuffer = dri2_wl_flush_front_buffer,833.getCapability = dri2_wl_get_capability,834};835836static void837wayland_throttle_callback(void *data,838struct wl_callback *callback,839uint32_t time)840{841struct dri2_egl_surface *dri2_surf = data;842843dri2_surf->throttle_callback = NULL;844wl_callback_destroy(callback);845}846847static const struct wl_callback_listener throttle_listener = {848.done = wayland_throttle_callback849};850851static EGLBoolean852get_fourcc(struct dri2_egl_display *dri2_dpy,853__DRIimage *image, int *fourcc)854{855EGLBoolean query;856int dri_format;857int visual_idx;858859query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FOURCC,860fourcc);861if (query)862return true;863864query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT,865&dri_format);866if (!query)867return false;868869visual_idx = dri2_wl_visual_idx_from_dri_image_format(dri_format);870if (visual_idx == -1)871return false;872873*fourcc = dri2_wl_visuals[visual_idx].wl_drm_format;874return true;875}876877static struct wl_buffer *878create_wl_buffer(struct dri2_egl_display *dri2_dpy,879struct dri2_egl_surface *dri2_surf,880__DRIimage *image)881{882struct wl_buffer *ret;883EGLBoolean query;884int width, height, fourcc, num_planes;885uint64_t modifier = DRM_FORMAT_MOD_INVALID;886887query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_WIDTH, &width);888query &= dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_HEIGHT,889&height);890query &= get_fourcc(dri2_dpy, image, &fourcc);891if (!query)892return NULL;893894query = dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NUM_PLANES,895&num_planes);896if (!query)897num_planes = 1;898899if (dri2_dpy->image->base.version >= 15) {900int mod_hi, mod_lo;901902query = dri2_dpy->image->queryImage(image,903__DRI_IMAGE_ATTRIB_MODIFIER_UPPER,904&mod_hi);905query &= dri2_dpy->image->queryImage(image,906__DRI_IMAGE_ATTRIB_MODIFIER_LOWER,907&mod_lo);908if (query) {909modifier = combine_u32_into_u64(mod_hi, mod_lo);910}911}912913bool supported_modifier = false;914bool mod_invalid_supported = false;915int visual_idx = dri2_wl_visual_idx_from_fourcc(fourcc);916assert(visual_idx != -1);917918uint64_t *mod;919u_vector_foreach(mod, &dri2_dpy->wl_modifiers[visual_idx]) {920if (*mod == DRM_FORMAT_MOD_INVALID) {921mod_invalid_supported = true;922}923if (*mod == modifier) {924supported_modifier = true;925break;926}927}928if (!supported_modifier && mod_invalid_supported) {929/* If the server has advertised DRM_FORMAT_MOD_INVALID then we trust930* that the client has allocated the buffer with the right implicit931* modifier for the format, even though it's allocated a buffer the932* server hasn't explicitly claimed to support. */933modifier = DRM_FORMAT_MOD_INVALID;934supported_modifier = true;935}936937if (dri2_dpy->wl_dmabuf && supported_modifier) {938struct zwp_linux_buffer_params_v1 *params;939int i;940941/* We don't need a wrapper for wl_dmabuf objects, because we have to942* create the intermediate params object; we can set the queue on this,943* and the wl_buffer inherits it race-free. */944params = zwp_linux_dmabuf_v1_create_params(dri2_dpy->wl_dmabuf);945if (dri2_surf)946wl_proxy_set_queue((struct wl_proxy *) params, dri2_surf->wl_queue);947948for (i = 0; i < num_planes; i++) {949__DRIimage *p_image;950int stride, offset;951int fd = -1;952953p_image = dri2_dpy->image->fromPlanar(image, i, NULL);954if (!p_image) {955assert(i == 0);956p_image = image;957}958959query = dri2_dpy->image->queryImage(p_image,960__DRI_IMAGE_ATTRIB_FD,961&fd);962query &= dri2_dpy->image->queryImage(p_image,963__DRI_IMAGE_ATTRIB_STRIDE,964&stride);965query &= dri2_dpy->image->queryImage(p_image,966__DRI_IMAGE_ATTRIB_OFFSET,967&offset);968if (image != p_image)969dri2_dpy->image->destroyImage(p_image);970971if (!query) {972if (fd >= 0)973close(fd);974zwp_linux_buffer_params_v1_destroy(params);975return NULL;976}977978zwp_linux_buffer_params_v1_add(params, fd, i, offset, stride,979modifier >> 32, modifier & 0xffffffff);980close(fd);981}982983ret = zwp_linux_buffer_params_v1_create_immed(params, width, height,984fourcc, 0);985zwp_linux_buffer_params_v1_destroy(params);986} else if (dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME) {987struct wl_drm *wl_drm =988dri2_surf ? dri2_surf->wl_drm_wrapper : dri2_dpy->wl_drm;989int fd, stride;990991if (num_planes > 1)992return NULL;993994dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd);995dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);996ret = wl_drm_create_prime_buffer(wl_drm, fd, width, height, fourcc, 0,997stride, 0, 0, 0, 0);998close(fd);999} else {1000struct wl_drm *wl_drm =1001dri2_surf ? dri2_surf->wl_drm_wrapper : dri2_dpy->wl_drm;1002int name, stride;10031004if (num_planes > 1)1005return NULL;10061007dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_NAME, &name);1008dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride);1009ret = wl_drm_create_buffer(wl_drm, name, width, height, stride, fourcc);1010}10111012return ret;1013}10141015static EGLBoolean1016try_damage_buffer(struct dri2_egl_surface *dri2_surf,1017const EGLint *rects,1018EGLint n_rects)1019{1020if (wl_proxy_get_version((struct wl_proxy *) dri2_surf->wl_surface_wrapper)1021< WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION)1022return EGL_FALSE;10231024for (int i = 0; i < n_rects; i++) {1025const int *rect = &rects[i * 4];10261027wl_surface_damage_buffer(dri2_surf->wl_surface_wrapper,1028rect[0],1029dri2_surf->base.Height - rect[1] - rect[3],1030rect[2], rect[3]);1031}1032return EGL_TRUE;1033}10341035/**1036* Called via eglSwapBuffers(), drv->SwapBuffers().1037*/1038static EGLBoolean1039dri2_wl_swap_buffers_with_damage(_EGLDisplay *disp,1040_EGLSurface *draw,1041const EGLint *rects,1042EGLint n_rects)1043{1044struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);1045struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);10461047if (!dri2_surf->wl_win)1048return _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_swap_buffers");10491050while (dri2_surf->throttle_callback != NULL)1051if (wl_display_dispatch_queue(dri2_dpy->wl_dpy,1052dri2_surf->wl_queue) == -1)1053return -1;10541055for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++)1056if (dri2_surf->color_buffers[i].age > 0)1057dri2_surf->color_buffers[i].age++;10581059/* Make sure we have a back buffer in case we're swapping without ever1060* rendering. */1061if (update_buffers_if_needed(dri2_surf) < 0)1062return _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers");10631064if (draw->SwapInterval > 0) {1065dri2_surf->throttle_callback =1066wl_surface_frame(dri2_surf->wl_surface_wrapper);1067wl_callback_add_listener(dri2_surf->throttle_callback,1068&throttle_listener, dri2_surf);1069}10701071dri2_surf->back->age = 1;1072dri2_surf->current = dri2_surf->back;1073dri2_surf->back = NULL;10741075if (!dri2_surf->current->wl_buffer) {1076__DRIimage *image;10771078if (dri2_dpy->is_different_gpu)1079image = dri2_surf->current->linear_copy;1080else1081image = dri2_surf->current->dri_image;10821083dri2_surf->current->wl_buffer =1084create_wl_buffer(dri2_dpy, dri2_surf, image);10851086dri2_surf->current->wl_release = false;10871088wl_buffer_add_listener(dri2_surf->current->wl_buffer,1089&wl_buffer_listener, dri2_surf);1090}10911092wl_surface_attach(dri2_surf->wl_surface_wrapper,1093dri2_surf->current->wl_buffer,1094dri2_surf->dx, dri2_surf->dy);10951096dri2_surf->wl_win->attached_width = dri2_surf->base.Width;1097dri2_surf->wl_win->attached_height = dri2_surf->base.Height;1098/* reset resize growing parameters */1099dri2_surf->dx = 0;1100dri2_surf->dy = 0;11011102/* If the compositor doesn't support damage_buffer, we deliberately1103* ignore the damage region and post maximum damage, due to1104* https://bugs.freedesktop.org/78190 */1105if (!n_rects || !try_damage_buffer(dri2_surf, rects, n_rects))1106wl_surface_damage(dri2_surf->wl_surface_wrapper,11070, 0, INT32_MAX, INT32_MAX);11081109if (dri2_dpy->is_different_gpu) {1110_EGLContext *ctx = _eglGetCurrentContext();1111struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);1112dri2_dpy->image->blitImage(dri2_ctx->dri_context,1113dri2_surf->current->linear_copy,1114dri2_surf->current->dri_image,11150, 0, dri2_surf->base.Width,1116dri2_surf->base.Height,11170, 0, dri2_surf->base.Width,1118dri2_surf->base.Height, 0);1119}11201121dri2_flush_drawable_for_swapbuffers(disp, draw);1122dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);11231124wl_surface_commit(dri2_surf->wl_surface_wrapper);11251126/* If we're not waiting for a frame callback then we'll at least throttle1127* to a sync callback so that we always give a chance for the compositor to1128* handle the commit and send a release event before checking for a free1129* buffer */1130if (dri2_surf->throttle_callback == NULL) {1131dri2_surf->throttle_callback = wl_display_sync(dri2_surf->wl_dpy_wrapper);1132wl_callback_add_listener(dri2_surf->throttle_callback,1133&throttle_listener, dri2_surf);1134}11351136wl_display_flush(dri2_dpy->wl_dpy);11371138return EGL_TRUE;1139}11401141static EGLint1142dri2_wl_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surface)1143{1144struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);11451146if (update_buffers_if_needed(dri2_surf) < 0) {1147_eglError(EGL_BAD_ALLOC, "dri2_query_buffer_age");1148return -1;1149}11501151return dri2_surf->back->age;1152}11531154static EGLBoolean1155dri2_wl_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)1156{1157return dri2_wl_swap_buffers_with_damage(disp, draw, NULL, 0);1158}11591160static struct wl_buffer *1161dri2_wl_create_wayland_buffer_from_image(_EGLDisplay *disp, _EGLImage *img)1162{1163struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);1164struct dri2_egl_image *dri2_img = dri2_egl_image(img);1165__DRIimage *image = dri2_img->dri_image;1166struct wl_buffer *buffer;1167int format, visual_idx;11681169/* Check the upstream display supports this buffer's format. */1170dri2_dpy->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &format);1171visual_idx = dri2_wl_visual_idx_from_dri_image_format(format);1172if (visual_idx == -1)1173goto bad_format;11741175if (!BITSET_TEST(dri2_dpy->formats, visual_idx))1176goto bad_format;11771178buffer = create_wl_buffer(dri2_dpy, NULL, image);11791180/* The buffer object will have been created with our internal event queue1181* because it is using wl_dmabuf/wl_drm as a proxy factory. We want the1182* buffer to be used by the application so we'll reset it to the display's1183* default event queue. This isn't actually racy, as the only event the1184* buffer can get is a buffer release, which doesn't happen with an explicit1185* attach. */1186if (buffer)1187wl_proxy_set_queue((struct wl_proxy *) buffer, NULL);11881189return buffer;11901191bad_format:1192_eglError(EGL_BAD_MATCH, "unsupported image format");1193return NULL;1194}11951196static int1197dri2_wl_authenticate(_EGLDisplay *disp, uint32_t id)1198{1199struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);1200int ret = 0;12011202if (dri2_dpy->is_render_node) {1203_eglLog(_EGL_WARNING, "wayland-egl: client asks server to "1204"authenticate for render-nodes");1205return 0;1206}1207dri2_dpy->authenticated = false;12081209wl_drm_authenticate(dri2_dpy->wl_drm, id);1210if (roundtrip(dri2_dpy) < 0)1211ret = -1;12121213if (!dri2_dpy->authenticated)1214ret = -1;12151216/* reset authenticated */1217dri2_dpy->authenticated = true;12181219return ret;1220}12211222static void1223drm_handle_device(void *data, struct wl_drm *drm, const char *device)1224{1225struct dri2_egl_display *dri2_dpy = data;1226drm_magic_t magic;12271228dri2_dpy->device_name = strdup(device);1229if (!dri2_dpy->device_name)1230return;12311232dri2_dpy->fd = loader_open_device(dri2_dpy->device_name);1233if (dri2_dpy->fd == -1) {1234_eglLog(_EGL_WARNING, "wayland-egl: could not open %s (%s)",1235dri2_dpy->device_name, strerror(errno));1236free(dri2_dpy->device_name);1237dri2_dpy->device_name = NULL;1238return;1239}12401241if (drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER) {1242dri2_dpy->authenticated = true;1243} else {1244if (drmGetMagic(dri2_dpy->fd, &magic)) {1245close(dri2_dpy->fd);1246dri2_dpy->fd = -1;1247free(dri2_dpy->device_name);1248dri2_dpy->device_name = NULL;1249_eglLog(_EGL_WARNING, "wayland-egl: drmGetMagic failed");1250return;1251}1252wl_drm_authenticate(dri2_dpy->wl_drm, magic);1253}1254}12551256static void1257drm_handle_format(void *data, struct wl_drm *drm, uint32_t format)1258{1259struct dri2_egl_display *dri2_dpy = data;1260int visual_idx = dri2_wl_visual_idx_from_fourcc(format);12611262if (visual_idx == -1)1263return;12641265BITSET_SET(dri2_dpy->formats, visual_idx);1266}12671268static void1269drm_handle_capabilities(void *data, struct wl_drm *drm, uint32_t value)1270{1271struct dri2_egl_display *dri2_dpy = data;12721273dri2_dpy->capabilities = value;1274}12751276static void1277drm_handle_authenticated(void *data, struct wl_drm *drm)1278{1279struct dri2_egl_display *dri2_dpy = data;12801281dri2_dpy->authenticated = true;1282}12831284static const struct wl_drm_listener drm_listener = {1285.device = drm_handle_device,1286.format = drm_handle_format,1287.authenticated = drm_handle_authenticated,1288.capabilities = drm_handle_capabilities1289};12901291static void1292dmabuf_ignore_format(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,1293uint32_t format)1294{1295/* formats are implicitly advertised by the 'modifier' event, so ignore */1296}12971298static void1299dmabuf_handle_modifier(void *data, struct zwp_linux_dmabuf_v1 *dmabuf,1300uint32_t format, uint32_t modifier_hi,1301uint32_t modifier_lo)1302{1303struct dri2_egl_display *dri2_dpy = data;1304int visual_idx = dri2_wl_visual_idx_from_fourcc(format);1305uint64_t *mod;13061307if (visual_idx == -1)1308return;13091310BITSET_SET(dri2_dpy->formats, visual_idx);13111312mod = u_vector_add(&dri2_dpy->wl_modifiers[visual_idx]);1313*mod = combine_u32_into_u64(modifier_hi, modifier_lo);1314}13151316static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {1317.format = dmabuf_ignore_format,1318.modifier = dmabuf_handle_modifier,1319};13201321static void1322registry_handle_global_drm(void *data, struct wl_registry *registry,1323uint32_t name, const char *interface,1324uint32_t version)1325{1326struct dri2_egl_display *dri2_dpy = data;13271328if (strcmp(interface, "wl_drm") == 0) {1329dri2_dpy->wl_drm =1330wl_registry_bind(registry, name, &wl_drm_interface, MIN2(version, 2));1331wl_drm_add_listener(dri2_dpy->wl_drm, &drm_listener, dri2_dpy);1332} else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0 && version >= 3) {1333dri2_dpy->wl_dmabuf =1334wl_registry_bind(registry, name, &zwp_linux_dmabuf_v1_interface,1335MIN2(version, 3));1336zwp_linux_dmabuf_v1_add_listener(dri2_dpy->wl_dmabuf, &dmabuf_listener,1337dri2_dpy);1338}1339}13401341static void1342registry_handle_global_remove(void *data, struct wl_registry *registry,1343uint32_t name)1344{1345}13461347static const struct wl_registry_listener registry_listener_drm = {1348.global = registry_handle_global_drm,1349.global_remove = registry_handle_global_remove1350};13511352static void1353dri2_wl_setup_swap_interval(_EGLDisplay *disp)1354{1355/* We can't use values greater than 1 on Wayland because we are using the1356* frame callback to synchronise the frame and the only way we be sure to1357* get a frame callback is to attach a new buffer. Therefore we can't just1358* sit drawing nothing to wait until the next ānā frame callbacks */13591360dri2_setup_swap_interval(disp, 1);1361}13621363static const struct dri2_egl_display_vtbl dri2_wl_display_vtbl = {1364.authenticate = dri2_wl_authenticate,1365.create_window_surface = dri2_wl_create_window_surface,1366.create_pixmap_surface = dri2_wl_create_pixmap_surface,1367.destroy_surface = dri2_wl_destroy_surface,1368.create_image = dri2_create_image_khr,1369.swap_buffers = dri2_wl_swap_buffers,1370.swap_buffers_with_damage = dri2_wl_swap_buffers_with_damage,1371.query_buffer_age = dri2_wl_query_buffer_age,1372.create_wayland_buffer_from_image = dri2_wl_create_wayland_buffer_from_image,1373.get_dri_drawable = dri2_surface_get_dri_drawable,1374};13751376static const __DRIextension *dri2_loader_extensions[] = {1377&dri2_loader_extension.base,1378&image_loader_extension.base,1379&image_lookup_extension.base,1380&use_invalidate.base,1381NULL,1382};13831384static const __DRIextension *image_loader_extensions[] = {1385&image_loader_extension.base,1386&image_lookup_extension.base,1387&use_invalidate.base,1388NULL,1389};13901391static EGLBoolean1392dri2_wl_add_configs_for_visuals(_EGLDisplay *disp)1393{1394struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);1395unsigned int format_count[ARRAY_SIZE(dri2_wl_visuals)] = { 0 };1396unsigned int count = 0;1397bool assigned;13981399for (unsigned i = 0; dri2_dpy->driver_configs[i]; i++) {1400assigned = false;14011402for (unsigned j = 0; j < ARRAY_SIZE(dri2_wl_visuals); j++) {1403struct dri2_egl_config *dri2_conf;14041405if (!BITSET_TEST(dri2_dpy->formats, j))1406continue;14071408dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i],1409count + 1, EGL_WINDOW_BIT, NULL, dri2_wl_visuals[j].rgba_shifts, dri2_wl_visuals[j].rgba_sizes);1410if (dri2_conf) {1411if (dri2_conf->base.ConfigID == count + 1)1412count++;1413format_count[j]++;1414assigned = true;1415}1416}14171418if (!assigned && dri2_dpy->is_different_gpu) {1419struct dri2_egl_config *dri2_conf;1420int alt_dri_image_format, c, s;14211422/* No match for config. Try if we can blitImage convert to a visual */1423c = dri2_wl_visual_idx_from_config(dri2_dpy,1424dri2_dpy->driver_configs[i]);14251426if (c == -1)1427continue;14281429/* Find optimal target visual for blitImage conversion, if any. */1430alt_dri_image_format = dri2_wl_visuals[c].alt_dri_image_format;1431s = dri2_wl_visual_idx_from_dri_image_format(alt_dri_image_format);14321433if (s == -1 || !BITSET_TEST(dri2_dpy->formats, s))1434continue;14351436/* Visual s works for the Wayland server, and c can be converted into s1437* by our client gpu during PRIME blitImage conversion to a linear1438* wl_buffer, so add visual c as supported by the client renderer.1439*/1440dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i],1441count + 1, EGL_WINDOW_BIT, NULL,1442dri2_wl_visuals[c].rgba_shifts,1443dri2_wl_visuals[c].rgba_sizes);1444if (dri2_conf) {1445if (dri2_conf->base.ConfigID == count + 1)1446count++;1447format_count[c]++;1448if (format_count[c] == 1)1449_eglLog(_EGL_DEBUG, "Client format %s to server format %s via "1450"PRIME blitImage.", dri2_wl_visuals[c].format_name,1451dri2_wl_visuals[s].format_name);1452}1453}1454}14551456for (unsigned i = 0; i < ARRAY_SIZE(format_count); i++) {1457if (!format_count[i]) {1458_eglLog(_EGL_DEBUG, "No DRI config supports native format %s",1459dri2_wl_visuals[i].format_name);1460}1461}14621463return (count != 0);1464}14651466static EGLBoolean1467dri2_initialize_wayland_drm(_EGLDisplay *disp)1468{1469_EGLDevice *dev;1470struct dri2_egl_display *dri2_dpy;14711472dri2_dpy = calloc(1, sizeof *dri2_dpy);1473if (!dri2_dpy)1474return _eglError(EGL_BAD_ALLOC, "eglInitialize");14751476dri2_dpy->fd = -1;1477disp->DriverData = (void *) dri2_dpy;1478if (disp->PlatformDisplay == NULL) {1479dri2_dpy->wl_dpy = wl_display_connect(NULL);1480if (dri2_dpy->wl_dpy == NULL)1481goto cleanup;1482dri2_dpy->own_device = true;1483} else {1484dri2_dpy->wl_dpy = disp->PlatformDisplay;1485}14861487dri2_dpy->wl_modifiers =1488calloc(ARRAY_SIZE(dri2_wl_visuals), sizeof(*dri2_dpy->wl_modifiers));1489if (!dri2_dpy->wl_modifiers)1490goto cleanup;1491for (int i = 0; i < ARRAY_SIZE(dri2_wl_visuals); i++) {1492if (!u_vector_init(&dri2_dpy->wl_modifiers[i], sizeof(uint64_t), 32))1493goto cleanup;1494}14951496dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);14971498dri2_dpy->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);1499if (dri2_dpy->wl_dpy_wrapper == NULL)1500goto cleanup;15011502wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_dpy_wrapper,1503dri2_dpy->wl_queue);15041505if (dri2_dpy->own_device)1506wl_display_dispatch_pending(dri2_dpy->wl_dpy);15071508dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy_wrapper);1509wl_registry_add_listener(dri2_dpy->wl_registry,1510®istry_listener_drm, dri2_dpy);1511if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_drm == NULL)1512goto cleanup;15131514if (roundtrip(dri2_dpy) < 0 || dri2_dpy->fd == -1)1515goto cleanup;15161517if (!dri2_dpy->authenticated &&1518(roundtrip(dri2_dpy) < 0 || !dri2_dpy->authenticated))1519goto cleanup;15201521dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd,1522&dri2_dpy->is_different_gpu);1523dev = _eglAddDevice(dri2_dpy->fd, false);1524if (!dev) {1525_eglError(EGL_NOT_INITIALIZED, "DRI2: failed to find EGLDevice");1526goto cleanup;1527}15281529disp->Device = dev;15301531if (dri2_dpy->is_different_gpu) {1532free(dri2_dpy->device_name);1533dri2_dpy->device_name = loader_get_device_name_for_fd(dri2_dpy->fd);1534if (!dri2_dpy->device_name) {1535_eglError(EGL_BAD_ALLOC, "wayland-egl: failed to get device name "1536"for requested GPU");1537goto cleanup;1538}1539}15401541/* we have to do the check now, because loader_get_user_preferred_fd1542* will return a render-node when the requested gpu is different1543* to the server, but also if the client asks for the same gpu than1544* the server by requesting its pci-id */1545dri2_dpy->is_render_node = drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER;15461547dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);1548if (dri2_dpy->driver_name == NULL) {1549_eglError(EGL_BAD_ALLOC, "DRI2: failed to get driver name");1550goto cleanup;1551}15521553/* render nodes cannot use Gem names, and thus do not support1554* the __DRI_DRI2_LOADER extension */1555if (!dri2_dpy->is_render_node) {1556dri2_dpy->loader_extensions = dri2_loader_extensions;1557if (!dri2_load_driver(disp)) {1558_eglError(EGL_BAD_ALLOC, "DRI2: failed to load driver");1559goto cleanup;1560}1561} else {1562dri2_dpy->loader_extensions = image_loader_extensions;1563if (!dri2_load_driver_dri3(disp)) {1564_eglError(EGL_BAD_ALLOC, "DRI3: failed to load driver");1565goto cleanup;1566}1567}15681569if (!dri2_create_screen(disp))1570goto cleanup;15711572if (!dri2_setup_extensions(disp))1573goto cleanup;15741575dri2_setup_screen(disp);15761577dri2_wl_setup_swap_interval(disp);15781579/* To use Prime, we must have _DRI_IMAGE v7 at least.1580* createImageFromFds support indicates that Prime export/import1581* is supported by the driver. Fall back to1582* gem names if we don't have Prime support. */15831584if (dri2_dpy->image->base.version < 7 ||1585dri2_dpy->image->createImageFromFds == NULL)1586dri2_dpy->capabilities &= ~WL_DRM_CAPABILITY_PRIME;15871588/* We cannot use Gem names with render-nodes, only prime fds (dma-buf).1589* The server needs to accept them */1590if (dri2_dpy->is_render_node &&1591!(dri2_dpy->capabilities & WL_DRM_CAPABILITY_PRIME)) {1592_eglLog(_EGL_WARNING, "wayland-egl: display is not render-node capable");1593goto cleanup;1594}15951596if (dri2_dpy->is_different_gpu &&1597(dri2_dpy->image->base.version < 9 ||1598dri2_dpy->image->blitImage == NULL)) {1599_eglLog(_EGL_WARNING, "wayland-egl: Different GPU selected, but the "1600"Image extension in the driver is not "1601"compatible. Version 9 or later and blitImage() "1602"are required");1603goto cleanup;1604}16051606if (!dri2_wl_add_configs_for_visuals(disp)) {1607_eglError(EGL_NOT_INITIALIZED, "DRI2: failed to add configs");1608goto cleanup;1609}16101611dri2_set_WL_bind_wayland_display(disp);1612/* When cannot convert EGLImage to wl_buffer when on a different gpu,1613* because the buffer of the EGLImage has likely a tiling mode the server1614* gpu won't support. These is no way to check for now. Thus do not support the1615* extension */1616if (!dri2_dpy->is_different_gpu)1617disp->Extensions.WL_create_wayland_buffer_from_image = EGL_TRUE;16181619disp->Extensions.EXT_buffer_age = EGL_TRUE;16201621disp->Extensions.EXT_swap_buffers_with_damage = EGL_TRUE;16221623/* Fill vtbl last to prevent accidentally calling virtual function during1624* initialization.1625*/1626dri2_dpy->vtbl = &dri2_wl_display_vtbl;16271628return EGL_TRUE;16291630cleanup:1631dri2_display_destroy(disp);1632return EGL_FALSE;1633}16341635static int1636dri2_wl_swrast_get_stride_for_format(int format, int w)1637{1638int visual_idx = dri2_wl_visual_idx_from_shm_format(format);16391640assume(visual_idx != -1);16411642return w * (dri2_wl_visuals[visual_idx].bpp / 8);1643}16441645static EGLBoolean1646dri2_wl_swrast_allocate_buffer(struct dri2_egl_surface *dri2_surf,1647int format, int w, int h,1648void **data, int *size,1649struct wl_buffer **buffer)1650{1651struct dri2_egl_display *dri2_dpy =1652dri2_egl_display(dri2_surf->base.Resource.Display);1653struct wl_shm_pool *pool;1654int fd, stride, size_map;1655void *data_map;16561657stride = dri2_wl_swrast_get_stride_for_format(format, w);1658size_map = h * stride;16591660/* Create a shareable buffer */1661fd = os_create_anonymous_file(size_map, NULL);1662if (fd < 0)1663return EGL_FALSE;16641665data_map = mmap(NULL, size_map, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);1666if (data_map == MAP_FAILED) {1667close(fd);1668return EGL_FALSE;1669}16701671/* Share it in a wl_buffer */1672pool = wl_shm_create_pool(dri2_dpy->wl_shm, fd, size_map);1673wl_proxy_set_queue((struct wl_proxy *)pool, dri2_surf->wl_queue);1674*buffer = wl_shm_pool_create_buffer(pool, 0, w, h, stride, format);1675wl_shm_pool_destroy(pool);1676close(fd);16771678*data = data_map;1679*size = size_map;1680return EGL_TRUE;1681}16821683static int1684swrast_update_buffers(struct dri2_egl_surface *dri2_surf)1685{1686struct dri2_egl_display *dri2_dpy =1687dri2_egl_display(dri2_surf->base.Resource.Display);16881689/* we need to do the following operations only once per frame */1690if (dri2_surf->back)1691return 0;16921693if (dri2_surf->wl_win &&1694(dri2_surf->base.Width != dri2_surf->wl_win->width ||1695dri2_surf->base.Height != dri2_surf->wl_win->height)) {16961697dri2_wl_release_buffers(dri2_surf);16981699dri2_surf->base.Width = dri2_surf->wl_win->width;1700dri2_surf->base.Height = dri2_surf->wl_win->height;1701dri2_surf->dx = dri2_surf->wl_win->dx;1702dri2_surf->dy = dri2_surf->wl_win->dy;1703dri2_surf->current = NULL;1704}17051706/* find back buffer */17071708/* There might be a buffer release already queued that wasn't processed */1709wl_display_dispatch_queue_pending(dri2_dpy->wl_dpy, dri2_surf->wl_queue);17101711/* try get free buffer already created */1712for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {1713if (!dri2_surf->color_buffers[i].locked &&1714dri2_surf->color_buffers[i].wl_buffer) {1715dri2_surf->back = &dri2_surf->color_buffers[i];1716break;1717}1718}17191720/* else choose any another free location */1721if (!dri2_surf->back) {1722for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {1723if (!dri2_surf->color_buffers[i].locked) {1724dri2_surf->back = &dri2_surf->color_buffers[i];1725if (!dri2_wl_swrast_allocate_buffer(dri2_surf,1726dri2_surf->format,1727dri2_surf->base.Width,1728dri2_surf->base.Height,1729&dri2_surf->back->data,1730&dri2_surf->back->data_size,1731&dri2_surf->back->wl_buffer)) {1732_eglError(EGL_BAD_ALLOC, "failed to allocate color buffer");1733return -1;1734}1735wl_buffer_add_listener(dri2_surf->back->wl_buffer,1736&wl_buffer_listener, dri2_surf);1737break;1738}1739}1740}17411742if (!dri2_surf->back) {1743_eglError(EGL_BAD_ALLOC, "failed to find free buffer");1744return -1;1745}17461747dri2_surf->back->locked = true;17481749/* If we have an extra unlocked buffer at this point, we had to do triple1750* buffering for a while, but now can go back to just double buffering.1751* That means we can free any unlocked buffer now. */1752for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {1753if (!dri2_surf->color_buffers[i].locked &&1754dri2_surf->color_buffers[i].wl_buffer) {1755wl_buffer_destroy(dri2_surf->color_buffers[i].wl_buffer);1756munmap(dri2_surf->color_buffers[i].data,1757dri2_surf->color_buffers[i].data_size);1758dri2_surf->color_buffers[i].wl_buffer = NULL;1759dri2_surf->color_buffers[i].data = NULL;1760}1761}17621763return 0;1764}17651766static void*1767dri2_wl_swrast_get_frontbuffer_data(struct dri2_egl_surface *dri2_surf)1768{1769/* if there has been a resize: */1770if (!dri2_surf->current)1771return NULL;17721773return dri2_surf->current->data;1774}17751776static void*1777dri2_wl_swrast_get_backbuffer_data(struct dri2_egl_surface *dri2_surf)1778{1779assert(dri2_surf->back);1780return dri2_surf->back->data;1781}17821783static void1784dri2_wl_swrast_commit_backbuffer(struct dri2_egl_surface *dri2_surf)1785{1786struct dri2_egl_display *dri2_dpy = dri2_egl_display(dri2_surf->base.Resource.Display);17871788while (dri2_surf->throttle_callback != NULL)1789if (wl_display_dispatch_queue(dri2_dpy->wl_dpy,1790dri2_surf->wl_queue) == -1)1791return;17921793if (dri2_surf->base.SwapInterval > 0) {1794dri2_surf->throttle_callback =1795wl_surface_frame(dri2_surf->wl_surface_wrapper);1796wl_callback_add_listener(dri2_surf->throttle_callback,1797&throttle_listener, dri2_surf);1798}17991800dri2_surf->current = dri2_surf->back;1801dri2_surf->back = NULL;18021803wl_surface_attach(dri2_surf->wl_surface_wrapper,1804dri2_surf->current->wl_buffer,1805dri2_surf->dx, dri2_surf->dy);18061807dri2_surf->wl_win->attached_width = dri2_surf->base.Width;1808dri2_surf->wl_win->attached_height = dri2_surf->base.Height;1809/* reset resize growing parameters */1810dri2_surf->dx = 0;1811dri2_surf->dy = 0;18121813wl_surface_damage(dri2_surf->wl_surface_wrapper,18140, 0, INT32_MAX, INT32_MAX);1815wl_surface_commit(dri2_surf->wl_surface_wrapper);18161817/* If we're not waiting for a frame callback then we'll at least throttle1818* to a sync callback so that we always give a chance for the compositor to1819* handle the commit and send a release event before checking for a free1820* buffer */1821if (dri2_surf->throttle_callback == NULL) {1822dri2_surf->throttle_callback = wl_display_sync(dri2_surf->wl_dpy_wrapper);1823wl_callback_add_listener(dri2_surf->throttle_callback,1824&throttle_listener, dri2_surf);1825}18261827wl_display_flush(dri2_dpy->wl_dpy);1828}18291830static void1831dri2_wl_swrast_get_drawable_info(__DRIdrawable * draw,1832int *x, int *y, int *w, int *h,1833void *loaderPrivate)1834{1835struct dri2_egl_surface *dri2_surf = loaderPrivate;18361837(void) swrast_update_buffers(dri2_surf);1838*x = 0;1839*y = 0;1840*w = dri2_surf->base.Width;1841*h = dri2_surf->base.Height;1842}18431844static void1845dri2_wl_swrast_get_image(__DRIdrawable * read,1846int x, int y, int w, int h,1847char *data, void *loaderPrivate)1848{1849struct dri2_egl_surface *dri2_surf = loaderPrivate;1850int copy_width = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w);1851int x_offset = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, x);1852int src_stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, dri2_surf->base.Width);1853int dst_stride = copy_width;1854char *src, *dst;18551856src = dri2_wl_swrast_get_frontbuffer_data(dri2_surf);1857if (!src) {1858memset(data, 0, copy_width * h);1859return;1860}18611862assert(data != src);1863assert(copy_width <= src_stride);18641865src += x_offset;1866src += y * src_stride;1867dst = data;18681869if (copy_width > src_stride-x_offset)1870copy_width = src_stride-x_offset;1871if (h > dri2_surf->base.Height-y)1872h = dri2_surf->base.Height-y;18731874for (; h>0; h--) {1875memcpy(dst, src, copy_width);1876src += src_stride;1877dst += dst_stride;1878}1879}18801881static void1882dri2_wl_swrast_put_image2(__DRIdrawable * draw, int op,1883int x, int y, int w, int h, int stride,1884char *data, void *loaderPrivate)1885{1886struct dri2_egl_surface *dri2_surf = loaderPrivate;1887int copy_width = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w);1888int dst_stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, dri2_surf->base.Width);1889int x_offset = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, x);1890char *src, *dst;18911892assert(copy_width <= stride);18931894(void) swrast_update_buffers(dri2_surf);1895dst = dri2_wl_swrast_get_backbuffer_data(dri2_surf);18961897/* partial copy, copy old content */1898if (copy_width < dst_stride)1899dri2_wl_swrast_get_image(draw, 0, 0,1900dri2_surf->base.Width, dri2_surf->base.Height,1901dst, loaderPrivate);19021903dst += x_offset;1904dst += y * dst_stride;19051906src = data;19071908/* drivers expect we do these checks (and some rely on it) */1909if (copy_width > dst_stride-x_offset)1910copy_width = dst_stride-x_offset;1911if (h > dri2_surf->base.Height-y)1912h = dri2_surf->base.Height-y;19131914for (; h>0; h--) {1915memcpy(dst, src, copy_width);1916src += stride;1917dst += dst_stride;1918}1919dri2_wl_swrast_commit_backbuffer(dri2_surf);1920}19211922static void1923dri2_wl_swrast_put_image(__DRIdrawable * draw, int op,1924int x, int y, int w, int h,1925char *data, void *loaderPrivate)1926{1927struct dri2_egl_surface *dri2_surf = loaderPrivate;1928int stride;19291930stride = dri2_wl_swrast_get_stride_for_format(dri2_surf->format, w);1931dri2_wl_swrast_put_image2(draw, op, x, y, w, h,1932stride, data, loaderPrivate);1933}19341935static EGLBoolean1936dri2_wl_swrast_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)1937{1938struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);1939struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);19401941if (!dri2_surf->wl_win)1942return _eglError(EGL_BAD_NATIVE_WINDOW, "dri2_swap_buffers");19431944dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);1945return EGL_TRUE;1946}19471948static void1949shm_handle_format(void *data, struct wl_shm *shm, uint32_t format)1950{1951struct dri2_egl_display *dri2_dpy = data;1952int visual_idx = dri2_wl_visual_idx_from_shm_format(format);19531954if (visual_idx == -1)1955return;19561957BITSET_SET(dri2_dpy->formats, visual_idx);1958}19591960static const struct wl_shm_listener shm_listener = {1961.format = shm_handle_format1962};19631964static void1965registry_handle_global_swrast(void *data, struct wl_registry *registry,1966uint32_t name, const char *interface,1967uint32_t version)1968{1969struct dri2_egl_display *dri2_dpy = data;19701971if (strcmp(interface, "wl_shm") == 0) {1972dri2_dpy->wl_shm =1973wl_registry_bind(registry, name, &wl_shm_interface, 1);1974wl_shm_add_listener(dri2_dpy->wl_shm, &shm_listener, dri2_dpy);1975}1976}19771978static const struct wl_registry_listener registry_listener_swrast = {1979.global = registry_handle_global_swrast,1980.global_remove = registry_handle_global_remove1981};19821983static const struct dri2_egl_display_vtbl dri2_wl_swrast_display_vtbl = {1984.authenticate = NULL,1985.create_window_surface = dri2_wl_create_window_surface,1986.create_pixmap_surface = dri2_wl_create_pixmap_surface,1987.destroy_surface = dri2_wl_destroy_surface,1988.create_image = dri2_create_image_khr,1989.swap_buffers = dri2_wl_swrast_swap_buffers,1990.get_dri_drawable = dri2_surface_get_dri_drawable,1991};19921993static const __DRIswrastLoaderExtension swrast_loader_extension = {1994.base = { __DRI_SWRAST_LOADER, 2 },19951996.getDrawableInfo = dri2_wl_swrast_get_drawable_info,1997.putImage = dri2_wl_swrast_put_image,1998.getImage = dri2_wl_swrast_get_image,1999.putImage2 = dri2_wl_swrast_put_image2,2000};20012002static const __DRIextension *swrast_loader_extensions[] = {2003&swrast_loader_extension.base,2004&image_lookup_extension.base,2005NULL,2006};20072008static EGLBoolean2009dri2_initialize_wayland_swrast(_EGLDisplay *disp)2010{2011_EGLDevice *dev;2012struct dri2_egl_display *dri2_dpy;20132014dri2_dpy = calloc(1, sizeof *dri2_dpy);2015if (!dri2_dpy)2016return _eglError(EGL_BAD_ALLOC, "eglInitialize");20172018dri2_dpy->fd = -1;2019disp->DriverData = (void *) dri2_dpy;2020if (disp->PlatformDisplay == NULL) {2021dri2_dpy->wl_dpy = wl_display_connect(NULL);2022if (dri2_dpy->wl_dpy == NULL)2023goto cleanup;2024dri2_dpy->own_device = true;2025} else {2026dri2_dpy->wl_dpy = disp->PlatformDisplay;2027}20282029dev = _eglAddDevice(dri2_dpy->fd, true);2030if (!dev) {2031_eglError(EGL_NOT_INITIALIZED, "DRI2: failed to find EGLDevice");2032goto cleanup;2033}20342035disp->Device = dev;20362037dri2_dpy->wl_queue = wl_display_create_queue(dri2_dpy->wl_dpy);20382039dri2_dpy->wl_dpy_wrapper = wl_proxy_create_wrapper(dri2_dpy->wl_dpy);2040if (dri2_dpy->wl_dpy_wrapper == NULL)2041goto cleanup;20422043wl_proxy_set_queue((struct wl_proxy *) dri2_dpy->wl_dpy_wrapper,2044dri2_dpy->wl_queue);20452046if (dri2_dpy->own_device)2047wl_display_dispatch_pending(dri2_dpy->wl_dpy);20482049dri2_dpy->wl_registry = wl_display_get_registry(dri2_dpy->wl_dpy_wrapper);2050wl_registry_add_listener(dri2_dpy->wl_registry,2051®istry_listener_swrast, dri2_dpy);20522053if (roundtrip(dri2_dpy) < 0 || dri2_dpy->wl_shm == NULL)2054goto cleanup;20552056if (roundtrip(dri2_dpy) < 0 || !BITSET_TEST_RANGE(dri2_dpy->formats,20570, EGL_DRI2_MAX_FORMATS))2058goto cleanup;20592060dri2_dpy->driver_name = strdup("swrast");2061if (!dri2_load_driver_swrast(disp))2062goto cleanup;20632064dri2_dpy->loader_extensions = swrast_loader_extensions;20652066if (!dri2_create_screen(disp))2067goto cleanup;20682069if (!dri2_setup_extensions(disp))2070goto cleanup;20712072dri2_setup_screen(disp);20732074dri2_wl_setup_swap_interval(disp);20752076if (!dri2_wl_add_configs_for_visuals(disp)) {2077_eglError(EGL_NOT_INITIALIZED, "DRI2: failed to add configs");2078goto cleanup;2079}20802081/* Fill vtbl last to prevent accidentally calling virtual function during2082* initialization.2083*/2084dri2_dpy->vtbl = &dri2_wl_swrast_display_vtbl;20852086return EGL_TRUE;20872088cleanup:2089dri2_display_destroy(disp);2090return EGL_FALSE;2091}20922093EGLBoolean2094dri2_initialize_wayland(_EGLDisplay *disp)2095{2096if (disp->Options.ForceSoftware)2097return dri2_initialize_wayland_swrast(disp);2098else2099return dri2_initialize_wayland_drm(disp);2100}21012102void2103dri2_teardown_wayland(struct dri2_egl_display *dri2_dpy)2104{2105if (dri2_dpy->wl_drm)2106wl_drm_destroy(dri2_dpy->wl_drm);2107if (dri2_dpy->wl_dmabuf)2108zwp_linux_dmabuf_v1_destroy(dri2_dpy->wl_dmabuf);2109if (dri2_dpy->wl_shm)2110wl_shm_destroy(dri2_dpy->wl_shm);2111if (dri2_dpy->wl_registry)2112wl_registry_destroy(dri2_dpy->wl_registry);2113if (dri2_dpy->wl_queue)2114wl_event_queue_destroy(dri2_dpy->wl_queue);2115if (dri2_dpy->wl_dpy_wrapper)2116wl_proxy_wrapper_destroy(dri2_dpy->wl_dpy_wrapper);21172118for (int i = 0; dri2_dpy->wl_modifiers && i < ARRAY_SIZE(dri2_wl_visuals); i++)2119u_vector_finish(&dri2_dpy->wl_modifiers[i]);2120free(dri2_dpy->wl_modifiers);21212122if (dri2_dpy->own_device)2123wl_display_disconnect(dri2_dpy->wl_dpy);2124}212521262127