13464ebd5Sriastradh/* 23464ebd5Sriastradh * Copyright © 2011 Intel Corporation 33464ebd5Sriastradh * 43464ebd5Sriastradh * Permission is hereby granted, free of charge, to any person obtaining a 53464ebd5Sriastradh * copy of this software and associated documentation files (the "Software"), 63464ebd5Sriastradh * to deal in the Software without restriction, including without limitation 73464ebd5Sriastradh * the rights to use, copy, modify, merge, publish, distribute, sublicense, 83464ebd5Sriastradh * and/or sell copies of the Software, and to permit persons to whom the 93464ebd5Sriastradh * Software is furnished to do so, subject to the following conditions: 103464ebd5Sriastradh * 113464ebd5Sriastradh * The above copyright notice and this permission notice (including the next 123464ebd5Sriastradh * paragraph) shall be included in all copies or substantial portions of the 133464ebd5Sriastradh * Software. 143464ebd5Sriastradh * 153464ebd5Sriastradh * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 163464ebd5Sriastradh * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 173464ebd5Sriastradh * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 183464ebd5Sriastradh * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 193464ebd5Sriastradh * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 203464ebd5Sriastradh * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 213464ebd5Sriastradh * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 223464ebd5Sriastradh * DEALINGS IN THE SOFTWARE. 233464ebd5Sriastradh * 243464ebd5Sriastradh * Authors: 253464ebd5Sriastradh * Benjamin Franzke <benjaminfranzke@googlemail.com> 263464ebd5Sriastradh */ 273464ebd5Sriastradh 283464ebd5Sriastradh#include <stdio.h> 293464ebd5Sriastradh#include <stdlib.h> 303464ebd5Sriastradh#include <stddef.h> 313464ebd5Sriastradh#include <stdint.h> 327e995a2eSmrg#include <stdbool.h> 333464ebd5Sriastradh#include <string.h> 34af69d88dSmrg#include <errno.h> 353464ebd5Sriastradh#include <limits.h> 367e995a2eSmrg#include <assert.h> 373464ebd5Sriastradh 383464ebd5Sriastradh#include <sys/types.h> 393464ebd5Sriastradh#include <unistd.h> 403464ebd5Sriastradh#include <dlfcn.h> 41af69d88dSmrg#include <xf86drm.h> 42d8407755Smaya#include "drm-uapi/drm_fourcc.h" 433464ebd5Sriastradh 443464ebd5Sriastradh#include <GL/gl.h> /* dri_interface needs GL types */ 453464ebd5Sriastradh#include <GL/internal/dri_interface.h> 463464ebd5Sriastradh 473464ebd5Sriastradh#include "gbm_driint.h" 483464ebd5Sriastradh 493464ebd5Sriastradh#include "gbmint.h" 501463c08dSmrg#include "loader_dri_helper.h" 51af69d88dSmrg#include "loader.h" 527e995a2eSmrg#include "util/debug.h" 537e995a2eSmrg#include "util/macros.h" 54af69d88dSmrg 55af69d88dSmrg/* For importing wl_buffer */ 56af69d88dSmrg#if HAVE_WAYLAND_PLATFORM 577e995a2eSmrg#include "wayland-drm.h" 587e995a2eSmrg#endif 597e995a2eSmrg 603464ebd5Sriastradhstatic __DRIimage * 613464ebd5Sriastradhdri_lookup_egl_image(__DRIscreen *screen, void *image, void *data) 623464ebd5Sriastradh{ 633464ebd5Sriastradh struct gbm_dri_device *dri = data; 643464ebd5Sriastradh 653464ebd5Sriastradh if (dri->lookup_image == NULL) 663464ebd5Sriastradh return NULL; 673464ebd5Sriastradh 683464ebd5Sriastradh return dri->lookup_image(screen, image, dri->lookup_user_data); 693464ebd5Sriastradh} 703464ebd5Sriastradh 711463c08dSmrgstatic GLboolean 721463c08dSmrgdri_validate_egl_image(void *image, void *data) 731463c08dSmrg{ 741463c08dSmrg struct gbm_dri_device *dri = data; 751463c08dSmrg 761463c08dSmrg if (dri->validate_image == NULL) 771463c08dSmrg return false; 781463c08dSmrg 791463c08dSmrg return dri->validate_image(image, dri->lookup_user_data); 801463c08dSmrg} 811463c08dSmrg 821463c08dSmrgstatic __DRIimage * 831463c08dSmrgdri_lookup_egl_image_validated(void *image, void *data) 841463c08dSmrg{ 851463c08dSmrg struct gbm_dri_device *dri = data; 861463c08dSmrg 871463c08dSmrg if (dri->lookup_image_validated == NULL) 881463c08dSmrg return NULL; 891463c08dSmrg 901463c08dSmrg return dri->lookup_image_validated(image, dri->lookup_user_data); 911463c08dSmrg} 921463c08dSmrg 93af69d88dSmrgstatic __DRIbuffer * 94af69d88dSmrgdri_get_buffers(__DRIdrawable * driDrawable, 95af69d88dSmrg int *width, int *height, 96af69d88dSmrg unsigned int *attachments, int count, 97af69d88dSmrg int *out_count, void *data) 98af69d88dSmrg{ 99af69d88dSmrg struct gbm_dri_surface *surf = data; 100af69d88dSmrg struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm); 101af69d88dSmrg 102af69d88dSmrg if (dri->get_buffers == NULL) 103af69d88dSmrg return NULL; 104af69d88dSmrg 105af69d88dSmrg return dri->get_buffers(driDrawable, width, height, attachments, 106af69d88dSmrg count, out_count, surf->dri_private); 107af69d88dSmrg} 108af69d88dSmrg 109af69d88dSmrgstatic void 110af69d88dSmrgdri_flush_front_buffer(__DRIdrawable * driDrawable, void *data) 111af69d88dSmrg{ 112af69d88dSmrg struct gbm_dri_surface *surf = data; 113af69d88dSmrg struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm); 114af69d88dSmrg 115af69d88dSmrg if (dri->flush_front_buffer != NULL) 116af69d88dSmrg dri->flush_front_buffer(driDrawable, surf->dri_private); 117af69d88dSmrg} 118af69d88dSmrg 119af69d88dSmrgstatic __DRIbuffer * 120af69d88dSmrgdri_get_buffers_with_format(__DRIdrawable * driDrawable, 121af69d88dSmrg int *width, int *height, 122af69d88dSmrg unsigned int *attachments, int count, 123af69d88dSmrg int *out_count, void *data) 124af69d88dSmrg{ 125af69d88dSmrg struct gbm_dri_surface *surf = data; 126af69d88dSmrg struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm); 127af69d88dSmrg 128af69d88dSmrg if (dri->get_buffers_with_format == NULL) 129af69d88dSmrg return NULL; 130af69d88dSmrg 131af69d88dSmrg return 132af69d88dSmrg dri->get_buffers_with_format(driDrawable, width, height, attachments, 133af69d88dSmrg count, out_count, surf->dri_private); 134af69d88dSmrg} 135af69d88dSmrg 1361463c08dSmrgstatic unsigned 1371463c08dSmrgdri_get_capability(void *loaderPrivate, enum dri_loader_cap cap) 1381463c08dSmrg{ 1391463c08dSmrg /* Note: loaderPrivate is _EGLDisplay* */ 1401463c08dSmrg switch (cap) { 1411463c08dSmrg case DRI_LOADER_CAP_FP16: 1421463c08dSmrg return 1; 1431463c08dSmrg default: 1441463c08dSmrg return 0; 1451463c08dSmrg } 1461463c08dSmrg} 1471463c08dSmrg 148af69d88dSmrgstatic int 149af69d88dSmrgimage_get_buffers(__DRIdrawable *driDrawable, 150af69d88dSmrg unsigned int format, 151af69d88dSmrg uint32_t *stamp, 152af69d88dSmrg void *loaderPrivate, 153af69d88dSmrg uint32_t buffer_mask, 154af69d88dSmrg struct __DRIimageList *buffers) 155af69d88dSmrg{ 156af69d88dSmrg struct gbm_dri_surface *surf = loaderPrivate; 157af69d88dSmrg struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm); 158af69d88dSmrg 159af69d88dSmrg if (dri->image_get_buffers == NULL) 160af69d88dSmrg return 0; 161af69d88dSmrg 162af69d88dSmrg return dri->image_get_buffers(driDrawable, format, stamp, 163af69d88dSmrg surf->dri_private, buffer_mask, buffers); 164af69d88dSmrg} 165af69d88dSmrg 166af69d88dSmrgstatic void 167af69d88dSmrgswrast_get_drawable_info(__DRIdrawable *driDrawable, 168af69d88dSmrg int *x, 169af69d88dSmrg int *y, 170af69d88dSmrg int *width, 171af69d88dSmrg int *height, 172af69d88dSmrg void *loaderPrivate) 173af69d88dSmrg{ 174af69d88dSmrg struct gbm_dri_surface *surf = loaderPrivate; 175af69d88dSmrg 176af69d88dSmrg *x = 0; 177af69d88dSmrg *y = 0; 1781463c08dSmrg *width = surf->base.v0.width; 1791463c08dSmrg *height = surf->base.v0.height; 180af69d88dSmrg} 181af69d88dSmrg 182af69d88dSmrgstatic void 183af69d88dSmrgswrast_put_image2(__DRIdrawable *driDrawable, 184af69d88dSmrg int op, 185af69d88dSmrg int x, 186af69d88dSmrg int y, 187af69d88dSmrg int width, 188af69d88dSmrg int height, 189af69d88dSmrg int stride, 190af69d88dSmrg char *data, 191af69d88dSmrg void *loaderPrivate) 192af69d88dSmrg{ 193af69d88dSmrg struct gbm_dri_surface *surf = loaderPrivate; 194af69d88dSmrg struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm); 195af69d88dSmrg 196af69d88dSmrg dri->swrast_put_image2(driDrawable, 197af69d88dSmrg op, x, y, 198af69d88dSmrg width, height, stride, 199af69d88dSmrg data, surf->dri_private); 200af69d88dSmrg} 201af69d88dSmrg 202af69d88dSmrgstatic void 203af69d88dSmrgswrast_put_image(__DRIdrawable *driDrawable, 204af69d88dSmrg int op, 205af69d88dSmrg int x, 206af69d88dSmrg int y, 207af69d88dSmrg int width, 208af69d88dSmrg int height, 209af69d88dSmrg char *data, 210af69d88dSmrg void *loaderPrivate) 211af69d88dSmrg{ 212382a3c73Schristos swrast_put_image2(driDrawable, op, x, y, width, height, 213d8407755Smaya width * 4, data, loaderPrivate); 214af69d88dSmrg} 215af69d88dSmrg 216af69d88dSmrgstatic void 217af69d88dSmrgswrast_get_image(__DRIdrawable *driDrawable, 218af69d88dSmrg int x, 219af69d88dSmrg int y, 220af69d88dSmrg int width, 221af69d88dSmrg int height, 222af69d88dSmrg char *data, 223af69d88dSmrg void *loaderPrivate) 224af69d88dSmrg{ 225af69d88dSmrg struct gbm_dri_surface *surf = loaderPrivate; 226af69d88dSmrg struct gbm_dri_device *dri = gbm_dri_device(surf->base.gbm); 227af69d88dSmrg 228af69d88dSmrg dri->swrast_get_image(driDrawable, 229af69d88dSmrg x, y, 230af69d88dSmrg width, height, 231af69d88dSmrg data, surf->dri_private); 232af69d88dSmrg} 233af69d88dSmrg 234af69d88dSmrgstatic const __DRIuseInvalidateExtension use_invalidate = { 235af69d88dSmrg .base = { __DRI_USE_INVALIDATE, 1 } 236af69d88dSmrg}; 237af69d88dSmrg 238af69d88dSmrgstatic const __DRIimageLookupExtension image_lookup_extension = { 2391463c08dSmrg .base = { __DRI_IMAGE_LOOKUP, 2 }, 240af69d88dSmrg 2411463c08dSmrg .lookupEGLImage = dri_lookup_egl_image, 2421463c08dSmrg .validateEGLImage = dri_validate_egl_image, 2431463c08dSmrg .lookupEGLImageValidated = dri_lookup_egl_image_validated, 244af69d88dSmrg}; 245af69d88dSmrg 246af69d88dSmrgstatic const __DRIdri2LoaderExtension dri2_loader_extension = { 2471463c08dSmrg .base = { __DRI_DRI2_LOADER, 4 }, 248af69d88dSmrg 249af69d88dSmrg .getBuffers = dri_get_buffers, 250af69d88dSmrg .flushFrontBuffer = dri_flush_front_buffer, 251af69d88dSmrg .getBuffersWithFormat = dri_get_buffers_with_format, 2521463c08dSmrg .getCapability = dri_get_capability, 2533464ebd5Sriastradh}; 2543464ebd5Sriastradh 255af69d88dSmrgstatic const __DRIimageLoaderExtension image_loader_extension = { 2561463c08dSmrg .base = { __DRI_IMAGE_LOADER, 2 }, 257af69d88dSmrg 258af69d88dSmrg .getBuffers = image_get_buffers, 259af69d88dSmrg .flushFrontBuffer = dri_flush_front_buffer, 2601463c08dSmrg .getCapability = dri_get_capability, 261af69d88dSmrg}; 262af69d88dSmrg 263af69d88dSmrgstatic const __DRIswrastLoaderExtension swrast_loader_extension = { 264af69d88dSmrg .base = { __DRI_SWRAST_LOADER, 2 }, 265af69d88dSmrg 266af69d88dSmrg .getDrawableInfo = swrast_get_drawable_info, 267af69d88dSmrg .putImage = swrast_put_image, 268af69d88dSmrg .getImage = swrast_get_image, 269af69d88dSmrg .putImage2 = swrast_put_image2 270af69d88dSmrg}; 271af69d88dSmrg 272af69d88dSmrgstatic const __DRIextension *gbm_dri_screen_extensions[] = { 273af69d88dSmrg &image_lookup_extension.base, 274af69d88dSmrg &use_invalidate.base, 275af69d88dSmrg &dri2_loader_extension.base, 276af69d88dSmrg &image_loader_extension.base, 277af69d88dSmrg &swrast_loader_extension.base, 278af69d88dSmrg NULL, 2793464ebd5Sriastradh}; 2803464ebd5Sriastradh 2813464ebd5Sriastradhstruct dri_extension_match { 2823464ebd5Sriastradh const char *name; 2833464ebd5Sriastradh int version; 2843464ebd5Sriastradh int offset; 2851463c08dSmrg bool optional; 2863464ebd5Sriastradh}; 2873464ebd5Sriastradh 2883464ebd5Sriastradhstatic struct dri_extension_match dri_core_extensions[] = { 2891463c08dSmrg { __DRI2_FLUSH, 1, offsetof(struct gbm_dri_device, flush), false }, 2901463c08dSmrg { __DRI_IMAGE, 1, offsetof(struct gbm_dri_device, image), false }, 2911463c08dSmrg { __DRI2_FENCE, 1, offsetof(struct gbm_dri_device, fence), true }, 2923464ebd5Sriastradh}; 2933464ebd5Sriastradh 2943464ebd5Sriastradhstatic struct dri_extension_match gbm_dri_device_extensions[] = { 2951463c08dSmrg { __DRI_CORE, 1, offsetof(struct gbm_dri_device, core), false }, 2961463c08dSmrg { __DRI_DRI2, 1, offsetof(struct gbm_dri_device, dri2), false }, 2973464ebd5Sriastradh}; 2983464ebd5Sriastradh 299af69d88dSmrgstatic struct dri_extension_match gbm_swrast_device_extensions[] = { 3001463c08dSmrg { __DRI_CORE, 1, offsetof(struct gbm_dri_device, core), false }, 3011463c08dSmrg { __DRI_SWRAST, 1, offsetof(struct gbm_dri_device, swrast), false }, 302af69d88dSmrg}; 303af69d88dSmrg 3041463c08dSmrgstatic bool 3053464ebd5Sriastradhdri_bind_extensions(struct gbm_dri_device *dri, 3061463c08dSmrg struct dri_extension_match *matches, size_t num_matches, 3073464ebd5Sriastradh const __DRIextension **extensions) 3083464ebd5Sriastradh{ 3091463c08dSmrg bool ret = true; 3103464ebd5Sriastradh void *field; 3113464ebd5Sriastradh 3121463c08dSmrg for (size_t i = 0; extensions[i]; i++) { 3131463c08dSmrg for (size_t j = 0; j < num_matches; j++) { 3143464ebd5Sriastradh if (strcmp(extensions[i]->name, matches[j].name) == 0 && 3153464ebd5Sriastradh extensions[i]->version >= matches[j].version) { 3163464ebd5Sriastradh field = ((char *) dri + matches[j].offset); 3173464ebd5Sriastradh *(const __DRIextension **) field = extensions[i]; 3183464ebd5Sriastradh } 3193464ebd5Sriastradh } 3203464ebd5Sriastradh } 3213464ebd5Sriastradh 3221463c08dSmrg for (size_t j = 0; j < num_matches; j++) { 3233464ebd5Sriastradh field = ((char *) dri + matches[j].offset); 3247e995a2eSmrg if ((*(const __DRIextension **) field == NULL) && !matches[j].optional) { 3251463c08dSmrg fprintf(stderr, "gbm: did not find extension %s version %d\n", 3261463c08dSmrg matches[j].name, matches[j].version); 3271463c08dSmrg ret = false; 3283464ebd5Sriastradh } 3293464ebd5Sriastradh } 3303464ebd5Sriastradh 3313464ebd5Sriastradh return ret; 3323464ebd5Sriastradh} 3333464ebd5Sriastradh 334af69d88dSmrgstatic const __DRIextension ** 335af69d88dSmrgdri_open_driver(struct gbm_dri_device *dri) 3363464ebd5Sriastradh{ 3377e995a2eSmrg /* Temporarily work around dri driver libs that need symbols in libglapi 3387e995a2eSmrg * but don't automatically link it in. 3397e995a2eSmrg */ 3407e995a2eSmrg /* XXX: Library name differs on per platforms basis. Update this as 3417e995a2eSmrg * osx/cygwin/windows/bsd gets support for GBM.. 3427e995a2eSmrg */ 3437e995a2eSmrg dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL); 3447e995a2eSmrg 345d8407755Smaya static const char *search_path_vars[] = { 346d8407755Smaya /* Read GBM_DRIVERS_PATH first for compatibility, but LIBGL_DRIVERS_PATH 347d8407755Smaya * is recommended over GBM_DRIVERS_PATH. 348d8407755Smaya */ 349d8407755Smaya "GBM_DRIVERS_PATH", 350d8407755Smaya /* Read LIBGL_DRIVERS_PATH if GBM_DRIVERS_PATH was not set. 351d8407755Smaya * LIBGL_DRIVERS_PATH is recommended over GBM_DRIVERS_PATH. 352d8407755Smaya */ 353d8407755Smaya "LIBGL_DRIVERS_PATH", 354d8407755Smaya NULL 355d8407755Smaya }; 356d8407755Smaya return loader_open_driver(dri->driver_name, &dri->driver, search_path_vars); 357af69d88dSmrg} 358af69d88dSmrg 359af69d88dSmrgstatic int 360af69d88dSmrgdri_load_driver(struct gbm_dri_device *dri) 361af69d88dSmrg{ 362af69d88dSmrg const __DRIextension **extensions; 363af69d88dSmrg 364af69d88dSmrg extensions = dri_open_driver(dri); 365af69d88dSmrg if (!extensions) 366af69d88dSmrg return -1; 3673464ebd5Sriastradh 3681463c08dSmrg if (!dri_bind_extensions(dri, gbm_dri_device_extensions, 3691463c08dSmrg ARRAY_SIZE(gbm_dri_device_extensions), 3701463c08dSmrg extensions)) { 3713464ebd5Sriastradh dlclose(dri->driver); 3723464ebd5Sriastradh fprintf(stderr, "failed to bind extensions\n"); 3733464ebd5Sriastradh return -1; 3743464ebd5Sriastradh } 3753464ebd5Sriastradh 376af69d88dSmrg dri->driver_extensions = extensions; 377af69d88dSmrg 3783464ebd5Sriastradh return 0; 3793464ebd5Sriastradh} 3803464ebd5Sriastradh 3813464ebd5Sriastradhstatic int 382af69d88dSmrgdri_load_driver_swrast(struct gbm_dri_device *dri) 383af69d88dSmrg{ 384af69d88dSmrg const __DRIextension **extensions; 385af69d88dSmrg 386af69d88dSmrg extensions = dri_open_driver(dri); 387af69d88dSmrg if (!extensions) 388af69d88dSmrg return -1; 389af69d88dSmrg 3901463c08dSmrg if (!dri_bind_extensions(dri, gbm_swrast_device_extensions, 3911463c08dSmrg ARRAY_SIZE(gbm_swrast_device_extensions), 3921463c08dSmrg extensions)) { 393af69d88dSmrg dlclose(dri->driver); 394af69d88dSmrg fprintf(stderr, "failed to bind extensions\n"); 395af69d88dSmrg return -1; 396af69d88dSmrg } 397af69d88dSmrg 398af69d88dSmrg dri->driver_extensions = extensions; 399af69d88dSmrg 400af69d88dSmrg return 0; 401af69d88dSmrg} 402af69d88dSmrg 403af69d88dSmrgstatic int 4047e995a2eSmrgdri_screen_create_dri2(struct gbm_dri_device *dri, char *driver_name) 4053464ebd5Sriastradh{ 4063464ebd5Sriastradh const __DRIextension **extensions; 4073464ebd5Sriastradh int ret = 0; 4083464ebd5Sriastradh 4097e995a2eSmrg dri->driver_name = driver_name; 4107e995a2eSmrg if (dri->driver_name == NULL) 4113464ebd5Sriastradh return -1; 4123464ebd5Sriastradh 4133464ebd5Sriastradh ret = dri_load_driver(dri); 4143464ebd5Sriastradh if (ret) { 4157e995a2eSmrg fprintf(stderr, "failed to load driver: %s\n", dri->driver_name); 4163464ebd5Sriastradh return ret; 4177e995a2eSmrg } 4183464ebd5Sriastradh 4197e995a2eSmrg dri->loader_extensions = gbm_dri_screen_extensions; 4203464ebd5Sriastradh 4213464ebd5Sriastradh if (dri->dri2 == NULL) 4223464ebd5Sriastradh return -1; 4233464ebd5Sriastradh 424af69d88dSmrg if (dri->dri2->base.version >= 4) { 4251463c08dSmrg dri->screen = dri->dri2->createNewScreen2(0, dri->base.v0.fd, 4267e995a2eSmrg dri->loader_extensions, 427af69d88dSmrg dri->driver_extensions, 428af69d88dSmrg &dri->driver_configs, dri); 429af69d88dSmrg } else { 4301463c08dSmrg dri->screen = dri->dri2->createNewScreen(0, dri->base.v0.fd, 4317e995a2eSmrg dri->loader_extensions, 432af69d88dSmrg &dri->driver_configs, dri); 433af69d88dSmrg } 434af69d88dSmrg if (dri->screen == NULL) 435af69d88dSmrg return -1; 4363464ebd5Sriastradh 4373464ebd5Sriastradh extensions = dri->core->getExtensions(dri->screen); 4381463c08dSmrg if (!dri_bind_extensions(dri, dri_core_extensions, 4391463c08dSmrg ARRAY_SIZE(dri_core_extensions), 4401463c08dSmrg extensions)) { 4413464ebd5Sriastradh ret = -1; 4423464ebd5Sriastradh goto free_screen; 4433464ebd5Sriastradh } 4443464ebd5Sriastradh 4453464ebd5Sriastradh dri->lookup_image = NULL; 4463464ebd5Sriastradh dri->lookup_user_data = NULL; 4473464ebd5Sriastradh 4483464ebd5Sriastradh return 0; 4493464ebd5Sriastradh 4503464ebd5Sriastradhfree_screen: 4513464ebd5Sriastradh dri->core->destroyScreen(dri->screen); 4523464ebd5Sriastradh 4533464ebd5Sriastradh return ret; 4543464ebd5Sriastradh} 4553464ebd5Sriastradh 456af69d88dSmrgstatic int 457af69d88dSmrgdri_screen_create_swrast(struct gbm_dri_device *dri) 458af69d88dSmrg{ 459af69d88dSmrg int ret; 460af69d88dSmrg 4617e995a2eSmrg dri->driver_name = strdup("swrast"); 4627e995a2eSmrg if (dri->driver_name == NULL) 463af69d88dSmrg return -1; 464af69d88dSmrg 465af69d88dSmrg ret = dri_load_driver_swrast(dri); 466af69d88dSmrg if (ret) { 467af69d88dSmrg fprintf(stderr, "failed to load swrast driver\n"); 468af69d88dSmrg return ret; 469af69d88dSmrg } 470af69d88dSmrg 4717e995a2eSmrg dri->loader_extensions = gbm_dri_screen_extensions; 472af69d88dSmrg 473af69d88dSmrg if (dri->swrast == NULL) 474af69d88dSmrg return -1; 475af69d88dSmrg 476af69d88dSmrg if (dri->swrast->base.version >= 4) { 4777e995a2eSmrg dri->screen = dri->swrast->createNewScreen2(0, dri->loader_extensions, 478af69d88dSmrg dri->driver_extensions, 479af69d88dSmrg &dri->driver_configs, dri); 480af69d88dSmrg } else { 4817e995a2eSmrg dri->screen = dri->swrast->createNewScreen(0, dri->loader_extensions, 482af69d88dSmrg &dri->driver_configs, dri); 483af69d88dSmrg } 484af69d88dSmrg if (dri->screen == NULL) 485af69d88dSmrg return -1; 486af69d88dSmrg 487af69d88dSmrg dri->lookup_image = NULL; 488af69d88dSmrg dri->lookup_user_data = NULL; 489af69d88dSmrg 490af69d88dSmrg return 0; 491af69d88dSmrg} 492af69d88dSmrg 493af69d88dSmrgstatic int 494af69d88dSmrgdri_screen_create(struct gbm_dri_device *dri) 495af69d88dSmrg{ 4967e995a2eSmrg char *driver_name; 497af69d88dSmrg 4981463c08dSmrg driver_name = loader_get_driver_for_fd(dri->base.v0.fd); 499af69d88dSmrg if (!driver_name) 500af69d88dSmrg return -1; 501af69d88dSmrg 502af69d88dSmrg return dri_screen_create_dri2(dri, driver_name); 503af69d88dSmrg} 504af69d88dSmrg 505af69d88dSmrgstatic int 506af69d88dSmrgdri_screen_create_sw(struct gbm_dri_device *dri) 507af69d88dSmrg{ 5087e995a2eSmrg char *driver_name; 509af69d88dSmrg int ret; 510af69d88dSmrg 511af69d88dSmrg driver_name = strdup("kms_swrast"); 512af69d88dSmrg if (!driver_name) 513af69d88dSmrg return -errno; 514af69d88dSmrg 515af69d88dSmrg ret = dri_screen_create_dri2(dri, driver_name); 5161463c08dSmrg if (ret != 0) 5171463c08dSmrg ret = dri_screen_create_swrast(dri); 5181463c08dSmrg if (ret != 0) 519af69d88dSmrg return ret; 520af69d88dSmrg 5211463c08dSmrg dri->software = true; 5221463c08dSmrg return 0; 523af69d88dSmrg} 524af69d88dSmrg 5257e995a2eSmrgstatic const struct gbm_dri_visual gbm_dri_visuals_table[] = { 5267e995a2eSmrg { 5277e995a2eSmrg GBM_FORMAT_R8, __DRI_IMAGE_FORMAT_R8, 5281463c08dSmrg { 0, -1, -1, -1 }, 5291463c08dSmrg { 8, 0, 0, 0 }, 5301463c08dSmrg }, 5311463c08dSmrg { 5321463c08dSmrg GBM_FORMAT_R16, __DRI_IMAGE_FORMAT_R16, 5331463c08dSmrg { 0, -1, -1, -1 }, 5341463c08dSmrg { 16, 0, 0, 0 }, 5357e995a2eSmrg }, 5367e995a2eSmrg { 5377e995a2eSmrg GBM_FORMAT_GR88, __DRI_IMAGE_FORMAT_GR88, 5381463c08dSmrg { 0, 8, -1, -1 }, 5391463c08dSmrg { 8, 8, 0, 0 }, 5407e995a2eSmrg }, 5417e995a2eSmrg { 5427e995a2eSmrg GBM_FORMAT_ARGB1555, __DRI_IMAGE_FORMAT_ARGB1555, 5431463c08dSmrg { 10, 5, 0, 11 }, 5441463c08dSmrg { 5, 5, 5, 1 }, 5457e995a2eSmrg }, 5467e995a2eSmrg { 5477e995a2eSmrg GBM_FORMAT_RGB565, __DRI_IMAGE_FORMAT_RGB565, 5481463c08dSmrg { 11, 5, 0, -1 }, 5491463c08dSmrg { 5, 6, 5, 0 }, 5507e995a2eSmrg }, 5517e995a2eSmrg { 5527e995a2eSmrg GBM_FORMAT_XRGB8888, __DRI_IMAGE_FORMAT_XRGB8888, 5531463c08dSmrg { 16, 8, 0, -1 }, 5541463c08dSmrg { 8, 8, 8, 0 }, 5557e995a2eSmrg }, 5567e995a2eSmrg { 5577e995a2eSmrg GBM_FORMAT_ARGB8888, __DRI_IMAGE_FORMAT_ARGB8888, 5581463c08dSmrg { 16, 8, 0, 24 }, 5591463c08dSmrg { 8, 8, 8, 8 }, 5607e995a2eSmrg }, 5617e995a2eSmrg { 5627e995a2eSmrg GBM_FORMAT_XBGR8888, __DRI_IMAGE_FORMAT_XBGR8888, 5631463c08dSmrg { 0, 8, 16, -1 }, 5641463c08dSmrg { 8, 8, 8, 0 }, 5657e995a2eSmrg }, 5667e995a2eSmrg { 5677e995a2eSmrg GBM_FORMAT_ABGR8888, __DRI_IMAGE_FORMAT_ABGR8888, 5681463c08dSmrg { 0, 8, 16, 24 }, 5691463c08dSmrg { 8, 8, 8, 8 }, 5707e995a2eSmrg }, 5717e995a2eSmrg { 5727e995a2eSmrg GBM_FORMAT_XRGB2101010, __DRI_IMAGE_FORMAT_XRGB2101010, 5731463c08dSmrg { 20, 10, 0, -1 }, 5741463c08dSmrg { 10, 10, 10, 0 }, 5757e995a2eSmrg }, 5767e995a2eSmrg { 5777e995a2eSmrg GBM_FORMAT_ARGB2101010, __DRI_IMAGE_FORMAT_ARGB2101010, 5781463c08dSmrg { 20, 10, 0, 30 }, 5791463c08dSmrg { 10, 10, 10, 2 }, 5807e995a2eSmrg }, 5817e995a2eSmrg { 5827e995a2eSmrg GBM_FORMAT_XBGR2101010, __DRI_IMAGE_FORMAT_XBGR2101010, 5831463c08dSmrg { 0, 10, 20, -1 }, 5841463c08dSmrg { 10, 10, 10, 0 }, 5857e995a2eSmrg }, 5867e995a2eSmrg { 5877e995a2eSmrg GBM_FORMAT_ABGR2101010, __DRI_IMAGE_FORMAT_ABGR2101010, 5881463c08dSmrg { 0, 10, 20, 30 }, 5891463c08dSmrg { 10, 10, 10, 2 }, 5901463c08dSmrg }, 5911463c08dSmrg { 5921463c08dSmrg GBM_FORMAT_XBGR16161616F, __DRI_IMAGE_FORMAT_XBGR16161616F, 5931463c08dSmrg { 0, 16, 32, -1 }, 5941463c08dSmrg { 16, 16, 16, 0 }, 5951463c08dSmrg true, 5961463c08dSmrg }, 5971463c08dSmrg { 5981463c08dSmrg GBM_FORMAT_ABGR16161616F, __DRI_IMAGE_FORMAT_ABGR16161616F, 5991463c08dSmrg { 0, 16, 32, 48 }, 6001463c08dSmrg { 16, 16, 16, 16 }, 6011463c08dSmrg true, 6027e995a2eSmrg }, 6037e995a2eSmrg}; 6047e995a2eSmrg 6057e995a2eSmrgstatic int 6067e995a2eSmrggbm_format_to_dri_format(uint32_t gbm_format) 6077e995a2eSmrg{ 6081463c08dSmrg gbm_format = gbm_core.v0.format_canonicalize(gbm_format); 6091463c08dSmrg for (size_t i = 0; i < ARRAY_SIZE(gbm_dri_visuals_table); i++) { 6107e995a2eSmrg if (gbm_dri_visuals_table[i].gbm_format == gbm_format) 6117e995a2eSmrg return gbm_dri_visuals_table[i].dri_image_format; 6127e995a2eSmrg } 6137e995a2eSmrg 6147e995a2eSmrg return 0; 6157e995a2eSmrg} 6167e995a2eSmrg 6177e995a2eSmrgstatic uint32_t 6187e995a2eSmrggbm_dri_to_gbm_format(int dri_format) 6197e995a2eSmrg{ 6201463c08dSmrg for (size_t i = 0; i < ARRAY_SIZE(gbm_dri_visuals_table); i++) { 6217e995a2eSmrg if (gbm_dri_visuals_table[i].dri_image_format == dri_format) 6227e995a2eSmrg return gbm_dri_visuals_table[i].gbm_format; 6237e995a2eSmrg } 6247e995a2eSmrg 6257e995a2eSmrg return 0; 6267e995a2eSmrg} 6277e995a2eSmrg 6287e995a2eSmrgstatic int 6297e995a2eSmrggbm_dri_is_format_supported(struct gbm_device *gbm, 6307e995a2eSmrg uint32_t format, 6317e995a2eSmrg uint32_t usage) 6327e995a2eSmrg{ 6337e995a2eSmrg struct gbm_dri_device *dri = gbm_dri_device(gbm); 6347e995a2eSmrg int count; 6357e995a2eSmrg 6367e995a2eSmrg if ((usage & GBM_BO_USE_CURSOR) && (usage & GBM_BO_USE_RENDERING)) 6377e995a2eSmrg return 0; 6387e995a2eSmrg 6391463c08dSmrg format = gbm_core.v0.format_canonicalize(format); 6407e995a2eSmrg if (gbm_format_to_dri_format(format) == 0) 6413464ebd5Sriastradh return 0; 6427e995a2eSmrg 6437e995a2eSmrg /* If there is no query, fall back to the small table which was originally 6447e995a2eSmrg * here. */ 6457e995a2eSmrg if (dri->image->base.version <= 15 || !dri->image->queryDmaBufModifiers) { 6467e995a2eSmrg switch (format) { 6477e995a2eSmrg case GBM_FORMAT_XRGB8888: 6487e995a2eSmrg case GBM_FORMAT_ARGB8888: 6497e995a2eSmrg case GBM_FORMAT_XBGR8888: 6507e995a2eSmrg return 1; 6517e995a2eSmrg default: 6527e995a2eSmrg return 0; 6537e995a2eSmrg } 6543464ebd5Sriastradh } 6553464ebd5Sriastradh 6561463c08dSmrg /* This returns false if the format isn't supported */ 6577e995a2eSmrg if (!dri->image->queryDmaBufModifiers(dri->screen, format, 0, NULL, NULL, 6587e995a2eSmrg &count)) 6593464ebd5Sriastradh return 0; 6603464ebd5Sriastradh 6611463c08dSmrg return 1; 6627e995a2eSmrg} 6637e995a2eSmrg 6647e995a2eSmrgstatic int 6657e995a2eSmrggbm_dri_get_format_modifier_plane_count(struct gbm_device *gbm, 6667e995a2eSmrg uint32_t format, 6677e995a2eSmrg uint64_t modifier) 6687e995a2eSmrg{ 6697e995a2eSmrg struct gbm_dri_device *dri = gbm_dri_device(gbm); 6707e995a2eSmrg uint64_t plane_count; 6717e995a2eSmrg 6727e995a2eSmrg if (dri->image->base.version < 16 || 6737e995a2eSmrg !dri->image->queryDmaBufFormatModifierAttribs) 6747e995a2eSmrg return -1; 6757e995a2eSmrg 6761463c08dSmrg format = gbm_core.v0.format_canonicalize(format); 6777e995a2eSmrg if (gbm_format_to_dri_format(format) == 0) 6787e995a2eSmrg return -1; 6797e995a2eSmrg 6807e995a2eSmrg if (!dri->image->queryDmaBufFormatModifierAttribs( 6817e995a2eSmrg dri->screen, format, modifier, 6827e995a2eSmrg __DRI_IMAGE_FORMAT_MODIFIER_ATTRIB_PLANE_COUNT, &plane_count)) 6837e995a2eSmrg return -1; 6847e995a2eSmrg 6857e995a2eSmrg return plane_count; 6863464ebd5Sriastradh} 6873464ebd5Sriastradh 688af69d88dSmrgstatic int 689af69d88dSmrggbm_dri_bo_write(struct gbm_bo *_bo, const void *buf, size_t count) 690af69d88dSmrg{ 691af69d88dSmrg struct gbm_dri_bo *bo = gbm_dri_bo(_bo); 692af69d88dSmrg 693af69d88dSmrg if (bo->image != NULL) { 694af69d88dSmrg errno = EINVAL; 695af69d88dSmrg return -1; 696af69d88dSmrg } 697af69d88dSmrg 698af69d88dSmrg memcpy(bo->map, buf, count); 699af69d88dSmrg 700af69d88dSmrg return 0; 701af69d88dSmrg} 702af69d88dSmrg 703af69d88dSmrgstatic int 704af69d88dSmrggbm_dri_bo_get_fd(struct gbm_bo *_bo) 705af69d88dSmrg{ 706af69d88dSmrg struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm); 707af69d88dSmrg struct gbm_dri_bo *bo = gbm_dri_bo(_bo); 708af69d88dSmrg int fd; 709af69d88dSmrg 710af69d88dSmrg if (bo->image == NULL) 711af69d88dSmrg return -1; 712af69d88dSmrg 7137e995a2eSmrg if (!dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_FD, &fd)) 7147e995a2eSmrg return -1; 715af69d88dSmrg 716af69d88dSmrg return fd; 717af69d88dSmrg} 718af69d88dSmrg 7197e995a2eSmrgstatic int 7207e995a2eSmrgget_number_planes(struct gbm_dri_device *dri, __DRIimage *image) 7217e995a2eSmrg{ 7227e995a2eSmrg int num_planes = 0; 7237e995a2eSmrg 7247e995a2eSmrg /* Dumb buffers are single-plane only. */ 7257e995a2eSmrg if (!image) 7267e995a2eSmrg return 1; 7277e995a2eSmrg 7287e995a2eSmrg dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_NUM_PLANES, &num_planes); 7297e995a2eSmrg 7307e995a2eSmrg if (num_planes <= 0) 7317e995a2eSmrg num_planes = 1; 7327e995a2eSmrg 7337e995a2eSmrg return num_planes; 7347e995a2eSmrg} 7357e995a2eSmrg 7367e995a2eSmrgstatic int 7377e995a2eSmrggbm_dri_bo_get_planes(struct gbm_bo *_bo) 7383464ebd5Sriastradh{ 7393464ebd5Sriastradh struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm); 7403464ebd5Sriastradh struct gbm_dri_bo *bo = gbm_dri_bo(_bo); 741af69d88dSmrg 7427e995a2eSmrg return get_number_planes(dri, bo->image); 7437e995a2eSmrg} 7447e995a2eSmrg 7457e995a2eSmrgstatic union gbm_bo_handle 7467e995a2eSmrggbm_dri_bo_get_handle_for_plane(struct gbm_bo *_bo, int plane) 7477e995a2eSmrg{ 7487e995a2eSmrg struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm); 7497e995a2eSmrg struct gbm_dri_bo *bo = gbm_dri_bo(_bo); 7507e995a2eSmrg union gbm_bo_handle ret; 7517e995a2eSmrg ret.s32 = -1; 7527e995a2eSmrg 7537e995a2eSmrg if (!dri->image || dri->image->base.version < 13 || !dri->image->fromPlanar) { 7541463c08dSmrg /* Preserve legacy behavior if plane is 0 */ 7551463c08dSmrg if (plane == 0) { 7561463c08dSmrg /* NOTE: return _bo->handle, *NOT* bo->handle which is invalid at this point */ 7571463c08dSmrg return _bo->v0.handle; 7581463c08dSmrg } 7591463c08dSmrg 7607e995a2eSmrg errno = ENOSYS; 7617e995a2eSmrg return ret; 7627e995a2eSmrg } 7637e995a2eSmrg 7647e995a2eSmrg if (plane >= get_number_planes(dri, bo->image)) { 7657e995a2eSmrg errno = EINVAL; 7667e995a2eSmrg return ret; 7677e995a2eSmrg } 7687e995a2eSmrg 7697e995a2eSmrg /* dumb BOs can only utilize non-planar formats */ 7707e995a2eSmrg if (!bo->image) { 7717e995a2eSmrg assert(plane == 0); 7727e995a2eSmrg ret.s32 = bo->handle; 7737e995a2eSmrg return ret; 7747e995a2eSmrg } 7757e995a2eSmrg 7767e995a2eSmrg __DRIimage *image = dri->image->fromPlanar(bo->image, plane, NULL); 7777e995a2eSmrg if (image) { 7787e995a2eSmrg dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_HANDLE, &ret.s32); 7797e995a2eSmrg dri->image->destroyImage(image); 780af69d88dSmrg } else { 7817e995a2eSmrg assert(plane == 0); 7827e995a2eSmrg dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE, &ret.s32); 783af69d88dSmrg } 7843464ebd5Sriastradh 7857e995a2eSmrg return ret; 7863464ebd5Sriastradh} 7873464ebd5Sriastradh 7881463c08dSmrgstatic int 7891463c08dSmrggbm_dri_bo_get_plane_fd(struct gbm_bo *_bo, int plane) 7901463c08dSmrg{ 7911463c08dSmrg struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm); 7921463c08dSmrg struct gbm_dri_bo *bo = gbm_dri_bo(_bo); 7931463c08dSmrg int fd = -1; 7941463c08dSmrg 7951463c08dSmrg if (!dri->image || dri->image->base.version < 13 || !dri->image->fromPlanar) { 7961463c08dSmrg /* Preserve legacy behavior if plane is 0 */ 7971463c08dSmrg if (plane == 0) 7981463c08dSmrg return gbm_dri_bo_get_fd(_bo); 7991463c08dSmrg 8001463c08dSmrg errno = ENOSYS; 8011463c08dSmrg return -1; 8021463c08dSmrg } 8031463c08dSmrg 8041463c08dSmrg /* dumb BOs can only utilize non-planar formats */ 8051463c08dSmrg if (!bo->image) { 8061463c08dSmrg errno = EINVAL; 8071463c08dSmrg return -1; 8081463c08dSmrg } 8091463c08dSmrg 8101463c08dSmrg if (plane >= get_number_planes(dri, bo->image)) { 8111463c08dSmrg errno = EINVAL; 8121463c08dSmrg return -1; 8131463c08dSmrg } 8141463c08dSmrg 8151463c08dSmrg __DRIimage *image = dri->image->fromPlanar(bo->image, plane, NULL); 8161463c08dSmrg if (image) { 8171463c08dSmrg dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_FD, &fd); 8181463c08dSmrg dri->image->destroyImage(image); 8191463c08dSmrg } else { 8201463c08dSmrg assert(plane == 0); 8211463c08dSmrg dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_FD, &fd); 8221463c08dSmrg } 8231463c08dSmrg 8241463c08dSmrg return fd; 8251463c08dSmrg} 8261463c08dSmrg 827af69d88dSmrgstatic uint32_t 8287e995a2eSmrggbm_dri_bo_get_stride(struct gbm_bo *_bo, int plane) 829af69d88dSmrg{ 8307e995a2eSmrg struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm); 8317e995a2eSmrg struct gbm_dri_bo *bo = gbm_dri_bo(_bo); 8327e995a2eSmrg __DRIimage *image; 8337e995a2eSmrg int stride = 0; 834af69d88dSmrg 8357e995a2eSmrg if (!dri->image || dri->image->base.version < 11 || !dri->image->fromPlanar) { 8367e995a2eSmrg /* Preserve legacy behavior if plane is 0 */ 8377e995a2eSmrg if (plane == 0) 8381463c08dSmrg return _bo->v0.stride; 8397e995a2eSmrg 8407e995a2eSmrg errno = ENOSYS; 8417e995a2eSmrg return 0; 8427e995a2eSmrg } 8437e995a2eSmrg 8447e995a2eSmrg if (plane >= get_number_planes(dri, bo->image)) { 8457e995a2eSmrg errno = EINVAL; 8467e995a2eSmrg return 0; 8477e995a2eSmrg } 8487e995a2eSmrg 8497e995a2eSmrg if (bo->image == NULL) { 8507e995a2eSmrg assert(plane == 0); 8511463c08dSmrg return _bo->v0.stride; 8527e995a2eSmrg } 8537e995a2eSmrg 8547e995a2eSmrg image = dri->image->fromPlanar(bo->image, plane, NULL); 8557e995a2eSmrg if (image) { 8567e995a2eSmrg dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_STRIDE, &stride); 8577e995a2eSmrg dri->image->destroyImage(image); 8587e995a2eSmrg } else { 8597e995a2eSmrg assert(plane == 0); 8607e995a2eSmrg dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE, &stride); 861af69d88dSmrg } 862af69d88dSmrg 8637e995a2eSmrg return (uint32_t)stride; 8647e995a2eSmrg} 8657e995a2eSmrg 8667e995a2eSmrgstatic uint32_t 8677e995a2eSmrggbm_dri_bo_get_offset(struct gbm_bo *_bo, int plane) 8687e995a2eSmrg{ 8697e995a2eSmrg struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm); 8707e995a2eSmrg struct gbm_dri_bo *bo = gbm_dri_bo(_bo); 8717e995a2eSmrg int offset = 0; 8727e995a2eSmrg 8737e995a2eSmrg /* These error cases do not actually return an error code, as the user 8747e995a2eSmrg * will also fail to obtain the handle/FD from the BO. In that case, the 8757e995a2eSmrg * offset is irrelevant, as they have no buffer to offset into, so 8767e995a2eSmrg * returning 0 is harmless. 8777e995a2eSmrg */ 8787e995a2eSmrg if (!dri->image || dri->image->base.version < 13 || !dri->image->fromPlanar) 8797e995a2eSmrg return 0; 8807e995a2eSmrg 8817e995a2eSmrg if (plane >= get_number_planes(dri, bo->image)) 8827e995a2eSmrg return 0; 8837e995a2eSmrg 8847e995a2eSmrg /* Dumb images have no offset */ 8857e995a2eSmrg if (bo->image == NULL) { 8867e995a2eSmrg assert(plane == 0); 8877e995a2eSmrg return 0; 8887e995a2eSmrg } 8897e995a2eSmrg 8907e995a2eSmrg __DRIimage *image = dri->image->fromPlanar(bo->image, plane, NULL); 8917e995a2eSmrg if (image) { 8927e995a2eSmrg dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_OFFSET, &offset); 8937e995a2eSmrg dri->image->destroyImage(image); 8947e995a2eSmrg } else { 8957e995a2eSmrg assert(plane == 0); 8967e995a2eSmrg dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_OFFSET, &offset); 8977e995a2eSmrg } 8987e995a2eSmrg 8997e995a2eSmrg return (uint32_t)offset; 9007e995a2eSmrg} 9017e995a2eSmrg 9027e995a2eSmrgstatic uint64_t 9037e995a2eSmrggbm_dri_bo_get_modifier(struct gbm_bo *_bo) 9047e995a2eSmrg{ 9057e995a2eSmrg struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm); 9067e995a2eSmrg struct gbm_dri_bo *bo = gbm_dri_bo(_bo); 9077e995a2eSmrg 9087e995a2eSmrg if (!dri->image || dri->image->base.version < 14) { 9097e995a2eSmrg errno = ENOSYS; 9107e995a2eSmrg return DRM_FORMAT_MOD_INVALID; 9117e995a2eSmrg } 9127e995a2eSmrg 9137e995a2eSmrg /* Dumb buffers have no modifiers */ 9147e995a2eSmrg if (!bo->image) 9157e995a2eSmrg return DRM_FORMAT_MOD_LINEAR; 9167e995a2eSmrg 9177e995a2eSmrg uint64_t ret = 0; 9187e995a2eSmrg int mod; 9197e995a2eSmrg if (!dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_MODIFIER_UPPER, 9207e995a2eSmrg &mod)) 9217e995a2eSmrg return DRM_FORMAT_MOD_INVALID; 9227e995a2eSmrg 9237e995a2eSmrg ret = (uint64_t)mod << 32; 9247e995a2eSmrg 9257e995a2eSmrg if (!dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_MODIFIER_LOWER, 9267e995a2eSmrg &mod)) 9277e995a2eSmrg return DRM_FORMAT_MOD_INVALID; 9287e995a2eSmrg 9297e995a2eSmrg ret |= (uint64_t)(mod & 0xffffffff); 9307e995a2eSmrg 931af69d88dSmrg return ret; 932af69d88dSmrg} 933af69d88dSmrg 9347e995a2eSmrgstatic void 9357e995a2eSmrggbm_dri_bo_destroy(struct gbm_bo *_bo) 9367e995a2eSmrg{ 9377e995a2eSmrg struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm); 9387e995a2eSmrg struct gbm_dri_bo *bo = gbm_dri_bo(_bo); 9397e995a2eSmrg struct drm_mode_destroy_dumb arg; 9407e995a2eSmrg 9417e995a2eSmrg if (bo->image != NULL) { 9427e995a2eSmrg dri->image->destroyImage(bo->image); 9437e995a2eSmrg } else { 9447e995a2eSmrg gbm_dri_bo_unmap_dumb(bo); 9457e995a2eSmrg memset(&arg, 0, sizeof(arg)); 9467e995a2eSmrg arg.handle = bo->handle; 9471463c08dSmrg drmIoctl(dri->base.v0.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &arg); 9487e995a2eSmrg } 9497e995a2eSmrg 9507e995a2eSmrg free(bo); 9517e995a2eSmrg} 9527e995a2eSmrg 9533464ebd5Sriastradhstatic struct gbm_bo * 954af69d88dSmrggbm_dri_bo_import(struct gbm_device *gbm, 955af69d88dSmrg uint32_t type, void *buffer, uint32_t usage) 9563464ebd5Sriastradh{ 9573464ebd5Sriastradh struct gbm_dri_device *dri = gbm_dri_device(gbm); 9583464ebd5Sriastradh struct gbm_dri_bo *bo; 959af69d88dSmrg __DRIimage *image; 960af69d88dSmrg unsigned dri_use = 0; 961af69d88dSmrg int gbm_format; 9623464ebd5Sriastradh 963af69d88dSmrg /* Required for query image WIDTH & HEIGHT */ 964af69d88dSmrg if (dri->image == NULL || dri->image->base.version < 4) { 965af69d88dSmrg errno = ENOSYS; 966af69d88dSmrg return NULL; 967af69d88dSmrg } 9683464ebd5Sriastradh 969af69d88dSmrg switch (type) { 970af69d88dSmrg#if HAVE_WAYLAND_PLATFORM 971af69d88dSmrg case GBM_BO_IMPORT_WL_BUFFER: 972af69d88dSmrg { 973af69d88dSmrg struct wl_drm_buffer *wb; 974af69d88dSmrg 975af69d88dSmrg if (!dri->wl_drm) { 976af69d88dSmrg errno = EINVAL; 977af69d88dSmrg return NULL; 978af69d88dSmrg } 979af69d88dSmrg 980af69d88dSmrg wb = wayland_drm_buffer_get(dri->wl_drm, (struct wl_resource *) buffer); 981af69d88dSmrg if (!wb) { 982af69d88dSmrg errno = EINVAL; 983af69d88dSmrg return NULL; 984af69d88dSmrg } 985af69d88dSmrg 986af69d88dSmrg image = dri->image->dupImage(wb->driver_buffer, NULL); 987af69d88dSmrg 9887e995a2eSmrg /* GBM_FORMAT_* is identical to WL_DRM_FORMAT_*, so no conversion 9897e995a2eSmrg * required. */ 9907e995a2eSmrg gbm_format = wb->format; 991af69d88dSmrg break; 992af69d88dSmrg } 993af69d88dSmrg#endif 994af69d88dSmrg 995af69d88dSmrg case GBM_BO_IMPORT_EGL_IMAGE: 996af69d88dSmrg { 997af69d88dSmrg int dri_format; 998af69d88dSmrg if (dri->lookup_image == NULL) { 999af69d88dSmrg errno = EINVAL; 1000af69d88dSmrg return NULL; 1001af69d88dSmrg } 1002af69d88dSmrg 1003af69d88dSmrg image = dri->lookup_image(dri->screen, buffer, dri->lookup_user_data); 1004af69d88dSmrg image = dri->image->dupImage(image, NULL); 1005af69d88dSmrg dri->image->queryImage(image, __DRI_IMAGE_ATTRIB_FORMAT, &dri_format); 1006af69d88dSmrg gbm_format = gbm_dri_to_gbm_format(dri_format); 1007af69d88dSmrg if (gbm_format == 0) { 1008af69d88dSmrg errno = EINVAL; 10097e995a2eSmrg dri->image->destroyImage(image); 1010af69d88dSmrg return NULL; 1011af69d88dSmrg } 1012af69d88dSmrg break; 1013af69d88dSmrg } 1014af69d88dSmrg 1015af69d88dSmrg case GBM_BO_IMPORT_FD: 1016af69d88dSmrg { 1017af69d88dSmrg struct gbm_import_fd_data *fd_data = buffer; 1018af69d88dSmrg int stride = fd_data->stride, offset = 0; 10197e995a2eSmrg int fourcc; 10207e995a2eSmrg 10217e995a2eSmrg /* GBM's GBM_FORMAT_* tokens are a strict superset of the DRI FourCC 10227e995a2eSmrg * tokens accepted by createImageFromFds, except for not supporting 10237e995a2eSmrg * the sARGB format. */ 10241463c08dSmrg fourcc = gbm_core.v0.format_canonicalize(fd_data->format); 1025af69d88dSmrg 1026af69d88dSmrg image = dri->image->createImageFromFds(dri->screen, 1027af69d88dSmrg fd_data->width, 1028af69d88dSmrg fd_data->height, 10297e995a2eSmrg fourcc, 1030af69d88dSmrg &fd_data->fd, 1, 1031af69d88dSmrg &stride, &offset, 1032af69d88dSmrg NULL); 10337e995a2eSmrg if (image == NULL) { 10347e995a2eSmrg errno = EINVAL; 10357e995a2eSmrg return NULL; 10367e995a2eSmrg } 1037af69d88dSmrg gbm_format = fd_data->format; 1038af69d88dSmrg break; 1039af69d88dSmrg } 1040af69d88dSmrg 10417e995a2eSmrg case GBM_BO_IMPORT_FD_MODIFIER: 10427e995a2eSmrg { 10437e995a2eSmrg struct gbm_import_fd_modifier_data *fd_data = buffer; 10447e995a2eSmrg unsigned int error; 10457e995a2eSmrg int fourcc; 10467e995a2eSmrg 10477e995a2eSmrg /* Import with modifier requires createImageFromDmaBufs2 */ 10487e995a2eSmrg if (dri->image == NULL || dri->image->base.version < 15 || 10497e995a2eSmrg dri->image->createImageFromDmaBufs2 == NULL) { 10507e995a2eSmrg errno = ENOSYS; 10517e995a2eSmrg return NULL; 10527e995a2eSmrg } 10537e995a2eSmrg 10547e995a2eSmrg /* GBM's GBM_FORMAT_* tokens are a strict superset of the DRI FourCC 10557e995a2eSmrg * tokens accepted by createImageFromDmaBufs2, except for not supporting 10567e995a2eSmrg * the sARGB format. */ 10571463c08dSmrg fourcc = gbm_core.v0.format_canonicalize(fd_data->format); 10587e995a2eSmrg 10597e995a2eSmrg image = dri->image->createImageFromDmaBufs2(dri->screen, fd_data->width, 10607e995a2eSmrg fd_data->height, fourcc, 10617e995a2eSmrg fd_data->modifier, 10627e995a2eSmrg fd_data->fds, 10637e995a2eSmrg fd_data->num_fds, 10647e995a2eSmrg fd_data->strides, 10657e995a2eSmrg fd_data->offsets, 10667e995a2eSmrg 0, 0, 0, 0, 10677e995a2eSmrg &error, NULL); 10687e995a2eSmrg if (image == NULL) { 10697e995a2eSmrg errno = ENOSYS; 10707e995a2eSmrg return NULL; 10717e995a2eSmrg } 10727e995a2eSmrg 10737e995a2eSmrg gbm_format = fourcc; 10747e995a2eSmrg break; 10757e995a2eSmrg } 10767e995a2eSmrg 1077af69d88dSmrg default: 1078af69d88dSmrg errno = ENOSYS; 10793464ebd5Sriastradh return NULL; 1080af69d88dSmrg } 1081af69d88dSmrg 10823464ebd5Sriastradh 10833464ebd5Sriastradh bo = calloc(1, sizeof *bo); 10847e995a2eSmrg if (bo == NULL) { 10857e995a2eSmrg dri->image->destroyImage(image); 10863464ebd5Sriastradh return NULL; 10877e995a2eSmrg } 10883464ebd5Sriastradh 1089af69d88dSmrg bo->image = image; 10903464ebd5Sriastradh 1091af69d88dSmrg if (usage & GBM_BO_USE_SCANOUT) 1092af69d88dSmrg dri_use |= __DRI_IMAGE_USE_SCANOUT; 1093af69d88dSmrg if (usage & GBM_BO_USE_CURSOR) 1094af69d88dSmrg dri_use |= __DRI_IMAGE_USE_CURSOR; 1095af69d88dSmrg if (dri->image->base.version >= 2 && 1096af69d88dSmrg !dri->image->validateUsage(bo->image, dri_use)) { 1097af69d88dSmrg errno = EINVAL; 10987e995a2eSmrg dri->image->destroyImage(bo->image); 1099af69d88dSmrg free(bo); 11003464ebd5Sriastradh return NULL; 1101af69d88dSmrg } 1102af69d88dSmrg 11037e995a2eSmrg bo->base.gbm = gbm; 11041463c08dSmrg bo->base.v0.format = gbm_format; 1105af69d88dSmrg 1106af69d88dSmrg dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_WIDTH, 11071463c08dSmrg (int*)&bo->base.v0.width); 1108af69d88dSmrg dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HEIGHT, 11091463c08dSmrg (int*)&bo->base.v0.height); 1110af69d88dSmrg dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE, 11111463c08dSmrg (int*)&bo->base.v0.stride); 11123464ebd5Sriastradh dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE, 11131463c08dSmrg &bo->base.v0.handle.s32); 11143464ebd5Sriastradh 11157e995a2eSmrg return &bo->base; 11163464ebd5Sriastradh} 11173464ebd5Sriastradh 1118af69d88dSmrgstatic struct gbm_bo * 1119af69d88dSmrgcreate_dumb(struct gbm_device *gbm, 1120af69d88dSmrg uint32_t width, uint32_t height, 1121af69d88dSmrg uint32_t format, uint32_t usage) 1122af69d88dSmrg{ 1123af69d88dSmrg struct gbm_dri_device *dri = gbm_dri_device(gbm); 1124af69d88dSmrg struct drm_mode_create_dumb create_arg; 1125af69d88dSmrg struct gbm_dri_bo *bo; 1126af69d88dSmrg struct drm_mode_destroy_dumb destroy_arg; 1127af69d88dSmrg int ret; 1128af69d88dSmrg int is_cursor, is_scanout; 1129af69d88dSmrg 1130af69d88dSmrg is_cursor = (usage & GBM_BO_USE_CURSOR) != 0 && 1131af69d88dSmrg format == GBM_FORMAT_ARGB8888; 1132af69d88dSmrg is_scanout = (usage & GBM_BO_USE_SCANOUT) != 0 && 11337e995a2eSmrg (format == GBM_FORMAT_XRGB8888 || format == GBM_FORMAT_XBGR8888); 1134af69d88dSmrg if (!is_cursor && !is_scanout) { 1135af69d88dSmrg errno = EINVAL; 1136af69d88dSmrg return NULL; 1137af69d88dSmrg } 1138af69d88dSmrg 1139af69d88dSmrg bo = calloc(1, sizeof *bo); 1140af69d88dSmrg if (bo == NULL) 1141af69d88dSmrg return NULL; 1142af69d88dSmrg 11437e995a2eSmrg memset(&create_arg, 0, sizeof(create_arg)); 1144af69d88dSmrg create_arg.bpp = 32; 1145af69d88dSmrg create_arg.width = width; 1146af69d88dSmrg create_arg.height = height; 1147af69d88dSmrg 11481463c08dSmrg ret = drmIoctl(dri->base.v0.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg); 1149af69d88dSmrg if (ret) 1150af69d88dSmrg goto free_bo; 1151af69d88dSmrg 11527e995a2eSmrg bo->base.gbm = gbm; 11531463c08dSmrg bo->base.v0.width = width; 11541463c08dSmrg bo->base.v0.height = height; 11551463c08dSmrg bo->base.v0.stride = create_arg.pitch; 11561463c08dSmrg bo->base.v0.format = format; 11571463c08dSmrg bo->base.v0.handle.u32 = create_arg.handle; 1158af69d88dSmrg bo->handle = create_arg.handle; 1159af69d88dSmrg bo->size = create_arg.size; 1160af69d88dSmrg 11617e995a2eSmrg if (gbm_dri_bo_map_dumb(bo) == NULL) 1162af69d88dSmrg goto destroy_dumb; 1163af69d88dSmrg 11647e995a2eSmrg return &bo->base; 1165af69d88dSmrg 1166af69d88dSmrgdestroy_dumb: 1167af69d88dSmrg memset(&destroy_arg, 0, sizeof destroy_arg); 1168af69d88dSmrg destroy_arg.handle = create_arg.handle; 11691463c08dSmrg drmIoctl(dri->base.v0.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg); 1170af69d88dSmrgfree_bo: 1171af69d88dSmrg free(bo); 1172af69d88dSmrg 1173af69d88dSmrg return NULL; 1174af69d88dSmrg} 1175af69d88dSmrg 11763464ebd5Sriastradhstatic struct gbm_bo * 11773464ebd5Sriastradhgbm_dri_bo_create(struct gbm_device *gbm, 11783464ebd5Sriastradh uint32_t width, uint32_t height, 11797e995a2eSmrg uint32_t format, uint32_t usage, 11807e995a2eSmrg const uint64_t *modifiers, 11817e995a2eSmrg const unsigned int count) 11823464ebd5Sriastradh{ 11833464ebd5Sriastradh struct gbm_dri_device *dri = gbm_dri_device(gbm); 11843464ebd5Sriastradh struct gbm_dri_bo *bo; 11853464ebd5Sriastradh int dri_format; 11863464ebd5Sriastradh unsigned dri_use = 0; 11873464ebd5Sriastradh 11881463c08dSmrg format = gbm_core.v0.format_canonicalize(format); 11897e995a2eSmrg 1190af69d88dSmrg if (usage & GBM_BO_USE_WRITE || dri->image == NULL) 1191af69d88dSmrg return create_dumb(gbm, width, height, format, usage); 1192af69d88dSmrg 11933464ebd5Sriastradh bo = calloc(1, sizeof *bo); 11943464ebd5Sriastradh if (bo == NULL) 11953464ebd5Sriastradh return NULL; 11963464ebd5Sriastradh 11977e995a2eSmrg bo->base.gbm = gbm; 11981463c08dSmrg bo->base.v0.width = width; 11991463c08dSmrg bo->base.v0.height = height; 12001463c08dSmrg bo->base.v0.format = format; 12013464ebd5Sriastradh 12027e995a2eSmrg dri_format = gbm_format_to_dri_format(format); 12037e995a2eSmrg if (dri_format == 0) { 1204af69d88dSmrg errno = EINVAL; 1205af69d88dSmrg goto failed; 12063464ebd5Sriastradh } 12073464ebd5Sriastradh 12083464ebd5Sriastradh if (usage & GBM_BO_USE_SCANOUT) 12093464ebd5Sriastradh dri_use |= __DRI_IMAGE_USE_SCANOUT; 1210af69d88dSmrg if (usage & GBM_BO_USE_CURSOR) 12113464ebd5Sriastradh dri_use |= __DRI_IMAGE_USE_CURSOR; 12127e995a2eSmrg if (usage & GBM_BO_USE_LINEAR) 12137e995a2eSmrg dri_use |= __DRI_IMAGE_USE_LINEAR; 12141463c08dSmrg if (usage & GBM_BO_USE_PROTECTED) 12151463c08dSmrg dri_use |= __DRI_IMAGE_USE_PROTECTED; 12163464ebd5Sriastradh 1217af69d88dSmrg /* Gallium drivers requires shared in order to get the handle/stride */ 1218af69d88dSmrg dri_use |= __DRI_IMAGE_USE_SHARE; 1219af69d88dSmrg 12201463c08dSmrg if (modifiers && (dri->image->base.version < 14 || 12211463c08dSmrg !dri->image->createImageWithModifiers)) { 12221463c08dSmrg errno = ENOSYS; 12231463c08dSmrg goto failed; 12247e995a2eSmrg } 12257e995a2eSmrg 12261463c08dSmrg bo->image = loader_dri_create_image(dri->screen, dri->image, width, height, 12271463c08dSmrg dri_format, dri_use, modifiers, count, 12281463c08dSmrg bo); 12293464ebd5Sriastradh if (bo->image == NULL) 1230af69d88dSmrg goto failed; 12313464ebd5Sriastradh 12321463c08dSmrg if (modifiers) 12331463c08dSmrg assert(gbm_dri_bo_get_modifier(&bo->base) != DRM_FORMAT_MOD_INVALID); 12341463c08dSmrg 12353464ebd5Sriastradh dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_HANDLE, 12361463c08dSmrg &bo->base.v0.handle.s32); 12373464ebd5Sriastradh dri->image->queryImage(bo->image, __DRI_IMAGE_ATTRIB_STRIDE, 12381463c08dSmrg (int *) &bo->base.v0.stride); 12393464ebd5Sriastradh 12407e995a2eSmrg return &bo->base; 1241af69d88dSmrg 1242af69d88dSmrgfailed: 1243af69d88dSmrg free(bo); 1244af69d88dSmrg return NULL; 1245af69d88dSmrg} 1246af69d88dSmrg 12477e995a2eSmrgstatic void * 12487e995a2eSmrggbm_dri_bo_map(struct gbm_bo *_bo, 12497e995a2eSmrg uint32_t x, uint32_t y, 12507e995a2eSmrg uint32_t width, uint32_t height, 12517e995a2eSmrg uint32_t flags, uint32_t *stride, void **map_data) 12527e995a2eSmrg{ 12537e995a2eSmrg struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm); 12547e995a2eSmrg struct gbm_dri_bo *bo = gbm_dri_bo(_bo); 12557e995a2eSmrg 12567e995a2eSmrg /* If it's a dumb buffer, we already have a mapping */ 12577e995a2eSmrg if (bo->map) { 12581463c08dSmrg *map_data = (char *)bo->map + (bo->base.v0.stride * y) + (x * 4); 12591463c08dSmrg *stride = bo->base.v0.stride; 12607e995a2eSmrg return *map_data; 12617e995a2eSmrg } 12627e995a2eSmrg 12637e995a2eSmrg if (!dri->image || dri->image->base.version < 12 || !dri->image->mapImage) { 12647e995a2eSmrg errno = ENOSYS; 12657e995a2eSmrg return NULL; 12667e995a2eSmrg } 12677e995a2eSmrg 12687e995a2eSmrg mtx_lock(&dri->mutex); 12697e995a2eSmrg if (!dri->context) 12707e995a2eSmrg dri->context = dri->dri2->createNewContext(dri->screen, NULL, 12717e995a2eSmrg NULL, NULL); 12727e995a2eSmrg assert(dri->context); 12737e995a2eSmrg mtx_unlock(&dri->mutex); 12747e995a2eSmrg 12757e995a2eSmrg /* GBM flags and DRI flags are the same, so just pass them on */ 12767e995a2eSmrg return dri->image->mapImage(dri->context, bo->image, x, y, 12777e995a2eSmrg width, height, flags, (int *)stride, 12787e995a2eSmrg map_data); 12797e995a2eSmrg} 12807e995a2eSmrg 12817e995a2eSmrgstatic void 12827e995a2eSmrggbm_dri_bo_unmap(struct gbm_bo *_bo, void *map_data) 12837e995a2eSmrg{ 12847e995a2eSmrg struct gbm_dri_device *dri = gbm_dri_device(_bo->gbm); 12857e995a2eSmrg struct gbm_dri_bo *bo = gbm_dri_bo(_bo); 12867e995a2eSmrg 12877e995a2eSmrg /* Check if it's a dumb buffer and check the pointer is in range */ 12887e995a2eSmrg if (bo->map) { 12897e995a2eSmrg assert(map_data >= bo->map); 12907e995a2eSmrg assert(map_data < (bo->map + bo->size)); 12917e995a2eSmrg return; 12927e995a2eSmrg } 12937e995a2eSmrg 12947e995a2eSmrg if (!dri->context || !dri->image || 12957e995a2eSmrg dri->image->base.version < 12 || !dri->image->unmapImage) 12967e995a2eSmrg return; 12977e995a2eSmrg 12987e995a2eSmrg dri->image->unmapImage(dri->context, bo->image, map_data); 12997e995a2eSmrg 13007e995a2eSmrg /* 13017e995a2eSmrg * Not all DRI drivers use direct maps. They may queue up DMA operations 13027e995a2eSmrg * on the mapping context. Since there is no explicit gbm flush 13037e995a2eSmrg * mechanism, we need to flush here. 13047e995a2eSmrg */ 13057e995a2eSmrg if (dri->flush->base.version >= 4) 13067e995a2eSmrg dri->flush->flush_with_flags(dri->context, NULL, __DRI2_FLUSH_CONTEXT, 0); 13077e995a2eSmrg} 13087e995a2eSmrg 13097e995a2eSmrg 1310af69d88dSmrgstatic struct gbm_surface * 1311af69d88dSmrggbm_dri_surface_create(struct gbm_device *gbm, 1312af69d88dSmrg uint32_t width, uint32_t height, 13137e995a2eSmrg uint32_t format, uint32_t flags, 13147e995a2eSmrg const uint64_t *modifiers, const unsigned count) 1315af69d88dSmrg{ 13167e995a2eSmrg struct gbm_dri_device *dri = gbm_dri_device(gbm); 1317af69d88dSmrg struct gbm_dri_surface *surf; 1318af69d88dSmrg 13197e995a2eSmrg if (modifiers && 13207e995a2eSmrg (!dri->image || dri->image->base.version < 14 || 13217e995a2eSmrg !dri->image->createImageWithModifiers)) { 13227e995a2eSmrg errno = ENOSYS; 13237e995a2eSmrg return NULL; 13247e995a2eSmrg } 13257e995a2eSmrg 13267e995a2eSmrg if (count) 13277e995a2eSmrg assert(modifiers); 13287e995a2eSmrg 13297e995a2eSmrg /* It's acceptable to create an image with INVALID modifier in the list, 13307e995a2eSmrg * but it cannot be on the only modifier (since it will certainly fail 13317e995a2eSmrg * later). While we could easily catch this after modifier creation, doing 13327e995a2eSmrg * the check here is a convenient debug check likely pointing at whatever 13337e995a2eSmrg * interface the client is using to build its modifier list. 13347e995a2eSmrg */ 13357e995a2eSmrg if (count == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID) { 13367e995a2eSmrg fprintf(stderr, "Only invalid modifier specified\n"); 13377e995a2eSmrg errno = EINVAL; 13387e995a2eSmrg } 13397e995a2eSmrg 1340af69d88dSmrg surf = calloc(1, sizeof *surf); 13417e995a2eSmrg if (surf == NULL) { 13427e995a2eSmrg errno = ENOMEM; 1343af69d88dSmrg return NULL; 13447e995a2eSmrg } 1345af69d88dSmrg 1346af69d88dSmrg surf->base.gbm = gbm; 13471463c08dSmrg surf->base.v0.width = width; 13481463c08dSmrg surf->base.v0.height = height; 13491463c08dSmrg surf->base.v0.format = gbm_core.v0.format_canonicalize(format); 13501463c08dSmrg surf->base.v0.flags = flags; 13517e995a2eSmrg if (!modifiers) { 13527e995a2eSmrg assert(!count); 13537e995a2eSmrg return &surf->base; 13547e995a2eSmrg } 13557e995a2eSmrg 13561463c08dSmrg surf->base.v0.modifiers = calloc(count, sizeof(*modifiers)); 13571463c08dSmrg if (count && !surf->base.v0.modifiers) { 13587e995a2eSmrg errno = ENOMEM; 13597e995a2eSmrg free(surf); 13607e995a2eSmrg return NULL; 13617e995a2eSmrg } 13627e995a2eSmrg 13637e995a2eSmrg /* TODO: We are deferring validation of modifiers until the image is actually 13647e995a2eSmrg * created. This deferred creation can fail due to a modifier-format 13657e995a2eSmrg * mismatch. The result is the client has a surface but no object to back it. 13667e995a2eSmrg */ 13671463c08dSmrg surf->base.v0.count = count; 13681463c08dSmrg memcpy(surf->base.v0.modifiers, modifiers, count * sizeof(*modifiers)); 1369af69d88dSmrg 1370af69d88dSmrg return &surf->base; 1371af69d88dSmrg} 1372af69d88dSmrg 1373af69d88dSmrgstatic void 1374af69d88dSmrggbm_dri_surface_destroy(struct gbm_surface *_surf) 1375af69d88dSmrg{ 1376af69d88dSmrg struct gbm_dri_surface *surf = gbm_dri_surface(_surf); 1377af69d88dSmrg 13781463c08dSmrg free(surf->base.v0.modifiers); 1379af69d88dSmrg free(surf); 13803464ebd5Sriastradh} 13813464ebd5Sriastradh 13823464ebd5Sriastradhstatic void 13833464ebd5Sriastradhdri_destroy(struct gbm_device *gbm) 13843464ebd5Sriastradh{ 13853464ebd5Sriastradh struct gbm_dri_device *dri = gbm_dri_device(gbm); 13867e995a2eSmrg unsigned i; 13877e995a2eSmrg 13887e995a2eSmrg if (dri->context) 13897e995a2eSmrg dri->core->destroyContext(dri->context); 13903464ebd5Sriastradh 13913464ebd5Sriastradh dri->core->destroyScreen(dri->screen); 13927e995a2eSmrg for (i = 0; dri->driver_configs[i]; i++) 13937e995a2eSmrg free((__DRIconfig *) dri->driver_configs[i]); 13943464ebd5Sriastradh free(dri->driver_configs); 13953464ebd5Sriastradh dlclose(dri->driver); 13967e995a2eSmrg free(dri->driver_name); 13973464ebd5Sriastradh 13983464ebd5Sriastradh free(dri); 13993464ebd5Sriastradh} 14003464ebd5Sriastradh 14013464ebd5Sriastradhstatic struct gbm_device * 14021463c08dSmrgdri_device_create(int fd, uint32_t gbm_backend_version) 14033464ebd5Sriastradh{ 14043464ebd5Sriastradh struct gbm_dri_device *dri; 14057e995a2eSmrg int ret; 14067e995a2eSmrg bool force_sw; 14073464ebd5Sriastradh 14081463c08dSmrg /* 14091463c08dSmrg * Since the DRI backend is built-in to the loader, the loader ABI version is 14101463c08dSmrg * guaranteed to match this backend's ABI version 14111463c08dSmrg */ 14121463c08dSmrg assert(gbm_core.v0.core_version == GBM_BACKEND_ABI_VERSION); 14131463c08dSmrg assert(gbm_core.v0.core_version == gbm_backend_version); 14141463c08dSmrg 14153464ebd5Sriastradh dri = calloc(1, sizeof *dri); 1416af69d88dSmrg if (!dri) 1417af69d88dSmrg return NULL; 14183464ebd5Sriastradh 14191463c08dSmrg dri->base.v0.fd = fd; 14201463c08dSmrg dri->base.v0.backend_version = gbm_backend_version; 14211463c08dSmrg dri->base.v0.bo_create = gbm_dri_bo_create; 14221463c08dSmrg dri->base.v0.bo_import = gbm_dri_bo_import; 14231463c08dSmrg dri->base.v0.bo_map = gbm_dri_bo_map; 14241463c08dSmrg dri->base.v0.bo_unmap = gbm_dri_bo_unmap; 14251463c08dSmrg dri->base.v0.is_format_supported = gbm_dri_is_format_supported; 14261463c08dSmrg dri->base.v0.get_format_modifier_plane_count = 14277e995a2eSmrg gbm_dri_get_format_modifier_plane_count; 14281463c08dSmrg dri->base.v0.bo_write = gbm_dri_bo_write; 14291463c08dSmrg dri->base.v0.bo_get_fd = gbm_dri_bo_get_fd; 14301463c08dSmrg dri->base.v0.bo_get_planes = gbm_dri_bo_get_planes; 14311463c08dSmrg dri->base.v0.bo_get_handle = gbm_dri_bo_get_handle_for_plane; 14321463c08dSmrg dri->base.v0.bo_get_plane_fd = gbm_dri_bo_get_plane_fd; 14331463c08dSmrg dri->base.v0.bo_get_stride = gbm_dri_bo_get_stride; 14341463c08dSmrg dri->base.v0.bo_get_offset = gbm_dri_bo_get_offset; 14351463c08dSmrg dri->base.v0.bo_get_modifier = gbm_dri_bo_get_modifier; 14361463c08dSmrg dri->base.v0.bo_destroy = gbm_dri_bo_destroy; 14371463c08dSmrg dri->base.v0.destroy = dri_destroy; 14381463c08dSmrg dri->base.v0.surface_create = gbm_dri_surface_create; 14391463c08dSmrg dri->base.v0.surface_destroy = gbm_dri_surface_destroy; 14401463c08dSmrg 14411463c08dSmrg dri->base.v0.name = "drm"; 14427e995a2eSmrg 14437e995a2eSmrg dri->visual_table = gbm_dri_visuals_table; 14447e995a2eSmrg dri->num_visuals = ARRAY_SIZE(gbm_dri_visuals_table); 14457e995a2eSmrg 14467e995a2eSmrg mtx_init(&dri->mutex, mtx_plain); 14477e995a2eSmrg 14487e995a2eSmrg force_sw = env_var_as_boolean("GBM_ALWAYS_SOFTWARE", false); 1449af69d88dSmrg if (!force_sw) { 1450af69d88dSmrg ret = dri_screen_create(dri); 1451af69d88dSmrg if (ret) 1452af69d88dSmrg ret = dri_screen_create_sw(dri); 1453af69d88dSmrg } else { 1454af69d88dSmrg ret = dri_screen_create_sw(dri); 14553464ebd5Sriastradh } 14563464ebd5Sriastradh 1457af69d88dSmrg if (ret) 1458af69d88dSmrg goto err_dri; 1459af69d88dSmrg 14607e995a2eSmrg return &dri->base; 1461af69d88dSmrg 1462af69d88dSmrgerr_dri: 1463af69d88dSmrg free(dri); 1464af69d88dSmrg 1465af69d88dSmrg return NULL; 14663464ebd5Sriastradh} 14673464ebd5Sriastradh 14683464ebd5Sriastradhstruct gbm_backend gbm_dri_backend = { 14691463c08dSmrg .v0.backend_version = GBM_BACKEND_ABI_VERSION, 14701463c08dSmrg .v0.backend_name = "dri", 14711463c08dSmrg .v0.create_device = dri_device_create, 14723464ebd5Sriastradh}; 1473