platform_android.c revision bc8b07a65722ad25aa52aa4918b51e236a13b09e
1/*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
5 * Copyright (C) 2010-2011 LunarG Inc.
6 *
7 * Based on platform_x11, which has
8 *
9 * Copyright © 2011 Intel Corporation
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 */
29
30#include <errno.h>
31#include <dlfcn.h>
32
33#if ANDROID_VERSION >= 0x402
34#include <sync/sync.h>
35#endif
36
37#include "loader.h"
38#include "egl_dri2.h"
39#include "egl_dri2_fallbacks.h"
40#include "gralloc_drm.h"
41
42static int
43get_format_bpp(int native)
44{
45   int bpp;
46
47   switch (native) {
48   case HAL_PIXEL_FORMAT_RGBA_8888:
49   case HAL_PIXEL_FORMAT_RGBX_8888:
50   case HAL_PIXEL_FORMAT_BGRA_8888:
51      bpp = 4;
52      break;
53   case HAL_PIXEL_FORMAT_RGB_888:
54      bpp = 3;
55      break;
56   case HAL_PIXEL_FORMAT_RGB_565:
57   case HAL_PIXEL_FORMAT_RGBA_5551:
58   case HAL_PIXEL_FORMAT_RGBA_4444:
59      bpp = 2;
60      break;
61   default:
62      bpp = 0;
63      break;
64   }
65
66   return bpp;
67}
68
69static int
70get_native_buffer_name(struct ANativeWindowBuffer *buf)
71{
72   return gralloc_drm_get_gem_handle(buf->handle);
73}
74
75static EGLBoolean
76droid_window_dequeue_buffer(struct dri2_egl_surface *dri2_surf)
77{
78#if ANDROID_VERSION >= 0x0402
79   int fence_fd;
80
81   if (dri2_surf->window->dequeueBuffer(dri2_surf->window, &dri2_surf->buffer,
82                                        &fence_fd))
83      return EGL_FALSE;
84
85   /* If access to the buffer is controlled by a sync fence, then block on the
86    * fence.
87    *
88    * It may be more performant to postpone blocking until there is an
89    * immediate need to write to the buffer. But doing so would require adding
90    * hooks to the DRI2 loader.
91    *
92    * From the ANativeWindow::dequeueBuffer documentation:
93    *
94    *    The libsync fence file descriptor returned in the int pointed to by
95    *    the fenceFd argument will refer to the fence that must signal
96    *    before the dequeued buffer may be written to.  A value of -1
97    *    indicates that the caller may access the buffer immediately without
98    *    waiting on a fence.  If a valid file descriptor is returned (i.e.
99    *    any value except -1) then the caller is responsible for closing the
100    *    file descriptor.
101    */
102    if (fence_fd >= 0) {
103       /* From the SYNC_IOC_WAIT documentation in <linux/sync.h>:
104        *
105        *    Waits indefinitely if timeout < 0.
106        */
107        int timeout = -1;
108        sync_wait(fence_fd, timeout);
109        close(fence_fd);
110   }
111
112   dri2_surf->buffer->common.incRef(&dri2_surf->buffer->common);
113#else
114   if (dri2_surf->window->dequeueBuffer(dri2_surf->window, &dri2_surf->buffer))
115      return EGL_FALSE;
116
117   dri2_surf->buffer->common.incRef(&dri2_surf->buffer->common);
118   dri2_surf->window->lockBuffer(dri2_surf->window, dri2_surf->buffer);
119#endif
120
121   return EGL_TRUE;
122}
123
124static EGLBoolean
125droid_window_enqueue_buffer(struct dri2_egl_surface *dri2_surf)
126{
127#if ANDROID_VERSION >= 0x0402
128   /* Queue the buffer without a sync fence. This informs the ANativeWindow
129    * that it may access the buffer immediately.
130    *
131    * From ANativeWindow::dequeueBuffer:
132    *
133    *    The fenceFd argument specifies a libsync fence file descriptor for
134    *    a fence that must signal before the buffer can be accessed.  If
135    *    the buffer can be accessed immediately then a value of -1 should
136    *    be used.  The caller must not use the file descriptor after it
137    *    is passed to queueBuffer, and the ANativeWindow implementation
138    *    is responsible for closing it.
139    */
140   int fence_fd = -1;
141   dri2_surf->window->queueBuffer(dri2_surf->window, dri2_surf->buffer,
142                                  fence_fd);
143#else
144   dri2_surf->window->queueBuffer(dri2_surf->window, dri2_surf->buffer);
145#endif
146
147   dri2_surf->buffer->common.decRef(&dri2_surf->buffer->common);
148   dri2_surf->buffer = NULL;
149
150   return EGL_TRUE;
151}
152
153static void
154droid_window_cancel_buffer(struct dri2_egl_surface *dri2_surf)
155{
156   /* no cancel buffer? */
157   droid_window_enqueue_buffer(dri2_surf);
158}
159
160static __DRIbuffer *
161droid_alloc_local_buffer(struct dri2_egl_surface *dri2_surf,
162                         unsigned int att, unsigned int format)
163{
164   struct dri2_egl_display *dri2_dpy =
165      dri2_egl_display(dri2_surf->base.Resource.Display);
166
167   if (att >= ARRAY_SIZE(dri2_surf->local_buffers))
168      return NULL;
169
170   if (!dri2_surf->local_buffers[att]) {
171      dri2_surf->local_buffers[att] =
172         dri2_dpy->dri2->allocateBuffer(dri2_dpy->dri_screen, att, format,
173               dri2_surf->base.Width, dri2_surf->base.Height);
174   }
175
176   return dri2_surf->local_buffers[att];
177}
178
179static void
180droid_free_local_buffers(struct dri2_egl_surface *dri2_surf)
181{
182   struct dri2_egl_display *dri2_dpy =
183      dri2_egl_display(dri2_surf->base.Resource.Display);
184   int i;
185
186   for (i = 0; i < ARRAY_SIZE(dri2_surf->local_buffers); i++) {
187      if (dri2_surf->local_buffers[i]) {
188         dri2_dpy->dri2->releaseBuffer(dri2_dpy->dri_screen,
189               dri2_surf->local_buffers[i]);
190         dri2_surf->local_buffers[i] = NULL;
191      }
192   }
193}
194
195static _EGLSurface *
196droid_create_surface(_EGLDriver *drv, _EGLDisplay *disp, EGLint type,
197		    _EGLConfig *conf, EGLNativeWindowType window,
198		    const EGLint *attrib_list)
199{
200   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
201   struct dri2_egl_config *dri2_conf = dri2_egl_config(conf);
202   struct dri2_egl_surface *dri2_surf;
203   dri2_surf = calloc(1, sizeof *dri2_surf);
204   if (!dri2_surf) {
205      _eglError(EGL_BAD_ALLOC, "droid_create_surface");
206      return NULL;
207   }
208
209   if (!_eglInitSurface(&dri2_surf->base, disp, type, conf, attrib_list))
210      goto cleanup_surface;
211
212   if (type == EGL_WINDOW_BIT) {
213      int format;
214
215      if (!window || window->common.magic != ANDROID_NATIVE_WINDOW_MAGIC) {
216         _eglError(EGL_BAD_NATIVE_WINDOW, "droid_create_surface");
217         goto cleanup_surface;
218      }
219      if (window->query(window, NATIVE_WINDOW_FORMAT, &format)) {
220         _eglError(EGL_BAD_NATIVE_WINDOW, "droid_create_surface");
221         goto cleanup_surface;
222      }
223
224      if (format != dri2_conf->base.NativeVisualID) {
225         _eglLog(_EGL_WARNING, "Native format mismatch: 0x%x != 0x%x",
226               format, dri2_conf->base.NativeVisualID);
227      }
228
229      window->query(window, NATIVE_WINDOW_WIDTH, &dri2_surf->base.Width);
230      window->query(window, NATIVE_WINDOW_HEIGHT, &dri2_surf->base.Height);
231   }
232
233   dri2_surf->dri_drawable =
234      (*dri2_dpy->dri2->createNewDrawable)(dri2_dpy->dri_screen,
235					   dri2_conf->dri_double_config,
236                                           dri2_surf);
237   if (dri2_surf->dri_drawable == NULL) {
238      _eglError(EGL_BAD_ALLOC, "dri2->createNewDrawable");
239      goto cleanup_surface;
240   }
241
242   if (window) {
243      window->common.incRef(&window->common);
244      dri2_surf->window = window;
245   }
246
247   return &dri2_surf->base;
248
249cleanup_surface:
250   free(dri2_surf);
251
252   return NULL;
253}
254
255static _EGLSurface *
256droid_create_window_surface(_EGLDriver *drv, _EGLDisplay *disp,
257			   _EGLConfig *conf, EGLNativeWindowType window,
258			   const EGLint *attrib_list)
259{
260   return droid_create_surface(drv, disp, EGL_WINDOW_BIT, conf,
261			      window, attrib_list);
262}
263
264static _EGLSurface *
265droid_create_pbuffer_surface(_EGLDriver *drv, _EGLDisplay *disp,
266			    _EGLConfig *conf, const EGLint *attrib_list)
267{
268   return droid_create_surface(drv, disp, EGL_PBUFFER_BIT, conf,
269			      NULL, attrib_list);
270}
271
272static EGLBoolean
273droid_destroy_surface(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *surf)
274{
275   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
276   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(surf);
277
278   if (!_eglPutSurface(surf))
279      return EGL_TRUE;
280
281   droid_free_local_buffers(dri2_surf);
282
283   if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
284      if (dri2_surf->buffer)
285         droid_window_cancel_buffer(dri2_surf);
286
287      dri2_surf->window->common.decRef(&dri2_surf->window->common);
288   }
289
290   (*dri2_dpy->core->destroyDrawable)(dri2_surf->dri_drawable);
291
292   free(dri2_surf);
293
294   return EGL_TRUE;
295}
296
297static EGLBoolean
298droid_swap_buffers(_EGLDriver *drv, _EGLDisplay *disp, _EGLSurface *draw)
299{
300   struct dri2_egl_driver *dri2_drv = dri2_egl_driver(drv);
301   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
302   struct dri2_egl_surface *dri2_surf = dri2_egl_surface(draw);
303   _EGLContext *ctx;
304
305   if (dri2_surf->base.Type != EGL_WINDOW_BIT)
306      return EGL_TRUE;
307
308   if (dri2_drv->glFlush) {
309      ctx = _eglGetCurrentContext();
310      if (ctx && ctx->DrawSurface == &dri2_surf->base)
311         dri2_drv->glFlush();
312   }
313
314   (*dri2_dpy->flush->flush)(dri2_surf->dri_drawable);
315
316   if (dri2_surf->buffer)
317      droid_window_enqueue_buffer(dri2_surf);
318
319   (*dri2_dpy->flush->invalidate)(dri2_surf->dri_drawable);
320
321   return EGL_TRUE;
322}
323
324static _EGLImage *
325dri2_create_image_android_native_buffer(_EGLDisplay *disp, _EGLContext *ctx,
326                                        struct ANativeWindowBuffer *buf)
327{
328   struct dri2_egl_display *dri2_dpy = dri2_egl_display(disp);
329   struct dri2_egl_image *dri2_img;
330   int name;
331   EGLint format;
332
333   if (ctx != NULL) {
334      /* From the EGL_ANDROID_image_native_buffer spec:
335       *
336       *     * If <target> is EGL_NATIVE_BUFFER_ANDROID and <ctx> is not
337       *       EGL_NO_CONTEXT, the error EGL_BAD_CONTEXT is generated.
338       */
339      _eglError(EGL_BAD_CONTEXT, "eglCreateEGLImageKHR: for "
340                "EGL_NATIVE_BUFFER_ANDROID, the context must be "
341                "EGL_NO_CONTEXT");
342      return NULL;
343   }
344
345   if (!buf || buf->common.magic != ANDROID_NATIVE_BUFFER_MAGIC ||
346       buf->common.version != sizeof(*buf)) {
347      _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR");
348      return NULL;
349   }
350
351   name = get_native_buffer_name(buf);
352   if (!name) {
353      _eglError(EGL_BAD_PARAMETER, "eglCreateEGLImageKHR");
354      return NULL;
355   }
356
357   /* see the table in droid_add_configs_for_visuals */
358   switch (buf->format) {
359   case HAL_PIXEL_FORMAT_BGRA_8888:
360      format = __DRI_IMAGE_FORMAT_ARGB8888;
361      break;
362   case HAL_PIXEL_FORMAT_RGB_565:
363      format = __DRI_IMAGE_FORMAT_RGB565;
364      break;
365   case HAL_PIXEL_FORMAT_RGBA_8888:
366      format = __DRI_IMAGE_FORMAT_ABGR8888;
367      break;
368   case HAL_PIXEL_FORMAT_RGBX_8888:
369      format = __DRI_IMAGE_FORMAT_XBGR8888;
370      break;
371   case HAL_PIXEL_FORMAT_RGB_888:
372   case HAL_PIXEL_FORMAT_RGBA_5551:
373   case HAL_PIXEL_FORMAT_RGBA_4444:
374      /* unsupported */
375   default:
376      _eglLog(_EGL_WARNING, "unsupported native buffer format 0x%x", buf->format);
377      return NULL;
378      break;
379   }
380
381   dri2_img = calloc(1, sizeof(*dri2_img));
382   if (!dri2_img) {
383      _eglError(EGL_BAD_ALLOC, "droid_create_image_mesa_drm");
384      return NULL;
385   }
386
387   if (!_eglInitImage(&dri2_img->base, disp)) {
388      free(dri2_img);
389      return NULL;
390   }
391
392   dri2_img->dri_image =
393      dri2_dpy->image->createImageFromName(dri2_dpy->dri_screen,
394					   buf->width,
395					   buf->height,
396					   format,
397					   name,
398					   buf->stride,
399					   dri2_img);
400   if (!dri2_img->dri_image) {
401      free(dri2_img);
402      _eglError(EGL_BAD_ALLOC, "droid_create_image_mesa_drm");
403      return NULL;
404   }
405
406   return &dri2_img->base;
407}
408
409static _EGLImage *
410droid_create_image_khr(_EGLDriver *drv, _EGLDisplay *disp,
411		       _EGLContext *ctx, EGLenum target,
412		       EGLClientBuffer buffer, const EGLint *attr_list)
413{
414   switch (target) {
415   case EGL_NATIVE_BUFFER_ANDROID:
416      return dri2_create_image_android_native_buffer(disp, ctx,
417            (struct ANativeWindowBuffer *) buffer);
418   default:
419      return dri2_create_image_khr(drv, disp, ctx, target, buffer, attr_list);
420   }
421}
422
423static void
424droid_init_driver_functions(_EGLDriver *drv)
425{
426   drv->API.CreatePbufferSurface = droid_create_pbuffer_surface;
427   drv->API.DestroySurface = droid_destroy_surface;
428
429   drv->API.CreateImageKHR = droid_create_image_khr;
430}
431
432static void
433droid_flush_front_buffer(__DRIdrawable * driDrawable, void *loaderPrivate)
434{
435}
436
437static int
438droid_get_buffers_parse_attachments(struct dri2_egl_surface *dri2_surf,
439                                    unsigned int *attachments, int count)
440{
441   int num_buffers = 0, i;
442
443   /* fill dri2_surf->buffers */
444   for (i = 0; i < count * 2; i += 2) {
445      __DRIbuffer *buf, *local;
446
447      assert(num_buffers < ARRAY_SIZE(dri2_surf->buffers));
448      buf = &dri2_surf->buffers[num_buffers];
449
450      switch (attachments[i]) {
451      case __DRI_BUFFER_BACK_LEFT:
452         if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
453            buf->attachment = attachments[i];
454            buf->name = get_native_buffer_name(dri2_surf->buffer);
455            buf->cpp = get_format_bpp(dri2_surf->buffer->format);
456            buf->pitch = dri2_surf->buffer->stride * buf->cpp;
457            buf->flags = 0;
458
459            if (buf->name)
460               num_buffers++;
461
462            break;
463         }
464         /* fall through for pbuffers */
465      case __DRI_BUFFER_DEPTH:
466      case __DRI_BUFFER_STENCIL:
467      case __DRI_BUFFER_ACCUM:
468      case __DRI_BUFFER_DEPTH_STENCIL:
469      case __DRI_BUFFER_HIZ:
470         local = droid_alloc_local_buffer(dri2_surf,
471               attachments[i], attachments[i + 1]);
472
473         if (local) {
474            *buf = *local;
475            num_buffers++;
476         }
477         break;
478      case __DRI_BUFFER_FRONT_LEFT:
479      case __DRI_BUFFER_FRONT_RIGHT:
480      case __DRI_BUFFER_FAKE_FRONT_LEFT:
481      case __DRI_BUFFER_FAKE_FRONT_RIGHT:
482      case __DRI_BUFFER_BACK_RIGHT:
483      default:
484         /* no front or right buffers */
485         break;
486      }
487   }
488
489   return num_buffers;
490}
491
492static __DRIbuffer *
493droid_get_buffers_with_format(__DRIdrawable * driDrawable,
494			     int *width, int *height,
495			     unsigned int *attachments, int count,
496			     int *out_count, void *loaderPrivate)
497{
498   struct dri2_egl_surface *dri2_surf = loaderPrivate;
499   struct dri2_egl_display *dri2_dpy =
500      dri2_egl_display(dri2_surf->base.Resource.Display);
501   int i;
502
503   if (dri2_surf->base.Type == EGL_WINDOW_BIT) {
504      /* try to dequeue the next back buffer */
505      if (!dri2_surf->buffer && !droid_window_dequeue_buffer(dri2_surf))
506         return NULL;
507
508      /* free outdated buffers and update the surface size */
509      if (dri2_surf->base.Width != dri2_surf->buffer->width ||
510          dri2_surf->base.Height != dri2_surf->buffer->height) {
511         droid_free_local_buffers(dri2_surf);
512         dri2_surf->base.Width = dri2_surf->buffer->width;
513         dri2_surf->base.Height = dri2_surf->buffer->height;
514      }
515   }
516
517   dri2_surf->buffer_count =
518      droid_get_buffers_parse_attachments(dri2_surf, attachments, count);
519
520   if (width)
521      *width = dri2_surf->base.Width;
522   if (height)
523      *height = dri2_surf->base.Height;
524
525   *out_count = dri2_surf->buffer_count;;
526
527   return dri2_surf->buffers;
528}
529
530static EGLBoolean
531droid_add_configs_for_visuals(_EGLDriver *drv, _EGLDisplay *dpy)
532{
533   struct dri2_egl_display *dri2_dpy = dri2_egl_display(dpy);
534   const struct {
535      int format;
536      unsigned int rgba_masks[4];
537   } visuals[] = {
538      { HAL_PIXEL_FORMAT_RGBA_8888, { 0xff, 0xff00, 0xff0000, 0xff000000 } },
539      { HAL_PIXEL_FORMAT_RGBX_8888, { 0xff, 0xff00, 0xff0000, 0x0 } },
540      { HAL_PIXEL_FORMAT_RGB_888,   { 0xff, 0xff00, 0xff0000, 0x0 } },
541      { HAL_PIXEL_FORMAT_RGB_565,   { 0xf800, 0x7e0, 0x1f, 0x0 } },
542      { HAL_PIXEL_FORMAT_BGRA_8888, { 0xff0000, 0xff00, 0xff, 0xff000000 } },
543      { 0, 0, { 0, 0, 0, 0 } }
544   };
545   int count, i, j;
546
547   count = 0;
548   for (i = 0; visuals[i].format; i++) {
549      int format_count = 0;
550
551      for (j = 0; dri2_dpy->driver_configs[j]; j++) {
552         const EGLint surface_type = EGL_WINDOW_BIT | EGL_PBUFFER_BIT;
553         struct dri2_egl_config *dri2_conf;
554         unsigned int double_buffered = 0;
555
556         dri2_dpy->core->getConfigAttrib(dri2_dpy->driver_configs[j],
557            __DRI_ATTRIB_DOUBLE_BUFFER, &double_buffered);
558
559         /* support only double buffered configs */
560         if (!double_buffered)
561            continue;
562
563         dri2_conf = dri2_add_config(dpy, dri2_dpy->driver_configs[j],
564               count + 1, surface_type, NULL, visuals[i].rgba_masks);
565         if (dri2_conf) {
566            dri2_conf->base.NativeVisualID = visuals[i].format;
567            dri2_conf->base.NativeVisualType = visuals[i].format;
568            count++;
569            format_count++;
570         }
571      }
572
573      if (!format_count) {
574         _eglLog(_EGL_DEBUG, "No DRI config supports native format 0x%x",
575               visuals[i].format);
576      }
577   }
578
579   /* post-process configs */
580   for (i = 0; i < dpy->Configs->Size; i++) {
581      struct dri2_egl_config *dri2_conf = dri2_egl_config(dpy->Configs->Elements[i]);
582
583      /* there is no front buffer so no OpenGL */
584      dri2_conf->base.RenderableType &= ~EGL_OPENGL_BIT;
585      dri2_conf->base.Conformant &= ~EGL_OPENGL_BIT;
586   }
587
588   return (count != 0);
589}
590
591static int
592droid_open_device(void)
593{
594   const hw_module_t *mod;
595   int fd = -1, err;
596
597   err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mod);
598   if (!err) {
599      const gralloc_module_t *gr = (gralloc_module_t *) mod;
600
601      err = -EINVAL;
602      if (gr->perform)
603         err = gr->perform(gr, GRALLOC_MODULE_PERFORM_GET_DRM_FD, &fd);
604   }
605   if (err || fd < 0) {
606      _eglLog(_EGL_WARNING, "fail to get drm fd");
607      fd = -1;
608   }
609
610   return (fd >= 0) ? dup(fd) : -1;
611}
612
613/* support versions < JellyBean */
614#ifndef ALOGW
615#define ALOGW LOGW
616#endif
617#ifndef ALOGD
618#define ALOGD LOGD
619#endif
620#ifndef ALOGI
621#define ALOGI LOGI
622#endif
623
624static void
625droid_log(EGLint level, const char *msg)
626{
627   switch (level) {
628   case _EGL_DEBUG:
629      ALOGD("%s", msg);
630      break;
631   case _EGL_INFO:
632      ALOGI("%s", msg);
633      break;
634   case _EGL_WARNING:
635      ALOGW("%s", msg);
636      break;
637   case _EGL_FATAL:
638      LOG_FATAL("%s", msg);
639      break;
640   default:
641      break;
642   }
643}
644
645static struct dri2_egl_display_vtbl droid_display_vtbl = {
646   .authenticate = NULL,
647   .create_window_surface = droid_create_window_surface,
648   .create_pixmap_surface = dri2_fallback_pixmap_surface,
649   .swap_interval = dri2_fallback_swap_interval,
650   .swap_buffers = droid_swap_buffers,
651   .swap_buffers_with_damage = dri2_fallback_swap_buffers_with_damage,
652};
653
654EGLBoolean
655dri2_initialize_android(_EGLDriver *drv, _EGLDisplay *dpy)
656{
657   struct dri2_egl_display *dri2_dpy;
658   const char *err;
659
660   _eglSetLogProc(droid_log);
661
662   loader_set_logger(_eglLog);
663
664   dri2_dpy = calloc(1, sizeof(*dri2_dpy));
665   if (!dri2_dpy)
666      return _eglError(EGL_BAD_ALLOC, "eglInitialize");
667
668   dpy->DriverData = (void *) dri2_dpy;
669
670   dri2_dpy->fd = droid_open_device();
671   if (dri2_dpy->fd < 0) {
672      err = "DRI2: failed to open device";
673      goto cleanup_display;
674   }
675
676   dri2_dpy->driver_name = loader_get_driver_for_fd(dri2_dpy->fd, 0);
677   if (dri2_dpy->driver_name == NULL) {
678      err = "DRI2: failed to get driver name";
679      goto cleanup_device;
680   }
681
682   if (!dri2_load_driver(dpy)) {
683      err = "DRI2: failed to load driver";
684      goto cleanup_driver_name;
685   }
686
687   dri2_dpy->dri2_loader_extension.base.name = __DRI_DRI2_LOADER;
688   dri2_dpy->dri2_loader_extension.base.version = 3;
689   dri2_dpy->dri2_loader_extension.getBuffers = NULL;
690   dri2_dpy->dri2_loader_extension.flushFrontBuffer = droid_flush_front_buffer;
691   dri2_dpy->dri2_loader_extension.getBuffersWithFormat =
692      droid_get_buffers_with_format;
693
694   dri2_dpy->extensions[0] = &dri2_dpy->dri2_loader_extension.base;
695   dri2_dpy->extensions[1] = &image_lookup_extension.base;
696   dri2_dpy->extensions[2] = &use_invalidate.base;
697   dri2_dpy->extensions[3] = NULL;
698
699   if (!dri2_create_screen(dpy)) {
700      err = "DRI2: failed to create screen";
701      goto cleanup_driver;
702   }
703
704   if (!droid_add_configs_for_visuals(drv, dpy)) {
705      err = "DRI2: failed to add configs";
706      goto cleanup_screen;
707   }
708
709   dpy->Extensions.ANDROID_image_native_buffer = EGL_TRUE;
710   dpy->Extensions.KHR_image_base = EGL_TRUE;
711
712   /* we're supporting EGL 1.4 */
713   dpy->VersionMajor = 1;
714   dpy->VersionMinor = 4;
715
716   droid_init_driver_functions(drv);
717
718   /* Fill vtbl last to prevent accidentally calling virtual function during
719    * initialization.
720    */
721   dri2_dpy->vtbl = &droid_display_vtbl;
722
723   return EGL_TRUE;
724
725cleanup_screen:
726   dri2_dpy->core->destroyScreen(dri2_dpy->dri_screen);
727cleanup_driver:
728   dlclose(dri2_dpy->driver);
729cleanup_driver_name:
730   free(dri2_dpy->driver_name);
731cleanup_device:
732   close(dri2_dpy->fd);
733cleanup_display:
734   free(dri2_dpy);
735
736   return _eglError(EGL_NOT_INITIALIZED, err);
737}
738