1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (c) 2014 The Chromium OS Authors. 5 * Copyright © 2011 Intel Corporation 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 * DEALINGS IN THE SOFTWARE. 24 */ 25 26#include <stdlib.h> 27#include <stdio.h> 28#include <string.h> 29#include <xf86drm.h> 30#include <dlfcn.h> 31#include <sys/types.h> 32#include <sys/stat.h> 33#include <fcntl.h> 34#include <unistd.h> 35 36#include "egl_dri2.h" 37#include "egl_dri2_fallbacks.h" 38#include "loader.h" 39 40static __DRIimage* 41surfaceless_alloc_image(struct dri2_egl_display *dri2_dpy, 42 struct dri2_egl_surface *dri2_surf) 43{ 44 return dri2_dpy->image->createImage( 45 dri2_dpy->dri_screen, 46 dri2_surf->base.Width, 47 dri2_surf->base.Height, 48 dri2_surf->visual, 49 0, 50 NULL); 51} 52 53static void 54surfaceless_free_images(struct dri2_egl_surface *dri2_surf) 55{ 56 struct dri2_egl_display *dri2_dpy = 57 dri2_egl_display(dri2_surf->base.Resource.Display); 58 59 if (dri2_surf->front) { 60 dri2_dpy->image->destroyImage(dri2_surf->front); 61 dri2_surf->front = NULL; 62 } 63} 64 65static int 66surfaceless_image_get_buffers(__DRIdrawable *driDrawable, 67 unsigned int format, 68 uint32_t *stamp, 69 void *loaderPrivate, 70 uint32_t buffer_mask, 71 struct __DRIimageList *buffers) 72{ 73 struct dri2_egl_surface *dri2_surf = loaderPrivate; 74 struct dri2_egl_display *dri2_dpy = 75 dri2_egl_display(dri2_surf->base.Resource.Display); 76 77 buffers->image_mask = 0; 78 buffers->front = NULL; 79 buffers->back = NULL; 80 81 /* The EGL 1.5 spec states that pbuffers are single-buffered. Specifically, 82 * the spec states that they have a back buffer but no front buffer, in 83 * contrast to pixmaps, which have a front buffer but no back buffer. 84 * 85 * Single-buffered surfaces with no front buffer confuse Mesa; so we deviate 86 * from the spec, following the precedent of Mesa's EGL X11 platform. The 87 * X11 platform correctly assigns pbuffers to single-buffered configs, but 88 * assigns the pbuffer a front buffer instead of a back buffer. 89 * 90 * Pbuffers in the X11 platform mostly work today, so let's just copy its 91 * behavior instead of trying to fix (and hence potentially breaking) the 92 * world. 93 */ 94 95 if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) { 96 97 if (!dri2_surf->front) 98 dri2_surf->front = 99 surfaceless_alloc_image(dri2_dpy, dri2_surf); 100 101 buffers->image_mask |= __DRI_IMAGE_BUFFER_FRONT; 102 buffers->front = dri2_surf->front; 103 } 104 105 return 1; 106} 107 108static _EGLSurface * 109dri2_surfaceless_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type, 110 _EGLConfig *conf, const EGLint *attrib_list) 111{ 112 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 113 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf); 114 struct dri2_egl_surface *dri2_surf; 115 const __DRIconfig *config; 116 117 /* Make sure to calloc so all pointers 118 * are originally NULL. 119 */ 120 dri2_surf = calloc(1, sizeof *dri2_surf); 121 122 if (!dri2_surf) { 123 _eglError(EGL_BAD_ALLOC, "eglCreatePbufferSurface"); 124 return NULL; 125 } 126 127 if (!dri2_init_surface(&dri2_surf->base, disp, type, conf, attrib_list, false)) 128 goto cleanup_surface; 129 130 config = dri2_get_dri_config(dri2_conf, type, 131 dri2_surf->base.GLColorspace); 132 133 if (!config) { 134 _eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration"); 135 goto cleanup_surface; 136 } 137 138 if (!dri2_create_drawable(dri2_dpy, config, dri2_surf)) 139 goto cleanup_surface; 140 141 if (conf->RedSize == 5) 142 dri2_surf->visual = __DRI_IMAGE_FORMAT_RGB565; 143 else if (conf->AlphaSize == 0) 144 dri2_surf->visual = __DRI_IMAGE_FORMAT_XRGB8888; 145 else 146 dri2_surf->visual = __DRI_IMAGE_FORMAT_ARGB8888; 147 148 return &dri2_surf->base; 149 150 cleanup_surface: 151 free(dri2_surf); 152 return NULL; 153} 154 155static EGLBoolean 156surfaceless_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf) 157{ 158 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 159 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); 160 161 surfaceless_free_images(dri2_surf); 162 163 dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable); 164 165 dri2_fini_surface(surf); 166 free(dri2_surf); 167 return EGL_TRUE; 168} 169 170static _EGLSurface * 171dri2_surfaceless_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp, 172 _EGLConfig *conf, const EGLint *attrib_list) 173{ 174 return dri2_surfaceless_create_surface(drv, disp, EGL_PBUFFER_BIT, conf, 175 attrib_list); 176} 177 178static EGLBoolean 179surfaceless_add_configs_for_visuals(_EGLDriver *drv, _EGLDisplay *disp) 180{ 181 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 182 static const struct { 183 const char *format_name; 184 unsigned int rgba_masks[4]; 185 } visuals[] = { 186 { "ARGB8888", { 0xff0000, 0xff00, 0xff, 0xff000000 } }, 187 { "RGB888", { 0xff0000, 0xff00, 0xff, 0x0 } }, 188 { "RGB565", { 0x00f800, 0x07e0, 0x1f, 0x0 } }, 189 }; 190 unsigned int format_count[ARRAY_SIZE(visuals)] = { 0 }; 191 unsigned int config_count = 0; 192 193 for (unsigned i = 0; dri2_dpy->driver_configs[i] != NULL; i++) { 194 for (unsigned j = 0; j < ARRAY_SIZE(visuals); j++) { 195 struct dri2_egl_config *dri2_conf; 196 197 dri2_conf = dri2_add_config(disp, dri2_dpy->driver_configs[i], 198 config_count + 1, EGL_PBUFFER_BIT, NULL, 199 visuals[j].rgba_masks); 200 201 if (dri2_conf) { 202 if (dri2_conf->base.ConfigID == config_count + 1) 203 config_count++; 204 format_count[j]++; 205 } 206 } 207 } 208 209 for (unsigned i = 0; i < ARRAY_SIZE(format_count); i++) { 210 if (!format_count[i]) { 211 _eglLog(_EGL_DEBUG, "No DRI config supports native format %s", 212 visuals[i].format_name); 213 } 214 } 215 216 return (config_count != 0); 217} 218 219static const struct dri2_egl_display_vtbl dri2_surfaceless_display_vtbl = { 220 .create_pixmap_surface = dri2_fallback_create_pixmap_surface, 221 .create_pbuffer_surface = dri2_surfaceless_create_pbuffer_surface, 222 .destroy_surface = surfaceless_destroy_surface, 223 .create_image = dri2_create_image_khr, 224 .swap_buffers_region = dri2_fallback_swap_buffers_region, 225 .set_damage_region = dri2_fallback_set_damage_region, 226 .post_sub_buffer = dri2_fallback_post_sub_buffer, 227 .copy_buffers = dri2_fallback_copy_buffers, 228 .query_buffer_age = dri2_fallback_query_buffer_age, 229 .create_wayland_buffer_from_image = dri2_fallback_create_wayland_buffer_from_image, 230 .get_sync_values = dri2_fallback_get_sync_values, 231 .get_dri_drawable = dri2_surface_get_dri_drawable, 232}; 233 234static void 235surfaceless_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate) 236{ 237} 238 239static const __DRIimageLoaderExtension image_loader_extension = { 240 .base = { __DRI_IMAGE_LOADER, 1 }, 241 .getBuffers = surfaceless_image_get_buffers, 242 .flushFrontBuffer = surfaceless_flush_front_buffer, 243}; 244 245static const __DRIswrastLoaderExtension swrast_loader_extension = { 246 .base = { __DRI_SWRAST_LOADER, 1 }, 247 .getDrawableInfo = NULL, 248 .putImage = NULL, 249 .getImage = NULL, 250}; 251 252static const __DRIextension *image_loader_extensions[] = { 253 &image_loader_extension.base, 254 &image_lookup_extension.base, 255 &use_invalidate.base, 256 NULL, 257}; 258 259static const __DRIextension *swrast_loader_extensions[] = { 260 &swrast_loader_extension.base, 261 &image_loader_extension.base, 262 &image_lookup_extension.base, 263 &use_invalidate.base, 264 NULL, 265}; 266 267static bool 268surfaceless_probe_device(_EGLDisplay *disp, bool swrast) 269{ 270#define MAX_DRM_DEVICES 64 271 const unsigned node_type = swrast ? DRM_NODE_PRIMARY : DRM_NODE_RENDER; 272 struct dri2_egl_display *dri2_dpy = disp->DriverData; 273 drmDevicePtr device, devices[MAX_DRM_DEVICES] = { NULL }; 274 int i, num_devices; 275 276 num_devices = drmGetDevices2(0, devices, ARRAY_SIZE(devices)); 277 if (num_devices < 0) 278 return false; 279 280 for (i = 0; i < num_devices; ++i) { 281 device = devices[i]; 282 283 if (!(device->available_nodes & (1 << node_type))) 284 continue; 285 286 dri2_dpy->fd = loader_open_device(device->nodes[node_type]); 287 if (dri2_dpy->fd < 0) 288 continue; 289 290 disp->Device = _eglAddDevice(dri2_dpy->fd, swrast); 291 if (!disp->Device) { 292 close(dri2_dpy->fd); 293 dri2_dpy->fd = -1; 294 continue; 295 } 296 297 char *driver_name = loader_get_driver_for_fd(dri2_dpy->fd); 298 if (swrast) { 299 /* Use kms swrast only with vgem / virtio_gpu. 300 * virtio-gpu fallbacks to software rendering when 3D features 301 * are unavailable since 6c5ab, and kms_swrast is more 302 * feature complete than swrast. 303 */ 304 if (strcmp(driver_name, "vgem") == 0 || 305 strcmp(driver_name, "virtio_gpu") == 0) 306 dri2_dpy->driver_name = strdup("kms_swrast"); 307 free(driver_name); 308 } else { 309 /* Use the given hardware driver */ 310 dri2_dpy->driver_name = driver_name; 311 } 312 313 if (dri2_dpy->driver_name && dri2_load_driver_dri3(disp)) 314 break; 315 316 free(dri2_dpy->driver_name); 317 dri2_dpy->driver_name = NULL; 318 close(dri2_dpy->fd); 319 dri2_dpy->fd = -1; 320 } 321 drmFreeDevices(devices, num_devices); 322 323 if (i == num_devices) 324 return false; 325 326 if (swrast) 327 dri2_dpy->loader_extensions = swrast_loader_extensions; 328 else 329 dri2_dpy->loader_extensions = image_loader_extensions; 330 331 return true; 332} 333 334static bool 335surfaceless_probe_device_sw(_EGLDisplay *disp) 336{ 337 struct dri2_egl_display *dri2_dpy = disp->DriverData; 338 339 dri2_dpy->fd = -1; 340 disp->Device = _eglAddDevice(dri2_dpy->fd, true); 341 assert(disp->Device); 342 343 dri2_dpy->driver_name = strdup("swrast"); 344 if (!dri2_dpy->driver_name) 345 return false; 346 347 if (!dri2_load_driver_swrast(disp)) { 348 free(dri2_dpy->driver_name); 349 dri2_dpy->driver_name = NULL; 350 return false; 351 } 352 353 dri2_dpy->loader_extensions = swrast_loader_extensions; 354 return true; 355} 356 357EGLBoolean 358dri2_initialize_surfaceless(_EGLDriver *drv, _EGLDisplay *disp) 359{ 360 struct dri2_egl_display *dri2_dpy; 361 const char* err; 362 bool driver_loaded = false; 363 364 dri2_dpy = calloc(1, sizeof *dri2_dpy); 365 if (!dri2_dpy) 366 return _eglError(EGL_BAD_ALLOC, "eglInitialize"); 367 368 dri2_dpy->fd = -1; 369 disp->DriverData = (void *) dri2_dpy; 370 371 if (!disp->Options.ForceSoftware) { 372 driver_loaded = surfaceless_probe_device(disp, false); 373 if (!driver_loaded) 374 _eglLog(_EGL_WARNING, 375 "No hardware driver found, falling back to software rendering"); 376 } 377 378 if (!driver_loaded) 379 driver_loaded = surfaceless_probe_device(disp, true); 380 381 if (!driver_loaded) { 382 _eglLog(_EGL_DEBUG, "Falling back to surfaceless swrast without DRM."); 383 if (!surfaceless_probe_device_sw(disp)) { 384 err = "DRI2: failed to load driver"; 385 goto cleanup; 386 } 387 } 388 389 if (!dri2_create_screen(disp)) { 390 err = "DRI2: failed to create screen"; 391 goto cleanup; 392 } 393 394 if (!dri2_setup_extensions(disp)) { 395 err = "DRI2: failed to find required DRI extensions"; 396 goto cleanup; 397 } 398 399 dri2_setup_screen(disp); 400 401 if (!surfaceless_add_configs_for_visuals(drv, disp)) { 402 err = "DRI2: failed to add configs"; 403 goto cleanup; 404 } 405 406 /* Fill vtbl last to prevent accidentally calling virtual function during 407 * initialization. 408 */ 409 dri2_dpy->vtbl = &dri2_surfaceless_display_vtbl; 410 411 return EGL_TRUE; 412 413cleanup: 414 dri2_display_destroy(disp); 415 return _eglError(EGL_NOT_INITIALIZED, err); 416} 417