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