1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      Android Java/JNI display driver
12  *
13  *      By Thomas Fjellstrom.
14  *
15  */
16 
17 #include "allegro5/allegro.h"
18 #include "allegro5/allegro_opengl.h"
19 #include "allegro5/internal/aintern_android.h"
20 #include "allegro5/internal/aintern_display.h"
21 #include "allegro5/internal/aintern_events.h"
22 #include "allegro5/internal/aintern_opengl.h"
23 #include "allegro5/internal/aintern_shader.h"
24 #include "allegro5/internal/aintern_pixels.h"
25 
26 #include "EGL/egl.h"
27 
28 ALLEGRO_DEBUG_CHANNEL("display")
29 
30 static ALLEGRO_DISPLAY_INTERFACE *vt;
31 static ALLEGRO_EXTRA_DISPLAY_SETTINGS main_thread_display_settings;
32 
33 static int select_best_visual_and_update(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *d);
34 static void android_set_display_option(ALLEGRO_DISPLAY *d, int o, int v);
35 static void _al_android_resize_display(ALLEGRO_DISPLAY_ANDROID *d, int width, int height);
36 static bool _al_android_init_display(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *display);
37 void _al_android_clear_current(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *d);
38 void  _al_android_make_current(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *d);
39 
40 JNI_FUNC(void, AllegroSurface, nativeOnCreate, (JNIEnv *env, jobject obj))
41 {
42    ALLEGRO_DEBUG("nativeOnCreate");
43    (void)env;
44    (void)obj;
45 
46    ALLEGRO_SYSTEM *system = (void *)al_get_system_driver();
47    ASSERT(system != NULL);
48 
49    ALLEGRO_DEBUG("AllegroSurface_nativeOnCreate");
50 
51    ALLEGRO_DISPLAY_ANDROID **dptr = _al_vector_ref(&system->displays, 0);
52    ALLEGRO_DISPLAY_ANDROID *d = *dptr;
53    ASSERT(d != NULL);
54 
55    d->recreate = true;
56 }
57 
58 JNI_FUNC(bool, AllegroSurface, nativeOnDestroy, (JNIEnv *env, jobject obj))
59 {
60    ALLEGRO_SYSTEM *sys = (void *)al_get_system_driver();
61    ASSERT(sys != NULL);
62 
63    ALLEGRO_DISPLAY_ANDROID **dptr = _al_vector_ref(&sys->displays, 0);
64    ALLEGRO_DISPLAY_ANDROID *display = *dptr;
65    ASSERT(display != NULL);
66 
67    ALLEGRO_DISPLAY *d = (ALLEGRO_DISPLAY *)display;
68 
69    ALLEGRO_DEBUG("AllegroSurface_nativeOnDestroy");
70    (void)obj;
71    (void)env;
72 
73    if (!display->created) {
74       ALLEGRO_DEBUG("Display creation failed, not sending HALT");
75       return false;
76    }
77 
78    display->created = false;
79 
80    if (display->is_destroy_display) {
81       return true;
82    }
83 
84    ALLEGRO_DEBUG("locking display event source: %p %p", d, &d->es);
85 
86    _al_event_source_lock(&d->es);
87 
88    if (_al_event_source_needs_to_generate_event(&d->es)) {
89       ALLEGRO_EVENT event;
90       event.display.type = ALLEGRO_EVENT_DISPLAY_HALT_DRAWING;
91       event.display.timestamp = al_current_time();
92       _al_event_source_emit_event(&d->es, &event);
93    }
94 
95    ALLEGRO_DEBUG("unlocking display event source");
96    _al_event_source_unlock(&d->es);
97 
98    // wait for acknowledge_drawing_halt
99    al_lock_mutex(display->mutex);
100    al_wait_cond(display->cond, display->mutex);
101    al_unlock_mutex(display->mutex);
102 
103    ALLEGRO_DEBUG("AllegroSurface_nativeOnDestroy end");
104 
105    return true;
106 }
107 
108 // FIXME: need to loop over the display list looking for the right surface
109 // object in the following jni callbacks
110 JNI_FUNC(void, AllegroSurface, nativeOnChange, (JNIEnv *env, jobject obj,
111    jint format, jint width, jint height))
112 {
113    ALLEGRO_SYSTEM *system = (void *)al_get_system_driver();
114    ASSERT(system != NULL);
115 
116    ALLEGRO_DISPLAY_ANDROID **dptr = _al_vector_ref(&system->displays, 0);
117    ALLEGRO_DISPLAY_ANDROID *d = *dptr;
118    ALLEGRO_DISPLAY *display = (ALLEGRO_DISPLAY*)d;
119    ASSERT(display != NULL);
120 
121    ALLEGRO_DEBUG("on change %dx%d!", width, height);
122    (void)format;
123 
124    if (!d->first_run && !d->recreate) {
125       _al_android_resize_display(d, width, height);
126       return;
127    }
128 
129    al_lock_mutex(d->mutex);
130 
131    if (d->first_run || d->recreate) {
132       d->surface_object = (*env)->NewGlobalRef(env, obj);
133       if (display->flags & ALLEGRO_FULLSCREEN_WINDOW) {
134          display->w = width;
135          display->h = height;
136       }
137    }
138 
139    bool ret = _al_android_init_display(env, d);
140    if (!ret && d->first_run) {
141       al_broadcast_cond(d->cond);
142       al_unlock_mutex(d->mutex);
143       return;
144    }
145 
146    _al_android_clear_current(env, d);
147 
148    d->created = true;
149    d->recreate = false;
150    d->resumed = false;
151 
152    if (!d->first_run) {
153       ALLEGRO_DEBUG("locking display event source: %p", d);
154       _al_event_source_lock(&display->es);
155 
156       ALLEGRO_DEBUG("check generate event");
157       if (_al_event_source_needs_to_generate_event(&display->es)) {
158          ALLEGRO_EVENT event;
159          event.display.type = ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING;
160          event.display.timestamp = al_current_time();
161          _al_event_source_emit_event(&display->es, &event);
162       }
163 
164       ALLEGRO_DEBUG("unlocking display event source");
165       _al_event_source_unlock(&display->es);
166    }
167 
168    if (d->first_run) {
169       al_broadcast_cond(d->cond);
170       d->first_run = false;
171    }
172    else {
173       ALLEGRO_DEBUG("Waiting for al_acknowledge_drawing_resume");
174       while (!d->resumed) {
175          al_wait_cond(d->cond, d->mutex);
176       }
177       ALLEGRO_DEBUG("Got al_acknowledge_drawing_resume");
178    }
179 
180    al_unlock_mutex(d->mutex);
181 
182    /* Send a resize event to signify that the display may have changed sizes. */
183    if (!d->first_run) {
184       _al_android_resize_display(d, width, height);
185    }
186 }
187 
188 JNI_FUNC(void, AllegroSurface, nativeOnJoystickAxis, (JNIEnv *env, jobject obj,
189    jint index, jint stick, jint axis, jfloat value))
190 {
191    (void)env;
192    (void)obj;
193    _al_android_generate_joystick_axis_event(index+1, stick, axis, value);
194 }
195 
196 JNI_FUNC(void, AllegroSurface, nativeOnJoystickButton, (JNIEnv *env, jobject obj,
197    jint index, jint button, jboolean down))
198 {
199    (void)env;
200    (void)obj;
201    _al_android_generate_joystick_button_event(index+1, button, down);
202 }
203 
_al_android_create_surface(JNIEnv * env,bool post)204 void _al_android_create_surface(JNIEnv *env, bool post)
205 {
206    if (post) {
207       _jni_callVoidMethod(env, _al_android_activity_object(),
208          "postCreateSurface");
209    }
210    else {
211       _jni_callVoidMethod(env, _al_android_activity_object(),
212          "createSurface");
213    }
214 }
215 
_al_android_destroy_surface(JNIEnv * env,jobject surface,bool post)216 void _al_android_destroy_surface(JNIEnv *env, jobject surface, bool post)
217 {
218    (void)surface;
219    if (post) {
220       _jni_callVoidMethodV(env, _al_android_activity_object(),
221          "postDestroySurface", "()V");
222    }
223    else {
224       _jni_callVoidMethodV(env, _al_android_activity_object(),
225          "destroySurface", "()V");
226    }
227 }
228 
_al_android_make_current(JNIEnv * env,ALLEGRO_DISPLAY_ANDROID * d)229 void  _al_android_make_current(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *d)
230 {
231    _jni_callVoidMethodV(env, d->surface_object, "egl_makeCurrent", "()V");
232 }
233 
_al_android_clear_current(JNIEnv * env,ALLEGRO_DISPLAY_ANDROID * d)234 void _al_android_clear_current(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *d)
235 {
236    _jni_callVoidMethodV(env, d->surface_object, "egl_clearCurrent", "()V");
237 }
238 
_al_android_init_display(JNIEnv * env,ALLEGRO_DISPLAY_ANDROID * display)239 static bool _al_android_init_display(JNIEnv *env,
240    ALLEGRO_DISPLAY_ANDROID *display)
241 {
242    ALLEGRO_SYSTEM_ANDROID *system = (void *)al_get_system_driver();
243    ALLEGRO_DISPLAY *d = (ALLEGRO_DISPLAY *)display;
244    int config_index;
245    bool programmable_pipeline;
246    int ret;
247 
248    ASSERT(system != NULL);
249    ASSERT(display != NULL);
250 
251    ALLEGRO_DEBUG("calling egl_Init");
252 
253    if (!_jni_callBooleanMethodV(env, display->surface_object,
254          "egl_Init", "()Z"))
255    {
256       // XXX should probably destroy the AllegroSurface here
257       ALLEGRO_ERROR("failed to initialize EGL");
258       display->failed = true;
259       return false;
260    }
261 
262    config_index = select_best_visual_and_update(env, display);
263    if (config_index < 0) {
264       // XXX should probably destroy the AllegroSurface here
265       ALLEGRO_ERROR("Failed to choose config.\n");
266       display->failed = true;
267       return false;
268    }
269 
270    programmable_pipeline = (d->flags & ALLEGRO_PROGRAMMABLE_PIPELINE);
271 
272    ALLEGRO_DEBUG("calling egl_createContext");
273    ret = _jni_callIntMethodV(env, display->surface_object,
274       "egl_createContext", "(IZ)I", config_index, programmable_pipeline);
275    if (!ret) {
276       // XXX should probably destroy the AllegroSurface here
277       ALLEGRO_ERROR("failed to create egl context!");
278       display->failed = true;
279       return false;
280    }
281 
282    ALLEGRO_DEBUG("calling egl_createSurface");
283    if (!_jni_callBooleanMethodV(env, display->surface_object,
284          "egl_createSurface", "()Z"))
285    {
286       // XXX should probably destroy the AllegroSurface here
287       ALLEGRO_ERROR("failed to create egl surface!");
288       display->failed = true;
289       return false;
290    }
291 
292    ALLEGRO_DEBUG("initialize ogl extensions");
293    _al_ogl_manage_extensions(d);
294    _al_ogl_set_extensions(d->ogl_extras->extension_api);
295 
296    _al_ogl_setup_gl(d);
297 
298    return true;
299 }
300 
301 
302 /* implementation helpers */
303 
_al_android_resize_display(ALLEGRO_DISPLAY_ANDROID * d,int width,int height)304 static void _al_android_resize_display(ALLEGRO_DISPLAY_ANDROID *d,
305    int width, int height)
306 {
307    ALLEGRO_DISPLAY *display = (ALLEGRO_DISPLAY *)d;
308    bool emitted_event = true;
309 
310    ALLEGRO_DEBUG("display resize");
311 
312    d->resize_acknowledge = false;
313    d->resize_acknowledge2 = false;
314 
315    ALLEGRO_DEBUG("locking mutex");
316    al_lock_mutex(d->mutex);
317    ALLEGRO_DEBUG("done locking mutex");
318 
319    ALLEGRO_DEBUG("locking display event source: %p", d);
320    _al_event_source_lock(&display->es);
321 
322    ALLEGRO_DEBUG("check generate event");
323    if(_al_event_source_needs_to_generate_event(&display->es)) {
324       ALLEGRO_EVENT event;
325       event.display.type = ALLEGRO_EVENT_DISPLAY_RESIZE;
326       event.display.timestamp = al_current_time();
327       event.display.x = 0; // FIXME: probably not correct
328       event.display.y = 0;
329       event.display.width = width;
330       event.display.height = height;
331       event.display.orientation = _al_android_get_display_orientation();
332       _al_event_source_emit_event(&display->es, &event);
333    }
334    else {
335       emitted_event = false;
336    }
337 
338    ALLEGRO_DEBUG("unlocking display event source");
339    _al_event_source_unlock(&display->es);
340 
341    if (emitted_event) {
342       ALLEGRO_DEBUG("waiting for display resize acknowledge");
343       while (!d->resize_acknowledge) {
344          ALLEGRO_DEBUG("calling al_wait_cond");
345          al_wait_cond(d->cond, d->mutex);
346       }
347       al_unlock_mutex(d->mutex);
348       ALLEGRO_DEBUG("done waiting for display resize acknowledge");
349    }
350 
351    display->w = width;
352    display->h = height;
353 
354    ALLEGRO_DEBUG("resize backbuffer");
355    _al_ogl_setup_gl(display);
356 
357    if (emitted_event) {
358       d->resize_acknowledge2 = true;
359       al_broadcast_cond(d->cond);
360    }
361 
362    al_unlock_mutex(d->mutex);
363 
364    ALLEGRO_DEBUG("done");
365 }
366 
call_initRequiredAttribs(JNIEnv * env,ALLEGRO_DISPLAY_ANDROID * d)367 static void call_initRequiredAttribs(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *d)
368 {
369    _jni_callVoidMethodV(env, d->surface_object,
370       "egl_initRequiredAttribs", "()V");
371 }
372 
call_setRequiredAttrib(JNIEnv * env,ALLEGRO_DISPLAY_ANDROID * d,int attr,int value)373 static void call_setRequiredAttrib(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *d,
374    int attr, int value)
375 {
376    _jni_callVoidMethodV(env, d->surface_object,
377       "egl_setRequiredAttrib", "(II)V", attr, value);
378 }
379 
call_chooseConfig(JNIEnv * env,ALLEGRO_DISPLAY_ANDROID * d)380 static int call_chooseConfig(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *d)
381 {
382    bool pp = (d->display.flags & ALLEGRO_PROGRAMMABLE_PIPELINE);
383    return _jni_callIntMethodV(env, d->surface_object,
384       "egl_chooseConfig", "(Z)I", pp);
385 }
386 
call_getConfigAttribs(JNIEnv * env,ALLEGRO_DISPLAY_ANDROID * d,int configIndex,ALLEGRO_EXTRA_DISPLAY_SETTINGS * eds)387 static void call_getConfigAttribs(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *d,
388    int configIndex, ALLEGRO_EXTRA_DISPLAY_SETTINGS *eds)
389 {
390    jintArray jArray;
391    jint *ptr;
392    int i;
393 
394    jArray = (*env)->NewIntArray(env, ALLEGRO_DISPLAY_OPTIONS_COUNT);
395    if (jArray == NULL) {
396       ALLEGRO_ERROR("NewIntArray failed\n");
397       return;
398    }
399 
400    _jni_callVoidMethodV(env, d->surface_object,
401       "egl_getConfigAttribs", "(I[I)V", configIndex, jArray);
402 
403    ptr = (*env)->GetIntArrayElements(env, jArray, 0);
404    for (i = 0; i < ALLEGRO_DISPLAY_OPTIONS_COUNT; i++) {
405       eds->settings[i] = ptr[i];
406    }
407 
408    (*env)->ReleaseIntArrayElements(env, jArray, ptr, 0);
409 }
410 
set_required_attribs(JNIEnv * env,ALLEGRO_DISPLAY_ANDROID * d,ALLEGRO_EXTRA_DISPLAY_SETTINGS * ref)411 static void set_required_attribs(JNIEnv *env, ALLEGRO_DISPLAY_ANDROID *d,
412    ALLEGRO_EXTRA_DISPLAY_SETTINGS *ref)
413 {
414    #define MAYBE_SET(v)                                                       \
415       do {                                                                    \
416          bool required = (ref->required & ((int64_t)1 << (v)));               \
417          if (required) {                                                      \
418             call_setRequiredAttrib(env, d, (v), ref->settings[(v)]);          \
419          }                                                                    \
420       } while (0)
421 
422    MAYBE_SET(ALLEGRO_RED_SIZE);
423    MAYBE_SET(ALLEGRO_GREEN_SIZE);
424    MAYBE_SET(ALLEGRO_BLUE_SIZE);
425    MAYBE_SET(ALLEGRO_ALPHA_SIZE);
426    MAYBE_SET(ALLEGRO_COLOR_SIZE);
427    MAYBE_SET(ALLEGRO_DEPTH_SIZE);
428    MAYBE_SET(ALLEGRO_STENCIL_SIZE);
429    MAYBE_SET(ALLEGRO_SAMPLE_BUFFERS);
430    MAYBE_SET(ALLEGRO_SAMPLES);
431 
432    #undef MAYBE_SET
433 }
434 
select_best_visual_and_update(JNIEnv * env,ALLEGRO_DISPLAY_ANDROID * d)435 static int select_best_visual_and_update(JNIEnv *env,
436    ALLEGRO_DISPLAY_ANDROID *d)
437 {
438    ALLEGRO_EXTRA_DISPLAY_SETTINGS *ref = &main_thread_display_settings;
439    ALLEGRO_EXTRA_DISPLAY_SETTINGS **eds = NULL;
440    int num_configs;
441    int chosen_index;
442    int i;
443 
444    ALLEGRO_DEBUG("Setting required display settings.\n");
445    call_initRequiredAttribs(env, d);
446    set_required_attribs(env, d, ref);
447 
448    ALLEGRO_DEBUG("Calling eglChooseConfig.\n");
449    num_configs = call_chooseConfig(env, d);
450    if (num_configs < 1) {
451       return -1;
452    }
453 
454    eds = al_calloc(num_configs, sizeof(*eds));
455 
456    for (i = 0; i < num_configs; i++) {
457       eds[i] = al_calloc(1, sizeof(*eds[i]));
458 
459       call_getConfigAttribs(env, d, i, eds[i]);
460 
461       eds[i]->settings[ALLEGRO_RENDER_METHOD] = 1;
462       eds[i]->settings[ALLEGRO_COMPATIBLE_DISPLAY] = 1;
463       eds[i]->settings[ALLEGRO_SWAP_METHOD] = 2;
464       eds[i]->settings[ALLEGRO_VSYNC] = 1;
465 
466       eds[i]->index = i;
467       eds[i]->score = _al_score_display_settings(eds[i], ref);
468    }
469 
470    ALLEGRO_DEBUG("Sorting configs.\n");
471    qsort(eds, num_configs, sizeof(*eds), _al_display_settings_sorter);
472 
473    chosen_index = eds[0]->index;
474    ALLEGRO_INFO("Chose config %i\n", chosen_index);
475 
476    d->display.extra_settings = *eds[0];
477 
478    /* Don't need this any more. */
479    for (i = 0; i < num_configs; i++) {
480       al_free(eds[i]);
481    }
482    al_free(eds);
483 
484    return chosen_index;
485 }
486 
487 /* driver implementation hooks */
488 
android_set_display_flag(ALLEGRO_DISPLAY * dpy,int flag,bool onoff)489 static bool android_set_display_flag(ALLEGRO_DISPLAY *dpy, int flag, bool onoff)
490 {
491    (void)dpy; (void)flag; (void)onoff;
492 
493    if (flag == ALLEGRO_FRAMELESS) {
494       _jni_callVoidMethodV(_al_android_get_jnienv(),
495          _al_android_activity_object(), "setAllegroFrameless", "(Z)V", onoff);
496    }
497 
498    return false;
499 }
500 
android_create_display(int w,int h)501 static ALLEGRO_DISPLAY *android_create_display(int w, int h)
502 {
503    ALLEGRO_DEBUG("begin");
504 
505    int flags = al_get_new_display_flags();
506 #ifndef ALLEGRO_CFG_OPENGL_PROGRAMMABLE_PIPELINE
507    if (flags & ALLEGRO_PROGRAMMABLE_PIPELINE) {
508       ALLEGRO_WARN("Programmable pipeline support not built.\n");
509       return NULL;
510    }
511 #endif
512 
513    ALLEGRO_DISPLAY_ANDROID *d = al_malloc(sizeof *d);
514    ALLEGRO_DISPLAY *display = (void *)d;
515 
516    ALLEGRO_OGL_EXTRAS *ogl = al_malloc(sizeof *ogl);
517    memset(d, 0, sizeof *d);
518    memset(ogl, 0, sizeof *ogl);
519    display->ogl_extras = ogl;
520    display->vt = _al_get_android_display_driver();
521    display->w = w;
522    display->h = h;
523    display->flags = flags;
524 
525    display->flags |= ALLEGRO_OPENGL;
526 #ifdef ALLEGRO_CFG_OPENGLES2
527    display->flags |= ALLEGRO_PROGRAMMABLE_PIPELINE;
528 #endif
529 #ifdef ALLEGRO_CFG_OPENGLES
530    display->flags |= ALLEGRO_OPENGL_ES_PROFILE;
531 #endif
532 
533    _al_event_source_init(&display->es);
534 
535    /* Java thread needs this but it's thread local.
536     * For now we assume display is created and set up in main thread.
537     */
538    main_thread_display_settings = *_al_get_new_display_settings();
539 
540    d->mutex = al_create_mutex();
541    d->cond = al_create_cond();
542    d->recreate = true;
543    d->first_run = true;
544    d->failed = false;
545 
546    ALLEGRO_SYSTEM *system = (void *)al_get_system_driver();
547    ASSERT(system != NULL);
548 
549    ALLEGRO_DISPLAY_ANDROID **add;
550    add = _al_vector_alloc_back(&system->displays);
551    *add = d;
552 
553    al_lock_mutex(d->mutex);
554 
555    // post create surface request and wait
556    _al_android_create_surface(_al_android_get_jnienv(), true);
557 
558    // wait for sizing to happen
559    ALLEGRO_DEBUG("waiting for surface onChange");
560    while (!d->created && !d->failed) {
561       al_wait_cond(d->cond, d->mutex);
562    }
563    al_unlock_mutex(d->mutex);
564    ALLEGRO_DEBUG("done waiting for surface onChange");
565 
566    if (d->failed) {
567       ALLEGRO_DEBUG("Display creation failed");
568       _al_vector_find_and_delete(&system->displays, &d);
569       al_free(ogl);
570       al_free(d);
571       return NULL;
572    }
573 
574    ALLEGRO_DEBUG("display: %p %ix%i", display, display->w, display->h);
575 
576    _al_android_clear_current(_al_android_get_jnienv(), d);
577    _al_android_make_current(_al_android_get_jnienv(), d);
578 
579    /* Don't need to repeat what this does */
580    android_set_display_option(display, ALLEGRO_SUPPORTED_ORIENTATIONS,
581       al_get_new_display_option(ALLEGRO_SUPPORTED_ORIENTATIONS, NULL));
582 
583    /* Fill in opengl version */
584    const int v = d->display.ogl_extras->ogl_info.version;
585    d->display.extra_settings.settings[ALLEGRO_OPENGL_MAJOR_VERSION] = (v >> 24) & 0xFF;
586    d->display.extra_settings.settings[ALLEGRO_OPENGL_MINOR_VERSION] = (v >> 16) & 0xFF;
587 
588    if (flags & ALLEGRO_FRAMELESS) {
589       android_set_display_flag(display, ALLEGRO_FRAMELESS, true);
590    }
591 
592    ALLEGRO_DEBUG("end");
593    return display;
594 }
595 
android_destroy_display(ALLEGRO_DISPLAY * dpy)596 static void android_destroy_display(ALLEGRO_DISPLAY *dpy)
597 {
598    ALLEGRO_DISPLAY_ANDROID *d = (ALLEGRO_DISPLAY_ANDROID*)dpy;
599 
600    ALLEGRO_DEBUG("clear current");
601 
602    if (!d->created) {
603       // if nativeOnDestroy was called (the app switched out) and
604       // then the display is destroyed before the app switches back
605       // in, there is no EGL context to destroy.
606       goto already_deleted;
607    }
608 
609    _al_android_clear_current(_al_android_get_jnienv(), d);
610 
611    al_lock_mutex(d->mutex);
612 
613    d->is_destroy_display = true;
614 
615    _al_android_destroy_surface(_al_android_get_jnienv(), d, true);
616 
617    /* I don't think we can use a condition for this, because there are two
618     * possibilities of how a nativeOnDestroy/surfaceDestroyed callback can be
619     * called. One is from here, manually, and one happens automatically and is
620     * out of our hands.
621     */
622    while (d->created) {
623    	al_rest(0.001);
624    }
625 
626    _al_event_source_free(&dpy->es);
627 
628 already_deleted:
629    // XXX: this causes a crash, no idea why as of yet
630    //ALLEGRO_DEBUG("destroy backbuffer");
631    //_al_ogl_destroy_backbuffer(al_get_backbuffer(dpy));
632 
633    ALLEGRO_DEBUG("destroy mutex");
634    al_destroy_mutex(d->mutex);
635 
636    ALLEGRO_DEBUG("destroy cond");
637    al_destroy_cond(d->cond);
638 
639    ALLEGRO_DEBUG("free ogl_extras");
640    al_free(dpy->ogl_extras);
641 
642    ALLEGRO_DEBUG("remove display from system list");
643    ALLEGRO_SYSTEM *s = al_get_system_driver();
644    _al_vector_find_and_delete(&s->displays, &d);
645 
646    _al_vector_free(&dpy->bitmaps);
647    al_free(dpy->vertex_cache);
648 
649    ALLEGRO_DEBUG("free display");
650    al_free(d);
651 
652    ALLEGRO_DEBUG("done");
653 }
654 
android_set_current_display(ALLEGRO_DISPLAY * dpy)655 static bool android_set_current_display(ALLEGRO_DISPLAY *dpy)
656 {
657    ALLEGRO_DEBUG("make current %p", dpy);
658 
659    if (al_get_current_display() != NULL){
660      _al_android_clear_current(_al_android_get_jnienv(),
661         (ALLEGRO_DISPLAY_ANDROID *)al_get_current_display());
662    }
663 
664    if (dpy) {
665       _al_android_make_current(_al_android_get_jnienv(),
666          (ALLEGRO_DISPLAY_ANDROID *)dpy);
667    }
668 
669    _al_ogl_update_render_state(dpy);
670 
671    return true;
672 }
673 
android_unset_current_display(ALLEGRO_DISPLAY * dpy)674 static void android_unset_current_display(ALLEGRO_DISPLAY *dpy)
675 {
676    ALLEGRO_DEBUG("unset current %p", dpy);
677    _al_android_clear_current(_al_android_get_jnienv(),
678       (ALLEGRO_DISPLAY_ANDROID *)dpy);
679 }
680 
android_flip_display(ALLEGRO_DISPLAY * dpy)681 static void android_flip_display(ALLEGRO_DISPLAY *dpy)
682 {
683    // Some Androids crash if you swap buffers with an fbo bound
684    // so temporarily change target to the backbuffer.
685    ALLEGRO_BITMAP *old_target = al_get_target_bitmap();
686    al_set_target_backbuffer(dpy);
687 
688    _jni_callVoidMethod(_al_android_get_jnienv(),
689       ((ALLEGRO_DISPLAY_ANDROID *)dpy)->surface_object, "egl_SwapBuffers");
690 
691    al_set_target_bitmap(old_target);
692 
693    /* Backup bitmaps created without ALLEGRO_NO_PRESERVE_TEXTURE that are
694     * dirty, to system memory.
695     */
696    al_backup_dirty_bitmaps(dpy);
697 }
698 
android_update_display_region(ALLEGRO_DISPLAY * dpy,int x,int y,int width,int height)699 static void android_update_display_region(ALLEGRO_DISPLAY *dpy, int x, int y,
700    int width, int height)
701 {
702    (void)x;
703    (void)y;
704    (void)width;
705    (void)height;
706    android_flip_display(dpy);
707 }
708 
android_acknowledge_resize(ALLEGRO_DISPLAY * dpy)709 static bool android_acknowledge_resize(ALLEGRO_DISPLAY *dpy)
710 {
711    ALLEGRO_DISPLAY_ANDROID *d = (ALLEGRO_DISPLAY_ANDROID *)dpy;
712 
713    ALLEGRO_DEBUG("clear current context");
714    _al_android_clear_current(_al_android_get_jnienv(), d);
715 
716    ALLEGRO_DEBUG("locking mutex");
717    al_lock_mutex(d->mutex);
718    d->resize_acknowledge = true;
719    al_broadcast_cond(d->cond);
720    ALLEGRO_DEBUG("broadcasted condvar");
721 
722    ALLEGRO_DEBUG("waiting for display resize acknowledge 2");
723    while (!d->resize_acknowledge2)  {
724       ALLEGRO_DEBUG("calling al_wait_cond");
725       al_wait_cond(d->cond, d->mutex);
726    }
727    al_unlock_mutex(d->mutex);
728    ALLEGRO_DEBUG("done waiting for display resize acknowledge 2");
729 
730    ALLEGRO_DEBUG("acquire context");
731    _al_android_make_current(_al_android_get_jnienv(), d);
732 
733    ALLEGRO_DEBUG("done");
734    return true;
735 }
736 
android_get_orientation(ALLEGRO_DISPLAY * dpy)737 static int android_get_orientation(ALLEGRO_DISPLAY *dpy)
738 {
739    (void)dpy;
740    return _al_android_get_display_orientation();
741 }
742 
android_is_compatible_bitmap(ALLEGRO_DISPLAY * dpy,ALLEGRO_BITMAP * bmp)743 static bool android_is_compatible_bitmap(ALLEGRO_DISPLAY *dpy,
744    ALLEGRO_BITMAP *bmp)
745 {
746    (void)dpy;
747    (void)bmp;
748    return true;
749 }
750 
android_resize_display(ALLEGRO_DISPLAY * dpy,int w,int h)751 static bool android_resize_display(ALLEGRO_DISPLAY *dpy, int w, int h)
752 {
753    (void)dpy;
754    (void)w;
755    (void)h;
756    return false;
757 }
758 
android_set_icons(ALLEGRO_DISPLAY * dpy,int num_icons,ALLEGRO_BITMAP * bmps[])759 static void android_set_icons(ALLEGRO_DISPLAY *dpy, int num_icons,
760    ALLEGRO_BITMAP *bmps[])
761 {
762    (void)dpy;
763    (void)num_icons;
764    (void)bmps;
765 }
766 
android_set_window_title(ALLEGRO_DISPLAY * dpy,const char * title)767 static void android_set_window_title(ALLEGRO_DISPLAY *dpy, const char *title)
768 {
769    (void)dpy; (void)title;
770 }
771 
android_set_window_position(ALLEGRO_DISPLAY * dpy,int x,int y)772 static void android_set_window_position(ALLEGRO_DISPLAY *dpy, int x, int y)
773 {
774    (void)dpy;
775    (void)x;
776    (void)y;
777 }
778 
android_get_window_position(ALLEGRO_DISPLAY * dpy,int * x,int * y)779 static void android_get_window_position(ALLEGRO_DISPLAY *dpy, int *x, int *y)
780 {
781    (void)dpy;
782    *x = *y = 0;
783 }
784 
android_wait_for_vsync(ALLEGRO_DISPLAY * dpy)785 static bool android_wait_for_vsync(ALLEGRO_DISPLAY *dpy)
786 {
787    (void)dpy;
788    return false;
789 }
790 
android_set_mouse_cursor(ALLEGRO_DISPLAY * dpy,ALLEGRO_MOUSE_CURSOR * cursor)791 static bool android_set_mouse_cursor(ALLEGRO_DISPLAY *dpy,
792    ALLEGRO_MOUSE_CURSOR *cursor)
793 {
794    (void)dpy; (void)cursor;
795    return false;
796 }
797 
android_set_system_mouse_cursor(ALLEGRO_DISPLAY * dpy,ALLEGRO_SYSTEM_MOUSE_CURSOR id)798 static bool android_set_system_mouse_cursor(ALLEGRO_DISPLAY *dpy,
799    ALLEGRO_SYSTEM_MOUSE_CURSOR id)
800 {
801    (void)dpy; (void)id;
802    return false;
803 }
804 
android_show_mouse_cursor(ALLEGRO_DISPLAY * dpy)805 static bool android_show_mouse_cursor(ALLEGRO_DISPLAY *dpy)
806 {
807    (void)dpy;
808    return false;
809 }
810 
android_hide_mouse_cursor(ALLEGRO_DISPLAY * dpy)811 static bool android_hide_mouse_cursor(ALLEGRO_DISPLAY *dpy)
812 {
813    (void)dpy;
814    return false;
815 }
816 
android_acknowledge_drawing_halt(ALLEGRO_DISPLAY * dpy)817 static void android_acknowledge_drawing_halt(ALLEGRO_DISPLAY *dpy)
818 {
819    int i;
820    ALLEGRO_DEBUG("android_acknowledge_drawing_halt");
821 
822    for (i = 0; i < (int)dpy->bitmaps._size; i++) {
823       ALLEGRO_BITMAP **bptr = _al_vector_ref(&dpy->bitmaps, i);
824       ALLEGRO_BITMAP *bmp = *bptr;
825       int bitmap_flags = al_get_bitmap_flags(bmp);
826 
827       if (!bmp->parent &&
828          !(bitmap_flags & ALLEGRO_MEMORY_BITMAP) &&
829          !(bitmap_flags & ALLEGRO_NO_PRESERVE_TEXTURE))
830       {
831          ALLEGRO_BITMAP_EXTRA_OPENGL *extra = bmp->extra;
832          al_remove_opengl_fbo(bmp);
833          glDeleteTextures(1, &extra->texture);
834          extra->texture = 0;
835       }
836    }
837 
838    ALLEGRO_DISPLAY_ANDROID *d = (ALLEGRO_DISPLAY_ANDROID *)dpy;
839 
840    _al_android_clear_current(_al_android_get_jnienv(), d);
841 
842    /* XXX mutex? */
843    al_broadcast_cond(d->cond);
844 
845    ALLEGRO_DEBUG("acknowledged drawing halt");
846 }
847 
android_broadcast_resume(ALLEGRO_DISPLAY_ANDROID * d)848 static void android_broadcast_resume(ALLEGRO_DISPLAY_ANDROID *d)
849 {
850    ALLEGRO_DEBUG("Broadcasting resume");
851    d->resumed = true;
852    al_broadcast_cond(d->cond);
853    ALLEGRO_DEBUG("done broadcasting resume");
854 }
855 
android_acknowledge_drawing_resume(ALLEGRO_DISPLAY * dpy)856 static void android_acknowledge_drawing_resume(ALLEGRO_DISPLAY *dpy)
857 {
858    unsigned i;
859 
860    ALLEGRO_DEBUG("begin");
861 
862    ALLEGRO_DISPLAY_ANDROID *d = (ALLEGRO_DISPLAY_ANDROID *)dpy;
863 
864    _al_android_clear_current(_al_android_get_jnienv(), d);
865    _al_android_make_current(_al_android_get_jnienv(), d);
866 
867    ALLEGRO_DEBUG("made current");
868 
869    if (dpy->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) {
870       dpy->default_shader = _al_create_default_shader(dpy->flags);
871    }
872 
873    // Bitmaps can still have stale shaders attached.
874    _al_glsl_unuse_shaders();
875 
876    // Restore the transformations.
877    dpy->vt->update_transformation(dpy, al_get_target_bitmap());
878 
879    // Restore bitmaps
880    // have to get this because new bitmaps could be created below
881    for (i = 0; i < _al_vector_size(&dpy->bitmaps); i++) {
882       ALLEGRO_BITMAP **bptr = _al_vector_ref(&dpy->bitmaps, i);
883       ALLEGRO_BITMAP *bmp = *bptr;
884       int bitmap_flags = al_get_bitmap_flags(bmp);
885 
886       if (!bmp->parent &&
887          !(bitmap_flags & ALLEGRO_MEMORY_BITMAP) &&
888          !(bitmap_flags & ALLEGRO_NO_PRESERVE_TEXTURE))
889       {
890          int format = al_get_bitmap_format(bmp);
891          format = _al_pixel_format_is_compressed(format) ? ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE : format;
892          _al_ogl_upload_bitmap_memory(bmp, format, bmp->memory);
893          bmp->dirty = false;
894       }
895    }
896 
897    android_broadcast_resume(d);
898 
899    ALLEGRO_DEBUG("acknowledge_drawing_resume end");
900 }
901 
android_set_display_option(ALLEGRO_DISPLAY * d,int o,int v)902 static void android_set_display_option(ALLEGRO_DISPLAY *d, int o, int v)
903 {
904    (void)d;
905 
906    if (o == ALLEGRO_SUPPORTED_ORIENTATIONS) {
907       _jni_callVoidMethodV(_al_android_get_jnienv(),
908          _al_android_activity_object(), "setAllegroOrientation", "(I)V", v);
909    }
910 }
911 
912 /* obtain a reference to the android driver */
_al_get_android_display_driver(void)913 ALLEGRO_DISPLAY_INTERFACE *_al_get_android_display_driver(void)
914 {
915    if (vt)
916       return vt;
917 
918    vt = al_malloc(sizeof *vt);
919    memset(vt, 0, sizeof *vt);
920 
921    vt->create_display = android_create_display;
922    vt->destroy_display = android_destroy_display;
923    vt->set_current_display = android_set_current_display;
924    vt->unset_current_display = android_unset_current_display;
925    vt->flip_display = android_flip_display;
926    vt->update_display_region = android_update_display_region;
927    vt->acknowledge_resize = android_acknowledge_resize;
928    vt->create_bitmap = _al_ogl_create_bitmap;
929    vt->get_backbuffer = _al_ogl_get_backbuffer;
930    vt->set_target_bitmap = _al_ogl_set_target_bitmap;
931 
932    vt->get_orientation = android_get_orientation;
933 
934    vt->is_compatible_bitmap = android_is_compatible_bitmap;
935    vt->resize_display = android_resize_display;
936    vt->set_icons = android_set_icons;
937    vt->set_window_title = android_set_window_title;
938    vt->set_window_position = android_set_window_position;
939    vt->get_window_position = android_get_window_position;
940    vt->set_display_flag = android_set_display_flag;
941    vt->wait_for_vsync = android_wait_for_vsync;
942 
943    vt->set_mouse_cursor = android_set_mouse_cursor;
944    vt->set_system_mouse_cursor = android_set_system_mouse_cursor;
945    vt->show_mouse_cursor = android_show_mouse_cursor;
946    vt->hide_mouse_cursor = android_hide_mouse_cursor;
947 
948    vt->acknowledge_drawing_halt = android_acknowledge_drawing_halt;
949    vt->acknowledge_drawing_resume = android_acknowledge_drawing_resume;
950 
951    vt->set_display_option = android_set_display_option;
952 
953    vt->update_render_state = _al_ogl_update_render_state;
954 
955    _al_ogl_add_drawing_functions(vt);
956    _al_android_add_clipboard_functions(vt);
957 
958    return vt;
959 }
960 
961 /* vim: set sts=3 sw=3 et: */
962