da7630cc517a2fee293c1c8e300a6d37950a914d
[platform/upstream/mesa.git] / src / egl / drivers / dri2 / platform_tizen.c
1 /*
2  * Mesa 3-D graphics library
3  *
4  * Copyright (C) 2017 Samsung Electronics co., Ltd. All Rights Reserved
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  * Copyright © 2011 Intel Corporation
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a
13  * copy of this software and associated documentation files (the "Software"),
14  * to deal in the Software without restriction, including without limitation
15  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16  * and/or sell copies of the Software, and to permit persons to whom the
17  * Software is furnished to do so, subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice (including the next
20  * paragraph) shall be included in all copies or substantial portions of the
21  * Software.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
27  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
28  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30  * DEALINGS IN THE SOFTWARE.
31  *
32  * Authors:
33  *    Gwan-gyeong Mun <kk.moon@samsung.com>
34  */
35
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <xf86drm.h>
40 #include <dlfcn.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44 #include <unistd.h>
45
46 #include "egl_dri2.h"
47 #include "loader.h"
48 #include "util/u_atomic.h"
49
50 #include <wayland-client.h>
51 #include <drm-uapi/drm_fourcc.h>
52
53 #include <drm_fourcc.h>
54
55 #include "tizen/tizen_utils.h"
56
57 int tbm_bufmgr_fd = -1;
58
59 static void tizen_free_local_buffers(struct dri2_egl_surface *dri2_surf);
60
61 /* createImageFromFds requires fourcc format */
62 static int get_fourcc(tbm_format format)
63 {
64    switch (format) {
65    case TBM_FORMAT_RGB565:   return DRM_FORMAT_RGB565;
66    case TBM_FORMAT_BGRA8888: return DRM_FORMAT_ARGB8888;
67    case TBM_FORMAT_RGBA8888: return DRM_FORMAT_ABGR8888;
68    case TBM_FORMAT_ARGB8888: return DRM_FORMAT_ARGB8888;
69    case TBM_FORMAT_ABGR8888: return DRM_FORMAT_ABGR8888;
70    case TBM_FORMAT_RGBX8888: return DRM_FORMAT_XBGR8888;
71    case TBM_FORMAT_XRGB8888: return DRM_FORMAT_XRGB8888;
72    default:
73       _eglLog(_EGL_WARNING, "unsupported native buffer format 0x%x", format);
74    }
75    return -1;
76 }
77
78 static int get_fourcc_yuv(tbm_format format)
79 {
80    switch (format) {
81    case TBM_FORMAT_NV12:   return DRM_FORMAT_NV12;
82    case TBM_FORMAT_NV21:   return DRM_FORMAT_NV12;
83    case TBM_FORMAT_YUV420: return DRM_FORMAT_YUV420;
84    case TBM_FORMAT_YVU420: return DRM_FORMAT_YVU420;
85    default:
86       _eglLog(_EGL_WARNING, "unsupported native yuv buffer format 0x%x", format);
87    }
88    return -1;
89 }
90
91 static bool is_yuv_format(tbm_format format)
92 {
93    if (get_fourcc_yuv(format) == -1)
94      return false;
95    else
96      return true;
97 }
98
99 static int get_format(tbm_format format)
100 {
101    switch (format) {
102    case TBM_FORMAT_RGB565:   return __DRI_IMAGE_FORMAT_RGB565;
103    case TBM_FORMAT_BGRA8888: return __DRI_IMAGE_FORMAT_ARGB8888;
104    case TBM_FORMAT_RGBA8888: return __DRI_IMAGE_FORMAT_ABGR8888;
105    case TBM_FORMAT_ARGB8888: return __DRI_IMAGE_FORMAT_ARGB8888;
106    case TBM_FORMAT_ABGR8888: return __DRI_IMAGE_FORMAT_ABGR8888;
107    case TBM_FORMAT_RGBX8888: return __DRI_IMAGE_FORMAT_XBGR8888;
108    case TBM_FORMAT_XRGB8888: return __DRI_IMAGE_FORMAT_XRGB8888;
109    default:
110       _eglLog(_EGL_WARNING, "unsupported native buffer format 0x%x", format);
111    }
112    return -1;
113 }
114
115 static int get_format_bpp(tbm_format format)
116 {
117    int bpp;
118
119    switch (format) {
120 #pragma GCC diagnostic push
121 #pragma GCC diagnostic ignored "-Wswitch"
122    case TBM_FORMAT_BGRA8888:
123    case TBM_FORMAT_RGBA8888:
124    case TBM_FORMAT_RGBX8888:
125    case TBM_FORMAT_ARGB8888:
126 #pragma GCC diagnostic pop
127    case TBM_FORMAT_XRGB8888:
128       bpp = 4;
129       break;
130    case TBM_FORMAT_RGB565:
131       bpp = 2;
132       break;
133    default:
134       bpp = 0;
135       break;
136    }
137
138    return bpp;
139 }
140
141 static int get_pitch(tbm_surface_h tbm_surface)
142 {
143    tbm_surface_info_s surf_info;
144
145    if (tbm_surface_get_info(tbm_surface, &surf_info) != TBM_SURFACE_ERROR_NONE) {
146      return 0;
147    }
148
149    return surf_info.planes[0].stride;
150 }
151
152 static int
153 get_native_buffer_fd(tbm_surface_h tbm_surface)
154 {
155    tbm_bo_handle bo_handle;
156    bo_handle = tbm_bo_get_handle(tbm_surface_internal_get_bo(tbm_surface, 0),
157                                  TBM_DEVICE_3D);
158
159    return (bo_handle.ptr != NULL) ? (int)bo_handle.u32 : -1;
160 }
161
162 static int
163 get_native_buffer_name(tbm_surface_h tbm_surface)
164 {
165    uint32_t bo_name;
166
167    bo_name = tbm_bo_export(tbm_surface_internal_get_bo(tbm_surface, 0));
168
169    return (bo_name != 0 ) ? (int)bo_name : -1;
170 }
171
172 static EGLBoolean
173 tizen_internal_wait_sync_for_release_fence(struct dri2_egl_surface *dri2_surf,
174                                            int32_t release_fence_fd)
175 {
176    _EGLContext *ctx = _eglGetCurrentContext();
177    _EGLDisplay *disp = dri2_surf->base.Resource.Display;
178
179    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
180    struct dri2_egl_context *dri2_ctx = dri2_egl_context(ctx);
181    struct dri2_egl_sync *dri2_sync;
182
183    EGLAttrib attrib_list[] = {
184       EGL_SYNC_NATIVE_FENCE_FD_TIZEN,
185       release_fence_fd,
186       EGL_NONE,
187    };
188
189    dri2_sync = calloc(1, sizeof(struct dri2_egl_sync));
190    if (!dri2_sync) {
191       close(release_fence_fd);
192       return EGL_FALSE;
193    }
194
195    if (!_eglInitSync(&dri2_sync->base, disp,
196                      EGL_SYNC_NATIVE_FENCE_TIZEN,
197                      attrib_list)) {
198       free(dri2_sync);
199       close(release_fence_fd);
200       return EGL_FALSE;
201    }
202
203    if (dri2_dpy->fence->create_fence_fd) {
204       dri2_sync->fence = dri2_dpy->fence->create_fence_fd(
205                                  dri2_ctx->dri_context,
206                                  dri2_sync->base.SyncFd);
207    }
208
209    if (!dri2_sync->fence) {
210       free(dri2_sync);
211       close(release_fence_fd);
212       return EGL_FALSE;
213    }
214
215    dri2_dpy->fence->server_wait_sync(dri2_ctx->dri_context,
216                                      dri2_sync->fence, 0);
217
218    close(dri2_sync->base.SyncFd);
219    if (dri2_sync->fence)
220       dri2_dpy->fence->destroy_fence(dri2_dpy->dri_screen, dri2_sync->fence);
221    free(dri2_sync);
222
223    return EGL_TRUE;
224 }
225
226 static EGLBoolean
227 tizen_window_dequeue_buffer(struct dri2_egl_surface *dri2_surf)
228 {
229    int width, height;
230    int32_t release_fence;
231
232    TRACE_BEGIN("DEQUEUE_BUFFER");
233    dri2_surf->tbm_surface = tpl_surface_dequeue_buffer_with_sync(
234                               dri2_surf->tpl_surface,
235                               UINT64_MAX,
236                               &release_fence);
237    TRACE_END();
238
239    if (!dri2_surf->tbm_surface)
240      return EGL_FALSE;
241
242    dri2_surf->valid = true;
243    tbm_surface_internal_ref(dri2_surf->tbm_surface);
244
245    if (release_fence != -1) {
246       EGLBoolean ret;
247       ret = tizen_internal_wait_sync_for_release_fence(dri2_surf, release_fence);
248       if (!ret) {
249          _eglLog(_EGL_WARNING, "%s : %d : failed to create sync fence.", __func__, __LINE__);
250       }
251    }
252
253    tpl_surface_get_size(dri2_surf->tpl_surface, &width, &height);
254    if (dri2_surf->base.Width != width ||
255        dri2_surf->base.Height != height) {
256       dri2_surf->base.Width = width;
257       dri2_surf->base.Height = height;
258       tizen_free_local_buffers(dri2_surf);
259    }
260
261    /* Record all the buffers created by tpl_surface (tbm_surface_queue)
262     *   and update back buffer * for updating buffer's age in swap_buffers.
263     */
264    EGLBoolean updated = EGL_FALSE;
265    for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
266       if (!dri2_surf->color_buffers[i].tbm_surface) {
267          dri2_surf->color_buffers[i].tbm_surface = dri2_surf->tbm_surface;
268          dri2_surf->color_buffers[i].age = 0;
269       }
270       if (dri2_surf->color_buffers[i].tbm_surface == dri2_surf->tbm_surface) {
271          dri2_surf->back = &dri2_surf->color_buffers[i];
272          updated = EGL_TRUE;
273          break;
274       }
275    }
276
277    if (!updated) {
278       /* In case of all the buffers were recreated , reset the color_buffers */
279       for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
280          dri2_surf->color_buffers[i].tbm_surface = NULL;
281          dri2_surf->color_buffers[i].age = 0;
282       }
283       dri2_surf->color_buffers[0].tbm_surface = dri2_surf->tbm_surface;
284       dri2_surf->back = &dri2_surf->color_buffers[0];
285    }
286
287    return EGL_TRUE;
288 }
289
290 static EGLBoolean
291 tizen_window_enqueue_buffer_with_damage(_EGLDisplay *disp,
292                                         struct dri2_egl_surface *dri2_surf,
293                                         const EGLint *rects,
294                                         EGLint n_rects)
295 {
296    tpl_result_t ret;
297    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
298    int fence_fd = -1;
299
300    /* To avoid blocking other EGL calls, release the display mutex before
301     * we enter tizen_window_enqueue_buffer() and re-acquire the mutex upon
302     * return.
303     */
304    simple_mtx_unlock(&disp->Mutex);
305
306    fence_fd = dri2_surf->out_fence_fd;
307
308    if (fence_fd >= 0 && dri2_surf->is_frontbuffer_mode) {
309       close(fence_fd);
310       fence_fd = -1;
311    }
312
313    dri2_surf->out_fence_fd = -1;
314
315    ret = tpl_surface_enqueue_buffer_with_damage_and_sync(dri2_surf->tpl_surface,
316                                                          dri2_surf->tbm_surface,
317                                                          n_rects, rects,
318                                                          fence_fd);
319
320    if (ret != TPL_ERROR_NONE) {
321       _eglLog(_EGL_DEBUG, "%s : %d :tpl_surface_enqueue fail", __func__, __LINE__);
322    }
323
324    tbm_surface_internal_unref(dri2_surf->tbm_surface);
325    dri2_surf->tbm_surface = NULL;
326    dri2_surf->back = NULL;
327
328    simple_mtx_unlock(&disp->Mutex);
329
330    if (dri2_surf->dri_image_back) {
331       dri2_dpy->image->destroyImage(dri2_surf->dri_image_back);
332       dri2_surf->dri_image_back = NULL;
333    }
334
335    return EGL_TRUE;
336 }
337
338 static EGLBoolean
339 tizen_window_enqueue_buffer(_EGLDisplay *disp, struct dri2_egl_surface *dri2_surf)
340 {
341    return tizen_window_enqueue_buffer_with_damage(disp, dri2_surf, NULL, 0);
342 }
343
344 static void
345 tizen_window_cancel_buffer(_EGLDisplay *disp, struct dri2_egl_surface *dri2_surf)
346 {
347    tizen_window_enqueue_buffer(disp, dri2_surf);
348 }
349
350 static __DRIbuffer *
351 tizen_alloc_local_buffer(struct dri2_egl_surface *dri2_surf,
352                          unsigned int att, unsigned int format)
353 {
354    struct dri2_egl_display *dri2_dpy =
355       dri2_egl_display(dri2_surf->base.Resource.Display);
356
357    if (att >= ARRAY_SIZE(dri2_surf->local_buffers))
358       return NULL;
359
360    if (!dri2_surf->local_buffers[att]) {
361       dri2_surf->local_buffers[att] =
362          dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen, att, format,
363                dri2_surf->base.Width, dri2_surf->base.Height);
364    }
365
366    return dri2_surf->local_buffers[att];
367 }
368
369 static void
370 tizen_free_local_buffers(struct dri2_egl_surface *dri2_surf)
371 {
372    struct dri2_egl_display *dri2_dpy =
373       dri2_egl_display(dri2_surf->base.Resource.Display);
374    int i;
375
376    for (i = 0; i < ARRAY_SIZE(dri2_surf->local_buffers); i++) {
377       if (dri2_surf->local_buffers[i]) {
378          dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
379                dri2_surf->local_buffers[i]);
380          dri2_surf->local_buffers[i] = NULL;
381       }
382    }
383 }
384
385 static _EGLSurface *
386 tizen_create_surface(_EGLDisplay *disp, EGLint type,
387                      _EGLConfig *conf, void *native_window,
388                      const EGLint *attrib_list)
389 {
390    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
391    struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
392    struct dri2_egl_surface *dri2_surf;
393    const __DRIconfig *config;
394    tpl_surface_type_t tpl_surf_type = TPL_SURFACE_ERROR;
395    tpl_result_t ret = TPL_ERROR_INVALID_PARAMETER;
396    char *env = getenv("EGL_FRONTBUFFER_ENABLE");
397
398    dri2_surf = calloc(1, sizeof *dri2_surf);
399    if (!dri2_surf) {
400       _eglError(EGL_BAD_ALLOC, "tizen_create_surface");
401       return NULL;
402    }
403
404    if (!dri2_init_surface(&dri2_surf->base, disp, type, conf, attrib_list,
405                           true, native_window))
406       goto cleanup_surface;
407
408    config = dri2_get_dri_config(dri2_conf, type,
409                                 dri2_surf->base.GLColorspace);
410    if (!config)
411       goto cleanup_surface;
412
413    if (type == EGL_WINDOW_BIT) {
414       unsigned int alpha, depth;
415
416       if (!native_window) {
417          _eglError(EGL_BAD_NATIVE_WINDOW, "tizen_create_surface needs vaild native window");
418          goto cleanup_surface;
419       }
420       dri2_surf->native_win = native_window;
421       dri2_surf->valid = true;
422       dri2_dpy->core->getConfigAttrib(config, __DRI_ATTRIB_DEPTH_SIZE, &depth);
423       dri2_dpy->core->getConfigAttrib(config, __DRI_ATTRIB_ALPHA_SIZE, &alpha);
424
425       ret = tpl_display_get_native_window_info(dri2_dpy->tpl_display,
426                                                (tpl_handle_t)native_window,
427                                                &dri2_surf->base.Width,
428                                                &dri2_surf->base.Height,
429                                                &dri2_surf->tbm_format,
430                                                depth, alpha);
431
432       if (ret != TPL_ERROR_NONE || dri2_surf->tbm_format == 0) {
433         _eglError(EGL_BAD_NATIVE_WINDOW, "tizen_create_surface fails on tpl_display_get_native_window_info()");
434         goto cleanup_surface;
435       }
436
437       tpl_surf_type = TPL_SURFACE_TYPE_WINDOW;
438    } else if (type == EGL_PIXMAP_BIT) {
439
440       if (!native_window) {
441          _eglError(EGL_BAD_NATIVE_PIXMAP, "tizen_create_surface needs valid native pixmap");
442          goto cleanup_surface;
443       }
444
445       ret = tpl_display_get_native_pixmap_info(dri2_dpy->tpl_display,
446                                                (tpl_handle_t)native_window,
447                                                &dri2_surf->base.Width,
448                                                &dri2_surf->base.Height,
449                                                &dri2_surf->tbm_format);
450
451       if (ret != TPL_ERROR_NONE || dri2_surf->tbm_format == 0) {
452         _eglError(EGL_BAD_NATIVE_PIXMAP, "tizen_create_surface fails on tpl_display_get_native_pixmap_info");
453         goto cleanup_surface;
454       }
455
456       tpl_surf_type = TPL_SURFACE_TYPE_PIXMAP;
457    }
458
459    if(type == EGL_WINDOW_BIT || type == EGL_PIXMAP_BIT) {
460       dri2_surf->tpl_surface = tpl_surface_create(dri2_dpy->tpl_display,
461                                                (tpl_handle_t)native_window,
462                                                tpl_surf_type,
463                                                dri2_surf->tbm_format);
464       if (!dri2_surf->tpl_surface)
465          goto cleanup_surface;
466    }
467
468    if (!dri2_create_drawable(dri2_dpy, config, dri2_surf, dri2_surf)) {
469       _eglError(EGL_BAD_ALLOC, "createNewDrawable");
470        goto cleanup_tpl_surface;
471    }
472
473    dri2_surf->is_frontbuffer_mode = EGL_FALSE;
474         if (env != NULL && atoi(env))
475         {
476                 tpl_result_t tpl_result = TPL_ERROR_NONE;
477                 tpl_result = tpl_surface_set_frontbuffer_mode(dri2_surf->tpl_surface, TPL_TRUE);
478       if (tpl_result == TPL_ERROR_NONE)
479          dri2_surf->is_frontbuffer_mode = EGL_TRUE;
480         }
481
482    return &dri2_surf->base;
483
484 cleanup_tpl_surface:
485    tpl_object_unreference((tpl_object_t *)dri2_surf->tpl_surface);
486 cleanup_surface:
487    free(dri2_surf);
488
489    return NULL;
490 }
491
492 static _EGLSurface *
493 tizen_create_window_surface(_EGLDisplay *disp,
494                             _EGLConfig *conf, void *native_window,
495                             const EGLint *attrib_list)
496 {
497    return tizen_create_surface(disp, EGL_WINDOW_BIT, conf,
498                                native_window, attrib_list);
499 }
500
501 static _EGLSurface *
502 tizen_create_pixmap_surface(_EGLDisplay *disp,
503                             _EGLConfig *conf, void *native_pixmap,
504                             const EGLint *attrib_list)
505 {
506    return tizen_create_surface(disp, EGL_PIXMAP_BIT, conf,
507                                native_pixmap, attrib_list);
508 }
509
510 static _EGLSurface *
511 tizen_create_pbuffer_surface(_EGLDisplay *disp,
512                              _EGLConfig *conf, const EGLint *attrib_list)
513 {
514    return tizen_create_surface(disp, EGL_PBUFFER_BIT, conf,
515                                NULL, attrib_list);
516 }
517
518 static EGLBoolean
519 tizen_destroy_surface(_EGLDisplay *disp, _EGLSurface *surf)
520 {
521    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
522    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
523
524    tizen_free_local_buffers(dri2_surf);
525
526    if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
527       if (dri2_surf->tbm_surface)
528          tizen_window_cancel_buffer(disp, dri2_surf);
529    }
530
531    if (dri2_surf->dri_image_back) {
532       _eglLog(_EGL_DEBUG, "%s : %d : destroy dri_image_back", __func__, __LINE__);
533       dri2_dpy->image->destroyImage(dri2_surf->dri_image_back);
534       dri2_surf->dri_image_back = NULL;
535    }
536
537    if (dri2_surf->dri_image_front) {
538       _eglLog(_EGL_DEBUG, "%s : %d : destroy dri_image_front", __func__, __LINE__);
539       dri2_dpy->image->destroyImage(dri2_surf->dri_image_front);
540       dri2_surf->dri_image_front = NULL;
541    }
542
543    dri2_dpy->core->destroyDrawable(dri2_surf->dri_drawable);
544
545    if (dri2_surf->tpl_surface)
546       tpl_object_unreference((tpl_object_t *)dri2_surf->tpl_surface);
547
548    dri2_fini_surface(surf);
549
550    free(dri2_surf);
551
552    return EGL_TRUE;
553 }
554
555 static int
556 update_buffers(struct dri2_egl_surface *dri2_surf)
557 {
558    if (dri2_surf->base.Type != EGL_WINDOW_BIT)
559       return 0;
560
561    if (dri2_surf->valid == false) {
562        int i;
563        if (dri2_surf->tbm_surface) {
564            tpl_surface_cancel_dequeued_buffer(dri2_surf->tpl_surface,
565                                               dri2_surf->tbm_surface);
566            tbm_surface_internal_unref(dri2_surf->tbm_surface);
567            for (i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
568                dri2_surf->color_buffers[i].tbm_surface = NULL;
569                dri2_surf->color_buffers[i].age = 0;
570            }
571
572        dri2_surf->back = NULL;
573        dri2_surf->tbm_surface = NULL;
574       }
575    }
576    /* try to dequeue the next back buffer */
577    if (!dri2_surf->tbm_surface && !tizen_window_dequeue_buffer(dri2_surf)) {
578       _eglLog(_EGL_WARNING, "Could not dequeue buffer from native window");
579       return -1;
580    }
581
582    return 0;
583 }
584
585 static int
586 get_front_bo(struct dri2_egl_surface *dri2_surf, unsigned int format)
587 {
588    struct dri2_egl_display *dri2_dpy =
589       dri2_egl_display(dri2_surf->base.Resource.Display);
590
591    if (dri2_surf->dri_image_front)
592       return 0;
593
594    if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
595       /* According current EGL spec, front buffer rendering
596        * for window surface is not supported now.
597        * and mesa doesn't have the implementation of this case.
598        * Add warning message, but not treat it as error.
599        */
600       _eglLog(_EGL_DEBUG, "DRI driver requested unsupported front buffer for window surface");
601    } else if (dri2_surf->base.Type == EGL_PBUFFER_BIT) {
602       dri2_surf->dri_image_front =
603           dri2_dpy->image->createImage(dri2_dpy->dri_screen,
604                                        dri2_surf->base.Width,
605                                        dri2_surf->base.Height,
606                                        format,
607                                        0,
608                                        dri2_surf);
609       if (!dri2_surf->dri_image_front) {
610          _eglLog(_EGL_WARNING, "dri2_image_front allocation failed");
611          return -1;
612       }
613    }
614
615    return 0;
616 }
617
618 static int
619 get_back_bo(struct dri2_egl_surface *dri2_surf, unsigned int format)
620 {
621    struct dri2_egl_display *dri2_dpy =
622       dri2_egl_display(dri2_surf->base.Resource.Display);
623    int fourcc, pitch;
624    int offset = 0, fd;
625    tbm_surface_info_s surf_info;
626    EGLBoolean query;
627    int width, height;
628
629    if (dri2_surf->dri_image_back) {
630       query = dri2_dpy->image->queryImage(dri2_surf->dri_image_back, __DRI_IMAGE_ATTRIB_WIDTH, &width);
631       query &= dri2_dpy->image->queryImage(dri2_surf->dri_image_back, __DRI_IMAGE_ATTRIB_HEIGHT, &height);
632
633       if (width == dri2_surf->base.Width && height == dri2_surf->base.Height)
634          return 0;
635       else {
636          dri2_dpy->image->destroyImage(dri2_surf->dri_image_back);
637          dri2_surf->dri_image_back = NULL;
638       }
639    }
640
641    if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
642       if (!dri2_surf->tbm_surface) {
643          _eglLog(_EGL_WARNING, "Could not get native buffer");
644          return -1;
645       }
646
647       fd = get_native_buffer_fd(dri2_surf->tbm_surface);
648       if (fd < 0) {
649          _eglLog(_EGL_WARNING, "Could not get native buffer FD");
650          return -1;
651       }
652
653       if (tbm_surface_get_info(dri2_surf->tbm_surface, &surf_info) != TBM_SURFACE_ERROR_NONE) {
654          _eglLog(_EGL_WARNING, "Could not get pitch");
655          return -1;
656       }
657
658       pitch = surf_info.planes[0].stride;
659       fourcc = get_fourcc(dri2_surf->tbm_format);
660
661       if (fourcc == -1 || pitch == 0) {
662          _eglLog(_EGL_WARNING, "Invalid buffer fourcc(%x) or pitch(%d)",
663                  fourcc, pitch);
664          return -1;
665       }
666
667       dri2_surf->base.Width = surf_info.width;
668       dri2_surf->base.Height = surf_info.height;
669
670       dri2_surf->dri_image_back =
671          dri2_dpy->image->createImageFromFds(dri2_dpy->dri_screen,
672                                              dri2_surf->base.Width,
673                                              dri2_surf->base.Height,
674                                              fourcc,
675                                              &fd,
676                                              1,
677                                              &pitch,
678                                              &offset,
679                                              dri2_surf);
680
681       if (!dri2_surf->dri_image_back) {
682          _eglLog(_EGL_WARNING, "failed to create DRI image from FD");
683          return -1;
684       }
685    } else if (dri2_surf->base.Type == EGL_PBUFFER_BIT) {
686       /* The EGL 1.5 spec states that pbuffers are single-buffered. Specifically,
687        * the spec states that they have a back buffer but no front buffer, in
688        * contrast to pixmaps, which have a front buffer but no back buffer.
689        *
690        * Single-buffered surfaces with no front buffer confuse Mesa; so we deviate
691        * from the spec, following the precedent of Mesa's EGL X11 platform. The
692        * X11 platform correctly assigns pbuffers to single-buffered configs, but
693        * assigns the pbuffer a front buffer instead of a back buffer.
694        *
695        * Pbuffers in the X11 platform mostly work today, so let's just copy its
696        * behavior instead of trying to fix (and hence potentially breaking) the
697        * world.
698        */
699       _eglLog(_EGL_DEBUG, "DRI driver requested unsupported back buffer for pbuffer surface");
700    }
701
702    return 0;
703 }
704
705 /* Some drivers will pass multiple bits in buffer_mask.
706  * For such case, will go through all the bits, and
707  * will not return error when unsupported buffer is requested, only
708  * return error when the allocation for supported buffer failed.
709  */
710 static int
711 tizen_image_get_buffers(__DRIdrawable *driDrawable, unsigned int format,
712                         uint32_t *stamp, void *loaderPrivate,
713                         uint32_t buffer_mask, struct __DRIimageList *images)
714 {
715    struct dri2_egl_surface *dri2_surf = loaderPrivate;
716
717    images->image_mask = 0;
718    images->front = NULL;
719    images->back = NULL;
720
721    if (update_buffers(dri2_surf) < 0)
722       return 0;
723
724    if (buffer_mask & __DRI_IMAGE_BUFFER_FRONT) {
725       if (get_front_bo(dri2_surf, format) < 0)
726          return 0;
727
728       if (dri2_surf->dri_image_front) {
729          images->front = dri2_surf->dri_image_front;
730          images->image_mask |= __DRI_IMAGE_BUFFER_FRONT;
731       }
732    }
733
734    if (buffer_mask & __DRI_IMAGE_BUFFER_BACK) {
735       if (get_back_bo(dri2_surf, format) < 0)
736          return 0;
737
738       if (dri2_surf->dri_image_back) {
739          images->back = dri2_surf->dri_image_back;
740          images->image_mask |= __DRI_IMAGE_BUFFER_BACK;
741       }
742    }
743
744    return 1;
745 }
746
747 static EGLint
748 tizen_query_buffer_age(_EGLDisplay *disp, _EGLSurface *surface)
749 {
750    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surface);
751
752    if (update_buffers(dri2_surf) < 0) {
753       _eglError(EGL_BAD_ALLOC, "tizen_query_buffer_age");
754       return 0;
755    }
756
757    return dri2_surf->back->age;
758 }
759
760 static EGLBoolean
761 tizen_swap_buffers_with_damage(_EGLDisplay *disp,
762                                _EGLSurface *draw, const EGLint *rects,
763                                EGLint n_rects)
764 {
765    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
766    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
767
768    if (dri2_surf->base.Type != EGL_WINDOW_BIT)
769       return EGL_TRUE;
770
771    for (int i = 0; i < ARRAY_SIZE(dri2_surf->color_buffers); i++) {
772       if (dri2_surf->color_buffers[i].age > 0)
773          dri2_surf->color_buffers[i].age++;
774    }
775
776    /* In case that application didn't draw anything before swapbuffer,
777     * dri2_surf->tbm_surface will be NULL here, but this should not be
778     * an error */
779    if (dri2_surf->tbm_surface) {
780       /* Make sure we have a back buffer in case we're swapping without
781       * ever rendering. */
782       if (get_back_bo(dri2_surf, 0) < 0) {
783          _eglError(EGL_BAD_ALLOC, "dri2_swap_buffers");
784          return EGL_FALSE;
785       }
786    }
787
788    if (dri2_surf->back)
789       dri2_surf->back->age = 1;
790
791    TRACE_BEGIN("DRI2_SWAP_BUFERS");
792    /* The buffer to enqueue should be the buffer in which
793     * the gpu drawing job is completed or after flush.
794     * If this is not guaranteed, it can lead to incorrect output.
795     */
796    if (dri2_dpy->swrast) {
797       dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
798    } else {
799       dri2_flush_drawable_for_swapbuffers(disp, draw);
800       dri2_dpy->flush->invalidate(dri2_surf->dri_drawable);
801    }
802    TRACE_END();
803
804    if (dri2_surf->tbm_surface)
805       tizen_window_enqueue_buffer_with_damage(disp, dri2_surf, rects, n_rects);
806
807    return EGL_TRUE;
808 }
809
810 static EGLBoolean
811 tizen_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
812 {
813    return tizen_swap_buffers_with_damage (disp, draw, NULL, 0);
814 }
815
816 static _EGLImage *
817 tizen_create_image_from_prime_fd_yuv(_EGLDisplay *disp, _EGLContext *ctx,
818                                      tbm_surface_h tbm_surface)
819
820 {
821    tbm_surface_info_s surf_info;
822    tbm_fd bo_fd[TBM_SURF_PLANE_MAX];
823    tbm_bo bo[TBM_SURF_PLANE_MAX];
824    int num_planes;
825    int i;
826    int fourcc;
827    size_t offsets[3] = {0, 0, 0};
828    size_t pitches[3] = {0, 0, 0};
829    int fds[3] = {-1, -1, -1};
830
831    if (tbm_surface_get_info(tbm_surface, &surf_info) != TBM_SURFACE_ERROR_NONE) {
832      _eglLog(_EGL_WARNING, "Could not get tbm_surface_info");
833      return NULL;
834    }
835
836    num_planes = surf_info.num_planes;
837    for (i = 0; i < num_planes; i++) {
838       tbm_bo_handle bo_handle;
839       int bo_idx = tbm_surface_internal_get_plane_bo_idx(tbm_surface, i);
840       bo[i] = tbm_surface_internal_get_bo (tbm_surface, bo_idx);
841       if (bo[i] == NULL) {
842         _eglLog(_EGL_WARNING, "Could not get tbm_surface_internal_bo");
843         return NULL;
844       }
845       bo_handle = tbm_bo_get_handle(bo[i], TBM_DEVICE_3D);
846       bo_fd[i] = bo_handle.u32;
847    }
848
849    fourcc = get_fourcc_yuv(tbm_surface_get_format(tbm_surface));
850    if (fourcc == -1) {
851      _eglLog(_EGL_WARNING, "Unsupported native yuv format");
852      return NULL;
853    }
854
855    switch (fourcc) {
856    case DRM_FORMAT_NV12:
857       fds[0] = bo_fd[0];
858       fds[1] = bo_fd[1];
859       offsets[0] = surf_info.planes[0].offset;
860       offsets[1] = surf_info.planes[1].offset;
861       pitches[0] = surf_info.planes[0].stride;
862       pitches[1] = surf_info.planes[1].stride;
863       break;
864    case DRM_FORMAT_YUV420:
865       fds[0] = bo_fd[0];
866       fds[1] = bo_fd[1];
867       fds[2] = bo_fd[2];
868       offsets[0] = surf_info.planes[0].offset;
869       offsets[1] = surf_info.planes[1].offset;
870       offsets[2] = surf_info.planes[2].offset;
871       pitches[0] = surf_info.planes[0].stride;
872       pitches[1] = surf_info.planes[1].stride;
873       pitches[2] = surf_info.planes[2].stride;
874       break;
875    case DRM_FORMAT_YVU420:
876       fds[0] = bo_fd[0];
877       fds[1] = bo_fd[2];
878       fds[2] = bo_fd[1];
879       offsets[0] = surf_info.planes[0].offset;
880       offsets[1] = surf_info.planes[2].offset;
881       offsets[2] = surf_info.planes[1].offset;
882       pitches[0] = surf_info.planes[0].stride;
883       pitches[1] = surf_info.planes[2].stride;
884       pitches[2] = surf_info.planes[1].stride;
885       break;
886     default:
887       _eglLog(_EGL_WARNING, "Unsupported native yuv format");
888       return NULL;
889    }
890
891    if (num_planes == 2) {
892       const EGLint attr_list_2plane[] = {
893          EGL_WIDTH, surf_info.width,
894          EGL_HEIGHT, surf_info.height,
895          EGL_LINUX_DRM_FOURCC_EXT, fourcc,
896          EGL_DMA_BUF_PLANE0_FD_EXT, fds[0],
897          EGL_DMA_BUF_PLANE0_PITCH_EXT, pitches[0],
898          EGL_DMA_BUF_PLANE0_OFFSET_EXT, offsets[0],
899          EGL_DMA_BUF_PLANE1_FD_EXT, fds[1],
900          EGL_DMA_BUF_PLANE1_PITCH_EXT, pitches[1],
901          EGL_DMA_BUF_PLANE1_OFFSET_EXT, offsets[1],
902          EGL_NONE, 0
903       };
904       return dri2_create_image_dma_buf(disp, ctx, NULL, attr_list_2plane);
905    } else if (num_planes == 3) {
906       const EGLint attr_list_3plane[] = {
907          EGL_WIDTH, surf_info.width,
908          EGL_HEIGHT, surf_info.height,
909          EGL_LINUX_DRM_FOURCC_EXT, fourcc,
910          EGL_DMA_BUF_PLANE0_FD_EXT, fds[0],
911          EGL_DMA_BUF_PLANE0_PITCH_EXT, pitches[0],
912          EGL_DMA_BUF_PLANE0_OFFSET_EXT, offsets[0],
913          EGL_DMA_BUF_PLANE1_FD_EXT, fds[1],
914          EGL_DMA_BUF_PLANE1_PITCH_EXT, pitches[1],
915          EGL_DMA_BUF_PLANE1_OFFSET_EXT, offsets[1],
916          EGL_DMA_BUF_PLANE2_FD_EXT, fds[2],
917          EGL_DMA_BUF_PLANE2_PITCH_EXT, pitches[2],
918          EGL_DMA_BUF_PLANE2_OFFSET_EXT, offsets[2],
919          EGL_NONE, 0
920       };
921       return dri2_create_image_dma_buf(disp, ctx, NULL, attr_list_3plane);
922    } else {
923       _eglLog(_EGL_WARNING, "Unsupported yuv planes");
924       return NULL;
925    }
926 }
927
928 static _EGLImage *
929 tizen_create_image_from_prime_fd(_EGLDisplay *disp, _EGLContext *ctx,
930                                  tbm_surface_h tbm_surface , int fd)
931 {
932    unsigned int pitch;
933    tbm_surface_info_s surf_info;
934    //unsigned int flags = tbm_bo_get_flags(tbm_surface_internal_get_bo(tbm_surface, 0));
935
936    if (is_yuv_format(tbm_surface_get_format(tbm_surface)))
937       return tizen_create_image_from_prime_fd_yuv(disp, ctx, tbm_surface);
938
939    const int fourcc = get_fourcc(tbm_surface_get_format(tbm_surface));
940    if (fourcc == -1) {
941       _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR");
942       return NULL;
943    }
944
945    if (tbm_surface_get_info(tbm_surface, &surf_info) != TBM_SURFACE_ERROR_NONE) {
946       _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR");
947       return NULL;
948    }
949    pitch = surf_info.planes[0].stride;
950
951    if (pitch == 0) {
952       _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR");
953       return NULL;
954    }
955
956    //TODO: get modifier from vendor driver/TBM
957    EGLint attr_list[50];
958    int atti = 0;
959
960    attr_list[atti++] = EGL_WIDTH;
961    attr_list[atti++] = surf_info.width;
962    attr_list[atti++] = EGL_HEIGHT;
963    attr_list[atti++] = surf_info.height;
964    attr_list[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
965    attr_list[atti++] = fourcc;
966    attr_list[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT;
967    attr_list[atti++] = fd;
968    attr_list[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
969    attr_list[atti++] = pitch;
970    attr_list[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
971    attr_list[atti++] = 0;
972
973    //TODO: v3d don't support this, need to check
974    /*if (flags == TBM_BO_TILED) {
975         attr_list[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
976         attr_list[atti++] = DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED & 0xFFFFFFFF;
977         attr_list[atti++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
978         attr_list[atti++] = DRM_FORMAT_MOD_BROADCOM_VC4_T_TILED >> 32;
979    }*/
980    attr_list[atti++] = EGL_NONE;
981    attr_list[atti++] = 0;
982
983    return dri2_create_image_dma_buf(disp, ctx, NULL, attr_list);
984 }
985
986 static _EGLImage *
987 tizen_create_image_from_name(_EGLDisplay *disp, _EGLContext *ctx,
988                              tbm_surface_h tbm_surface)
989 {
990    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
991    struct dri2_egl_image *dri2_img;
992    int name;
993    int format;
994    unsigned int pitch;
995    tbm_surface_info_s surf_info;
996
997    name = get_native_buffer_name(tbm_surface);
998    if (!name) {
999       _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR");
1000       return NULL;
1001    }
1002
1003    format = get_format(tbm_surface_get_format(tbm_surface));
1004    if (format == -1)
1005        return NULL;
1006
1007    if (tbm_surface_get_info(tbm_surface, &surf_info) != TBM_SURFACE_ERROR_NONE) {
1008       _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR");
1009       return NULL;
1010    }
1011    pitch = surf_info.planes[0].stride;
1012
1013    if (pitch == 0) {
1014       _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR");
1015       return NULL;
1016    }
1017
1018    dri2_img = calloc(1, sizeof(*dri2_img));
1019    if (!dri2_img) {
1020       _eglError(EGL_BAD_ALLOC, "tizen_create_image_mesa_drm");
1021       return NULL;
1022    }
1023
1024    _eglInitImage(&dri2_img->base, disp);
1025
1026    dri2_img->dri_image =
1027       dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
1028                                            surf_info.width,
1029                                            surf_info.height,
1030                                            format,
1031                                            name,
1032                                            pitch,
1033                                            dri2_img);
1034    if (!dri2_img->dri_image) {
1035       free(dri2_img);
1036       _eglError(EGL_BAD_ALLOC, "tizen_create_image_mesa_drm");
1037       return NULL;
1038    }
1039
1040    return &dri2_img->base;
1041 }
1042
1043 static EGLBoolean
1044 tizen_query_surface(_EGLDisplay *dpy, _EGLSurface *surf,
1045                     EGLint attribute, EGLint *value)
1046 {
1047    struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
1048    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
1049    int width = 0, height = 0;
1050
1051    if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
1052            if (tpl_display_get_native_window_info(dri2_dpy->tpl_display,
1053                                            dri2_surf->native_win,
1054                                            &width, &height, NULL, 0, 0) != TPL_ERROR_NONE)
1055                 return EGL_FALSE;
1056
1057            switch (attribute) {
1058                    case EGL_WIDTH:
1059                            if (dri2_surf->native_win) {
1060                                    *value = width;
1061                                    return EGL_TRUE;
1062                            }
1063                            break;
1064                    case EGL_HEIGHT:
1065                            if (dri2_surf->native_win) {
1066                                    *value = height;
1067                                    return EGL_TRUE;
1068                            }
1069                            break;
1070                    default:
1071                            break;
1072             }
1073    }
1074    return _eglQuerySurface(dpy, surf, attribute, value);
1075 }
1076
1077 static _EGLImage *
1078 dri2_create_image_tizen_native_buffer(_EGLDisplay *disp,
1079                                       _EGLContext *ctx,
1080                                       tbm_surface_h tbm_surface)
1081 {
1082    int fd;
1083
1084    fd = get_native_buffer_fd(tbm_surface);
1085    if (fd >= 0)
1086       return tizen_create_image_from_prime_fd(disp, ctx, tbm_surface, fd);
1087
1088    return tizen_create_image_from_name(disp, ctx, tbm_surface);
1089 }
1090
1091 static _EGLImage *
1092 dri2_create_image_tizen_wl_buffer(_EGLDisplay *disp,
1093                                   _EGLContext *ctx,
1094                                   tpl_handle_t native_pixmap)
1095 {
1096    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1097    int fd;
1098    tbm_surface_h tbm_surface = NULL;
1099
1100    tbm_surface = tpl_display_get_buffer_from_native_pixmap(dri2_dpy->tpl_display,
1101                                                            (tpl_handle_t)native_pixmap);
1102    if (!tbm_surface)
1103      return NULL;
1104
1105    fd = get_native_buffer_fd(tbm_surface);
1106    if (fd >= 0)
1107       return tizen_create_image_from_prime_fd(disp, ctx, tbm_surface, fd);
1108
1109    return tizen_create_image_from_name(disp, ctx, tbm_surface);
1110 }
1111
1112 static _EGLImage *
1113 tizen_create_image_khr(_EGLDisplay *disp,
1114                        _EGLContext *ctx, EGLenum target,
1115                        EGLClientBuffer buffer, const EGLint *attr_list)
1116 {
1117    switch (target) {
1118    case EGL_NATIVE_SURFACE_TIZEN:
1119       return dri2_create_image_tizen_native_buffer(disp, ctx,
1120                                                    (tbm_surface_h)buffer);
1121    case EGL_WAYLAND_BUFFER_WL:
1122       return dri2_create_image_tizen_wl_buffer(disp, ctx, (tpl_handle_t)buffer);
1123    default:
1124       return dri2_create_image_khr(disp, ctx, target, buffer, attr_list);
1125    }
1126 }
1127
1128 static void
1129 tizen_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
1130 {
1131 }
1132
1133 static bool
1134 tizen_validate_drawable(__DRIdrawable * driDrawable, void *loaderPrivate)
1135 {
1136    struct dri2_egl_surface *dri2_surf = loaderPrivate;
1137    bool v = true;
1138    tpl_result_t res = TPL_ERROR_NONE;
1139    int width, height;
1140
1141    res = tpl_surface_get_size(dri2_surf->tpl_surface, &width, &height);
1142    if (res != TPL_ERROR_NONE)
1143       return false;
1144
1145    if ((width != dri2_surf->base.Width) || (height != dri2_surf->base.Height))
1146       v = false;
1147
1148    dri2_surf->valid = v;
1149    return v;
1150 }
1151
1152 static int
1153 tizen_get_buffers_parse_attachments(struct dri2_egl_surface *dri2_surf,
1154                                     unsigned int *attachments, int count)
1155 {
1156    int num_buffers = 0, i;
1157
1158    /* fill dri2_surf->buffers */
1159    for (i = 0; i < count * 2; i += 2) {
1160       __DRIbuffer *buf, *local;
1161
1162       assert(num_buffers < ARRAY_SIZE(dri2_surf->buffers));
1163       buf = &dri2_surf->buffers[num_buffers];
1164
1165       switch (attachments[i]) {
1166       case __DRI_BUFFER_BACK_LEFT:
1167          if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
1168             buf->attachment = attachments[i];
1169             buf->name = get_native_buffer_name(dri2_surf->tbm_surface);
1170             buf->cpp = get_format_bpp(tbm_surface_get_format(dri2_surf->tbm_surface));
1171             buf->pitch = get_pitch(dri2_surf->tbm_surface);
1172             buf->flags = 0;
1173
1174             if (buf->name)
1175                num_buffers++;
1176
1177             break;
1178          }
1179          /* fall through for pbuffers */
1180       case __DRI_BUFFER_FRONT_LEFT:
1181          if (dri2_surf->base.Type != EGL_PBUFFER_BIT)
1182             break;
1183       case __DRI_BUFFER_DEPTH:
1184       case __DRI_BUFFER_STENCIL:
1185       case __DRI_BUFFER_ACCUM:
1186       case __DRI_BUFFER_DEPTH_STENCIL:
1187       case __DRI_BUFFER_HIZ:
1188          local = tizen_alloc_local_buffer(dri2_surf, attachments[i], attachments[i + 1]);
1189
1190          if (local) {
1191             *buf = *local;
1192             num_buffers++;
1193          }
1194          break;
1195       case __DRI_BUFFER_FRONT_RIGHT:
1196       case __DRI_BUFFER_FAKE_FRONT_LEFT:
1197       case __DRI_BUFFER_FAKE_FRONT_RIGHT:
1198       case __DRI_BUFFER_BACK_RIGHT:
1199       default:
1200          /* no front or right buffers */
1201          break;
1202       }
1203    }
1204
1205    return num_buffers;
1206 }
1207
1208 static __DRIbuffer *
1209 tizen_get_buffers_with_format(__DRIdrawable * driDrawable,
1210                               int *width, int *height,
1211                               unsigned int *attachments, int count,
1212                               int *out_count, void *loaderPrivate)
1213 {
1214    struct dri2_egl_surface *dri2_surf = loaderPrivate;
1215
1216    if (update_buffers(dri2_surf) < 0)
1217       return NULL;
1218
1219    dri2_surf->buffer_count =
1220       tizen_get_buffers_parse_attachments(dri2_surf, attachments, count);
1221
1222    if (width)
1223       *width = dri2_surf->base.Width;
1224    if (height)
1225       *height = dri2_surf->base.Height;
1226
1227    *out_count = dri2_surf->buffer_count;
1228
1229    return dri2_surf->buffers;
1230 }
1231
1232 static int
1233 tizen_swrast_get_stride_for_format(tbm_format format, int w)
1234 {
1235    switch (format) {
1236    case TBM_FORMAT_RGB565:
1237       return 2 * w;
1238 #pragma GCC diagnostic push
1239 #pragma GCC diagnostic ignored "-Wswitch"
1240    case TBM_FORMAT_BGRA8888:
1241    case TBM_FORMAT_RGBA8888:
1242 #pragma GCC diagnostic pop
1243    case TBM_FORMAT_RGBX8888:
1244    default:
1245       return 4 * w;
1246    }
1247 }
1248
1249 static void
1250 tizen_swrast_get_drawable_info(__DRIdrawable * draw,
1251                                int *x, int *y, int *w, int *h,
1252                                void *loaderPrivate)
1253 {
1254    struct dri2_egl_surface *dri2_surf = loaderPrivate;
1255
1256    if (!dri2_surf->tbm_surface) {
1257       if (update_buffers(dri2_surf) < 0)
1258          return;
1259    }
1260
1261    *x = 0;
1262    *y = 0;
1263    *w = dri2_surf->base.Width;
1264    *h = dri2_surf->base.Height;
1265 }
1266
1267 static void
1268 tizen_swrast_get_image(__DRIdrawable * read,
1269                        int x, int y, int w, int h,
1270                        char *data, void *loaderPrivate)
1271 {
1272    struct dri2_egl_surface *dri2_surf = loaderPrivate;
1273    tbm_surface_info_s surf_info;
1274    int ret = TBM_SURFACE_ERROR_NONE;
1275    int internal_stride, stride, i;
1276
1277    if (!dri2_surf->tbm_surface) {
1278       if (update_buffers(dri2_surf) < 0)
1279          return;
1280    }
1281
1282    ret = tbm_surface_map(dri2_surf->tbm_surface, TBM_SURF_OPTION_READ, &surf_info);
1283
1284    if (ret != TBM_SURFACE_ERROR_NONE) {
1285       _eglLog(_EGL_WARNING, "Could not tbm_surface_map");
1286       return;
1287    }
1288
1289    internal_stride = surf_info.planes[0].stride;
1290    stride = w * 4;
1291
1292    for (i = 0; i < h; i++) {
1293       memcpy(data + i * stride,
1294              surf_info.planes[0].ptr + (x + i) * internal_stride + y, stride);
1295    }
1296
1297    tbm_surface_unmap(dri2_surf->tbm_surface);
1298 }
1299
1300 static void
1301 tizen_swrast_put_image2(__DRIdrawable * draw, int op,
1302                         int x, int y, int w, int h, int stride,
1303                         char *data, void *loaderPrivate)
1304 {
1305    struct dri2_egl_surface *dri2_surf = loaderPrivate;
1306    tbm_surface_info_s surf_info;
1307    int ret = TBM_SURFACE_ERROR_NONE;
1308    int internal_stride, i;
1309
1310    if (op != __DRI_SWRAST_IMAGE_OP_DRAW &&
1311        op != __DRI_SWRAST_IMAGE_OP_SWAP)
1312       return;
1313
1314    if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
1315       if (!dri2_surf->tbm_surface) {
1316         if (update_buffers(dri2_surf) < 0) {
1317            _eglLog(_EGL_WARNING, "Could not get native buffer");
1318            return;
1319         }
1320       }
1321
1322       ret = tbm_surface_map(dri2_surf->tbm_surface, TBM_SURF_OPTION_WRITE, &surf_info);
1323       if (ret != TBM_SURFACE_ERROR_NONE) {
1324          _eglLog(_EGL_WARNING, "Could not tbm_surface_map");
1325          return;
1326       }
1327
1328       internal_stride = surf_info.planes[0].stride;
1329
1330       for (i = 0; i < h; i++) {
1331          memcpy(surf_info.planes[0].ptr + (x + i) * internal_stride + y,
1332                 data + i * stride, stride);
1333       }
1334
1335       tbm_surface_unmap(dri2_surf->tbm_surface);
1336       tpl_surface_enqueue_buffer_with_damage_and_sync(dri2_surf->tpl_surface,
1337                                                          dri2_surf->tbm_surface,
1338                                                          0, NULL, -1);
1339       tbm_surface_internal_unref(dri2_surf->tbm_surface);
1340       dri2_surf->tbm_surface = NULL;
1341       dri2_surf->back = NULL;
1342    }
1343 }
1344
1345 static void
1346 tizen_swrast_put_image(__DRIdrawable * draw, int op,
1347                          int x, int y, int w, int h,
1348                          char *data, void *loaderPrivate)
1349 {
1350    struct dri2_egl_surface *dri2_surf = loaderPrivate;
1351    int stride;
1352
1353    if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
1354       if (!dri2_surf->tbm_surface) {
1355         if (update_buffers(dri2_surf) < 0) {
1356            _eglLog(_EGL_WARNING, "Could not get native buffer");
1357            return;
1358         }
1359       }
1360
1361       stride = tizen_swrast_get_stride_for_format(dri2_surf->tbm_format, w);
1362       tizen_swrast_put_image2(draw, op, x, y, w, h, stride, data, loaderPrivate);
1363    }
1364 }
1365
1366 static EGLBoolean
1367 tizen_add_configs(_EGLDisplay *dpy)
1368 {
1369    struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
1370    int count, i;
1371    struct rgba_masks {
1372       unsigned int red;
1373       unsigned int green;
1374       unsigned int blue;
1375       unsigned int alpha;
1376    } pbuffer_masks[] = {
1377          { 0xff0000, 0xff00, 0xff, 0xff000000 }, /* ARGB8888 */
1378          { 0xff0000, 0xff00, 0xff, 0x0 },        /* RGB888 */
1379          { 0x00f800, 0x07e0, 0x1f, 0x0 },        /* RGB565 */
1380    };
1381
1382    for (i = 0, count = 0; dri2_dpy->driver_configs[i]; i++) {
1383       struct dri2_egl_config *dri2_cfg;
1384       unsigned int red, blue, green, alpha, depth;
1385       int surface_type = 0;
1386       tpl_bool_t is_slow;
1387       EGLint attr_list[] = {
1388          EGL_NATIVE_VISUAL_ID, 0,
1389          EGL_NONE,
1390       };
1391       tpl_result_t res;
1392       struct rgba_masks masks;
1393       int j;
1394
1395       dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i],
1396                                       __DRI_ATTRIB_RED_SIZE, &red);
1397       dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i],
1398                                       __DRI_ATTRIB_GREEN_SIZE, &green);
1399       dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i],
1400                                       __DRI_ATTRIB_BLUE_SIZE, &blue);
1401       dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i],
1402                                       __DRI_ATTRIB_ALPHA_SIZE, &alpha);
1403       dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i],
1404                                       __DRI_ATTRIB_DEPTH_SIZE, &depth);
1405
1406       res = tpl_display_query_config(dri2_dpy->tpl_display, TPL_SURFACE_TYPE_WINDOW,
1407                                      red, green, blue, alpha, depth,
1408                                      &attr_list[1], &is_slow);
1409       if (res == TPL_ERROR_NONE)
1410         surface_type |= EGL_WINDOW_BIT;
1411
1412       res = tpl_display_query_config(dri2_dpy->tpl_display, TPL_SURFACE_TYPE_PIXMAP,
1413                                      red, green, blue, alpha, depth,
1414                                      &attr_list[1], &is_slow);
1415       if (res == TPL_ERROR_NONE)
1416         surface_type |= EGL_PIXMAP_BIT;
1417
1418       dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i],
1419                                       __DRI_ATTRIB_RED_MASK, &masks.red);
1420       dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i],
1421                                       __DRI_ATTRIB_GREEN_MASK, &masks.green);
1422       dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i],
1423                                       __DRI_ATTRIB_BLUE_MASK, &masks.blue);
1424       dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[i],
1425                                       __DRI_ATTRIB_ALPHA_MASK, &masks.alpha);
1426
1427       for (j = 0; j < ARRAY_SIZE(pbuffer_masks); j++) {
1428          const struct rgba_masks *pbuffer_mask = &pbuffer_masks[j];
1429
1430          if (pbuffer_mask->red   == masks.red &&
1431              pbuffer_mask->green == masks.green &&
1432              pbuffer_mask->blue  == masks.blue &&
1433              pbuffer_mask->alpha == masks.alpha) {
1434             surface_type |= EGL_PBUFFER_BIT;
1435             break;
1436          }
1437       }
1438
1439       if (!surface_type)
1440         continue;
1441
1442       dri2_cfg = dri2_add_config(dpy, dri2_dpy->driver_configs[i], count + 1,
1443                                  surface_type, &attr_list[0], NULL, NULL);
1444       if (dri2_cfg)
1445         count++;
1446    }
1447
1448    return (count != 0);
1449 }
1450
1451 static EGLBoolean tizen_set_swap_interval(_EGLDisplay *dpy,
1452                                           _EGLSurface *surf, EGLint interval)
1453 {
1454    tpl_result_t res = TPL_ERROR_NONE;
1455    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
1456
1457    res = tpl_surface_set_post_interval(dri2_surf->tpl_surface, interval);
1458
1459    if (res != TPL_ERROR_NONE)
1460      return EGL_FALSE;
1461
1462    return EGL_TRUE;
1463 }
1464
1465 static struct dri2_egl_display_vtbl tizen_display_vtbl = {
1466    .authenticate = NULL,
1467    .create_window_surface = tizen_create_window_surface,
1468    .create_pixmap_surface = tizen_create_pixmap_surface,
1469    .create_pbuffer_surface = tizen_create_pbuffer_surface,
1470    .destroy_surface = tizen_destroy_surface,
1471    .create_image = tizen_create_image_khr,
1472    .swap_interval = tizen_set_swap_interval,
1473    .swap_buffers = tizen_swap_buffers,
1474    .swap_buffers_with_damage = tizen_swap_buffers_with_damage,
1475    .query_buffer_age = tizen_query_buffer_age,
1476    .query_surface = tizen_query_surface,
1477    .create_wayland_buffer_from_image = NULL,
1478    .get_dri_drawable = dri2_surface_get_dri_drawable,
1479 };
1480
1481 static const __DRIdri2LoaderExtension tizen_dri2_loader_extension = {
1482    .base = { __DRI_DRI2_LOADER, 3 },
1483
1484    .getBuffers           = NULL,
1485    .getBuffersWithFormat = tizen_get_buffers_with_format,
1486    .flushFrontBuffer     = tizen_flush_front_buffer,
1487    .validate            = tizen_validate_drawable,
1488 };
1489
1490 static const __DRIimageLoaderExtension tizen_image_loader_extension = {
1491    .base = { __DRI_IMAGE_LOADER, 1 },
1492
1493    .getBuffers          = tizen_image_get_buffers,
1494    .flushFrontBuffer    = tizen_flush_front_buffer,
1495    .validate            = tizen_validate_drawable,
1496 };
1497
1498 static const __DRIswrastLoaderExtension tizen_swrast_loader_extension = {
1499    .base = { __DRI_SWRAST_LOADER, 2 },
1500
1501    .getDrawableInfo = tizen_swrast_get_drawable_info,
1502    .putImage        = tizen_swrast_put_image,
1503    .getImage        = tizen_swrast_get_image,
1504    .putImage2       = tizen_swrast_put_image2,
1505 };
1506
1507 static const __DRIextension *tizen_dri2_loader_extensions[] = {
1508    &tizen_dri2_loader_extension.base,
1509    &tizen_image_loader_extension.base,
1510    &image_lookup_extension.base,
1511    &use_invalidate.base,
1512    NULL,
1513 };
1514
1515 static const __DRIextension *tizen_image_loader_extensions[] = {
1516    &tizen_image_loader_extension.base,
1517    &image_lookup_extension.base,
1518    &use_invalidate.base,
1519    NULL,
1520 };
1521
1522 static const __DRIextension *tizen_swrast_loader_extensions[] = {
1523    &tizen_swrast_loader_extension.base,
1524    &image_lookup_extension.base,
1525    NULL,
1526 };
1527
1528 static EGLBoolean
1529 tizen_swrast_swap_buffers(_EGLDisplay *disp, _EGLSurface *draw)
1530 {
1531    struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1532    struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
1533
1534    dri2_dpy->core->swapBuffers(dri2_surf->dri_drawable);
1535    return EGL_TRUE;
1536 }
1537
1538 static const struct dri2_egl_display_vtbl tizen_swrast_display_vtbl = {
1539    .authenticate = NULL,
1540    .create_window_surface = tizen_create_window_surface,
1541    .create_pixmap_surface = tizen_create_pixmap_surface,
1542    .create_pbuffer_surface = tizen_create_pbuffer_surface,
1543    .destroy_surface = tizen_destroy_surface,
1544    .create_image = tizen_create_image_khr,
1545    .swap_buffers = tizen_swrast_swap_buffers,
1546    .get_dri_drawable = dri2_surface_get_dri_drawable,
1547 };
1548
1549
1550 EGLBoolean
1551 dri2_initialize_tizen(_EGLDisplay *disp)
1552 {
1553    _EGLDevice *dev;
1554    struct dri2_egl_display *dri2_dpy;
1555    tpl_display_t *tpl_display = NULL;
1556    tpl_backend_type_t tpl_backend = TPL_BACKEND_UNKNOWN;
1557    const char *err;
1558    int tbm_bufmgr_fd = -1;
1559    int master_fd = -1;
1560    char *tbm_bufmgr_device_name = NULL;
1561    int hw_accel = (getenv("LIBGL_ALWAYS_SOFTWARE") == NULL);
1562
1563    loader_set_logger(_eglLog);
1564
1565    dri2_dpy = calloc(1, sizeof *dri2_dpy);
1566    if (!dri2_dpy)
1567       return _eglError(EGL_BAD_ALLOC, "eglInitialize");
1568
1569    disp->DriverData = (void *) dri2_dpy;
1570
1571    /* Allocate an new native display, if argument passed to 
1572       eglGetDisplay() is EGL_DEFAULT_DISPLAY, it will cause
1573       error in __tpl_wayland_egl_display_init() */
1574    if (disp->PlatformDisplay == NULL) {
1575       disp->PlatformDisplay = wl_display_connect(NULL);
1576       if (disp->PlatformDisplay == NULL) {
1577          err = "DRI2: failed to get native display";
1578          goto cleanup_display;
1579       }
1580       dri2_dpy->own_device = 1;
1581    }
1582
1583    /* Can find the backend type of libtpl-egl through PlatformDisplay */
1584    tpl_backend = tpl_display_get_backend_type(disp->PlatformDisplay);
1585    /* If tpl_backend is a wayland client, thread backend should be used
1586     * to use dri2_surf->out_fence_fd. */
1587    if (tpl_backend == TPL_BACKEND_WAYLAND)
1588       tpl_backend = TPL_BACKEND_WAYLAND_THREAD;
1589
1590    tpl_display = tpl_display_create(tpl_backend, disp->PlatformDisplay);
1591    if (!tpl_display) {
1592       err = "DRI2: failed to create tpl_display";
1593       goto cleanup_display;
1594    }
1595    dri2_dpy->tpl_display = tpl_display;
1596
1597    /* Get tbm_bufmgr's fd */
1598    tbm_bufmgr_fd = tbm_drm_helper_get_fd();
1599    if (tbm_bufmgr_fd == -1) {
1600       err = "DRI2: failed to get tbm_bufmgr fd";
1601       goto cleanup_device;
1602    }
1603
1604    if (hw_accel) {
1605 #if 0//FOR REF: it's another way, to open v3d directly
1606 #define MAX_DRM_DEVICES 32
1607        drmDevicePtr device, devices[MAX_DRM_DEVICES] = { NULL };
1608        int num_devices;
1609        num_devices = drmGetDevices2(0, devices, ARRAY_SIZE(devices));
1610        for (int i = 0; i < num_devices; i++) {
1611            device = devices[i];
1612
1613            if (!(device->available_nodes & (1 << DRM_NODE_RENDER)))
1614               continue;
1615
1616            dri2_dpy->fd = loader_open_device(device->nodes[DRM_NODE_RENDER]);
1617            if (dri2_dpy->fd < 0) {
1618                _eglLog(_EGL_WARNING, "%s() Failed to open DRM device %s",
1619                        __func__, device->nodes[DRM_NODE_RENDER]);
1620            continue;
1621        }
1622        else
1623            break;
1624       }
1625       drmFreeDevices(devices, num_devices);
1626 #endif
1627
1628       if (drmGetNodeTypeFromFd(tbm_bufmgr_fd) == DRM_NODE_RENDER) {
1629
1630          tbm_bufmgr_device_name = loader_get_device_name_for_fd(tbm_bufmgr_fd);
1631          if (tbm_bufmgr_device_name == NULL) {
1632             err = "DRI2: failed to get tbm_bufmgr device name";
1633             goto cleanup_device;
1634          }
1635          dri2_dpy->fd = loader_open_device(tbm_bufmgr_device_name);
1636
1637       } else if ((master_fd = tbm_drm_helper_get_master_fd()) >= 0) {
1638             close(master_fd);
1639             // display server always has master_fd,
1640             // so tbm_bufmgr_fd is the master_fd if it can get the tbm_master_fd.
1641             tbm_bufmgr_device_name = loader_get_device_name_for_fd(tbm_bufmgr_fd);
1642             if (tbm_bufmgr_device_name == NULL) {
1643                err = "DRI2: failed to get tbm_bufmgr device name";
1644                goto cleanup_device;
1645             }
1646             dri2_dpy->fd = loader_open_device(tbm_bufmgr_device_name);
1647       } else {
1648          if (!tbm_drm_helper_get_auth_info(&dri2_dpy->fd, NULL, NULL)) {
1649             err = "DRI2: failed to get fd from tbm_drm_helper_get_auth_info()";
1650             goto cleanup_device;
1651          }
1652       }
1653
1654       dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd);
1655       if (dri2_dpy->driver_name == NULL) {
1656          err = "DRI2: failed to get driver name";
1657          goto cleanup_device;
1658       }
1659
1660       dri2_dpy->is_render_node = drmGetNodeTypeFromFd(dri2_dpy->fd) == DRM_NODE_RENDER;
1661       /* render nodes cannot use Gem names, and thus do not support
1662        * the __DRI_DRI2_LOADER extension */
1663
1664       if (!dri2_dpy->is_render_node) {
1665         dri2_dpy->loader_extensions = tizen_dri2_loader_extensions;
1666         if (!dri2_load_driver(disp)) {
1667             err = "DRI2: failed to load driver";
1668             goto cleanup_driver_name;
1669         }
1670       } else {
1671         dri2_dpy->loader_extensions = tizen_image_loader_extensions;
1672         if (!dri2_load_driver_dri3(disp)) {
1673             err = "DRI3: failed to load driver";
1674             goto cleanup_driver_name;
1675         }
1676       }
1677    } else {
1678       dri2_dpy->fd = tbm_bufmgr_fd;
1679       dri2_dpy->driver_name = strdup("swrast");
1680       if (!dri2_load_driver_swrast(disp)) {
1681          err = "DRI2: failed to load swrast driver";
1682          goto cleanup_device;
1683       }
1684       dri2_dpy->loader_extensions = tizen_swrast_loader_extensions;
1685    }
1686
1687    if (!dri2_create_screen(disp)) {
1688       err = "DRI2: failed to create screen";
1689       goto cleanup_driver;
1690    }
1691
1692
1693    dev = _eglAddDevice(dri2_dpy->fd, false);
1694    if (!dev) {
1695       err = "DRI2: failed to find EGLDevice";
1696       goto cleanup_screen;;
1697    }
1698
1699    disp->Device = dev;
1700
1701    if(dri2_dpy->fd != tbm_bufmgr_fd) {
1702       close(dri2_dpy->fd);
1703    }
1704    close(tbm_bufmgr_fd);
1705    tbm_bufmgr_fd = -1;
1706    dri2_dpy->fd = -1;
1707
1708    if (!dri2_setup_extensions(disp)) {
1709       err = "DRI2: failed to find required DRI extensions";
1710       goto cleanup_screen;
1711    }
1712
1713    dri2_setup_screen(disp);
1714
1715    dri2_setup_swap_interval(disp, 1);
1716
1717    if (!tizen_add_configs(disp)) {
1718       err = "DRI2: failed to add configs";
1719       goto cleanup_screen;
1720    }
1721
1722    /* Fill vtbl last to prevent accidentally calling virtual function during
1723     * initialization.
1724     */
1725    if (hw_accel)
1726       dri2_dpy->vtbl = &tizen_display_vtbl;
1727    else
1728       dri2_dpy->vtbl = &tizen_swrast_display_vtbl;
1729
1730    disp->Extensions.EXT_buffer_age = EGL_FALSE;
1731    disp->Extensions.EXT_swap_buffers_with_damage = EGL_FALSE; /*disable partial buffer swap*/
1732    disp->Extensions.TIZEN_image_native_surface = EGL_TRUE;
1733    disp->Extensions.WL_bind_wayland_display = EGL_TRUE;
1734    disp->Extensions.WL_create_wayland_buffer_from_image = EGL_FALSE;
1735    disp->Extensions.KHR_fence_sync = EGL_TRUE;
1736
1737    if (dri2_dpy->fence->base.version >= 2 &&
1738        dri2_dpy->fence->get_capabilities) {
1739       unsigned capabilities =
1740          dri2_dpy->fence->get_capabilities(dri2_dpy->dri_screen);
1741       disp->Extensions.TIZEN_native_fence_sync =
1742          (capabilities & __DRI_FENCE_CAP_NATIVE_FD) != 0;
1743       disp->Extensions.ANDROID_native_fence_sync = disp->Extensions.TIZEN_native_fence_sync;
1744    }
1745
1746    return EGL_TRUE;
1747
1748 cleanup_screen:
1749    dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
1750 cleanup_driver:
1751    dlclose(dri2_dpy->driver);
1752 cleanup_driver_name:
1753    free(dri2_dpy->driver_name);
1754 cleanup_device:
1755    tpl_object_unreference((tpl_object_t *)tpl_display);
1756 cleanup_display:
1757    if (dri2_dpy->own_device) {
1758       wl_display_disconnect(disp->PlatformDisplay);
1759       disp->PlatformDisplay = NULL;
1760    }
1761    free(dri2_dpy);
1762    disp->DriverData = NULL;
1763
1764    return _eglError(EGL_NOT_INITIALIZED, err);
1765 }
1766
1767 void
1768 dri2_teardown_tizen(_EGLDisplay *disp)
1769 {
1770     struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
1771
1772     if (dri2_dpy->tpl_display)
1773         tpl_object_unreference((tpl_object_t *)(dri2_dpy->tpl_display));
1774
1775     if (tbm_bufmgr_fd > 0)
1776         close(tbm_bufmgr_fd);
1777
1778     if (dri2_dpy->own_device)
1779         wl_display_disconnect(disp->PlatformDisplay);
1780 }