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