Path: blob/21.2-virgl/src/egl/drivers/dri2/platform_x11_dri3.c
4570 views
/*1* Copyright © 2015 Boyan Ding2*3* Permission to use, copy, modify, distribute, and sell this software and its4* documentation for any purpose is hereby granted without fee, provided that5* the above copyright notice appear in all copies and that both that copyright6* notice and this permission notice appear in supporting documentation, and7* that the name of the copyright holders not be used in advertising or8* publicity pertaining to distribution of the software without specific,9* written prior permission. The copyright holders make no representations10* about the suitability of this software for any purpose. It is provided "as11* is" without express or implied warranty.12*13* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,14* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO15* EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR16* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,17* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER18* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE19* OF THIS SOFTWARE.20*/2122#include <stdbool.h>23#include <stdlib.h>24#include <string.h>25#include <unistd.h>2627#include <xcb/xcb.h>28#include <xcb/dri3.h>29#include <xcb/present.h>30#include <xcb/xfixes.h>3132#include <xf86drm.h>33#include "util/macros.h"3435#include "egl_dri2.h"36#include "platform_x11_dri3.h"3738#include "loader.h"39#include "loader_dri3_helper.h"4041static struct dri3_egl_surface *42loader_drawable_to_egl_surface(struct loader_dri3_drawable *draw) {43size_t offset = offsetof(struct dri3_egl_surface, loader_drawable);44return (struct dri3_egl_surface *)(((void*) draw) - offset);45}4647static void48egl_dri3_set_drawable_size(struct loader_dri3_drawable *draw,49int width, int height)50{51struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);5253dri3_surf->surf.base.Width = width;54dri3_surf->surf.base.Height = height;55}5657static bool58egl_dri3_in_current_context(struct loader_dri3_drawable *draw)59{60struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);61_EGLContext *ctx = _eglGetCurrentContext();6263return ctx->Resource.Display == dri3_surf->surf.base.Resource.Display;64}6566static __DRIcontext *67egl_dri3_get_dri_context(struct loader_dri3_drawable *draw)68{69_EGLContext *ctx = _eglGetCurrentContext();70struct dri2_egl_context *dri2_ctx;71if (!ctx)72return NULL;73dri2_ctx = dri2_egl_context(ctx);74return dri2_ctx->dri_context;75}7677static __DRIscreen *78egl_dri3_get_dri_screen(void)79{80_EGLContext *ctx = _eglGetCurrentContext();81struct dri2_egl_context *dri2_ctx;82if (!ctx)83return NULL;84dri2_ctx = dri2_egl_context(ctx);85return dri2_egl_display(dri2_ctx->base.Resource.Display)->dri_screen;86}8788static void89egl_dri3_flush_drawable(struct loader_dri3_drawable *draw, unsigned flags)90{91struct dri3_egl_surface *dri3_surf = loader_drawable_to_egl_surface(draw);92_EGLDisplay *disp = dri3_surf->surf.base.Resource.Display;9394dri2_flush_drawable_for_swapbuffers(disp, &dri3_surf->surf.base);95}9697static const struct loader_dri3_vtable egl_dri3_vtable = {98.set_drawable_size = egl_dri3_set_drawable_size,99.in_current_context = egl_dri3_in_current_context,100.get_dri_context = egl_dri3_get_dri_context,101.get_dri_screen = egl_dri3_get_dri_screen,102.flush_drawable = egl_dri3_flush_drawable,103.show_fps = NULL,104};105106static EGLBoolean107dri3_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)108{109struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);110struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);111xcb_drawable_t drawable = dri3_surf->loader_drawable.drawable;112113loader_dri3_drawable_fini(&dri3_surf->loader_drawable);114115if (surf->Type == EGL_PBUFFER_BIT)116xcb_free_pixmap (dri2_dpy->conn, drawable);117118dri2_fini_surface(surf);119free(surf);120121return EGL_TRUE;122}123124static EGLBoolean125dri3_set_swap_interval(_EGLDisplay *disp, _EGLSurface *surf, EGLint interval)126{127struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);128129dri3_surf->surf.base.SwapInterval = interval;130loader_dri3_set_swap_interval(&dri3_surf->loader_drawable, interval);131132return EGL_TRUE;133}134135static _EGLSurface *136dri3_create_surface(_EGLDisplay *disp, EGLint type, _EGLConfig *conf,137void *native_surface, const EGLint *attrib_list)138{139struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);140struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);141struct dri3_egl_surface *dri3_surf;142const __DRIconfig *dri_config;143xcb_drawable_t drawable;144145dri3_surf = calloc(1, sizeof *dri3_surf);146if (!dri3_surf) {147_eglError(EGL_BAD_ALLOC, "dri3_create_surface");148return NULL;149}150151if (!dri2_init_surface(&dri3_surf->surf.base, disp, type, conf,152attrib_list, false, native_surface))153goto cleanup_surf;154155if (type == EGL_PBUFFER_BIT) {156drawable = xcb_generate_id(dri2_dpy->conn);157xcb_create_pixmap(dri2_dpy->conn, conf->BufferSize,158drawable, dri2_dpy->screen->root,159dri3_surf->surf.base.Width, dri3_surf->surf.base.Height);160} else {161STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_surface));162drawable = (uintptr_t) native_surface;163}164165dri_config = dri2_get_dri_config(dri2_conf, type,166dri3_surf->surf.base.GLColorspace);167168if (!dri_config) {169_eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration");170goto cleanup_pixmap;171}172173if (loader_dri3_drawable_init(dri2_dpy->conn, drawable,174dri2_dpy->dri_screen,175dri2_dpy->is_different_gpu,176dri2_dpy->multibuffers_available,177dri_config,178&dri2_dpy->loader_dri3_ext,179&egl_dri3_vtable,180&dri3_surf->loader_drawable)) {181_eglError(EGL_BAD_ALLOC, "dri3_surface_create");182goto cleanup_pixmap;183}184185if (dri3_surf->surf.base.ProtectedContent &&186dri2_dpy->is_different_gpu) {187_eglError(EGL_BAD_ALLOC, "dri3_surface_create");188goto cleanup_pixmap;189}190191dri3_surf->loader_drawable.is_protected_content =192dri3_surf->surf.base.ProtectedContent;193194return &dri3_surf->surf.base;195196cleanup_pixmap:197if (type == EGL_PBUFFER_BIT)198xcb_free_pixmap(dri2_dpy->conn, drawable);199cleanup_surf:200free(dri3_surf);201202return NULL;203}204205static int206dri3_authenticate(_EGLDisplay *disp, uint32_t id)207{208#ifdef HAVE_WAYLAND_PLATFORM209struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);210211if (dri2_dpy->device_name) {212_eglLog(_EGL_WARNING,213"Wayland client render node authentication is unnecessary");214return 0;215}216217_eglLog(_EGL_WARNING,218"Wayland client primary node authentication isn't supported");219#endif220221return -1;222}223224/**225* Called via eglCreateWindowSurface(), drv->CreateWindowSurface().226*/227static _EGLSurface *228dri3_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf,229void *native_window, const EGLint *attrib_list)230{231struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);232_EGLSurface *surf;233234surf = dri3_create_surface(disp, EGL_WINDOW_BIT, conf,235native_window, attrib_list);236if (surf != NULL)237dri3_set_swap_interval(disp, surf, dri2_dpy->default_swap_interval);238239return surf;240}241242static _EGLSurface *243dri3_create_pixmap_surface(_EGLDisplay *disp, _EGLConfig *conf,244void *native_pixmap, const EGLint *attrib_list)245{246return dri3_create_surface(disp, EGL_PIXMAP_BIT, conf,247native_pixmap, attrib_list);248}249250static _EGLSurface *251dri3_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf,252const EGLint *attrib_list)253{254return dri3_create_surface(disp, EGL_PBUFFER_BIT, conf,255NULL, attrib_list);256}257258static EGLBoolean259dri3_get_sync_values(_EGLDisplay *display, _EGLSurface *surface,260EGLuint64KHR *ust, EGLuint64KHR *msc,261EGLuint64KHR *sbc)262{263struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surface);264265return loader_dri3_wait_for_msc(&dri3_surf->loader_drawable, 0, 0, 0,266(int64_t *) ust, (int64_t *) msc,267(int64_t *) sbc) ? EGL_TRUE : EGL_FALSE;268}269270static _EGLImage *271dri3_create_image_khr_pixmap(_EGLDisplay *disp, _EGLContext *ctx,272EGLClientBuffer buffer, const EGLint *attr_list)273{274struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);275struct dri2_egl_image *dri2_img;276xcb_drawable_t drawable;277xcb_dri3_buffer_from_pixmap_cookie_t bp_cookie;278xcb_dri3_buffer_from_pixmap_reply_t *bp_reply;279unsigned int format;280281drawable = (xcb_drawable_t) (uintptr_t) buffer;282bp_cookie = xcb_dri3_buffer_from_pixmap(dri2_dpy->conn, drawable);283bp_reply = xcb_dri3_buffer_from_pixmap_reply(dri2_dpy->conn,284bp_cookie, NULL);285if (!bp_reply) {286_eglError(EGL_BAD_ALLOC, "xcb_dri3_buffer_from_pixmap");287return NULL;288}289290format = dri2_format_for_depth(dri2_dpy, bp_reply->depth);291if (format == __DRI_IMAGE_FORMAT_NONE) {292_eglError(EGL_BAD_PARAMETER,293"dri3_create_image_khr: unsupported pixmap depth");294free(bp_reply);295return EGL_NO_IMAGE_KHR;296}297298dri2_img = malloc(sizeof *dri2_img);299if (!dri2_img) {300_eglError(EGL_BAD_ALLOC, "dri3_create_image_khr");301free(bp_reply);302return EGL_NO_IMAGE_KHR;303}304305_eglInitImage(&dri2_img->base, disp);306307dri2_img->dri_image = loader_dri3_create_image(dri2_dpy->conn,308bp_reply,309format,310dri2_dpy->dri_screen,311dri2_dpy->image,312dri2_img);313314free(bp_reply);315316return &dri2_img->base;317}318319#ifdef HAVE_DRI3_MODIFIERS320static _EGLImage *321dri3_create_image_khr_pixmap_from_buffers(_EGLDisplay *disp, _EGLContext *ctx,322EGLClientBuffer buffer,323const EGLint *attr_list)324{325struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);326struct dri2_egl_image *dri2_img;327xcb_dri3_buffers_from_pixmap_cookie_t bp_cookie;328xcb_dri3_buffers_from_pixmap_reply_t *bp_reply;329xcb_drawable_t drawable;330unsigned int format;331332drawable = (xcb_drawable_t) (uintptr_t) buffer;333bp_cookie = xcb_dri3_buffers_from_pixmap(dri2_dpy->conn, drawable);334bp_reply = xcb_dri3_buffers_from_pixmap_reply(dri2_dpy->conn,335bp_cookie, NULL);336337if (!bp_reply) {338_eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");339return EGL_NO_IMAGE_KHR;340}341342format = dri2_format_for_depth(dri2_dpy, bp_reply->depth);343if (format == __DRI_IMAGE_FORMAT_NONE) {344_eglError(EGL_BAD_PARAMETER,345"dri3_create_image_khr: unsupported pixmap depth");346free(bp_reply);347return EGL_NO_IMAGE_KHR;348}349350dri2_img = malloc(sizeof *dri2_img);351if (!dri2_img) {352_eglError(EGL_BAD_ALLOC, "dri3_create_image_khr");353free(bp_reply);354return EGL_NO_IMAGE_KHR;355}356357_eglInitImage(&dri2_img->base, disp);358359dri2_img->dri_image = loader_dri3_create_image_from_buffers(dri2_dpy->conn,360bp_reply,361format,362dri2_dpy->dri_screen,363dri2_dpy->image,364dri2_img);365free(bp_reply);366367if (!dri2_img->dri_image) {368_eglError(EGL_BAD_ATTRIBUTE, "dri3_create_image_khr");369free(dri2_img);370return EGL_NO_IMAGE_KHR;371}372373return &dri2_img->base;374}375#endif376377static _EGLImage *378dri3_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target,379EGLClientBuffer buffer, const EGLint *attr_list)380{381#ifdef HAVE_DRI3_MODIFIERS382struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);383#endif384385switch (target) {386case EGL_NATIVE_PIXMAP_KHR:387#ifdef HAVE_DRI3_MODIFIERS388if (dri2_dpy->multibuffers_available)389return dri3_create_image_khr_pixmap_from_buffers(disp, ctx, buffer,390attr_list);391#endif392return dri3_create_image_khr_pixmap(disp, ctx, buffer, attr_list);393default:394return dri2_create_image_khr(disp, ctx, target, buffer, attr_list);395}396}397398/**399* Called by the driver when it needs to update the real front buffer with the400* contents of its fake front buffer.401*/402static void403dri3_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate)404{405struct loader_dri3_drawable *draw = loaderPrivate;406(void) driDrawable;407408/* There does not seem to be any kind of consensus on whether we should409* support front-buffer rendering or not:410* http://lists.freedesktop.org/archives/mesa-dev/2013-June/040129.html411*/412if (!draw->is_pixmap)413_eglLog(_EGL_WARNING, "FIXME: egl/x11 doesn't support front buffer rendering.");414}415416const __DRIimageLoaderExtension dri3_image_loader_extension = {417.base = { __DRI_IMAGE_LOADER, 1 },418419.getBuffers = loader_dri3_get_buffers,420.flushFrontBuffer = dri3_flush_front_buffer,421};422423static EGLBoolean424dri3_swap_buffers_with_damage(_EGLDisplay *disp, _EGLSurface *draw,425const EGLint *rects, EGLint n_rects)426{427struct dri3_egl_surface *dri3_surf = dri3_egl_surface(draw);428429return loader_dri3_swap_buffers_msc(&dri3_surf->loader_drawable,4300, 0, 0, 0,431rects, n_rects,432draw->SwapBehavior == EGL_BUFFER_PRESERVED) != -1;433}434435static EGLBoolean436dri3_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)437{438return dri3_swap_buffers_with_damage(disp, draw, NULL, 0);439}440441static EGLBoolean442dri3_copy_buffers(_EGLDisplay *disp, _EGLSurface *surf, void *native_pixmap_target)443{444struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);445xcb_pixmap_t target;446447STATIC_ASSERT(sizeof(uintptr_t) == sizeof(native_pixmap_target));448target = (uintptr_t) native_pixmap_target;449450loader_dri3_copy_drawable(&dri3_surf->loader_drawable, target,451dri3_surf->loader_drawable.drawable);452453return EGL_TRUE;454}455456static int457dri3_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surf)458{459struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);460461return loader_dri3_query_buffer_age(&dri3_surf->loader_drawable);462}463464static EGLBoolean465dri3_query_surface(_EGLDisplay *disp, _EGLSurface *surf,466EGLint attribute, EGLint *value)467{468struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);469470switch (attribute) {471case EGL_WIDTH:472case EGL_HEIGHT:473loader_dri3_update_drawable_geometry(&dri3_surf->loader_drawable);474break;475default:476break;477}478479return _eglQuerySurface(disp, surf, attribute, value);480}481482static __DRIdrawable *483dri3_get_dri_drawable(_EGLSurface *surf)484{485struct dri3_egl_surface *dri3_surf = dri3_egl_surface(surf);486487return dri3_surf->loader_drawable.dri_drawable;488}489490static void491dri3_close_screen_notify(_EGLDisplay *disp)492{493struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);494495loader_dri3_close_screen(dri2_dpy->dri_screen);496}497498struct dri2_egl_display_vtbl dri3_x11_display_vtbl = {499.authenticate = dri3_authenticate,500.create_window_surface = dri3_create_window_surface,501.create_pixmap_surface = dri3_create_pixmap_surface,502.create_pbuffer_surface = dri3_create_pbuffer_surface,503.destroy_surface = dri3_destroy_surface,504.create_image = dri3_create_image_khr,505.swap_interval = dri3_set_swap_interval,506.swap_buffers = dri3_swap_buffers,507.swap_buffers_with_damage = dri3_swap_buffers_with_damage,508.copy_buffers = dri3_copy_buffers,509.query_buffer_age = dri3_query_buffer_age,510.query_surface = dri3_query_surface,511.get_sync_values = dri3_get_sync_values,512.get_dri_drawable = dri3_get_dri_drawable,513.close_screen_notify = dri3_close_screen_notify,514};515516/* Only request versions of these protocols which we actually support. */517#define DRI3_SUPPORTED_MAJOR 1518#define PRESENT_SUPPORTED_MAJOR 1519520#ifdef HAVE_DRI3_MODIFIERS521#define DRI3_SUPPORTED_MINOR 2522#define PRESENT_SUPPORTED_MINOR 2523#else524#define PRESENT_SUPPORTED_MINOR 0525#define DRI3_SUPPORTED_MINOR 0526#endif527528EGLBoolean529dri3_x11_connect(struct dri2_egl_display *dri2_dpy)530{531xcb_dri3_query_version_reply_t *dri3_query;532xcb_dri3_query_version_cookie_t dri3_query_cookie;533xcb_present_query_version_reply_t *present_query;534xcb_present_query_version_cookie_t present_query_cookie;535xcb_xfixes_query_version_reply_t *xfixes_query;536xcb_xfixes_query_version_cookie_t xfixes_query_cookie;537xcb_generic_error_t *error;538const xcb_query_extension_reply_t *extension;539540xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_dri3_id);541xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_present_id);542xcb_prefetch_extension_data (dri2_dpy->conn, &xcb_xfixes_id);543544extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_dri3_id);545if (!(extension && extension->present))546return EGL_FALSE;547548extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_present_id);549if (!(extension && extension->present))550return EGL_FALSE;551552extension = xcb_get_extension_data(dri2_dpy->conn, &xcb_xfixes_id);553if (!(extension && extension->present))554return EGL_FALSE;555556dri3_query_cookie = xcb_dri3_query_version(dri2_dpy->conn,557DRI3_SUPPORTED_MAJOR,558DRI3_SUPPORTED_MINOR);559560present_query_cookie = xcb_present_query_version(dri2_dpy->conn,561PRESENT_SUPPORTED_MAJOR,562PRESENT_SUPPORTED_MINOR);563564xfixes_query_cookie = xcb_xfixes_query_version(dri2_dpy->conn,565XCB_XFIXES_MAJOR_VERSION,566XCB_XFIXES_MINOR_VERSION);567568dri3_query =569xcb_dri3_query_version_reply(dri2_dpy->conn, dri3_query_cookie, &error);570if (dri3_query == NULL || error != NULL) {571_eglLog(_EGL_WARNING, "DRI3: failed to query the version");572free(dri3_query);573free(error);574return EGL_FALSE;575}576577dri2_dpy->dri3_major_version = dri3_query->major_version;578dri2_dpy->dri3_minor_version = dri3_query->minor_version;579free(dri3_query);580581present_query =582xcb_present_query_version_reply(dri2_dpy->conn,583present_query_cookie, &error);584if (present_query == NULL || error != NULL) {585_eglLog(_EGL_WARNING, "DRI3: failed to query Present version");586free(present_query);587free(error);588return EGL_FALSE;589}590591dri2_dpy->present_major_version = present_query->major_version;592dri2_dpy->present_minor_version = present_query->minor_version;593free(present_query);594595xfixes_query =596xcb_xfixes_query_version_reply(dri2_dpy->conn,597xfixes_query_cookie, &error);598if (xfixes_query == NULL || error != NULL ||599xfixes_query->major_version < 2) {600_eglLog(_EGL_WARNING, "DRI3: failed to query xfixes version");601free(error);602free(xfixes_query);603return EGL_FALSE;604}605free(xfixes_query);606607dri2_dpy->fd = loader_dri3_open(dri2_dpy->conn, dri2_dpy->screen->root, 0);608if (dri2_dpy->fd < 0) {609int conn_error = xcb_connection_has_error(dri2_dpy->conn);610_eglLog(_EGL_WARNING, "DRI3: Screen seems not DRI3 capable");611612if (conn_error)613_eglLog(_EGL_WARNING, "DRI3: Failed to initialize");614615return EGL_FALSE;616}617618dri2_dpy->fd = loader_get_user_preferred_fd(dri2_dpy->fd, &dri2_dpy->is_different_gpu);619620dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);621if (!dri2_dpy->driver_name) {622_eglLog(_EGL_WARNING, "DRI3: No driver found");623close(dri2_dpy->fd);624return EGL_FALSE;625}626627#ifdef HAVE_WAYLAND_PLATFORM628/* Only try to get a render device name since dri3 doesn't provide a629* mechanism for authenticating client opened device node fds. If this630* fails then don't advertise the extension. */631dri2_dpy->device_name = drmGetRenderDeviceNameFromFd(dri2_dpy->fd);632#endif633634return EGL_TRUE;635}636637638