1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      OpenGL bitmap locking (GLES).
12  *
13  *      See LICENSE.txt for copyright information.
14  */
15 
16 #include "allegro5/allegro.h"
17 #include "allegro5/allegro_opengl.h"
18 #include "allegro5/internal/aintern.h"
19 #include "allegro5/internal/aintern_opengl.h"
20 #include "allegro5/internal/aintern_pixels.h"
21 
22 #if defined ALLEGRO_ANDROID
23    #include "allegro5/internal/aintern_android.h"
24 #endif
25 
26 #include "ogl_helpers.h"
27 
28 /*
29  * This is the GLES implementation of ogl_lock_region and ogl_unlock_region.
30  * The version for desktop GL is in ogl_lock.c.  They are pretty similar again
31  * so probably could consider unifying them again.
32  */
33 #if defined(ALLEGRO_CFG_OPENGLES)
34 
35 ALLEGRO_DEBUG_CHANNEL("opengl")
36 
37 #define get_glformat(f, c) _al_ogl_get_glformat((f), (c))
38 
39 /*
40  * Helpers - duplicates code in ogl_bitmap.c for now
41  */
42 
ogl_pixel_alignment(int pixel_size)43 static int ogl_pixel_alignment(int pixel_size)
44 {
45    /* Valid alignments are: 1, 2, 4, 8 bytes. */
46    switch (pixel_size) {
47       case 1:
48       case 2:
49       case 4:
50       case 8:
51          return pixel_size;
52       case 3:
53          return 1;
54       case 16: /* float32 */
55          return 4;
56       default:
57          ASSERT(false);
58          return 4;
59    }
60 }
61 
ogl_pitch(int w,int pixel_size)62 static int ogl_pitch(int w, int pixel_size)
63 {
64    int pitch = w * pixel_size;
65    return pitch;
66 }
67 
68 
69 
70 /*
71  * Locking
72  */
73 
74 static ALLEGRO_LOCKED_REGION *ogl_lock_region_bb_readonly(
75    ALLEGRO_BITMAP *bitmap, int x, int y, int w, int h, int real_format);
76 static ALLEGRO_LOCKED_REGION *ogl_lock_region_bb_proxy(ALLEGRO_BITMAP *bitmap,
77    int x, int y, int w, int h, int real_format, int flags);
78 static ALLEGRO_LOCKED_REGION *ogl_lock_region_nonbb(ALLEGRO_BITMAP *bitmap,
79    int x, int y, int w, int h, int real_format, int flags);
80 static bool ogl_lock_region_nonbb_writeonly(
81    ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap,
82    int x, int gl_y, int w, int h, int real_format);
83 static bool ogl_lock_region_nonbb_readwrite(
84    ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap,
85    int x, int gl_y, int w, int h, int real_format, bool* restore_fbo);
86 static bool ogl_lock_region_nonbb_readwrite_fbo(
87    ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap,
88    int x, int gl_y, int w, int h, int real_format);
89 
90 
_al_ogl_lock_region_gles(ALLEGRO_BITMAP * bitmap,int x,int y,int w,int h,int format,int flags)91 ALLEGRO_LOCKED_REGION *_al_ogl_lock_region_gles(ALLEGRO_BITMAP *bitmap,
92    int x, int y, int w, int h, int format, int flags)
93 {
94    ALLEGRO_BITMAP_EXTRA_OPENGL * const ogl_bitmap = bitmap->extra;
95    ALLEGRO_DISPLAY *disp;
96    int real_format;
97 
98    if (format == ALLEGRO_PIXEL_FORMAT_ANY) {
99       /* Never pick compressed formats with ANY, as it interacts weirdly with
100        * existing code (e.g. al_get_pixel_size() etc) */
101       int bitmap_format = al_get_bitmap_format(bitmap);
102       if (_al_pixel_format_is_compressed(bitmap_format)) {
103          // XXX Get a good format from the driver?
104          format = ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE;
105       }
106       else {
107          format = bitmap_format;
108       }
109    }
110 
111    disp = al_get_current_display();
112    real_format = _al_get_real_pixel_format(disp, format);
113 
114    if (ogl_bitmap->is_backbuffer) {
115       if (flags & ALLEGRO_LOCK_READONLY) {
116          return ogl_lock_region_bb_readonly(bitmap, x, y, w, h, real_format);
117       }
118       else {
119          return ogl_lock_region_bb_proxy(bitmap, x, y, w, h, real_format,
120             flags);
121       }
122    }
123    else {
124       return ogl_lock_region_nonbb(bitmap, x, y, w, h, real_format, flags);
125    }
126 }
127 
128 
ogl_lock_region_bb_readonly(ALLEGRO_BITMAP * bitmap,int x,int y,int w,int h,int real_format)129 static ALLEGRO_LOCKED_REGION *ogl_lock_region_bb_readonly(
130    ALLEGRO_BITMAP *bitmap, int x, int y, int w, int h, int real_format)
131 {
132    ALLEGRO_BITMAP_EXTRA_OPENGL * const ogl_bitmap = bitmap->extra;
133    const int pixel_size = al_get_pixel_size(real_format);
134    const int pitch = ogl_pitch(w, pixel_size);
135    const int gl_y = bitmap->h - y - h;
136    GLenum e;
137 
138    ogl_bitmap->lock_buffer = al_malloc(pitch * h);
139    if (ogl_bitmap->lock_buffer == NULL) {
140       ALLEGRO_ERROR("Out of memory\n");
141       return false;
142    }
143 
144    /* NOTE: GLES can only read 4 byte pixels (or one other implementation
145     * defined format), we have to convert
146     */
147    glReadPixels(x, gl_y, w, h,
148       GL_RGBA, GL_UNSIGNED_BYTE,
149       ogl_bitmap->lock_buffer);
150    e = glGetError();
151    if (e) {
152       ALLEGRO_ERROR("glReadPixels for format %s failed (%s).\n",
153          _al_pixel_format_name(ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE), _al_gl_error_string(e));
154       al_free(ogl_bitmap->lock_buffer);
155       ogl_bitmap->lock_buffer = NULL;
156       return false;
157    }
158 
159    ALLEGRO_DEBUG("Converting from format %d -> %d\n",
160       ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, real_format);
161 
162    /* That's right, we convert in-place.
163     * (safe as long as dst size <= src size, which it always is)
164     */
165    _al_convert_bitmap_data(ogl_bitmap->lock_buffer,
166       ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE,
167       ogl_pitch(w, 4),
168       ogl_bitmap->lock_buffer,
169       real_format,
170       pitch,
171       0, 0, 0, 0,
172       w, h);
173 
174    bitmap->locked_region.data = ogl_bitmap->lock_buffer + pitch * (h - 1);
175    bitmap->locked_region.format = real_format;
176    bitmap->locked_region.pitch = -pitch;
177    bitmap->locked_region.pixel_size = pixel_size;
178    return &bitmap->locked_region;
179 }
180 
181 
ogl_lock_region_bb_proxy(ALLEGRO_BITMAP * bitmap,int x,int y,int w,int h,int real_format,int flags)182 static ALLEGRO_LOCKED_REGION *ogl_lock_region_bb_proxy(ALLEGRO_BITMAP *bitmap,
183    int x, int y, int w, int h, int real_format, int flags)
184 {
185    ALLEGRO_BITMAP_EXTRA_OPENGL * const ogl_bitmap = bitmap->extra;
186    ALLEGRO_BITMAP *proxy;
187    ALLEGRO_LOCKED_REGION *lr;
188    const int pixel_size = al_get_pixel_size(real_format);
189    const int pitch = ogl_pitch(w, pixel_size);
190 
191    ALLEGRO_DEBUG("Creating backbuffer proxy bitmap\n");
192    proxy = _al_create_bitmap_params(al_get_current_display(),
193       w, h, real_format, ALLEGRO_VIDEO_BITMAP|ALLEGRO_NO_PRESERVE_TEXTURE,
194       0, 0);
195    if (!proxy) {
196       return NULL;
197    }
198 
199    ALLEGRO_DEBUG("Locking backbuffer proxy bitmap\n");
200    proxy->lock_x = 0;
201    proxy->lock_y = 0;
202    proxy->lock_w = w;
203    proxy->lock_h = h;
204    proxy->lock_flags = flags;
205    lr = ogl_lock_region_nonbb(proxy, 0, 0, w, h, real_format, flags);
206    if (!lr) {
207       al_destroy_bitmap(proxy);
208       return NULL;
209    }
210 
211    if (!(flags & ALLEGRO_LOCK_WRITEONLY)) {
212       ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_proxy = proxy->extra;
213       const int gl_y = bitmap->h - y - h;
214       GLenum e;
215 
216       /* NOTE: GLES can only read 4 byte pixels (or one other implementation
217        * defined format), we have to convert
218        */
219       glReadPixels(x, gl_y, w, h,
220          GL_RGBA, GL_UNSIGNED_BYTE,
221          ogl_proxy->lock_buffer);
222       e = glGetError();
223       if (e) {
224          ALLEGRO_ERROR("glReadPixels for format %s failed (%s).\n",
225             _al_pixel_format_name(ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE), _al_gl_error_string(e));
226          al_destroy_bitmap(proxy);
227          return NULL;
228       }
229 
230       ALLEGRO_DEBUG("Converting from format %d -> %d\n",
231          ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, real_format);
232 
233       /* That's right, we convert in-place.
234        * (safe as long as dst size <= src size, which it always is)
235        */
236       _al_convert_bitmap_data(ogl_proxy->lock_buffer,
237          ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE,
238          ogl_pitch(w, 4),
239          ogl_proxy->lock_buffer,
240          real_format,
241          pitch,
242          0, 0, 0, 0,
243          w, h);
244    }
245 
246    proxy->locked = true;
247    bitmap->locked_region = proxy->locked_region;
248    ogl_bitmap->lock_proxy = proxy;
249    return lr;
250 }
251 
252 
ogl_lock_region_nonbb(ALLEGRO_BITMAP * bitmap,int x,int y,int w,int h,int real_format,int flags)253 static ALLEGRO_LOCKED_REGION *ogl_lock_region_nonbb(ALLEGRO_BITMAP *bitmap,
254    int x, int y, int w, int h, int real_format, int flags)
255 {
256    ALLEGRO_BITMAP_EXTRA_OPENGL * const ogl_bitmap = bitmap->extra;
257    const int gl_y = bitmap->h - y - h;
258    ALLEGRO_DISPLAY *disp;
259    ALLEGRO_DISPLAY *old_disp = NULL;
260    ALLEGRO_BITMAP *old_target = al_get_target_bitmap();
261    bool ok;
262    bool restore_fbo = false;
263 
264    disp = al_get_current_display();
265 
266    /* Change OpenGL context if necessary. */
267    if (!disp ||
268       (_al_get_bitmap_display(bitmap)->ogl_extras->is_shared == false &&
269        _al_get_bitmap_display(bitmap) != disp))
270    {
271       old_disp = disp;
272       _al_set_current_display_only(_al_get_bitmap_display(bitmap));
273    }
274 
275    ok = true;
276 
277    /* Set up the pixel store state.  We will need to match it when unlocking.
278     * There may be other pixel store state we should be setting.
279     * See also pitfalls 7 & 8 from:
280     * http://www.opengl.org/resources/features/KilgardTechniques/oglpitfall/
281     */
282    {
283       const int pixel_size = al_get_pixel_size(real_format);
284       const int pixel_alignment = ogl_pixel_alignment(pixel_size);
285       GLenum e;
286       glPixelStorei(GL_PACK_ALIGNMENT, pixel_alignment);
287       e = glGetError();
288       if (e) {
289          ALLEGRO_ERROR("glPixelStorei(GL_PACK_ALIGNMENT, %d) failed (%s).\n",
290             pixel_alignment, _al_gl_error_string(e));
291          ok = false;
292       }
293    }
294 
295    if (ok) {
296       if (flags & ALLEGRO_LOCK_WRITEONLY) {
297          ALLEGRO_DEBUG("Locking non-backbuffer WRITEONLY\n");
298          ok = ogl_lock_region_nonbb_writeonly(bitmap, ogl_bitmap,
299             x, gl_y, w, h, real_format);
300       }
301       else {
302          ALLEGRO_DEBUG("Locking non-backbuffer %s\n",
303             (flags & ALLEGRO_LOCK_READONLY) ? "READONLY" : "READWRITE");
304          ok = ogl_lock_region_nonbb_readwrite(bitmap, ogl_bitmap,
305             x, gl_y, w, h, real_format, &restore_fbo);
306       }
307    }
308 
309    /* Restore state after switching FBO. */
310    if (restore_fbo) {
311       if (!old_target) {
312          /* Old target was NULL; release the context. */
313          _al_set_current_display_only(NULL);
314       }
315       else if (!_al_get_bitmap_display(old_target)) {
316          /* Old target was memory bitmap; leave the current display alone. */
317       }
318       else if (old_target != bitmap) {
319          /* Old target was another OpenGL bitmap. */
320          _al_ogl_setup_fbo(_al_get_bitmap_display(old_target), old_target);
321       }
322    }
323 
324    ASSERT(al_get_target_bitmap() == old_target);
325 
326    if (old_disp != NULL) {
327       _al_set_current_display_only(old_disp);
328    }
329 
330    if (ok) {
331       return &bitmap->locked_region;
332    }
333 
334    ALLEGRO_ERROR("Failed to lock region\n");
335    ASSERT(ogl_bitmap->lock_buffer == NULL);
336    return NULL;
337 }
338 
339 
ogl_lock_region_nonbb_writeonly(ALLEGRO_BITMAP * bitmap,ALLEGRO_BITMAP_EXTRA_OPENGL * ogl_bitmap,int x,int gl_y,int w,int h,int real_format)340 static bool ogl_lock_region_nonbb_writeonly(
341    ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap,
342    int x, int gl_y, int w, int h, int real_format)
343 {
344    const int pixel_size = al_get_pixel_size(real_format);
345    const int pitch = ogl_pitch(w, pixel_size);
346    (void) x;
347    (void) gl_y;
348 
349    ogl_bitmap->lock_buffer = al_malloc(pitch * h);
350    if (ogl_bitmap->lock_buffer == NULL) {
351       return false;
352    }
353 
354    bitmap->locked_region.data = ogl_bitmap->lock_buffer + pitch * (h - 1);
355    bitmap->locked_region.format = real_format;
356    bitmap->locked_region.pitch = -pitch;
357    bitmap->locked_region.pixel_size = pixel_size;
358 
359    // Not sure why this is needed on Pi
360    if (IS_RASPBERRYPI) {
361       glFlush();
362    }
363 
364    return true;
365 }
366 
367 
ogl_lock_region_nonbb_readwrite(ALLEGRO_BITMAP * bitmap,ALLEGRO_BITMAP_EXTRA_OPENGL * ogl_bitmap,int x,int gl_y,int w,int h,int real_format,bool * restore_fbo)368 static bool ogl_lock_region_nonbb_readwrite(
369    ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap,
370    int x, int gl_y, int w, int h, int real_format, bool* restore_fbo)
371 {
372    bool ok;
373 
374    ASSERT(bitmap->parent == NULL);
375    ASSERT(bitmap->locked == false);
376    ASSERT(_al_get_bitmap_display(bitmap) == al_get_current_display());
377 
378    /* Try to create an FBO if there isn't one. */
379    *restore_fbo =
380       _al_ogl_setup_fbo_non_backbuffer(_al_get_bitmap_display(bitmap), bitmap);
381 
382    /* Unlike in desktop GL, there seems to be nothing we can do without an FBO. */
383    if (*restore_fbo && ogl_bitmap->fbo_info) {
384       ok = ogl_lock_region_nonbb_readwrite_fbo(bitmap, ogl_bitmap,
385          x, gl_y, w, h, real_format);
386    }
387    else {
388       ALLEGRO_ERROR("no fbo\n");
389       ok = false;
390    }
391 
392    return ok;
393 }
394 
395 
ogl_lock_region_nonbb_readwrite_fbo(ALLEGRO_BITMAP * bitmap,ALLEGRO_BITMAP_EXTRA_OPENGL * ogl_bitmap,int x,int gl_y,int w,int h,int real_format)396 static bool ogl_lock_region_nonbb_readwrite_fbo(
397    ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap,
398    int x, int gl_y, int w, int h, int real_format)
399 {
400    const int pixel_size = al_get_pixel_size(real_format);
401    const int pitch = ogl_pitch(w, pixel_size);
402    const int start_h = h;
403    GLint old_fbo;
404    GLenum e;
405    bool ok;
406 
407    ASSERT(ogl_bitmap->fbo_info);
408 
409    old_fbo = _al_ogl_bind_framebuffer(ogl_bitmap->fbo_info->fbo);
410    e = glGetError();
411    if (e) {
412       ALLEGRO_ERROR("glBindFramebufferEXT failed (%s).\n",
413          _al_gl_error_string(e));
414       return false;
415    }
416 
417    ok = true;
418 
419    /* Allocate a buffer big enough for both purposes. This requires more
420     * memory to be held for the period of the lock, but overall less
421     * memory is needed to complete the lock.
422     */
423    if (ok) {
424       size_t size = _ALLEGRO_MAX(pitch * h, ogl_pitch(w, 4) * h);
425       ogl_bitmap->lock_buffer = al_malloc(size);
426       if (ogl_bitmap->lock_buffer == NULL) {
427          ok = false;
428       }
429    }
430 
431    if (ok) {
432       /* NOTE: GLES can only read 4 byte pixels (or one other implementation
433        * defined format), we have to convert
434        */
435       glReadPixels(x, gl_y, w, h,
436          GL_RGBA, GL_UNSIGNED_BYTE,
437          ogl_bitmap->lock_buffer);
438       e = glGetError();
439       if (e) {
440          ALLEGRO_ERROR("glReadPixels for format %s failed (%s).\n",
441             _al_pixel_format_name(ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE), _al_gl_error_string(e));
442          al_free(ogl_bitmap->lock_buffer);
443          ogl_bitmap->lock_buffer = NULL;
444          ok = false;
445       }
446    }
447 
448    if (ok) {
449       ALLEGRO_DEBUG("Converting from format %d -> %d\n",
450          ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE, real_format);
451 
452       /* That's right, we convert in-place.
453        * (safe as long as dst size <= src size, which it always is)
454        */
455       _al_convert_bitmap_data(ogl_bitmap->lock_buffer,
456          ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE,
457          ogl_pitch(w, 4),
458          ogl_bitmap->lock_buffer,
459          real_format,
460          pitch,
461          0, 0, 0, 0,
462          w, h);
463 
464       bitmap->locked_region.data = ogl_bitmap->lock_buffer + pitch * (start_h - 1);
465       bitmap->locked_region.format = real_format;
466       bitmap->locked_region.pitch = -pitch;
467       bitmap->locked_region.pixel_size = pixel_size;
468       ok = true;
469    }
470 
471    _al_ogl_bind_framebuffer(old_fbo);
472 
473    return ok;
474 }
475 
476 
477 
478 /*
479  * Unlocking
480  */
481 
482 static void ogl_unlock_region_bb_proxy(ALLEGRO_BITMAP *bitmap,
483    ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap);
484 static void ogl_unlock_region_nonbb(ALLEGRO_BITMAP *bitmap,
485    ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap);
486 static void ogl_unlock_region_nonbb_2(ALLEGRO_BITMAP *bitmap,
487    ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y, int orig_format);
488 static void ogl_unlock_region_nonbb_nonfbo_conv(ALLEGRO_BITMAP *bitmap,
489    ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y, int orig_format);
490 static void ogl_unlock_region_nonbb_nonfbo_noconv(ALLEGRO_BITMAP *bitmap,
491    ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y, int orig_format);
492 
493 
_al_ogl_unlock_region_gles(ALLEGRO_BITMAP * bitmap)494 void _al_ogl_unlock_region_gles(ALLEGRO_BITMAP *bitmap)
495 {
496    ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap = bitmap->extra;
497 
498    if (bitmap->lock_flags & ALLEGRO_LOCK_READONLY) {
499       ALLEGRO_DEBUG("Unlocking READONLY\n");
500       ASSERT(ogl_bitmap->lock_proxy == NULL);
501    }
502    else if (ogl_bitmap->lock_proxy != NULL) {
503       ogl_unlock_region_bb_proxy(bitmap, ogl_bitmap);
504    }
505    else {
506       ogl_unlock_region_nonbb(bitmap, ogl_bitmap);
507    }
508 
509    al_free(ogl_bitmap->lock_buffer);
510    ogl_bitmap->lock_buffer = NULL;
511 }
512 
513 
ogl_unlock_region_bb_proxy(ALLEGRO_BITMAP * bitmap,ALLEGRO_BITMAP_EXTRA_OPENGL * ogl_bitmap)514 static void ogl_unlock_region_bb_proxy(ALLEGRO_BITMAP *bitmap,
515    ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap)
516 {
517    ALLEGRO_BITMAP *proxy = ogl_bitmap->lock_proxy;
518 
519    ASSERT(proxy);
520    ASSERT(ogl_bitmap->lock_buffer == NULL);
521 
522    ALLEGRO_DEBUG("Unlocking backbuffer proxy bitmap\n");
523    _al_ogl_unlock_region_gles(proxy);
524    proxy->locked = false;
525 
526    ALLEGRO_DEBUG("Drawing proxy to backbuffer\n");
527    {
528       ALLEGRO_DISPLAY *disp;
529       ALLEGRO_STATE state0;
530       ALLEGRO_TRANSFORM t;
531       bool held;
532 
533       disp = al_get_current_display();
534       held = al_is_bitmap_drawing_held();
535       if (held) {
536          al_hold_bitmap_drawing(false);
537       }
538       al_store_state(&state0, ALLEGRO_STATE_TARGET_BITMAP |
539          ALLEGRO_STATE_TRANSFORM | ALLEGRO_STATE_BLENDER |
540          ALLEGRO_STATE_PROJECTION_TRANSFORM);
541       {
542          al_set_target_bitmap(bitmap);
543          al_identity_transform(&t);
544          al_use_transform(&t);
545          al_orthographic_transform(&t, 0, 0, -1, disp->w, disp->h, 1);
546          al_use_projection_transform(&t);
547          al_set_blender(ALLEGRO_ADD, ALLEGRO_ONE, ALLEGRO_ZERO);
548          al_draw_bitmap(proxy, bitmap->lock_x, bitmap->lock_y, 0);
549       }
550       al_restore_state(&state0);
551       al_hold_bitmap_drawing(held);
552    }
553 
554    ALLEGRO_DEBUG("Destroying backbuffer proxy bitmap\n");
555    al_destroy_bitmap(proxy);
556    ogl_bitmap->lock_proxy = NULL;
557 }
558 
559 
ogl_unlock_region_nonbb(ALLEGRO_BITMAP * bitmap,ALLEGRO_BITMAP_EXTRA_OPENGL * ogl_bitmap)560 static void ogl_unlock_region_nonbb(ALLEGRO_BITMAP *bitmap,
561    ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap)
562 {
563    const int gl_y = bitmap->h - bitmap->lock_y - bitmap->lock_h;
564    ALLEGRO_DISPLAY *old_disp = NULL;
565    ALLEGRO_DISPLAY *disp;
566    int orig_format;
567    GLenum e;
568 
569    disp = al_get_current_display();
570    orig_format = _al_get_real_pixel_format(disp, al_get_bitmap_format(bitmap));
571 
572    /* Change OpenGL context if necessary. */
573    if (!disp ||
574       (_al_get_bitmap_display(bitmap)->ogl_extras->is_shared == false &&
575        _al_get_bitmap_display(bitmap) != disp))
576    {
577       old_disp = disp;
578       _al_set_current_display_only(_al_get_bitmap_display(bitmap));
579    }
580 
581    /* Desktop code sets GL_UNPACK_ALIGNMENT here instead of later. */
582 
583    ogl_unlock_region_nonbb_2(bitmap, ogl_bitmap, gl_y, orig_format);
584 
585    /* If using FBOs, we need to regenerate mipmaps explicitly now. */
586    /* XXX why don't we check ogl_bitmap->fbo_info? */
587    if ((al_get_bitmap_flags(bitmap) & ALLEGRO_MIPMAP) &&
588        (al_get_opengl_extension_list()->ALLEGRO_GL_OES_framebuffer_object ||
589         IS_OPENGLES) /* FIXME */)
590    {
591       glGenerateMipmapEXT(GL_TEXTURE_2D);
592       e = glGetError();
593       if (e) {
594          ALLEGRO_ERROR("glGenerateMipmapEXT for texture %d failed (%s).\n",
595             ogl_bitmap->texture, _al_gl_error_string(e));
596       }
597    }
598 
599    if (old_disp) {
600       _al_set_current_display_only(old_disp);
601    }
602 }
603 
604 
ogl_unlock_region_nonbb_2(ALLEGRO_BITMAP * bitmap,ALLEGRO_BITMAP_EXTRA_OPENGL * ogl_bitmap,int gl_y,int orig_format)605 static void ogl_unlock_region_nonbb_2(ALLEGRO_BITMAP *bitmap,
606    ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y, int orig_format)
607 {
608    GLint fbo;
609    GLenum e;
610 
611 #ifdef ALLEGRO_ANDROID
612    fbo = _al_android_get_curr_fbo();
613 #else
614    glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &fbo);
615 #endif
616    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
617 #ifdef ALLEGRO_ANDROID
618    _al_android_set_curr_fbo(0);
619 #endif
620 
621    glBindTexture(GL_TEXTURE_2D, ogl_bitmap->texture);
622    e = glGetError();
623    if (e) {
624       ALLEGRO_ERROR("glBindTexture failed (%s).\n", _al_gl_error_string(e));
625    }
626 
627    /* Differs from desktop code. */
628    ALLEGRO_DEBUG("Unlocking non-backbuffer (non-FBO)\n");
629    if (bitmap->locked_region.format != orig_format) {
630       ALLEGRO_DEBUG(
631          "Unlocking non-backbuffer non-FBO with conversion (%d -> %d)\n",
632          bitmap->locked_region.format, orig_format);
633       ogl_unlock_region_nonbb_nonfbo_conv(bitmap, ogl_bitmap, gl_y,
634          orig_format);
635    }
636    else {
637       ALLEGRO_DEBUG("Unlocking non-backbuffer non-FBO without conversion\n");
638       ogl_unlock_region_nonbb_nonfbo_noconv(bitmap, ogl_bitmap, gl_y,
639          orig_format);
640    }
641 
642    glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo);
643 #ifdef ALLEGRO_ANDROID
644    _al_android_set_curr_fbo(fbo);
645 #endif
646 }
647 
648 
ogl_unlock_region_nonbb_nonfbo_conv(ALLEGRO_BITMAP * bitmap,ALLEGRO_BITMAP_EXTRA_OPENGL * ogl_bitmap,int gl_y,int orig_format)649 static void ogl_unlock_region_nonbb_nonfbo_conv(ALLEGRO_BITMAP *bitmap,
650    ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y, int orig_format)
651 {
652    const int lock_format = bitmap->locked_region.format;
653    const int orig_pixel_size = al_get_pixel_size(orig_format);
654    const int dst_pitch = bitmap->lock_w * orig_pixel_size;
655    unsigned char * const tmpbuf = al_malloc(dst_pitch * bitmap->lock_h);
656    GLenum e;
657 
658    _al_convert_bitmap_data(
659       ogl_bitmap->lock_buffer,
660       bitmap->locked_region.format,
661       -bitmap->locked_region.pitch,
662       tmpbuf,
663       orig_format,
664       dst_pitch,
665       0, 0, 0, 0,
666       bitmap->lock_w, bitmap->lock_h);
667 
668    glPixelStorei(GL_UNPACK_ALIGNMENT, ogl_pixel_alignment(orig_pixel_size));
669 
670    glTexSubImage2D(GL_TEXTURE_2D, 0,
671       bitmap->lock_x, gl_y,
672       bitmap->lock_w, bitmap->lock_h,
673       get_glformat(orig_format, 2),
674       get_glformat(orig_format, 1),
675       tmpbuf);
676    e = glGetError();
677    if (e) {
678       ALLEGRO_ERROR("glTexSubImage2D for format %d failed (%s).\n",
679          lock_format, _al_gl_error_string(e));
680    }
681 
682    al_free(tmpbuf);
683 }
684 
685 
ogl_unlock_region_nonbb_nonfbo_noconv(ALLEGRO_BITMAP * bitmap,ALLEGRO_BITMAP_EXTRA_OPENGL * ogl_bitmap,int gl_y,int orig_format)686 static void ogl_unlock_region_nonbb_nonfbo_noconv(ALLEGRO_BITMAP *bitmap,
687    ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y, int orig_format)
688 {
689    const int lock_format = bitmap->locked_region.format;
690    const int orig_pixel_size = al_get_pixel_size(orig_format);
691    GLenum e;
692 
693    glPixelStorei(GL_UNPACK_ALIGNMENT, ogl_pixel_alignment(orig_pixel_size));
694    e = glGetError();
695    if (e) {
696       ALLEGRO_ERROR("glPixelStorei for format %s failed (%s).\n",
697          _al_pixel_format_name(lock_format), _al_gl_error_string(e));
698    }
699 
700    glTexSubImage2D(GL_TEXTURE_2D, 0,
701       bitmap->lock_x, gl_y,
702       bitmap->lock_w, bitmap->lock_h,
703       get_glformat(lock_format, 2),
704       get_glformat(lock_format, 1),
705       ogl_bitmap->lock_buffer);
706    e = glGetError();
707    if (e) {
708       ALLEGRO_ERROR("glTexSubImage2D for format %s failed (%s).\n",
709          _al_pixel_format_name(lock_format), _al_gl_error_string(e));
710    }
711 }
712 
713 
714 #endif
715 
716 /* vim: set sts=3 sw=3 et: */
717