native_android.cpp revision 112e68c5039ff717848304f0c28a07c5b39c7f45
1/*
2 * Mesa 3-D graphics library
3 * Version:  7.12
4 *
5 * Copyright (C) 2010-2011 Chia-I Wu <olvaffe@gmail.com>
6 * Copyright (C) 2010-2011 LunarG Inc.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 * DEALINGS IN THE SOFTWARE.
25 */
26
27#define LOG_TAG "EGL-GALLIUM"
28#include <cutils/log.h>
29#include <cutils/properties.h>
30#include <hardware/gralloc.h>
31#include <utils/Errors.h>
32#include <ui/android_native_buffer.h>
33
34extern "C" {
35#include "egllog.h"
36}
37
38#include "util/u_memory.h"
39#include "util/u_inlines.h"
40#include "util/u_format.h"
41#include "util/u_box.h"
42#include "common/native.h"
43#include "common/native_helper.h"
44#include "android/android_sw_winsys.h"
45#include "state_tracker/drm_driver.h"
46
47struct android_config;
48
49struct android_display {
50   struct native_display base;
51
52   boolean use_drm;
53   const struct native_event_handler *event_handler;
54   struct android_config *configs;
55   int num_configs;
56};
57
58struct android_surface {
59   struct native_surface base;
60
61   struct android_display *adpy;
62   android_native_window_t *win;
63
64   /* staging color buffer for when buffer preserving is enabled */
65   struct pipe_resource *color_res;
66
67   uint stamp;
68   android_native_buffer_t *buf;
69   struct pipe_resource *buf_res;
70
71   /* cache the current back buffers */
72   struct {
73      int width;
74      int height;
75      int format;
76   } cache_key;
77   void *cache_handles[2];
78   struct pipe_resource *cache_resources[2];
79};
80
81struct android_config {
82   struct native_config base;
83};
84
85static INLINE struct android_display *
86android_display(const struct native_display *ndpy)
87{
88   return (struct android_display *) ndpy;
89}
90
91static INLINE struct android_surface *
92android_surface(const struct native_surface *nsurf)
93{
94   return (struct android_surface *) nsurf;
95}
96
97static INLINE struct android_config *
98android_config(const struct native_config *nconf)
99{
100   return (struct android_config *) nconf;
101}
102
103namespace android {
104
105static enum pipe_format
106get_pipe_format(int native)
107{
108   enum pipe_format fmt;
109
110   switch (native) {
111   case HAL_PIXEL_FORMAT_RGBA_8888:
112      fmt = PIPE_FORMAT_R8G8B8A8_UNORM;
113      break;
114   case HAL_PIXEL_FORMAT_RGBX_8888:
115      fmt = PIPE_FORMAT_R8G8B8X8_UNORM;
116      break;
117   case HAL_PIXEL_FORMAT_RGB_888:
118      fmt = PIPE_FORMAT_R8G8B8_UNORM;
119      break;
120   case HAL_PIXEL_FORMAT_RGB_565:
121      fmt = PIPE_FORMAT_B5G6R5_UNORM;
122      break;
123   case HAL_PIXEL_FORMAT_BGRA_8888:
124      fmt = PIPE_FORMAT_B8G8R8A8_UNORM;
125      break;
126   case HAL_PIXEL_FORMAT_RGBA_5551:
127      /* fmt = PIPE_FORMAT_A1B5G5R5_UNORM; */
128   case HAL_PIXEL_FORMAT_RGBA_4444:
129      /* fmt = PIPE_FORMAT_A4B4G4R4_UNORM; */
130   default:
131      LOGE("unsupported native format 0x%x", native);
132      fmt = PIPE_FORMAT_NONE;
133      break;
134   }
135
136   return fmt;
137}
138
139#include <gralloc_drm_handle.h>
140static int
141get_handle_name(buffer_handle_t handle)
142{
143   struct gralloc_drm_handle_t *dh;
144
145   /* check that the buffer is allocated by drm_gralloc and cast */
146   dh = gralloc_drm_handle(handle);
147
148   return (dh) ? dh->name : 0;
149}
150
151/**
152 * Import an android_native_buffer_t allocated by the server.
153 */
154static struct pipe_resource *
155import_buffer(struct android_display *adpy, const struct pipe_resource *templ,
156              struct android_native_buffer_t *abuf)
157{
158   struct pipe_screen *screen = adpy->base.screen;
159   struct pipe_resource *res;
160
161   if (templ->bind & PIPE_BIND_RENDER_TARGET) {
162      if (!screen->is_format_supported(screen, templ->format,
163               templ->target, 0, PIPE_BIND_RENDER_TARGET))
164         LOGW("importing unsupported buffer as render target");
165   }
166   if (templ->bind & PIPE_BIND_SAMPLER_VIEW) {
167      if (!screen->is_format_supported(screen, templ->format,
168               templ->target, 0, PIPE_BIND_SAMPLER_VIEW))
169         LOGW("importing unsupported buffer as sampler view");
170   }
171
172   if (adpy->use_drm) {
173      struct winsys_handle handle;
174
175      memset(&handle, 0, sizeof(handle));
176      handle.type = DRM_API_HANDLE_TYPE_SHARED;
177      /* for DRM, we need the GEM name */
178      handle.handle = get_handle_name(abuf->handle);
179      if (!handle.handle) {
180         LOGE("unable to import invalid buffer %p", abuf);
181         return NULL;
182      }
183
184      handle.stride =
185         abuf->stride * util_format_get_blocksize(templ->format);
186
187      res = screen->resource_from_handle(screen, templ, &handle);
188   }
189   else {
190      struct android_winsys_handle handle;
191
192      memset(&handle, 0, sizeof(handle));
193      handle.handle = abuf->handle;
194      handle.stride =
195         abuf->stride * util_format_get_blocksize(templ->format);
196
197      res = screen->resource_from_handle(screen,
198            templ, (struct winsys_handle *) &handle);
199   }
200
201   if (!res)
202      LOGE("failed to import buffer %p", abuf);
203
204   return res;
205}
206
207static void
208android_surface_clear_cache(struct native_surface *nsurf)
209{
210   struct android_surface *asurf = android_surface(nsurf);
211   int i;
212
213   for (i = 0; i < Elements(asurf->cache_handles); i++) {
214      asurf->cache_handles[i] = NULL;
215      pipe_resource_reference(&asurf->cache_resources[i], NULL);
216   }
217
218   memset(&asurf->cache_key, 0, sizeof(asurf->cache_key));
219}
220
221static struct pipe_resource *
222android_surface_add_cache(struct native_surface *nsurf,
223                          struct android_native_buffer_t *abuf)
224{
225   struct android_surface *asurf = android_surface(nsurf);
226   void *handle;
227   int idx;
228
229   /* how about abuf->usage? */
230   if (asurf->cache_key.width != abuf->width ||
231       asurf->cache_key.height != abuf->height ||
232       asurf->cache_key.format != abuf->format)
233      android_surface_clear_cache(&asurf->base);
234
235   if (asurf->adpy->use_drm)
236      handle = (void *) get_handle_name(abuf->handle);
237   else
238      handle = (void *) abuf->handle;
239   /* NULL is invalid */
240   if (!handle) {
241      LOGE("invalid buffer native buffer %p", abuf);
242      return NULL;
243   }
244
245   /* find the slot to use */
246   for (idx = 0; idx < Elements(asurf->cache_handles); idx++) {
247      if (asurf->cache_handles[idx] == handle || !asurf->cache_handles[idx])
248         break;
249   }
250   if (idx == Elements(asurf->cache_handles)) {
251      LOGW("cache full: buf %p, width %d, height %d, format %d, usage 0x%x",
252            abuf, abuf->width, abuf->height, abuf->format, abuf->usage);
253      android_surface_clear_cache(&asurf->base);
254      idx = 0;
255   }
256
257   if (idx == 0) {
258      asurf->cache_key.width = abuf->width;
259      asurf->cache_key.height = abuf->height;
260      asurf->cache_key.format = abuf->format;
261   }
262
263   if (!asurf->cache_handles[idx]) {
264      struct pipe_resource templ;
265
266      assert(!asurf->cache_resources[idx]);
267
268      memset(&templ, 0, sizeof(templ));
269      templ.target = PIPE_TEXTURE_2D;
270      templ.format = get_pipe_format(asurf->buf->format);
271      templ.bind = PIPE_BIND_RENDER_TARGET;
272      if (!asurf->adpy->use_drm) {
273         templ.bind |= PIPE_BIND_TRANSFER_WRITE |
274                       PIPE_BIND_TRANSFER_READ;
275      }
276
277      templ.width0 = asurf->buf->width;
278      templ.height0 = asurf->buf->height;
279      templ.depth0 = 1;
280      templ.array_size = 1;
281
282      if (templ.format != PIPE_FORMAT_NONE) {
283         asurf->cache_resources[idx] =
284            import_buffer(asurf->adpy, &templ, asurf->buf);
285      }
286      else {
287         asurf->cache_resources[idx] = NULL;
288      }
289
290      asurf->cache_handles[idx] = handle;
291   }
292
293   return asurf->cache_resources[idx];
294}
295
296/**
297 * Dequeue the next back buffer for rendering.
298 */
299static boolean
300android_surface_dequeue_buffer(struct native_surface *nsurf)
301{
302   struct android_surface *asurf = android_surface(nsurf);
303   struct pipe_resource *res;
304
305   if (asurf->win->dequeueBuffer(asurf->win, &asurf->buf) != NO_ERROR) {
306      LOGE("failed to dequeue window %p", asurf->win);
307      return FALSE;
308   }
309
310   asurf->buf->common.incRef(&asurf->buf->common);
311   asurf->win->lockBuffer(asurf->win, asurf->buf);
312
313   res = android_surface_add_cache(&asurf->base, asurf->buf);
314   if (!res)
315      return FALSE;
316
317   pipe_resource_reference(&asurf->buf_res, res);
318
319   return TRUE;
320}
321
322/**
323 * Enqueue the back buffer.  This will make it the next front buffer.
324 */
325static boolean
326android_surface_enqueue_buffer(struct native_surface *nsurf)
327{
328   struct android_surface *asurf = android_surface(nsurf);
329
330   pipe_resource_reference(&asurf->buf_res, NULL);
331
332   asurf->win->queueBuffer(asurf->win, asurf->buf);
333
334   asurf->buf->common.decRef(&asurf->buf->common);
335   asurf->buf = NULL;
336
337   return TRUE;
338}
339
340static boolean
341android_surface_swap_buffers(struct native_surface *nsurf)
342{
343   struct android_surface *asurf = android_surface(nsurf);
344   struct android_display *adpy = asurf->adpy;
345
346   if (!asurf->buf)
347      return TRUE;
348
349   android_surface_enqueue_buffer(&asurf->base);
350
351   asurf->stamp++;
352   adpy->event_handler->invalid_surface(&adpy->base,
353         &asurf->base, asurf->stamp);
354
355   return TRUE;
356}
357
358static void
359copy_resources(struct native_display *ndpy,
360               struct pipe_resource *src,
361               struct pipe_resource *dst)
362{
363   struct pipe_context *pipe;
364   struct pipe_box box;
365
366   pipe = ndpy_get_copy_context(ndpy);
367   if (!pipe)
368      return;
369
370   u_box_origin_2d(src->width0, src->height0, &box);
371   pipe->resource_copy_region(pipe, dst, 0, 0, 0, 0, src, 0, &box);
372   pipe->flush(pipe, NULL);
373}
374
375static boolean
376android_surface_present(struct native_surface *nsurf,
377                        enum native_attachment natt,
378                        boolean preserve,
379                        uint swap_interval)
380{
381   struct android_surface *asurf = android_surface(nsurf);
382   struct android_display *adpy = asurf->adpy;
383   boolean ret;
384
385   if (swap_interval || natt != NATIVE_ATTACHMENT_BACK_LEFT)
386      return FALSE;
387
388   /* we always render to color_res first when it exists */
389   if (asurf->color_res) {
390      copy_resources(&adpy->base, asurf->color_res, asurf->buf_res);
391      if (!preserve)
392         pipe_resource_reference(&asurf->color_res, NULL);
393   }
394   else if (preserve) {
395      struct pipe_resource templ;
396
397      memset(&templ, 0, sizeof(templ));
398      templ.target = asurf->buf_res->target;
399      templ.format = asurf->buf_res->format;
400      templ.bind = PIPE_BIND_RENDER_TARGET;
401      templ.width0 = asurf->buf_res->width0;
402      templ.height0 = asurf->buf_res->height0;
403      templ.depth0 = asurf->buf_res->depth0;
404      templ.array_size = asurf->buf_res->array_size;
405
406      asurf->color_res =
407         adpy->base.screen->resource_create(adpy->base.screen, &templ);
408      if (!asurf->color_res)
409         return FALSE;
410
411      /* preserve the contents */
412      copy_resources(&adpy->base, asurf->buf_res, asurf->color_res);
413   }
414
415   return android_surface_swap_buffers(nsurf);
416}
417
418static boolean
419android_surface_validate(struct native_surface *nsurf, uint attachment_mask,
420                         unsigned int *seq_num, struct pipe_resource **textures,
421                         int *width, int *height)
422{
423   struct android_surface *asurf = android_surface(nsurf);
424   struct winsys_handle handle;
425
426   if (!asurf->buf) {
427      if (!android_surface_dequeue_buffer(&asurf->base))
428         return FALSE;
429
430      /* color_res must be compatible with buf_res */
431      if (asurf->color_res &&
432          (asurf->color_res->format != asurf->buf_res->format ||
433           asurf->color_res->width0 != asurf->buf_res->width0 ||
434           asurf->color_res->height0 != asurf->buf_res->height0))
435         pipe_resource_reference(&asurf->color_res, NULL);
436   }
437
438   if (textures) {
439      /* we have access to only the back buffer */
440      const enum native_attachment att = NATIVE_ATTACHMENT_BACK_LEFT;
441
442      if (native_attachment_mask_test(attachment_mask, att)) {
443         textures[att] = NULL;
444         pipe_resource_reference(&textures[att],
445               (asurf->color_res) ? asurf->color_res : asurf->buf_res);
446      }
447   }
448
449   if (seq_num)
450      *seq_num = asurf->stamp;
451   if (width)
452      *width = asurf->buf->width;
453   if (height)
454      *height = asurf->buf->height;
455
456   return TRUE;
457}
458
459static void
460android_surface_wait(struct native_surface *nsurf)
461{
462}
463
464static void
465android_surface_destroy(struct native_surface *nsurf)
466{
467   struct android_surface *asurf = android_surface(nsurf);
468   int i;
469
470   pipe_resource_reference(&asurf->color_res, NULL);
471
472   if (asurf->buf)
473      android_surface_enqueue_buffer(&asurf->base);
474
475   android_surface_clear_cache(&asurf->base);
476
477   asurf->win->common.decRef(&asurf->win->common);
478
479   FREE(asurf);
480}
481
482static struct native_surface *
483android_display_create_window_surface(struct native_display *ndpy,
484                                      EGLNativeWindowType win,
485                                      const struct native_config *nconf)
486{
487   struct android_display *adpy = android_display(ndpy);
488   struct android_config *aconf = android_config(nconf);
489   struct android_surface *asurf;
490   enum pipe_format format;
491   int val;
492
493   if (win->common.magic != ANDROID_NATIVE_WINDOW_MAGIC) {
494      LOGE("invalid native window with magic 0x%x", win->common.magic);
495      return NULL;
496   }
497   if (win->query(win, NATIVE_WINDOW_FORMAT, &val)) {
498      LOGE("failed to query native window format");
499      return NULL;
500   }
501   format = get_pipe_format(val);
502   if (format != nconf->color_format) {
503      LOGW("native window format 0x%x != config format 0x%x",
504            format, nconf->color_format);
505      if (!adpy->base.screen->is_format_supported(adpy->base.screen,
506               format, PIPE_TEXTURE_2D, 0, PIPE_BIND_RENDER_TARGET)) {
507         LOGE("and the native window cannot be used as a render target");
508         return NULL;
509      }
510   }
511
512   asurf = CALLOC_STRUCT(android_surface);
513   if (!asurf)
514      return NULL;
515
516   asurf->adpy = adpy;
517   asurf->win = win;
518   asurf->win->common.incRef(&asurf->win->common);
519
520   /* request buffers that are for CPU access */
521   if (!adpy->use_drm) {
522      native_window_set_usage(asurf->win,
523            GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
524   }
525
526   asurf->base.destroy = android_surface_destroy;
527   asurf->base.present = android_surface_present;
528   asurf->base.validate = android_surface_validate;
529   asurf->base.wait = android_surface_wait;
530
531   return &asurf->base;
532}
533
534static boolean
535android_display_init_configs(struct native_display *ndpy)
536{
537   struct android_display *adpy = android_display(ndpy);
538   const int native_formats[] = {
539      HAL_PIXEL_FORMAT_RGBA_8888,
540      HAL_PIXEL_FORMAT_RGBX_8888,
541      HAL_PIXEL_FORMAT_RGB_888,
542      HAL_PIXEL_FORMAT_RGB_565,
543      HAL_PIXEL_FORMAT_BGRA_8888,
544   };
545   int i;
546
547   adpy->configs = (struct android_config *)
548      CALLOC(Elements(native_formats), sizeof(*adpy->configs));
549   if (!adpy->configs)
550      return FALSE;
551
552   for (i = 0; i < Elements(native_formats); i++) {
553      enum pipe_format color_format;
554      struct android_config *aconf;
555
556      color_format = get_pipe_format(native_formats[i]);
557      if (color_format == PIPE_FORMAT_NONE ||
558          !adpy->base.screen->is_format_supported(adpy->base.screen,
559               color_format, PIPE_TEXTURE_2D, 0, PIPE_BIND_RENDER_TARGET)) {
560         LOGI("skip unsupported native format 0x%x", native_formats[i]);
561         continue;
562      }
563
564      aconf = &adpy->configs[adpy->num_configs++];
565      /* only the back buffer */
566      aconf->base.buffer_mask = 1 << NATIVE_ATTACHMENT_BACK_LEFT;
567      aconf->base.color_format = color_format;
568      aconf->base.window_bit = TRUE;
569
570      aconf->base.native_visual_id = native_formats[i];
571      aconf->base.native_visual_type = native_formats[i];
572   }
573
574   return TRUE;
575}
576
577static boolean
578android_display_init_drm(struct native_display *ndpy)
579{
580   struct android_display *adpy = android_display(ndpy);
581   const hw_module_t *mod;
582   int fd, err;
583
584   /* get the authorized fd from gralloc */
585   err = hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mod);
586   if (!err) {
587      const gralloc_module_t *gr = (gralloc_module_t *) mod;
588
589      err = -EINVAL;
590      if (gr->perform)
591         err = gr->perform(gr, GRALLOC_MODULE_PERFORM_GET_DRM_FD, &fd);
592   }
593   if (!err && fd >= 0) {
594      adpy->base.screen =
595         adpy->event_handler->new_drm_screen(&adpy->base, NULL, fd);
596   }
597
598   if (adpy->base.screen) {
599      LOGI("using DRM screen");
600      return TRUE;
601   }
602   else {
603      LOGW("failed to create DRM screen");
604      LOGW("will fall back to other EGL drivers if any");
605      return FALSE;
606   }
607}
608
609static boolean
610android_display_init_sw(struct native_display *ndpy)
611{
612   struct android_display *adpy = android_display(ndpy);
613   struct sw_winsys *ws;
614
615   ws = android_create_sw_winsys();
616   if (ws) {
617      adpy->base.screen =
618         adpy->event_handler->new_sw_screen(&adpy->base, ws);
619   }
620
621   if (adpy->base.screen) {
622      LOGI("using SW screen");
623      return TRUE;
624   }
625   else {
626      LOGE("failed to create SW screen");
627      return FALSE;
628   }
629}
630
631static boolean
632android_display_init_screen(struct native_display *ndpy)
633{
634   struct android_display *adpy = android_display(ndpy);
635
636   if (adpy->use_drm)
637      android_display_init_drm(&adpy->base);
638   else
639      android_display_init_sw(&adpy->base);
640
641   if (!adpy->base.screen)
642      return FALSE;
643
644   if (!android_display_init_configs(&adpy->base)) {
645      adpy->base.screen->destroy(adpy->base.screen);
646      adpy->base.screen = NULL;
647      return FALSE;
648   }
649
650   return TRUE;
651}
652
653static void
654android_display_destroy(struct native_display *ndpy)
655{
656   struct android_display *adpy = android_display(ndpy);
657
658   FREE(adpy->configs);
659   if (adpy->base.screen)
660      adpy->base.screen->destroy(adpy->base.screen);
661   FREE(adpy);
662}
663
664static const struct native_config **
665android_display_get_configs(struct native_display *ndpy, int *num_configs)
666{
667   struct android_display *adpy = android_display(ndpy);
668   const struct native_config **configs;
669   int i;
670
671   configs = (const struct native_config **)
672      MALLOC(adpy->num_configs * sizeof(*configs));
673   if (configs) {
674      for (i = 0; i < adpy->num_configs; i++)
675         configs[i] = (const struct native_config *) &adpy->configs[i];
676      if (num_configs)
677         *num_configs = adpy->num_configs;
678   }
679
680   return configs;
681}
682
683static int
684android_display_get_param(struct native_display *ndpy,
685                          enum native_param_type param)
686{
687   int val;
688
689   switch (param) {
690   case NATIVE_PARAM_PRESERVE_BUFFER:
691      val = 1;
692      break;
693   default:
694      val = 0;
695      break;
696   }
697
698   return val;
699}
700
701static struct pipe_resource *
702android_display_import_buffer(struct native_display *ndpy,
703                              struct native_buffer *nbuf)
704{
705   struct android_display *adpy = android_display(ndpy);
706   struct android_native_buffer_t *abuf;
707   enum pipe_format format;
708   struct pipe_resource templ;
709
710   if (nbuf->type != NATIVE_BUFFER_ANDROID)
711      return NULL;
712
713   abuf = nbuf->u.android;
714
715   if (!abuf || abuf->common.magic != ANDROID_NATIVE_BUFFER_MAGIC ||
716       abuf->common.version != sizeof(*abuf)) {
717      LOGE("invalid android native buffer");
718      return NULL;
719   }
720
721   format = get_pipe_format(abuf->format);
722   if (format == PIPE_FORMAT_NONE)
723      return NULL;
724
725   memset(&templ, 0, sizeof(templ));
726   templ.target = PIPE_TEXTURE_2D;
727   templ.format = format;
728   /* assume for texturing only */
729   templ.bind = PIPE_BIND_SAMPLER_VIEW;
730   templ.width0 = abuf->width;
731   templ.height0 = abuf->height;
732   templ.depth0 = 1;
733   templ.array_size = 1;
734
735   return import_buffer(adpy, &templ, abuf);
736}
737
738static boolean
739android_display_export_buffer(struct native_display *ndpy,
740                              struct pipe_resource *res,
741                              struct native_buffer *nbuf)
742{
743   return FALSE;
744}
745
746static struct native_display_buffer android_display_buffer = {
747   android_display_import_buffer,
748   android_display_export_buffer
749};
750
751static struct android_display *
752android_display_create(const struct native_event_handler *event_handler,
753                       boolean use_sw)
754{
755   struct android_display *adpy;
756   char value[PROPERTY_VALUE_MAX];
757   boolean force_sw;
758
759   /* check if SW renderer is forced */
760   if (property_get("debug.mesa.software", value, NULL))
761      force_sw = (atoi(value) != 0);
762   else
763      force_sw = debug_get_bool_option("EGL_SOFTWARE", FALSE);
764   if (force_sw)
765      use_sw = TRUE;
766
767   adpy = CALLOC_STRUCT(android_display);
768   if (!adpy)
769      return NULL;
770
771   adpy->event_handler = event_handler;
772   adpy->use_drm = !use_sw;
773
774   adpy->base.init_screen = android_display_init_screen;
775   adpy->base.destroy = android_display_destroy;
776   adpy->base.get_param = android_display_get_param;
777   adpy->base.get_configs = android_display_get_configs;
778   adpy->base.create_window_surface = android_display_create_window_surface;
779
780   adpy->base.buffer = &android_display_buffer;
781
782   return adpy;
783}
784
785static const struct native_event_handler *android_event_handler;
786
787static struct native_display *
788native_create_display(void *dpy, boolean use_sw)
789{
790   struct android_display *adpy;
791
792   adpy = android_display_create(android_event_handler, use_sw);
793
794   return (adpy) ? &adpy->base : NULL;
795}
796
797static const struct native_platform android_platform = {
798   "Android", /* name */
799   native_create_display
800};
801
802}; /* namespace android */
803
804using namespace android;
805
806static void
807android_log(EGLint level, const char *msg)
808{
809   switch (level) {
810   case _EGL_DEBUG:
811      LOGD("%s", msg);
812      break;
813   case _EGL_INFO:
814      LOGI("%s", msg);
815      break;
816   case _EGL_WARNING:
817      LOGW("%s", msg);
818      break;
819   case _EGL_FATAL:
820      LOG_FATAL("%s", msg);
821      break;
822   default:
823      break;
824   }
825}
826
827const struct native_platform *
828native_get_android_platform(const struct native_event_handler *event_handler)
829{
830   android_event_handler = event_handler;
831   /* use Android logger */
832   _eglSetLogProc(android_log);
833
834   return &android_platform;
835}
836