1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (c) 2021 Huawei Device Co., Ltd. * 5 * 6 * Based on platform_android, which has 7 * 8 * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com> 9 * Copyright (C) 2010-2011 LunarG Inc. 10 * 11 * Based on platform_x11, which has 12 * 13 * Copyright © 2011 Intel Corporation 14 * 15 * Permission is hereby granted, free of charge, to any person obtaining a 16 * copy of this software and associated documentation files (the "Software"), 17 * to deal in the Software without restriction, including without limitation 18 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 19 * and/or sell copies of the Software, and to permit persons to whom the 20 * Software is furnished to do so, subject to the following conditions: 21 * 22 * The above copyright notice and this permission notice shall be included 23 * in all copies or substantial portions of the Software. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 26 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 27 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 28 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 29 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 30 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 31 * DEALINGS IN THE SOFTWARE. 32 */ 33 34#include <errno.h> 35#include <dirent.h> 36#include <dlfcn.h> 37#include <fcntl.h> 38#include <xf86drm.h> 39#include <stdbool.h> 40#include <stdio.h> 41#include <sys/types.h> 42#include <drm-uapi/drm_fourcc.h> 43 44#include "util/compiler.h" 45#include "util/os_file.h" 46 47#include "loader.h" 48#include "egl_dri2.h" 49#include "platform_ohos.h" 50#include "libsync.h" 51#ifdef HAVE_DRM_GRALLOC 52#include <gralloc_drm_handle.h> 53#include "gralloc_drm.h" 54#endif /* HAVE_DRM_GRALLOC */ 55#include "ohos_log.h" 56 57#define ALIGN(val, align) (((val) + (align)-1) & ~((align)-1)) 58 59static int 60get_format_bpp(int native) 61{ 62 int bpp; 63 64 switch (native) { 65 case PIXEL_FMT_RGBA_8888: 66 case PIXEL_FMT_RGBX_8888: 67 case PIXEL_FMT_BGRA_8888: 68 bpp = 4; 69 break; 70 case PIXEL_FMT_RGB_565: 71 bpp = 2; 72 break; 73 default: 74 bpp = 0; 75 break; 76 } 77 78 return bpp; 79} 80 81/* returns # of fds, and by reference the actual fds */ 82static unsigned 83get_native_buffer_fds(struct ANativeWindowBuffer *buf, int fds[3]) 84{ 85 BufferHandle *handle = GetBufferHandleFromNative(buf); 86 if (handle == NULL) { 87 return 0; 88 } 89 90 fds[0] = handle->fd; 91 return 1; 92} 93 94/* createImageFromFds requires fourcc format */ 95static int get_fourcc(int native) 96{ 97 switch (native) { 98 case PIXEL_FMT_RGB_565: 99 return DRM_FORMAT_RGB565; 100 case PIXEL_FMT_BGRA_8888: 101 return DRM_FORMAT_ARGB8888; 102 case PIXEL_FMT_RGBA_8888: 103 return DRM_FORMAT_ABGR8888; 104 case PIXEL_FMT_RGBX_8888: 105 return DRM_FORMAT_XBGR8888; 106 default: 107 _eglLog(_EGL_WARNING, "unsupported native buffer format 0x%{public}x", native); 108 } 109 return -1; 110} 111 112static int 113native_window_buffer_get_buffer_info(struct dri2_egl_display *dri2_dpy, 114 struct ANativeWindowBuffer *buf, 115 struct buffer_info *out_buf_info) 116{ 117 int num_planes = 0; 118 int drm_fourcc = 0; 119 int pitch = 0; 120 int fds[3]; 121 /* 122 * Non-YUV formats could *also* have multiple planes, such as ancillary 123 * color compression state buffer, but the rest of the code isn't ready 124 * yet to deal with modifiers: 125 */ 126 num_planes = get_native_buffer_fds(buf, fds); 127 if (num_planes == 0) { 128 return -EINVAL; 129 } 130 131 assert(num_planes == 1); 132 BufferHandle *bufferHandle; 133 bufferHandle = GetBufferHandleFromNative(buf); 134 drm_fourcc = get_fourcc(bufferHandle->format); 135 if (drm_fourcc == -1) { 136 _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR"); 137 return -EINVAL; 138 } 139 pitch = bufferHandle->stride; 140 if (pitch == 0) { 141 _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR"); 142 return -EINVAL; 143 } 144 145 *out_buf_info = (struct buffer_info) { 146 .width = bufferHandle->width, 147 .height = bufferHandle->height, 148 .drm_fourcc = drm_fourcc, 149 .num_planes = num_planes, 150 .fds = {fds[0], -1, -1, -1}, 151 .modifier = DRM_FORMAT_MOD_INVALID, 152 .offsets = {0, 0, 0, 0}, 153 .pitches = {pitch, 0, 0, 0}, 154 .yuv_color_space = EGL_ITU_REC601_EXT, 155 .sample_range = EGL_YUV_NARROW_RANGE_EXT, 156 .horizontal_siting = EGL_YUV_CHROMA_SITING_0_EXT, 157 .vertical_siting = EGL_YUV_CHROMA_SITING_0_EXT, 158 }; 159 160 return 0; 161} 162 163static __DRIimage * 164ohos_create_image_from_buffer_info(struct dri2_egl_display *dri2_dpy, 165 struct buffer_info *buf_info, 166 void *priv) 167{ 168 unsigned error; 169 170 if (dri2_dpy->image->base.version >= 15 && 171 dri2_dpy->image->createImageFromDmaBufs2 != NULL) { 172 return dri2_dpy->image->createImageFromDmaBufs2( 173 dri2_dpy->dri_screen, buf_info->width, buf_info->height, 174 buf_info->drm_fourcc, buf_info->modifier, buf_info->fds, 175 buf_info->num_planes, buf_info->pitches, buf_info->offsets, 176 buf_info->yuv_color_space, buf_info->sample_range, 177 buf_info->horizontal_siting, buf_info->vertical_siting, &error, 178 priv); 179 } 180 181 return dri2_dpy->image->createImageFromDmaBufs( 182 dri2_dpy->dri_screen, buf_info->width, buf_info->height, 183 buf_info->drm_fourcc, buf_info->fds, buf_info->num_planes, 184 buf_info->pitches, buf_info->offsets, buf_info->yuv_color_space, 185 buf_info->sample_range, buf_info->horizontal_siting, 186 buf_info->vertical_siting, &error, priv); 187} 188 189static __DRIimage * 190ohos_create_image_from_native_buffer(_EGLDisplay *disp, 191 struct ANativeWindowBuffer *buf, 192 void *priv) 193{ 194 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 195 struct buffer_info buf_info; 196 __DRIimage *img = NULL; 197 198 /* If dri driver is gallium virgl, real modifier info queried back from 199 * CrOS info (and potentially mapper metadata if integrated later) cannot 200 * get resolved and the buffer import will fail. Thus the fallback behavior 201 * is preserved down to native_window_buffer_get_buffer_info() so that the 202 * buffer can be imported without modifier info as a last resort. 203 */ 204 205 if (!native_window_buffer_get_buffer_info(dri2_dpy, buf, &buf_info)) { 206 img = ohos_create_image_from_buffer_info(dri2_dpy, &buf_info, priv); 207 } 208 209 return img; 210} 211 212static EGLBoolean 213ohos_window_dequeue_buffer(struct dri2_egl_surface *dri2_surf) 214{ 215 int fence_fd; 216 217 if (ANativeWindow_dequeueBuffer(dri2_surf->window, &dri2_surf->buffer, 218 &fence_fd)) { 219 return EGL_FALSE; 220 } 221 222 /* If access to the buffer is controlled by a sync fence, then block on the 223 * fence. 224 * 225 * It may be more performant to postpone blocking until there is an 226 * immediate need to write to the buffer. But doing so would require adding 227 * hooks to the DRI2 loader. 228 * 229 * From the ANativeWindow_dequeueBuffer documentation: 230 * 231 * The libsync fence file descriptor returned in the int pointed to by 232 * the fenceFd argument will refer to the fence that must signal 233 * before the dequeued buffer may be written to. A value of -1 234 * indicates that the caller may access the buffer immediately without 235 * waiting on a fence. If a valid file descriptor is returned (i.e. 236 * any value except -1) then the caller is responsible for closing the 237 * file descriptor. 238 */ 239 if (fence_fd >= 0) { 240 /* From the SYNC_IOC_WAIT documentation in <linux/sync.h>: 241 * 242 * Waits indefinitely if timeout < 0. 243 */ 244 int timeout = -1; 245 sync_wait(fence_fd, timeout); 246 close(fence_fd); 247 } 248 /* Record all the buffers created by ANativeWindow and update back buffer 249 * for updating buffer's age in swap_buffers. 250 */ 251 EGLBoolean updated = EGL_FALSE; 252 for (int i = 0; i < dri2_surf->color_buffers_count; i++) { 253 if (!dri2_surf->color_buffers[i].buffer) { 254 dri2_surf->color_buffers[i].buffer = dri2_surf->buffer; 255 } 256 if (dri2_surf->color_buffers[i].buffer == dri2_surf->buffer) { 257 dri2_surf->back = &dri2_surf->color_buffers[i]; 258 updated = EGL_TRUE; 259 break; 260 } 261 } 262 263 if (!updated) { 264 /* In case of all the buffers were recreated by ANativeWindow, reset 265 * the color_buffers 266 */ 267 for (int i = 0; i < dri2_surf->color_buffers_count; i++) { 268 dri2_surf->color_buffers[i].buffer = NULL; 269 dri2_surf->color_buffers[i].age = 0; 270 } 271 dri2_surf->color_buffers[0].buffer = dri2_surf->buffer; 272 dri2_surf->back = &dri2_surf->color_buffers[0]; 273 } 274 275 return EGL_TRUE; 276} 277 278static EGLBoolean 279ohos_window_enqueue_buffer(_EGLDisplay *disp, struct dri2_egl_surface *dri2_surf) 280{ 281 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 282 283 /* To avoid blocking other EGL calls, release the display mutex before 284 * we enter ohos_window_enqueue_buffer() and re-acquire the mutex upon 285 * return. 286 */ 287 mtx_unlock(&disp->Mutex); 288 289 /* Queue the buffer with stored out fence fd. The ANativeWindow or buffer 290 * consumer may choose to wait for the fence to signal before accessing 291 * it. If fence fd value is -1, buffer can be accessed by consumer 292 * immediately. Consumer or application shouldn't rely on timestamp 293 * associated with fence if the fence fd is -1. 294 * 295 * Ownership of fd is transferred to consumer after queueBuffer and the 296 * consumer is responsible for closing it. Caller must not use the fd 297 * after passing it to queueBuffer. 298 */ 299 int fence_fd = dri2_surf->out_fence_fd; 300 dri2_surf->out_fence_fd = -1; 301 ANativeWindow_queueBuffer(dri2_surf->window, dri2_surf->buffer, fence_fd); 302 303 dri2_surf->buffer = NULL; 304 dri2_surf->back = NULL; 305 306 mtx_lock(&disp->Mutex); 307 308 if (dri2_surf->dri_image_back) { 309 dri2_dpy->image->destroyImage(dri2_surf->dri_image_back); 310 dri2_surf->dri_image_back = NULL; 311 } 312 313 return EGL_TRUE; 314} 315 316static void 317ohos_window_cancel_buffer(struct dri2_egl_surface *dri2_surf) 318{ 319 int ret; 320 int fence_fd = dri2_surf->out_fence_fd; 321 322 dri2_surf->out_fence_fd = -1; 323 ret = ANativeWindow_cancelBuffer(dri2_surf->window, dri2_surf->buffer, 324 fence_fd); 325 dri2_surf->buffer = NULL; 326 if (ret < 0) { 327 _eglLog(_EGL_WARNING, "ANativeWindow_cancelBuffer failed"); 328 dri2_surf->base.Lost = EGL_TRUE; 329 } 330} 331 332static _EGLSurface * 333ohos_create_surface(_EGLDisplay *disp, EGLint type, _EGLConfig *conf, 334 void *native_window, const EGLint *attrib_list) 335{ 336 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 337 struct dri2_egl_config *dri2_conf = dri2_egl_config(conf); 338 struct dri2_egl_surface *dri2_surf; 339 struct ANativeWindow *window = native_window; 340 const __DRIconfig *config; 341 342 dri2_surf = calloc(1, sizeof *dri2_surf); 343 if (!dri2_surf) { 344 _eglError(EGL_BAD_ALLOC, "ohos_create_surface"); 345 return NULL; 346 } 347 348 if (!dri2_init_surface(&dri2_surf->base, disp, type, conf, attrib_list, 349 true, native_window)) { 350 goto cleanup_surface; 351 } 352 353 if (type == EGL_WINDOW_BIT) { 354 int format; 355 int buffer_count; 356 357 format = ANativeWindow_getFormat(window); 358 if (format < 0) { 359 _eglError(EGL_BAD_NATIVE_WINDOW, "ohos_create_surface"); 360 goto cleanup_surface; 361 } 362 363 /* Required buffer caching slots. */ 364 buffer_count = 3; // default use 3 buffer 365 366 dri2_surf->color_buffers = calloc(buffer_count, 367 sizeof(*dri2_surf->color_buffers)); 368 if (!dri2_surf->color_buffers) { 369 _eglError(EGL_BAD_ALLOC, "ohos_create_surface"); 370 goto cleanup_surface; 371 } 372 dri2_surf->color_buffers_count = buffer_count; 373 374 if (format != dri2_conf->base.NativeVisualID) { 375 _eglLog(_EGL_WARNING, "Native format mismatch: 0x%{public}x != 0x%{public}x", 376 format, dri2_conf->base.NativeVisualID); 377 } 378 379 NativeWindowHandleOpt(window, GET_BUFFER_GEOMETRY, &dri2_surf->base.Height, &dri2_surf->base.Width); 380 } 381 382 config = dri2_get_dri_config(dri2_conf, type, 383 dri2_surf->base.GLColorspace); 384 if (!config) { 385 _eglError(EGL_BAD_MATCH, "Unsupported surfacetype/colorspace configuration"); 386 goto cleanup_surface; 387 } 388 389 if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf)) { 390 goto cleanup_surface; 391 } 392 393 if (window) { 394 ANativeWindow_acquire(window); 395 dri2_surf->window = window; 396 } 397 398 return &dri2_surf->base; 399 400cleanup_surface: 401 if (dri2_surf->color_buffers_count) { 402 free(dri2_surf->color_buffers); 403 } 404 free(dri2_surf); 405 406 return NULL; 407} 408 409static _EGLSurface * 410ohos_create_window_surface(_EGLDisplay *disp, _EGLConfig *conf, 411 void *native_window, const EGLint *attrib_list) 412{ 413 return ohos_create_surface(disp, EGL_WINDOW_BIT, conf, 414 native_window, attrib_list); 415} 416 417static _EGLSurface * 418ohos_create_pbuffer_surface(_EGLDisplay *disp, _EGLConfig *conf, 419 const EGLint *attrib_list) 420{ 421 return ohos_create_surface(disp, EGL_PBUFFER_BIT, conf, 422 NULL, attrib_list); 423} 424 425static EGLBoolean 426ohos_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf) 427{ 428 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 429 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); 430 431 dri2_egl_surface_free_local_buffers(dri2_surf); 432 433 if (dri2_surf->base.Type == EGL_WINDOW_BIT) { 434 if (dri2_surf->buffer) { 435 ohos_window_cancel_buffer(dri2_surf); 436 } 437 438 ANativeWindow_release(dri2_surf->window); 439 } 440 441 if (dri2_surf->dri_image_back) { 442 _eglLog(_EGL_DEBUG, "%{public}s : %{public}d : destroy dri_image_back", __func__, __LINE__); 443 dri2_dpy->image->destroyImage(dri2_surf->dri_image_back); 444 dri2_surf->dri_image_back = NULL; 445 } 446 447 if (dri2_surf->dri_image_front) { 448 _eglLog(_EGL_DEBUG, "%{public}s : %{public}d : destroy dri_image_front", __func__, __LINE__); 449 dri2_dpy->image->destroyImage(dri2_surf->dri_image_front); 450 dri2_surf->dri_image_front = NULL; 451 } 452 453 dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable); 454 455 dri2_fini_surface(surf); 456 free(dri2_surf->color_buffers); 457 free(dri2_surf); 458 459 return EGL_TRUE; 460} 461 462static int 463update_buffers(struct dri2_egl_surface *dri2_surf) 464{ 465 if (dri2_surf->base.Lost) { 466 return -1; 467 } 468 469 if (dri2_surf->base.Type != EGL_WINDOW_BIT) { 470 return 0; 471 } 472 473 /* try to dequeue the next back buffer */ 474 if (!dri2_surf->buffer && !ohos_window_dequeue_buffer(dri2_surf)) { 475 _eglLog(_EGL_WARNING, "Could not dequeue buffer from native window"); 476 dri2_surf->base.Lost = EGL_TRUE; 477 return -1; 478 } 479 BufferHandle *handle = GetBufferHandleFromNative(dri2_surf->buffer); 480 /* free outdated buffers and update the surface size */ 481 if (dri2_surf->base.Width != handle->width || 482 dri2_surf->base.Height != handle->height) { 483 dri2_egl_surface_free_local_buffers(dri2_surf); 484 dri2_surf->base.Width = handle->width; 485 dri2_surf->base.Height = handle->height; 486 } 487 488 return 0; 489} 490 491static int 492get_front_bo(struct dri2_egl_surface *dri2_surf, unsigned int format) 493{ 494 struct dri2_egl_display *dri2_dpy = 495 dri2_egl_display(dri2_surf->base.Resource.Display); 496 497 if (dri2_surf->dri_image_front) { 498 return 0; 499 } 500 501 if (dri2_surf->base.Type == EGL_WINDOW_BIT) { 502 /* According current EGL spec, front buffer rendering 503 * for window surface is not supported now. 504 * and mesa doesn't have the implementation of this case. 505 * Add warning message, but not treat it as error. 506 */ 507 _eglLog(_EGL_DEBUG, "DRI driver requested unsupported front buffer for window surface"); 508 } else if (dri2_surf->base.Type == EGL_PBUFFER_BIT) { 509 dri2_surf->dri_image_front = 510 dri2_dpy->image->createImage(dri2_dpy->dri_screen, 511 dri2_surf->base.Width, 512 dri2_surf->base.Height, 513 format, 514 0, 515 NULL); 516 if (!dri2_surf->dri_image_front) { 517 _eglLog(_EGL_WARNING, "dri2_image_front allocation failed"); 518 return -1; 519 } 520 } 521 522 return 0; 523} 524 525static int 526get_back_bo(struct dri2_egl_surface *dri2_surf) 527{ 528 _EGLDisplay *disp = dri2_surf->base.Resource.Display; 529 530 if (dri2_surf->dri_image_back) { 531 return 0; 532 } 533 534 if (dri2_surf->base.Type == EGL_WINDOW_BIT) { 535 if (!dri2_surf->buffer) { 536 _eglLog(_EGL_WARNING, "Could not get native buffer"); 537 return -1; 538 } 539 540 dri2_surf->dri_image_back = 541 ohos_create_image_from_native_buffer(disp, dri2_surf->buffer, NULL); 542 if (!dri2_surf->dri_image_back) { 543 _eglLog(_EGL_WARNING, "failed to create DRI image from FD"); 544 return -1; 545 } 546 } else if (dri2_surf->base.Type == EGL_PBUFFER_BIT) { 547 /* The EGL 1.5 spec states that pbuffers are single-buffered. Specifically, 548 * the spec states that they have a back buffer but no front buffer, in 549 * contrast to pixmaps, which have a front buffer but no back buffer. 550 * 551 * Single-buffered surfaces with no front buffer confuse Mesa; so we deviate 552 * from the spec, following the precedent of Mesa's EGL X11 platform. The 553 * X11 platform correctly assigns pbuffers to single-buffered configs, but 554 * assigns the pbuffer a front buffer instead of a back buffer. 555 * 556 * Pbuffers in the X11 platform mostly work today, so let's just copy its 557 * behavior instead of trying to fix (and hence potentially breaking) the 558 * world. 559 */ 560 _eglLog(_EGL_DEBUG, "DRI driver requested unsupported back buffer for pbuffer surface"); 561 } 562 563 return 0; 564} 565 566/* Some drivers will pass multiple bits in buffer_mask. 567 * For such case, will go through all the bits, and 568 * will not return error when unsupported buffer is requested, only 569 * return error when the allocation for supported buffer failed. 570 */ 571static int 572ohos_image_get_buffers(__DRIdrawable *driDrawable, 573 unsigned int format, 574 uint32_t *stamp, 575 void *loaderPrivate, 576 uint32_t buffer_mask, 577 struct __DRIimageList *images) 578{ 579 struct dri2_egl_surface *dri2_surf = loaderPrivate; 580 581 images->image_mask = 0; 582 images->front = NULL; 583 images->back = NULL; 584 585 if (update_buffers(dri2_surf) < 0) { 586 return 0; 587 } 588 589 if (_eglSurfaceInSharedBufferMode(&dri2_surf->base)) { 590 if (get_back_bo(dri2_surf) < 0) { 591 return 0; 592 } 593 594 /* We have dri_image_back because this is a window surface and 595 * get_back_bo() succeeded. 596 */ 597 assert(dri2_surf->dri_image_back); 598 images->back = dri2_surf->dri_image_back; 599 images->image_mask |= __DRI_IMAGE_BUFFER_SHARED; 600 601 /* There exists no accompanying back nor front buffer. */ 602 return 1; 603 } 604 605 if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) { 606 if (get_front_bo(dri2_surf, format) < 0) { 607 return 0; 608 } 609 610 if (dri2_surf->dri_image_front) { 611 images->front = dri2_surf->dri_image_front; 612 images->image_mask |= __DRI_IMAGE_BUFFER_FRONT; 613 } 614 } 615 616 if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) { 617 if (get_back_bo(dri2_surf) < 0) { 618 return 0; 619 } 620 621 if (dri2_surf->dri_image_back) { 622 images->back = dri2_surf->dri_image_back; 623 images->image_mask |= __DRI_IMAGE_BUFFER_BACK; 624 } 625 } 626 627 return 1; 628} 629 630static EGLint 631ohos_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surface) 632{ 633 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface); 634 635 if (update_buffers(dri2_surf) < 0) { 636 _eglError(EGL_BAD_ALLOC, "ohos_query_buffer_age"); 637 return -1; 638 } 639 640 return dri2_surf->back ? dri2_surf->back->age : 0; 641} 642 643static EGLBoolean 644ohos_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw) 645{ 646 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 647 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw); 648 const bool has_mutable_rb = _eglSurfaceHasMutableRenderBuffer(draw); 649 650 /* From the EGL_KHR_mutable_render_buffer spec (v12): 651 * 652 * If surface is a single-buffered window, pixmap, or pbuffer surface 653 * for which there is no pending change to the EGL_RENDER_BUFFER 654 * attribute, eglSwapBuffers has no effect. 655 */ 656 if (has_mutable_rb && 657 draw->RequestedRenderBuffer == EGL_SINGLE_BUFFER && 658 draw->ActiveRenderBuffer == EGL_SINGLE_BUFFER) { 659 _eglLog(_EGL_DEBUG, "%{public}s: remain in shared buffer mode", __func__); 660 return EGL_TRUE; 661 } 662 663 for (int i = 0; i < dri2_surf->color_buffers_count; i++) { 664 if (dri2_surf->color_buffers[i].age > 0) { 665 dri2_surf->color_buffers[i].age++; 666 } 667 } 668 669 /* "XXX: we don't use get_back_bo() since it causes regressions in 670 * several dEQP tests. 671 */ 672 if (dri2_surf->back) { 673 dri2_surf->back->age = 1; 674 } 675 676 dri2_flush_drawable_for_swapbuffers(disp, draw); 677 678 /* dri2_surf->buffer can be null even when no error has occured. For 679 * example, if the user has called no GL rendering commands since the 680 * previous eglSwapBuffers, then the driver may have not triggered 681 * a callback to ANativeWindow_dequeueBuffer, in which case 682 * dri2_surf->buffer remains null. 683 */ 684 if (dri2_surf->buffer) { 685 ohos_window_enqueue_buffer(disp, dri2_surf); 686 } 687 688 dri2_dpy->flush->invalidate(dri2_surf->dri_drawable); 689 690 return EGL_TRUE; 691} 692 693static EGLBoolean 694ohos_query_surface(_EGLDisplay *disp, _EGLSurface *surf, 695 EGLint attribute, EGLint *value) 696{ 697 struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf); 698 EGLint dummy; 699 switch (attribute) { 700 case EGL_WIDTH: 701 if (dri2_surf->base.Type == EGL_WINDOW_BIT && dri2_surf->window) { 702 NativeWindowHandleOpt(dri2_surf->window, 703 GET_BUFFER_GEOMETRY, &dummy, value); 704 return EGL_TRUE; 705 } 706 break; 707 case EGL_HEIGHT: 708 if (dri2_surf->base.Type == EGL_WINDOW_BIT && dri2_surf->window) { 709 NativeWindowHandleOpt(dri2_surf->window, 710 GET_BUFFER_GEOMETRY, value, &dummy); 711 return EGL_TRUE; 712 } 713 break; 714 default: 715 break; 716 } 717 return _eglQuerySurface(disp, surf, attribute, value); 718} 719 720static _EGLImage * 721dri2_create_image_ohos_native_buffer(_EGLDisplay *disp, 722 _EGLContext *ctx, 723 struct ANativeWindowBuffer *buf) 724{ 725 if (ctx != NULL) { 726 /* From the EGL_OHOS_image_native_buffer spec: 727 * 728 * * If <target> is EGL_NATIVE_BUFFER_OHOS and <ctx> is not 729 * EGL_NO_CONTEXT, the error EGL_BAD_CONTEXT is generated. 730 */ 731 _eglError(EGL_BAD_CONTEXT, "eglCreateEGLImageKHR: for " 732 "EGL_NATIVE_BUFFER_OHOS, the context must be " 733 "EGL_NO_CONTEXT"); 734 return NULL; 735 } 736 __DRIimage *dri_image = 737 ohos_create_image_from_native_buffer(disp, buf, buf); 738 739 if (dri_image) { 740 return dri2_create_image_from_dri(disp, dri_image); 741 } 742 743 return NULL; 744} 745 746static _EGLImage * 747ohos_create_image_khr(_EGLDisplay *disp, _EGLContext *ctx, EGLenum target, 748 EGLClientBuffer buffer, const EGLint *attr_list) 749{ 750 switch (target) { 751 case EGL_NATIVE_BUFFER_OHOS: 752 return dri2_create_image_ohos_native_buffer(disp, ctx, 753 (struct ANativeWindowBuffer *)buffer); 754 default: 755 return dri2_create_image_khr(disp, ctx, target, buffer, attr_list); 756 } 757} 758 759static void 760ohos_flush_front_buffer(__DRIdrawable *driDrawable, void *loaderPrivate) 761{ 762} 763 764#ifdef HAVE_DRM_GRALLOC 765static int 766ohos_get_buffers_parse_attachments(struct dri2_egl_surface *dri2_surf, 767 unsigned int *attachments, int count) 768{ 769 int num_buffers = 0; 770 771 /* fill dri2_surf->buffers */ 772 for (int i = 0; i < count * 2; i += 2) { 773 __DRIbuffer *buf, *local; 774 775 assert(num_buffers < ARRAY_SIZE(dri2_surf->buffers)); 776 buf = &dri2_surf->buffers[num_buffers]; 777 778 switch (attachments[i]) { 779 case __DRI_BUFFER_BACK_LEFT: 780 if (dri2_surf->base.Type == EGL_WINDOW_BIT) { 781 buf->attachment = attachments[i]; 782 buf->name = get_native_buffer_name(dri2_surf->buffer); 783 buf->cpp = get_format_bpp(dri2_surf->buffer->format); 784 buf->pitch = dri2_surf->buffer->stride * buf->cpp; 785 buf->flags = 0; 786 787 buf->name ? num_buffers++ : 0; 788 789 break; 790 } 791 FALLTHROUGH; /* for pbuffers */ 792 case __DRI_BUFFER_DEPTH: 793 case __DRI_BUFFER_STENCIL: 794 case __DRI_BUFFER_ACCUM: 795 case __DRI_BUFFER_DEPTH_STENCIL: 796 case __DRI_BUFFER_HIZ: 797 local = dri2_egl_surface_alloc_local_buffer(dri2_surf, 798 attachments[i], attachments[i + 1]); 799 800 if (local) { 801 *buf = *local; 802 num_buffers++; 803 } 804 break; 805 case __DRI_BUFFER_FRONT_LEFT: 806 case __DRI_BUFFER_FRONT_RIGHT: 807 case __DRI_BUFFER_FAKE_FRONT_LEFT: 808 case __DRI_BUFFER_FAKE_FRONT_RIGHT: 809 case __DRI_BUFFER_BACK_RIGHT: 810 default: 811 /* no front or right buffers */ 812 break; 813 } 814 } 815 816 return num_buffers; 817} 818 819static __DRIbuffer * 820ohos_get_buffers_with_format(__DRIdrawable *driDrawable, 821 int *width, int *height, 822 unsigned int *attachments, int count, 823 int *out_count, void *loaderPrivate) 824{ 825 struct dri2_egl_surface *dri2_surf = loaderPrivate; 826 827 if (update_buffers(dri2_surf) < 0) { 828 return NULL; 829 } 830 831 *out_count = ohos_get_buffers_parse_attachments(dri2_surf, attachments, count); 832 833 if (width) { 834 *width = dri2_surf->base.Width; 835 } 836 if (height) { 837 *height = dri2_surf->base.Height; 838 } 839 840 return dri2_surf->buffers; 841} 842#endif /* HAVE_DRM_GRALLOC */ 843 844static unsigned 845ohos_get_capability(void *loaderPrivate, enum dri_loader_cap cap) 846{ 847 /* Note: loaderPrivate is _EGLDisplay* */ 848 switch (cap) { 849 case DRI_LOADER_CAP_RGBA_ORDERING: 850 return 1; 851 default: 852 return 0; 853 } 854} 855 856static void 857ohos_destroy_loader_image_state(void *loaderPrivate) 858{ 859} 860 861static EGLBoolean 862ohos_add_configs_for_visuals(_EGLDisplay *disp) 863{ 864 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 865 static const struct { 866 int format; 867 int rgba_shifts[4]; 868 unsigned int rgba_sizes[4]; 869 } visuals[] = { 870 {PIXEL_FMT_RGBA_8888, {0, 8, 16, 24}, {8, 8, 8, 8}}, 871 {PIXEL_FMT_RGBX_8888, {0, 8, 16, -1}, {8, 8, 8, 0}}, 872 {PIXEL_FMT_RGB_565, {11, 5, 0, -1}, {5, 6, 5, 0}}, 873 /* This must be after PIXEL_FMT_RGBA_8888, we only keep BGRA 874 * visual if it turns out RGBA visual is not available. 875 */ 876 {PIXEL_FMT_BGRA_8888, {16, 8, 0, 24}, {8, 8, 8, 8}}, 877 }; 878 879 unsigned int format_count[ARRAY_SIZE(visuals)] = {0}; 880 int config_count = 0; 881 882 bool has_rgba = false; 883 for (int i = 0; i < ARRAY_SIZE(visuals); i++) { 884 if (visuals[i].format == PIXEL_FMT_BGRA_8888 && has_rgba) { 885 continue; 886 } 887 for (int j = 0; dri2_dpy->driver_configs[j]; j++) { 888 const EGLint surface_type = EGL_WINDOW_BIT | EGL_PBUFFER_BIT; 889 890 const EGLint config_attrs[] = { 891 EGL_NATIVE_VISUAL_ID, visuals[i].format, 892 EGL_NATIVE_VISUAL_TYPE, visuals[i].format, 893 EGL_NONE}; 894 895 struct dri2_egl_config *dri2_conf = 896 dri2_add_config(disp, dri2_dpy->driver_configs[j], 897 config_count + 1, surface_type, config_attrs, 898 visuals[i].rgba_shifts, visuals[i].rgba_sizes); 899 if (dri2_conf) { 900 (dri2_conf->base.ConfigID == config_count + 1) ? config_count++ : 0; 901 format_count[i]++; 902 } 903 } 904 if (visuals[i].format == PIXEL_FMT_RGBA_8888 && format_count[i]) { 905 has_rgba = true; 906 } 907 } 908 909 for (int i = 0; i < ARRAY_SIZE(format_count); i++) { 910 if (!format_count[i]) { 911 _eglLog(_EGL_DEBUG, "No DRI config supports native format 0x%{public}x", 912 visuals[i].format); 913 } 914 } 915 916 return (config_count != 0); 917} 918 919static const struct dri2_egl_display_vtbl ohos_display_vtbl = { 920 .authenticate = NULL, 921 .create_window_surface = ohos_create_window_surface, 922 .create_pbuffer_surface = ohos_create_pbuffer_surface, 923 .destroy_surface = ohos_destroy_surface, 924 .create_image = ohos_create_image_khr, 925 .swap_buffers = ohos_swap_buffers, 926 .swap_interval = NULL, 927 .query_buffer_age = ohos_query_buffer_age, 928 .query_surface = ohos_query_surface, 929 .get_dri_drawable = dri2_surface_get_dri_drawable, 930}; 931 932static const __DRIimageLoaderExtension ohos_image_loader_extension = { 933 .base = {__DRI_IMAGE_LOADER, 4}, 934 935 .getBuffers = ohos_image_get_buffers, 936 .flushFrontBuffer = ohos_flush_front_buffer, 937 .getCapability = ohos_get_capability, 938 .flushSwapBuffers = NULL, 939 .destroyLoaderImageState = ohos_destroy_loader_image_state, 940}; 941 942static void 943ohos_display_shared_buffer(__DRIdrawable *driDrawable, int fence_fd, 944 void *loaderPrivate) 945{ 946 struct dri2_egl_surface *dri2_surf = loaderPrivate; 947 struct ANativeWindowBuffer *old_buffer UNUSED = dri2_surf->buffer; 948 949 if (!_eglSurfaceInSharedBufferMode(&dri2_surf->base)) { 950 _eglLog(_EGL_WARNING, "%{public}s: internal error: buffer is not shared", 951 __func__); 952 return; 953 } 954 955 if (fence_fd >= 0) { 956 /* The driver's fence is more recent than the surface's out fence, if it 957 * exists at all. So use the driver's fence. 958 */ 959 if (dri2_surf->out_fence_fd >= 0) { 960 close(dri2_surf->out_fence_fd); 961 dri2_surf->out_fence_fd = -1; 962 } 963 } else if (dri2_surf->out_fence_fd >= 0) { 964 fence_fd = dri2_surf->out_fence_fd; 965 dri2_surf->out_fence_fd = -1; 966 } 967 968 if (ANativeWindow_queueBuffer(dri2_surf->window, dri2_surf->buffer, 969 fence_fd)) { 970 _eglLog(_EGL_WARNING, "%{public}s: ANativeWindow_queueBuffer failed", __func__); 971 close(fence_fd); 972 return; 973 } 974 975 fence_fd = -1; 976 977 if (ANativeWindow_dequeueBuffer(dri2_surf->window, &dri2_surf->buffer, 978 &fence_fd)) { 979 /* Tear down the surface because it no longer has a back buffer. */ 980 struct dri2_egl_display *dri2_dpy = 981 dri2_egl_display(dri2_surf->base.Resource.Display); 982 983 _eglLog(_EGL_WARNING, "%{public}s: ANativeWindow_dequeueBuffer failed", __func__); 984 985 dri2_surf->base.Lost = true; 986 dri2_surf->buffer = NULL; 987 dri2_surf->back = NULL; 988 989 if (dri2_surf->dri_image_back) { 990 dri2_dpy->image->destroyImage(dri2_surf->dri_image_back); 991 dri2_surf->dri_image_back = NULL; 992 } 993 994 dri2_dpy->flush->invalidate(dri2_surf->dri_drawable); 995 return; 996 } 997 998 if (fence_fd < 0) { 999 return; 1000 } 1001 1002 /* Access to the buffer is controlled by a sync fence. Block on it. 1003 * 1004 * Ideally, we would submit the fence to the driver, and the driver would 1005 * postpone command execution until it signalled. But DRI lacks API for 1006 * that (as of 2018-04-11). 1007 * 1008 * SYNC_IOC_WAIT waits forever if timeout < 0 1009 */ 1010 sync_wait(fence_fd, -1); 1011 close(fence_fd); 1012} 1013 1014static const __DRImutableRenderBufferLoaderExtension ohos_mutable_render_buffer_extension = { 1015 .base = {__DRI_MUTABLE_RENDER_BUFFER_LOADER, 1}, 1016 .displaySharedBuffer = ohos_display_shared_buffer, 1017}; 1018 1019static const __DRIextension *ohos_image_loader_extensions[] = { 1020 &ohos_image_loader_extension.base, 1021 &image_lookup_extension.base, 1022 &use_invalidate.base, 1023 &ohos_mutable_render_buffer_extension.base, 1024 NULL, 1025}; 1026 1027static EGLBoolean 1028ohos_load_driver(_EGLDisplay *disp, bool swrast) 1029{ 1030 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 1031 1032 dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd); 1033 if (dri2_dpy->driver_name == NULL) { 1034 return false; 1035 } 1036 1037#ifdef HAVE_DRM_GRALLOC 1038 /* Handle control nodes using __DRI_DRI2_LOADER extension and GEM names 1039 * for backwards compatibility with drm_gralloc. (Do not use on new 1040 * systems.) */ 1041 dri2_dpy->loader_extensions = ohos_dri2_loader_extensions; 1042 if (!dri2_load_driver(disp)) { 1043 goto error; 1044 } 1045#else 1046 if (swrast) { 1047 /* Use kms swrast only with vgem / virtio_gpu. 1048 * virtio-gpu fallbacks to software rendering when 3D features 1049 * are unavailable since 6c5ab. 1050 */ 1051 if (strcmp(dri2_dpy->driver_name, "vgem") == 0 || 1052 strcmp(dri2_dpy->driver_name, "virtio_gpu") == 0) { 1053 free(dri2_dpy->driver_name); 1054 dri2_dpy->driver_name = strdup("kms_swrast"); 1055 } else { 1056 goto error; 1057 } 1058 } 1059 1060 dri2_dpy->loader_extensions = ohos_image_loader_extensions; 1061 if (!dri2_load_driver_dri3(disp)) { 1062 goto error; 1063 } 1064#endif 1065 1066 return true; 1067 1068error: 1069 free(dri2_dpy->driver_name); 1070 dri2_dpy->driver_name = NULL; 1071 return false; 1072} 1073 1074static void 1075ohos_unload_driver(_EGLDisplay *disp) 1076{ 1077 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 1078 1079 dlclose(dri2_dpy->driver); 1080 dri2_dpy->driver = NULL; 1081 free(dri2_dpy->driver_name); 1082 dri2_dpy->driver_name = NULL; 1083} 1084 1085static int 1086ohos_filter_device(_EGLDisplay *disp, int fd, const char *vendor) 1087{ 1088 drmVersionPtr ver = drmGetVersion(fd); 1089 if (!ver) { 1090 return -1; 1091 } 1092 1093 if (strcmp(vendor, ver->name) != 0) { 1094 drmFreeVersion(ver); 1095 return -1; 1096 } 1097 1098 drmFreeVersion(ver); 1099 return 0; 1100} 1101 1102static EGLBoolean 1103ohos_probe_device(_EGLDisplay *disp, bool swrast) 1104{ 1105 /* Check that the device is supported, by attempting to: 1106 * - load the dri module 1107 * - and, create a screen 1108 */ 1109 if (!ohos_load_driver(disp, swrast)) { 1110 return EGL_FALSE; 1111 } 1112 1113 if (!dri2_create_screen(disp)) { 1114 _eglLog(_EGL_WARNING, "DRI2: failed to create screen"); 1115 ohos_unload_driver(disp); 1116 return EGL_FALSE; 1117 } 1118 return EGL_TRUE; 1119} 1120 1121#ifdef HAVE_DRM_GRALLOC 1122static EGLBoolean 1123ohos_open_device(_EGLDisplay *disp, bool swrast) 1124{ 1125 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 1126 int fd = -1, err = -EINVAL; 1127 1128 if (swrast) { 1129 return EGL_FALSE; 1130 } 1131 1132 if (dri2_dpy->gralloc->perform) { 1133 err = dri2_dpy->gralloc->perform(dri2_dpy->gralloc, 1134 GRALLOC_MODULE_PERFORM_GET_DRM_FD, 1135 &fd); 1136 } 1137 if (err || fd < 0) { 1138 _eglLog(_EGL_WARNING, "fail to get drm fd"); 1139 return EGL_FALSE; 1140 } 1141 1142 dri2_dpy->fd = os_dupfd_cloexec(fd); 1143 if (dri2_dpy->fd < 0) { 1144 return EGL_FALSE; 1145 } 1146 1147 if (drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER) { 1148 return EGL_FALSE; 1149 } 1150 1151 return ohos_probe_device(disp, swrast); 1152} 1153#else 1154static EGLBoolean 1155ohos_open_device(_EGLDisplay *disp, bool swrast) 1156{ 1157#define MAX_DRM_DEVICES 64 1158 struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp); 1159 drmDevicePtr device, devices[MAX_DRM_DEVICES] = {NULL}; 1160 int num_devices; 1161 1162 char *vendor_name = NULL; 1163 1164#ifdef EGL_FORCE_RENDERNODE 1165 const unsigned node_type = DRM_NODE_RENDER; 1166#else 1167 const unsigned node_type = swrast ? DRM_NODE_PRIMARY : DRM_NODE_RENDER; 1168#endif 1169 1170 num_devices = drmGetDevices2(0, devices, ARRAY_SIZE(devices)); 1171 _eglLog(_EGL_WARNING, "ohos_open_device %{public}d", num_devices); 1172 if (num_devices < 0) { 1173 return EGL_FALSE; 1174 } 1175 1176 for (int i = 0; i < num_devices; i++) { 1177 device = devices[i]; 1178 1179 if (!(device->available_nodes & (1 << node_type))) { 1180 continue; 1181 } 1182 1183 dri2_dpy->fd = loader_open_device(device->nodes[node_type]); 1184 if (dri2_dpy->fd < 0) { 1185 DISPLAY_LOGI(); 1186 _eglLog(_EGL_WARNING, "%{public}s() Failed to open DRM device %{public}s", 1187 __func__, device->nodes[node_type]); 1188 continue; 1189 } 1190 1191 /* If a vendor is explicitly provided, we use only that. 1192 * Otherwise we fall-back the first device that is supported. 1193 */ 1194 DISPLAY_LOGI("vendor_name %{public}s", vendor_name); 1195 if (vendor_name) { 1196 if (ohos_filter_device(disp, dri2_dpy->fd, vendor_name)) { 1197 /* Device does not match - try next device */ 1198 close(dri2_dpy->fd); 1199 dri2_dpy->fd = -1; 1200 DISPLAY_LOGI(); 1201 continue; 1202 } 1203 /* If the requested device matches - use it. Regardless if 1204 * init fails, do not fall-back to any other device. 1205 */ 1206 if (!ohos_probe_device(disp, false)) { 1207 close(dri2_dpy->fd); 1208 dri2_dpy->fd = -1; 1209 } 1210 DISPLAY_LOGI(); 1211 break; 1212 } 1213 if (ohos_probe_device(disp, swrast)) { 1214 break; 1215 } 1216 DISPLAY_LOGI(); 1217 /* No explicit request - attempt the next device */ 1218 close(dri2_dpy->fd); 1219 dri2_dpy->fd = -1; 1220 } 1221 drmFreeDevices(devices, num_devices); 1222 DISPLAY_LOGI(); 1223 if (dri2_dpy->fd < 0) { 1224 DISPLAY_LOGI(); 1225 _eglLog(_EGL_WARNING, "Failed to open %{public}s DRM device", 1226 vendor_name ? "desired" : "any"); 1227 return EGL_FALSE; 1228 } 1229 1230 return EGL_TRUE; 1231#undef MAX_DRM_DEVICES 1232} 1233 1234#endif 1235 1236EGLBoolean 1237dri2_initialize_ohos(_EGLDisplay *disp) 1238{ 1239 _EGLDevice *dev; 1240 bool device_opened = false; 1241 struct dri2_egl_display *dri2_dpy; 1242 const char *err; 1243 1244 dri2_dpy = calloc(1, sizeof(*dri2_dpy)); 1245 if (!dri2_dpy) 1246 return _eglError(EGL_BAD_ALLOC, "eglInitialize"); 1247 1248 dri2_dpy->fd = -1; 1249 1250 disp->DriverData = (void *)dri2_dpy; 1251 device_opened = ohos_open_device(disp, disp->Options.ForceSoftware); 1252 1253 if (!device_opened) { 1254 err = "DRI2: failed to open device"; 1255 goto cleanup; 1256 } 1257 1258 dev = _eglAddDevice(dri2_dpy->fd, false); 1259 if (!dev) { 1260 err = "DRI2: failed to find EGLDevice"; 1261 goto cleanup; 1262 } 1263 1264 disp->Device = dev; 1265 1266 if (!dri2_setup_extensions(disp)) { 1267 err = "DRI2: failed to setup extensions"; 1268 goto cleanup; 1269 } 1270 1271 dri2_setup_screen(disp); 1272 1273 dri2_setup_swap_interval(disp, 1); 1274 1275 disp->Extensions.KHR_image = EGL_TRUE; 1276 1277 /* Create configs *after* enabling extensions because presence of DRI 1278 * driver extensions can affect the capabilities of EGLConfigs. 1279 */ 1280 if (!ohos_add_configs_for_visuals(disp)) { 1281 err = "DRI2: failed to add configs"; 1282 goto cleanup; 1283 } 1284 1285 /* Fill vtbl last to prevent accidentally calling virtual function during 1286 * initialization. 1287 */ 1288 dri2_dpy->vtbl = &ohos_display_vtbl; 1289 1290 return EGL_TRUE; 1291 1292cleanup: 1293 dri2_display_destroy(disp); 1294 return _eglError(EGL_NOT_INITIALIZED, err); 1295} 1296