1 /* ______ ___ ___
2 * /\ _ \ /\_ \ /\_ \
3 * \ \ \L\ \\//\ \ \//\ \ __ __ _ __ ___
4 * \ \ __ \ \ \ \ \ \ \ /'__`\ /'_ `\/\`'__\/ __`\
5 * \ \ \/\ \ \_\ \_ \_\ \_/\ __//\ \L\ \ \ \//\ \L\ \
6 * \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7 * \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8 * /\____/
9 * \_/__/
10 *
11 * OpenGL bitmap locking.
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 /*
23 * This is an attempt to refactor ogl_lock_region and ogl_unlock_region.
24 * To begin with it only supports desktop OpenGL. Support for mobile platforms
25 * should be migrated here gradually, but PLEASE try not to do it by inserting
26 * #ifdefs everywhere. Combined with huge functions, that made the previous
27 * version very hard to follow and prone to break.
28 */
29 #if !defined(ALLEGRO_CFG_OPENGLES)
30
31 ALLEGRO_DEBUG_CHANNEL("opengl")
32
33 #define get_glformat(f, c) _al_ogl_get_glformat((f), (c))
34
35
36 /*
37 * Helpers - duplicates code in ogl_bitmap.c for now
38 */
39
ogl_pixel_alignment(int pixel_size)40 static int ogl_pixel_alignment(int pixel_size)
41 {
42 /* Valid alignments are: 1, 2, 4, 8 bytes. */
43 switch (pixel_size) {
44 case 1:
45 case 2:
46 case 4:
47 case 8:
48 return pixel_size;
49 case 3:
50 return 1;
51 case 16: /* float32 */
52 return 4;
53 default:
54 ASSERT(false);
55 return 4;
56 }
57 }
58
ogl_pitch(int w,int pixel_size)59 static int ogl_pitch(int w, int pixel_size)
60 {
61 int pitch = w * pixel_size;
62 return pitch;
63 }
64
exactly_15bpp(int pixel_format)65 static bool exactly_15bpp(int pixel_format)
66 {
67 return pixel_format == ALLEGRO_PIXEL_FORMAT_RGB_555
68 || pixel_format == ALLEGRO_PIXEL_FORMAT_BGR_555;
69 }
70
71
72
73 /*
74 * Locking
75 */
76
77 static bool ogl_lock_region_backbuffer(
78 ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap,
79 int x, int gl_y, int w, int h, int 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 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 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 format);
89 static bool ogl_lock_region_nonbb_readwrite_nonfbo(
90 ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap,
91 int x, int gl_y, int w, int h, int format);
92
93
_al_ogl_lock_region_new(ALLEGRO_BITMAP * bitmap,int x,int y,int w,int h,int format,int flags)94 ALLEGRO_LOCKED_REGION *_al_ogl_lock_region_new(ALLEGRO_BITMAP *bitmap,
95 int x, int y, int w, int h, int format, int flags)
96 {
97 ALLEGRO_BITMAP_EXTRA_OPENGL * const ogl_bitmap = bitmap->extra;
98 const GLint gl_y = bitmap->h - y - h;
99 ALLEGRO_DISPLAY *disp;
100 ALLEGRO_DISPLAY *old_disp = NULL;
101 ALLEGRO_BITMAP *old_target = al_get_target_bitmap();
102 GLenum e;
103 bool ok;
104 bool restore_fbo = false;
105 bool reset_alignment = false;
106
107 if (format == ALLEGRO_PIXEL_FORMAT_ANY) {
108 /* Never pick compressed formats with ANY, as it interacts weirdly with
109 * existing code (e.g. al_get_pixel_size() etc) */
110 int bitmap_format = al_get_bitmap_format(bitmap);
111 if (_al_pixel_format_is_compressed(bitmap_format)) {
112 // XXX Get a good format from the driver?
113 format = ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE;
114 }
115 else {
116 format = bitmap_format;
117 }
118 }
119
120 disp = al_get_current_display();
121 format = _al_get_real_pixel_format(disp, format);
122
123 /* Change OpenGL context if necessary. */
124 if (!disp ||
125 (_al_get_bitmap_display(bitmap)->ogl_extras->is_shared == false &&
126 _al_get_bitmap_display(bitmap) != disp))
127 {
128 old_disp = disp;
129 _al_set_current_display_only(_al_get_bitmap_display(bitmap));
130 }
131
132 ok = true;
133
134 /* Set up the pixel store state. We will need to match it when unlocking.
135 * There may be other pixel store state we should be setting.
136 * See also pitfalls 7 & 8 from:
137 * http://www.opengl.org/resources/features/KilgardTechniques/oglpitfall/
138 */
139 int previous_alignment;
140 glGetIntegerv(GL_PACK_ALIGNMENT, &previous_alignment);
141 {
142 const int pixel_size = al_get_pixel_size(format);
143 const int pixel_alignment = ogl_pixel_alignment(pixel_size);
144 if (previous_alignment != pixel_alignment) {
145 reset_alignment = true;
146 glPixelStorei(GL_PACK_ALIGNMENT, pixel_alignment);
147 e = glGetError();
148 if (e) {
149 ALLEGRO_ERROR("glPixelStorei(GL_PACK_ALIGNMENT, %d) failed (%s).\n",
150 pixel_alignment, _al_gl_error_string(e));
151 ok = false;
152 }
153 }
154 }
155
156 if (ok) {
157 if (ogl_bitmap->is_backbuffer) {
158 ALLEGRO_DEBUG("Locking backbuffer\n");
159 ok = ogl_lock_region_backbuffer(bitmap, ogl_bitmap,
160 x, gl_y, w, h, format, flags);
161 }
162 else if (flags & ALLEGRO_LOCK_WRITEONLY) {
163 ALLEGRO_DEBUG("Locking non-backbuffer WRITEONLY\n");
164 ok = ogl_lock_region_nonbb_writeonly(bitmap, ogl_bitmap,
165 x, gl_y, w, h, format);
166 }
167 else {
168 ALLEGRO_DEBUG("Locking non-backbuffer READWRITE\n");
169 ok = ogl_lock_region_nonbb_readwrite(bitmap, ogl_bitmap,
170 x, gl_y, w, h, format, &restore_fbo);
171 }
172 }
173
174 if (reset_alignment) {
175 glPixelStorei(GL_PACK_ALIGNMENT, previous_alignment);
176 }
177
178 /* Restore state after switching FBO. */
179 if (restore_fbo) {
180 if (!old_target) {
181 /* Old target was NULL; release the context. */
182 _al_set_current_display_only(NULL);
183 }
184 else if (!_al_get_bitmap_display(old_target)) {
185 /* Old target was memory bitmap; leave the current display alone. */
186 }
187 else if (old_target != bitmap) {
188 /* Old target was another OpenGL bitmap. */
189 _al_ogl_setup_fbo(_al_get_bitmap_display(old_target), old_target);
190 }
191 }
192
193 ASSERT(al_get_target_bitmap() == old_target);
194
195 if (old_disp != NULL) {
196 _al_set_current_display_only(old_disp);
197 }
198
199 if (ok) {
200 return &bitmap->locked_region;
201 }
202
203 ALLEGRO_ERROR("Failed to lock region\n");
204 ASSERT(ogl_bitmap->lock_buffer == NULL);
205 return NULL;
206 }
207
208
ogl_lock_region_backbuffer(ALLEGRO_BITMAP * bitmap,ALLEGRO_BITMAP_EXTRA_OPENGL * ogl_bitmap,int x,int gl_y,int w,int h,int format,int flags)209 static bool ogl_lock_region_backbuffer(
210 ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap,
211 int x, int gl_y, int w, int h, int format, int flags)
212 {
213 const int pixel_size = al_get_pixel_size(format);
214 const int pitch = ogl_pitch(w, pixel_size);
215 GLenum e;
216
217 ogl_bitmap->lock_buffer = al_malloc(pitch * h);
218 if (ogl_bitmap->lock_buffer == NULL) {
219 return false;
220 }
221
222 if (!(flags & ALLEGRO_LOCK_WRITEONLY)) {
223 glReadPixels(x, gl_y, w, h,
224 get_glformat(format, 2),
225 get_glformat(format, 1),
226 ogl_bitmap->lock_buffer);
227 e = glGetError();
228 if (e) {
229 ALLEGRO_ERROR("glReadPixels for format %s failed (%s).\n",
230 _al_pixel_format_name(format), _al_gl_error_string(e));
231 al_free(ogl_bitmap->lock_buffer);
232 ogl_bitmap->lock_buffer = NULL;
233 return false;
234 }
235 }
236
237 bitmap->locked_region.data = ogl_bitmap->lock_buffer + pitch * (h - 1);
238 bitmap->locked_region.format = format;
239 bitmap->locked_region.pitch = -pitch;
240 bitmap->locked_region.pixel_size = pixel_size;
241 return true;
242 }
243
244
ogl_lock_region_nonbb_writeonly(ALLEGRO_BITMAP * bitmap,ALLEGRO_BITMAP_EXTRA_OPENGL * ogl_bitmap,int x,int gl_y,int w,int h,int format)245 static bool ogl_lock_region_nonbb_writeonly(
246 ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap,
247 int x, int gl_y, int w, int h, int format)
248 {
249 const int pixel_size = al_get_pixel_size(format);
250 const int pitch = ogl_pitch(w, pixel_size);
251 (void) x;
252 (void) gl_y;
253
254 ogl_bitmap->lock_buffer = al_malloc(pitch * h);
255 if (ogl_bitmap->lock_buffer == NULL) {
256 return false;
257 }
258
259 bitmap->locked_region.data = ogl_bitmap->lock_buffer + pitch * (h - 1);
260 bitmap->locked_region.format = format;
261 bitmap->locked_region.pitch = -pitch;
262 bitmap->locked_region.pixel_size = pixel_size;
263 return true;
264 }
265
266
ogl_lock_region_nonbb_readwrite(ALLEGRO_BITMAP * bitmap,ALLEGRO_BITMAP_EXTRA_OPENGL * ogl_bitmap,int x,int gl_y,int w,int h,int format,bool * restore_fbo)267 static bool ogl_lock_region_nonbb_readwrite(
268 ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap,
269 int x, int gl_y, int w, int h, int format, bool* restore_fbo)
270 {
271 bool ok;
272
273 ASSERT(bitmap->parent == NULL);
274 ASSERT(bitmap->locked == false);
275 ASSERT(_al_get_bitmap_display(bitmap) == al_get_current_display());
276
277 /* Try to create an FBO if there isn't one. */
278 *restore_fbo =
279 _al_ogl_setup_fbo_non_backbuffer(_al_get_bitmap_display(bitmap), bitmap);
280
281 if (ogl_bitmap->fbo_info) {
282 ALLEGRO_DEBUG("Locking non-backbuffer READWRITE with fbo\n");
283 ok = ogl_lock_region_nonbb_readwrite_fbo(bitmap, ogl_bitmap,
284 x, gl_y, w, h, format);
285 }
286 else {
287 ALLEGRO_DEBUG("Locking non-backbuffer READWRITE no fbo\n");
288 ok = ogl_lock_region_nonbb_readwrite_nonfbo(bitmap, ogl_bitmap,
289 x, gl_y, w, h, format);
290 }
291
292 return ok;
293 }
294
295
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 format)296 static bool ogl_lock_region_nonbb_readwrite_fbo(
297 ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap,
298 int x, int gl_y, int w, int h, int format)
299 {
300 const int pixel_size = al_get_pixel_size(format);
301 const int pitch = ogl_pitch(w, pixel_size);
302 GLint old_fbo;
303 GLenum e;
304 bool ok;
305
306 glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT, &old_fbo);
307 e = glGetError();
308 if (e) {
309 ALLEGRO_ERROR("glGetIntegerv(GL_FRAMEBUFFER_BINDING_EXT) failed (%s).\n",
310 _al_gl_error_string(e));
311 return false;
312 }
313
314 ok = true;
315
316 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ogl_bitmap->fbo_info->fbo);
317 e = glGetError();
318 if (e) {
319 ALLEGRO_ERROR("glBindFramebufferEXT failed (%s).\n",
320 _al_gl_error_string(e));
321 ok = false;
322 }
323
324 if (ok) {
325 ogl_bitmap->lock_buffer = al_malloc(pitch * h);
326 if (ogl_bitmap->lock_buffer == NULL) {
327 ok = false;
328 }
329 }
330
331 if (ok) {
332 glReadPixels(x, gl_y, w, h,
333 get_glformat(format, 2),
334 get_glformat(format, 1),
335 ogl_bitmap->lock_buffer);
336 e = glGetError();
337 if (e) {
338 ALLEGRO_ERROR("glReadPixels for format %s failed (%s).\n",
339 _al_pixel_format_name(format), _al_gl_error_string(e));
340 }
341 }
342
343 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, old_fbo);
344
345 if (ok) {
346 bitmap->locked_region.data = ogl_bitmap->lock_buffer + pitch * (h - 1);
347 bitmap->locked_region.format = format;
348 bitmap->locked_region.pitch = -pitch;
349 bitmap->locked_region.pixel_size = pixel_size;
350 return true;
351 }
352
353 al_free(ogl_bitmap->lock_buffer);
354 ogl_bitmap->lock_buffer = NULL;
355 return ok;
356 }
357
358
ogl_lock_region_nonbb_readwrite_nonfbo(ALLEGRO_BITMAP * bitmap,ALLEGRO_BITMAP_EXTRA_OPENGL * ogl_bitmap,int x,int gl_y,int w,int h,int format)359 static bool ogl_lock_region_nonbb_readwrite_nonfbo(
360 ALLEGRO_BITMAP *bitmap, ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap,
361 int x, int gl_y, int w, int h, int format)
362 {
363 /* No FBO - fallback to reading the entire texture */
364 const int pixel_size = al_get_pixel_size(format);
365 const int pitch = ogl_pitch(ogl_bitmap->true_w, pixel_size);
366 GLenum e;
367 bool ok;
368 (void) w;
369
370 ogl_bitmap->lock_buffer = al_malloc(pitch * ogl_bitmap->true_h);
371 if (ogl_bitmap->lock_buffer == NULL) {
372 return false;
373 }
374
375 ok = true;
376
377 glBindTexture(GL_TEXTURE_2D, ogl_bitmap->texture);
378 glGetTexImage(GL_TEXTURE_2D, 0,
379 get_glformat(format, 2),
380 get_glformat(format, 1),
381 ogl_bitmap->lock_buffer);
382
383 e = glGetError();
384 if (e) {
385 ALLEGRO_ERROR("glGetTexImage for format %s failed (%s).\n",
386 _al_pixel_format_name(format), _al_gl_error_string(e));
387 al_free(ogl_bitmap->lock_buffer);
388 ogl_bitmap->lock_buffer = NULL;
389 ok = false;
390 }
391
392 if (ok) {
393 bitmap->locked_region.data = ogl_bitmap->lock_buffer +
394 pitch * (gl_y + h - 1) + pixel_size * x;
395 bitmap->locked_region.format = format;
396 bitmap->locked_region.pitch = -pitch;
397 bitmap->locked_region.pixel_size = pixel_size;
398 }
399
400 return ok;
401 }
402
403
404
405 /*
406 * Unlocking
407 */
408
409 static void ogl_unlock_region_non_readonly(ALLEGRO_BITMAP *bitmap,
410 ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap);
411 static void ogl_unlock_region_backbuffer(ALLEGRO_BITMAP *bitmap,
412 ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y);
413 static void ogl_unlock_region_nonbb_fbo(ALLEGRO_BITMAP *bitmap,
414 ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y, int orig_format);
415 static void ogl_unlock_region_nonbb_fbo_writeonly(ALLEGRO_BITMAP *bitmap,
416 ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y, int orig_format);
417 static void ogl_unlock_region_nonbb_fbo_readwrite(ALLEGRO_BITMAP *bitmap,
418 ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y);
419 static void ogl_unlock_region_nonbb_nonfbo(ALLEGRO_BITMAP *bitmap,
420 ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y);
421
422
_al_ogl_unlock_region_new(ALLEGRO_BITMAP * bitmap)423 void _al_ogl_unlock_region_new(ALLEGRO_BITMAP *bitmap)
424 {
425 ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap = bitmap->extra;
426
427 if (bitmap->lock_flags & ALLEGRO_LOCK_READONLY) {
428 ALLEGRO_DEBUG("Unlocking non-backbuffer READONLY\n");
429 }
430 else {
431 ogl_unlock_region_non_readonly(bitmap, ogl_bitmap);
432 }
433
434 al_free(ogl_bitmap->lock_buffer);
435 ogl_bitmap->lock_buffer = NULL;
436 }
437
438
ogl_unlock_region_non_readonly(ALLEGRO_BITMAP * bitmap,ALLEGRO_BITMAP_EXTRA_OPENGL * ogl_bitmap)439 static void ogl_unlock_region_non_readonly(ALLEGRO_BITMAP *bitmap,
440 ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap)
441 {
442 const int lock_format = bitmap->locked_region.format;
443 const int gl_y = bitmap->h - bitmap->lock_y - bitmap->lock_h;
444 ALLEGRO_DISPLAY *old_disp = NULL;
445 ALLEGRO_DISPLAY *disp;
446 int orig_format;
447 bool biased_alpha = false;
448 bool reset_alignment = false;
449 GLenum e;
450
451 disp = al_get_current_display();
452 orig_format = _al_get_real_pixel_format(disp, _al_get_bitmap_memory_format(bitmap));
453
454 /* Change OpenGL context if necessary. */
455 if (!disp ||
456 (_al_get_bitmap_display(bitmap)->ogl_extras->is_shared == false &&
457 _al_get_bitmap_display(bitmap) != disp))
458 {
459 old_disp = disp;
460 _al_set_current_display_only(_al_get_bitmap_display(bitmap));
461 }
462
463 /* Keep this in sync with ogl_lock_region. */
464 int previous_alignment;
465 glGetIntegerv(GL_UNPACK_ALIGNMENT, &previous_alignment);
466 {
467 const int lock_pixel_size = al_get_pixel_size(lock_format);
468 const int pixel_alignment = ogl_pixel_alignment(lock_pixel_size);
469 if (pixel_alignment != previous_alignment) {
470 reset_alignment = true;
471 glPixelStorei(GL_UNPACK_ALIGNMENT, pixel_alignment);
472 e = glGetError();
473 if (e) {
474 ALLEGRO_ERROR("glPixelStorei(GL_UNPACK_ALIGNMENT, %d) failed (%s).\n",
475 pixel_alignment, _al_gl_error_string(e));
476 }
477 }
478 }
479 if (exactly_15bpp(lock_format)) {
480 /* OpenGL does not support 15-bpp internal format without an alpha,
481 * so when storing such data we must ensure the alpha bit is set.
482 */
483 glPixelTransferi(GL_ALPHA_BIAS, 1);
484 biased_alpha = true;
485 }
486
487 if (ogl_bitmap->is_backbuffer) {
488 ALLEGRO_DEBUG("Unlocking backbuffer\n");
489 ogl_unlock_region_backbuffer(bitmap, ogl_bitmap, gl_y);
490 }
491 else {
492 glBindTexture(GL_TEXTURE_2D, ogl_bitmap->texture);
493 if (ogl_bitmap->fbo_info) {
494 ALLEGRO_DEBUG("Unlocking non-backbuffer (FBO)\n");
495 ogl_unlock_region_nonbb_fbo(bitmap, ogl_bitmap, gl_y, orig_format);
496 }
497 else {
498 ALLEGRO_DEBUG("Unlocking non-backbuffer (non-FBO)\n");
499 ogl_unlock_region_nonbb_nonfbo(bitmap, ogl_bitmap, gl_y);
500 }
501
502 /* If using FBOs, we need to regenerate mipmaps explicitly now. */
503 /* XXX why don't we check ogl_bitmap->fbo_info? */
504 if ((al_get_bitmap_flags(bitmap) & ALLEGRO_MIPMAP) &&
505 al_get_opengl_extension_list()->ALLEGRO_GL_EXT_framebuffer_object)
506 {
507 glGenerateMipmapEXT(GL_TEXTURE_2D);
508 e = glGetError();
509 if (e) {
510 ALLEGRO_ERROR("glGenerateMipmapEXT for texture %d failed (%s).\n",
511 ogl_bitmap->texture, _al_gl_error_string(e));
512 }
513 }
514 }
515
516 if (biased_alpha) {
517 glPixelTransferi(GL_ALPHA_BIAS, 0);
518 }
519 if (reset_alignment) {
520 glPixelStorei(GL_UNPACK_ALIGNMENT, previous_alignment);
521 }
522
523 if (old_disp) {
524 _al_set_current_display_only(old_disp);
525 }
526 }
527
528
ogl_unlock_region_backbuffer(ALLEGRO_BITMAP * bitmap,ALLEGRO_BITMAP_EXTRA_OPENGL * ogl_bitmap,int gl_y)529 static void ogl_unlock_region_backbuffer(ALLEGRO_BITMAP *bitmap,
530 ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y)
531 {
532 const int lock_format = bitmap->locked_region.format;
533 bool popmatrix = false;
534 GLenum e;
535 GLint program = 0;
536 ALLEGRO_DISPLAY *display = al_get_current_display();
537
538 if (display->flags & ALLEGRO_PROGRAMMABLE_PIPELINE) {
539 // FIXME: This is a hack where we temporarily disable the active shader.
540 // It will only work on Desktop OpenGL in non-strict mode where we even
541 // can switch back to the fixed pipeline. The correct way would be to not
542 // use any OpenGL 2 functions (like glDrawPixels). Probably we will want
543 // separate OpenGL <= 2 (including OpenGL ES 1) and OpenGL >= 3 (including
544 // OpenGL ES >= 2) drivers at some point.
545 glGetIntegerv(GL_CURRENT_PROGRAM, &program);
546 glUseProgram(0);
547 }
548
549 /* glWindowPos2i may not be available. */
550 if (al_get_opengl_version() >= _ALLEGRO_OPENGL_VERSION_1_4) {
551 glWindowPos2i(bitmap->lock_x, gl_y);
552 }
553 else {
554 /* glRasterPos is affected by the current modelview and projection
555 * matrices (so maybe we actually need to reset both of them?).
556 * The coordinate is also clipped; the small offset was required to
557 * prevent it being culled on one of my machines. --pw
558 *
559 * Consider using glWindowPos2fMESAemulate from:
560 * http://www.opengl.org/resources/features/KilgardTechniques/oglpitfall/
561 */
562 glPushMatrix();
563 glLoadIdentity();
564 glRasterPos2f(bitmap->lock_x, bitmap->lock_y + bitmap->lock_h - 1e-4f);
565 popmatrix = true;
566 }
567
568 glDisable(GL_TEXTURE_2D);
569 glDisable(GL_BLEND);
570 glDrawPixels(bitmap->lock_w, bitmap->lock_h,
571 get_glformat(lock_format, 2),
572 get_glformat(lock_format, 1),
573 ogl_bitmap->lock_buffer);
574 e = glGetError();
575 if (e) {
576 ALLEGRO_ERROR("glDrawPixels for format %s failed (%s).\n",
577 _al_pixel_format_name(lock_format), _al_gl_error_string(e));
578 }
579
580 if (popmatrix) {
581 glPopMatrix();
582 }
583
584 if (program != 0) {
585 glUseProgram(program);
586 }
587 }
588
589
ogl_unlock_region_nonbb_fbo(ALLEGRO_BITMAP * bitmap,ALLEGRO_BITMAP_EXTRA_OPENGL * ogl_bitmap,int gl_y,int orig_format)590 static void ogl_unlock_region_nonbb_fbo(ALLEGRO_BITMAP *bitmap,
591 ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y, int orig_format)
592 {
593 if (bitmap->lock_flags & ALLEGRO_LOCK_WRITEONLY) {
594 ALLEGRO_DEBUG("Unlocking non-backbuffer FBO WRITEONLY\n");
595 ogl_unlock_region_nonbb_fbo_writeonly(bitmap, ogl_bitmap, gl_y,
596 orig_format);
597 }
598 else {
599 ALLEGRO_DEBUG("Unlocking non-backbuffer FBO READWRITE\n");
600 ogl_unlock_region_nonbb_fbo_readwrite(bitmap, ogl_bitmap, gl_y);
601 }
602 }
603
604
ogl_unlock_region_nonbb_fbo_writeonly(ALLEGRO_BITMAP * bitmap,ALLEGRO_BITMAP_EXTRA_OPENGL * ogl_bitmap,int gl_y,int orig_format)605 static void ogl_unlock_region_nonbb_fbo_writeonly(ALLEGRO_BITMAP *bitmap,
606 ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y, int orig_format)
607 {
608 const int lock_format = bitmap->locked_region.format;
609 const int orig_pixel_size = al_get_pixel_size(orig_format);
610 const int dst_pitch = bitmap->lock_w * orig_pixel_size;
611 unsigned char * const tmpbuf = al_malloc(dst_pitch * bitmap->lock_h);
612 GLenum e;
613
614 _al_convert_bitmap_data(
615 ogl_bitmap->lock_buffer,
616 bitmap->locked_region.format,
617 -bitmap->locked_region.pitch,
618 tmpbuf,
619 orig_format,
620 dst_pitch,
621 0, 0, 0, 0,
622 bitmap->lock_w, bitmap->lock_h);
623
624 glTexSubImage2D(GL_TEXTURE_2D, 0,
625 bitmap->lock_x, gl_y,
626 bitmap->lock_w, bitmap->lock_h,
627 get_glformat(orig_format, 2),
628 get_glformat(orig_format, 1),
629 tmpbuf);
630 e = glGetError();
631 if (e) {
632 ALLEGRO_ERROR("glTexSubImage2D for format %d failed (%s).\n",
633 lock_format, _al_gl_error_string(e));
634 }
635
636 al_free(tmpbuf);
637 }
638
639
ogl_unlock_region_nonbb_fbo_readwrite(ALLEGRO_BITMAP * bitmap,ALLEGRO_BITMAP_EXTRA_OPENGL * ogl_bitmap,int gl_y)640 static void ogl_unlock_region_nonbb_fbo_readwrite(ALLEGRO_BITMAP *bitmap,
641 ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y)
642 {
643 const int lock_format = bitmap->locked_region.format;
644 GLenum e;
645 GLint tex_internalformat;
646
647 glTexSubImage2D(GL_TEXTURE_2D, 0, bitmap->lock_x, gl_y,
648 bitmap->lock_w, bitmap->lock_h,
649 get_glformat(lock_format, 2),
650 get_glformat(lock_format, 1),
651 ogl_bitmap->lock_buffer);
652
653 e = glGetError();
654 if (e) {
655 ALLEGRO_ERROR("glTexSubImage2D for format %s failed (%s).\n",
656 _al_pixel_format_name(lock_format), _al_gl_error_string(e));
657 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
658 GL_TEXTURE_INTERNAL_FORMAT, &tex_internalformat);
659 ALLEGRO_DEBUG("x/y/w/h: %d/%d/%d/%d, internal format: %d\n",
660 bitmap->lock_x, gl_y, bitmap->lock_w, bitmap->lock_h,
661 tex_internalformat);
662 }
663 }
664
665
ogl_unlock_region_nonbb_nonfbo(ALLEGRO_BITMAP * bitmap,ALLEGRO_BITMAP_EXTRA_OPENGL * ogl_bitmap,int gl_y)666 static void ogl_unlock_region_nonbb_nonfbo(ALLEGRO_BITMAP *bitmap,
667 ALLEGRO_BITMAP_EXTRA_OPENGL *ogl_bitmap, int gl_y)
668 {
669 const int lock_format = bitmap->locked_region.format;
670 unsigned char *start_ptr;
671 GLenum e;
672
673 if (bitmap->lock_flags & ALLEGRO_LOCK_WRITEONLY) {
674 ALLEGRO_DEBUG("Unlocking non-backbuffer non-FBO WRITEONLY\n");
675 start_ptr = ogl_bitmap->lock_buffer;
676 }
677 else {
678 ALLEGRO_DEBUG("Unlocking non-backbuffer non-FBO READWRITE\n");
679 glPixelStorei(GL_UNPACK_ROW_LENGTH, ogl_bitmap->true_w);
680 start_ptr = (unsigned char *)bitmap->lock_data
681 + (bitmap->lock_h - 1) * bitmap->locked_region.pitch;
682 }
683
684 glTexSubImage2D(GL_TEXTURE_2D, 0,
685 bitmap->lock_x, gl_y,
686 bitmap->lock_w, bitmap->lock_h,
687 get_glformat(lock_format, 2),
688 get_glformat(lock_format, 1),
689 start_ptr);
690
691 e = glGetError();
692 if (e) {
693 ALLEGRO_ERROR("glTexSubImage2D for format %s failed (%s).\n",
694 _al_pixel_format_name(lock_format), _al_gl_error_string(e));
695 }
696 }
697
698
699 #endif
700
701 /* vim: set sts=3 sw=3 et: */
702