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