1 /*
2 * Cogl
3 *
4 * A Low Level GPU Graphics and Utilities API
5 *
6 * Copyright (C) 2007,2008,2009 Intel Corporation.
7 * Copyright (C) 2010 Red Hat, Inc.
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use, copy,
13 * modify, merge, publish, distribute, sublicense, and/or sell copies
14 * of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be
18 * included in all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
24 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
25 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27 * SOFTWARE.
28 *
29 *
30 *
31 * Authors:
32 * Matthew Allum <mallum@openedhand.com>
33 * Neil Roberts <neil@linux.intel.com>
34 * Robert Bragg <robert@linux.intel.com>
35 */
36
37 #ifdef HAVE_CONFIG_H
38 #include "cogl-config.h"
39 #endif
40
41 #include "cogl-util.h"
42 #include "cogl-bitmap.h"
43 #include "cogl-bitmap-private.h"
44 #include "cogl-buffer-private.h"
45 #include "cogl-pixel-buffer-private.h"
46 #include "cogl-private.h"
47 #include "cogl-texture-private.h"
48 #include "cogl-texture-driver.h"
49 #include "cogl-texture-2d-sliced-private.h"
50 #include "cogl-texture-2d-private.h"
51 #include "cogl-texture-2d-gl.h"
52 #include "cogl-texture-3d-private.h"
53 #include "cogl-texture-rectangle-private.h"
54 #include "cogl-sub-texture-private.h"
55 #include "cogl-atlas-texture-private.h"
56 #include "cogl-pipeline.h"
57 #include "cogl-context-private.h"
58 #include "cogl-object-private.h"
59 #include "cogl-object-private.h"
60 #include "cogl-primitives.h"
61 #include "cogl-framebuffer-private.h"
62 #include "cogl1-context.h"
63 #include "cogl-sub-texture.h"
64 #include "cogl-primitive-texture.h"
65 #include "cogl-error-private.h"
66 #include "cogl-gtype-private.h"
67
68 #include <string.h>
69 #include <stdlib.h>
70 #include <math.h>
71
72 /* This isn't defined in the GLES headers */
73 #ifndef GL_RED
74 #define GL_RED 0x1903
75 #endif
76
77 COGL_GTYPE_DEFINE_INTERFACE (Texture, texture);
78
79 uint32_t
cogl_texture_error_quark(void)80 cogl_texture_error_quark (void)
81 {
82 return g_quark_from_static_string ("cogl-texture-error-quark");
83 }
84
85 /* XXX:
86 * The CoglObject macros don't support any form of inheritance, so for
87 * now we implement the CoglObject support for the CoglTexture
88 * abstract class manually.
89 */
90
91 static GSList *_cogl_texture_types;
92
93 void
_cogl_texture_register_texture_type(const CoglObjectClass * klass)94 _cogl_texture_register_texture_type (const CoglObjectClass *klass)
95 {
96 _cogl_texture_types = g_slist_prepend (_cogl_texture_types, (void *) klass);
97 }
98
99 CoglBool
cogl_is_texture(void * object)100 cogl_is_texture (void *object)
101 {
102 CoglObject *obj = (CoglObject *)object;
103 GSList *l;
104
105 if (object == NULL)
106 return FALSE;
107
108 for (l = _cogl_texture_types; l; l = l->next)
109 if (l->data == obj->klass)
110 return TRUE;
111
112 return FALSE;
113 }
114
115 void
_cogl_texture_init(CoglTexture * texture,CoglContext * context,int width,int height,CoglPixelFormat src_format,CoglTextureLoader * loader,const CoglTextureVtable * vtable)116 _cogl_texture_init (CoglTexture *texture,
117 CoglContext *context,
118 int width,
119 int height,
120 CoglPixelFormat src_format,
121 CoglTextureLoader *loader,
122 const CoglTextureVtable *vtable)
123 {
124 texture->context = context;
125 texture->max_level = 0;
126 texture->width = width;
127 texture->height = height;
128 texture->allocated = FALSE;
129 texture->vtable = vtable;
130 texture->framebuffers = NULL;
131
132 texture->loader = loader;
133
134 _cogl_texture_set_internal_format (texture, src_format);
135
136 /* Although we want to initialize texture::components according
137 * to the source format, we always want the internal layout to
138 * be considered premultiplied by default.
139 *
140 * NB: this ->premultiplied state is user configurable so to avoid
141 * awkward documentation, setting this to 'true' does not depend on
142 * ->components having an alpha component (we will simply ignore the
143 * premultiplied status later if there is no alpha component).
144 * This way we don't have to worry about updating the
145 * ->premultiplied state in _set_components(). Similarly we don't
146 * have to worry about updating the ->components state in
147 * _set_premultiplied().
148 */
149 texture->premultiplied = TRUE;
150 }
151
152 static void
_cogl_texture_free_loader(CoglTexture * texture)153 _cogl_texture_free_loader (CoglTexture *texture)
154 {
155 if (texture->loader)
156 {
157 CoglTextureLoader *loader = texture->loader;
158 switch (loader->src_type)
159 {
160 case COGL_TEXTURE_SOURCE_TYPE_SIZED:
161 case COGL_TEXTURE_SOURCE_TYPE_EGL_IMAGE:
162 case COGL_TEXTURE_SOURCE_TYPE_GL_FOREIGN:
163 case COGL_TEXTURE_SOURCE_TYPE_EGL_IMAGE_EXTERNAL:
164 break;
165 case COGL_TEXTURE_SOURCE_TYPE_BITMAP:
166 cogl_object_unref (loader->src.bitmap.bitmap);
167 break;
168 }
169 g_slice_free (CoglTextureLoader, loader);
170 texture->loader = NULL;
171 }
172 }
173
174 CoglTextureLoader *
_cogl_texture_create_loader(void)175 _cogl_texture_create_loader (void)
176 {
177 return g_slice_new0 (CoglTextureLoader);
178 }
179
180 void
_cogl_texture_free(CoglTexture * texture)181 _cogl_texture_free (CoglTexture *texture)
182 {
183 _cogl_texture_free_loader (texture);
184
185 free (texture);
186 }
187
188 CoglBool
_cogl_texture_needs_premult_conversion(CoglPixelFormat src_format,CoglPixelFormat dst_format)189 _cogl_texture_needs_premult_conversion (CoglPixelFormat src_format,
190 CoglPixelFormat dst_format)
191 {
192 return ((src_format & dst_format & COGL_A_BIT) &&
193 src_format != COGL_PIXEL_FORMAT_A_8 &&
194 dst_format != COGL_PIXEL_FORMAT_A_8 &&
195 (src_format & COGL_PREMULT_BIT) !=
196 (dst_format & COGL_PREMULT_BIT));
197 }
198
199 CoglBool
_cogl_texture_is_foreign(CoglTexture * texture)200 _cogl_texture_is_foreign (CoglTexture *texture)
201 {
202 if (texture->vtable->is_foreign)
203 return texture->vtable->is_foreign (texture);
204 else
205 return FALSE;
206 }
207
208 unsigned int
cogl_texture_get_width(CoglTexture * texture)209 cogl_texture_get_width (CoglTexture *texture)
210 {
211 return texture->width;
212 }
213
214 unsigned int
cogl_texture_get_height(CoglTexture * texture)215 cogl_texture_get_height (CoglTexture *texture)
216 {
217 return texture->height;
218 }
219
220 CoglPixelFormat
_cogl_texture_get_format(CoglTexture * texture)221 _cogl_texture_get_format (CoglTexture *texture)
222 {
223 if (!texture->allocated)
224 cogl_texture_allocate (texture, NULL);
225 return texture->vtable->get_format (texture);
226 }
227
228 int
cogl_texture_get_max_waste(CoglTexture * texture)229 cogl_texture_get_max_waste (CoglTexture *texture)
230 {
231 return texture->vtable->get_max_waste (texture);
232 }
233
234 int
_cogl_texture_get_n_levels(CoglTexture * texture)235 _cogl_texture_get_n_levels (CoglTexture *texture)
236 {
237 int width = cogl_texture_get_width (texture);
238 int height = cogl_texture_get_height (texture);
239 int max_dimension = MAX (width, height);
240
241 if (cogl_is_texture_3d (texture))
242 {
243 CoglTexture3D *tex_3d = COGL_TEXTURE_3D (texture);
244 max_dimension = MAX (max_dimension, tex_3d->depth);
245 }
246
247 return _cogl_util_fls (max_dimension);
248 }
249
250 void
_cogl_texture_get_level_size(CoglTexture * texture,int level,int * width,int * height,int * depth)251 _cogl_texture_get_level_size (CoglTexture *texture,
252 int level,
253 int *width,
254 int *height,
255 int *depth)
256 {
257 int current_width = cogl_texture_get_width (texture);
258 int current_height = cogl_texture_get_height (texture);
259 int current_depth;
260 int i;
261
262 if (cogl_is_texture_3d (texture))
263 {
264 CoglTexture3D *tex_3d = COGL_TEXTURE_3D (texture);
265 current_depth = tex_3d->depth;
266 }
267 else
268 current_depth = 0;
269
270 /* NB: The OpenGL spec (like D3D) uses a floor() convention to
271 * round down the size of a mipmap level when dividing the size
272 * of the previous level results in a fraction...
273 */
274 for (i = 0; i < level; i++)
275 {
276 current_width = MAX (1, current_width >> 1);
277 current_height = MAX (1, current_height >> 1);
278 current_depth = MAX (1, current_depth >> 1);
279 }
280
281 if (width)
282 *width = current_width;
283 if (height)
284 *height = current_height;
285 if (depth)
286 *depth = current_depth;
287 }
288
289 CoglBool
cogl_texture_is_sliced(CoglTexture * texture)290 cogl_texture_is_sliced (CoglTexture *texture)
291 {
292 if (!texture->allocated)
293 cogl_texture_allocate (texture, NULL);
294 return texture->vtable->is_sliced (texture);
295 }
296
297 /* If this returns FALSE, that implies _foreach_sub_texture_in_region
298 * will be needed to iterate over multiple sub textures for regions whos
299 * texture coordinates extend out of the range [0,1]
300 */
301 CoglBool
_cogl_texture_can_hardware_repeat(CoglTexture * texture)302 _cogl_texture_can_hardware_repeat (CoglTexture *texture)
303 {
304 if (!texture->allocated)
305 cogl_texture_allocate (texture, NULL);
306 return texture->vtable->can_hardware_repeat (texture);
307 }
308
309 /* NB: You can't use this with textures comprised of multiple sub textures (use
310 * cogl_texture_is_sliced() to check) since coordinate transformation for such
311 * textures will be different for each slice. */
312 void
_cogl_texture_transform_coords_to_gl(CoglTexture * texture,float * s,float * t)313 _cogl_texture_transform_coords_to_gl (CoglTexture *texture,
314 float *s,
315 float *t)
316 {
317 texture->vtable->transform_coords_to_gl (texture, s, t);
318 }
319
320 CoglTransformResult
_cogl_texture_transform_quad_coords_to_gl(CoglTexture * texture,float * coords)321 _cogl_texture_transform_quad_coords_to_gl (CoglTexture *texture,
322 float *coords)
323 {
324 return texture->vtable->transform_quad_coords_to_gl (texture, coords);
325 }
326
327 CoglBool
cogl_texture_get_gl_texture(CoglTexture * texture,GLuint * out_gl_handle,GLenum * out_gl_target)328 cogl_texture_get_gl_texture (CoglTexture *texture,
329 GLuint *out_gl_handle,
330 GLenum *out_gl_target)
331 {
332 if (!texture->allocated)
333 cogl_texture_allocate (texture, NULL);
334
335 return texture->vtable->get_gl_texture (texture,
336 out_gl_handle, out_gl_target);
337 }
338
339 CoglTextureType
_cogl_texture_get_type(CoglTexture * texture)340 _cogl_texture_get_type (CoglTexture *texture)
341 {
342 return texture->vtable->get_type (texture);
343 }
344
345 void
_cogl_texture_pre_paint(CoglTexture * texture,CoglTexturePrePaintFlags flags)346 _cogl_texture_pre_paint (CoglTexture *texture, CoglTexturePrePaintFlags flags)
347 {
348 /* Assert that the storage for the texture exists already if we're
349 * about to reference it for painting.
350 *
351 * Note: we abort on error here since it's a bit late to do anything
352 * about it if we fail to allocate the texture and the app could
353 * have explicitly allocated the texture earlier to handle problems
354 * gracefully.
355 *
356 * XXX: Maybe it could even be considered a programmer error if the
357 * texture hasn't been allocated by this point since it implies we
358 * are abount to paint with undefined texture contents?
359 */
360 cogl_texture_allocate (texture, NULL);
361
362 texture->vtable->pre_paint (texture, flags);
363 }
364
365 void
_cogl_texture_ensure_non_quad_rendering(CoglTexture * texture)366 _cogl_texture_ensure_non_quad_rendering (CoglTexture *texture)
367 {
368 texture->vtable->ensure_non_quad_rendering (texture);
369 }
370
371 CoglBool
_cogl_texture_set_region_from_bitmap(CoglTexture * texture,int src_x,int src_y,int width,int height,CoglBitmap * bmp,int dst_x,int dst_y,int level,CoglError ** error)372 _cogl_texture_set_region_from_bitmap (CoglTexture *texture,
373 int src_x,
374 int src_y,
375 int width,
376 int height,
377 CoglBitmap *bmp,
378 int dst_x,
379 int dst_y,
380 int level,
381 CoglError **error)
382 {
383 _COGL_RETURN_VAL_IF_FAIL ((cogl_bitmap_get_width (bmp) - src_x)
384 >= width, FALSE);
385 _COGL_RETURN_VAL_IF_FAIL ((cogl_bitmap_get_height (bmp) - src_y)
386 >= height, FALSE);
387 _COGL_RETURN_VAL_IF_FAIL (width > 0, FALSE);
388 _COGL_RETURN_VAL_IF_FAIL (height > 0, FALSE);
389
390 /* Assert that the storage for this texture has been allocated */
391 if (!cogl_texture_allocate (texture, error))
392 return FALSE;
393
394 /* Note that we don't prepare the bitmap for upload here because
395 some backends may be internally using a different format for the
396 actual GL texture than that reported by
397 _cogl_texture_get_format. For example the atlas textures are
398 always stored in an RGBA texture even if the texture format is
399 advertised as RGB. */
400
401 return texture->vtable->set_region (texture,
402 src_x, src_y,
403 dst_x, dst_y,
404 width, height,
405 level,
406 bmp,
407 error);
408 }
409
410 CoglBool
cogl_texture_set_region_from_bitmap(CoglTexture * texture,int src_x,int src_y,int dst_x,int dst_y,unsigned int dst_width,unsigned int dst_height,CoglBitmap * bitmap)411 cogl_texture_set_region_from_bitmap (CoglTexture *texture,
412 int src_x,
413 int src_y,
414 int dst_x,
415 int dst_y,
416 unsigned int dst_width,
417 unsigned int dst_height,
418 CoglBitmap *bitmap)
419 {
420 CoglError *ignore_error = NULL;
421 CoglBool status =
422 _cogl_texture_set_region_from_bitmap (texture,
423 src_x, src_y,
424 dst_width, dst_height,
425 bitmap,
426 dst_x, dst_y,
427 0, /* level */
428 &ignore_error);
429
430 if (!status)
431 cogl_error_free (ignore_error);
432 return status;
433 }
434
435 CoglBool
_cogl_texture_set_region(CoglTexture * texture,int width,int height,CoglPixelFormat format,int rowstride,const uint8_t * data,int dst_x,int dst_y,int level,CoglError ** error)436 _cogl_texture_set_region (CoglTexture *texture,
437 int width,
438 int height,
439 CoglPixelFormat format,
440 int rowstride,
441 const uint8_t *data,
442 int dst_x,
443 int dst_y,
444 int level,
445 CoglError **error)
446 {
447 CoglContext *ctx = texture->context;
448 CoglBitmap *source_bmp;
449 CoglBool ret;
450
451 _COGL_RETURN_VAL_IF_FAIL (format != COGL_PIXEL_FORMAT_ANY, FALSE);
452
453 /* Rowstride from width if none specified */
454 if (rowstride == 0)
455 rowstride = _cogl_pixel_format_get_bytes_per_pixel (format) * width;
456
457 /* Init source bitmap */
458 source_bmp = cogl_bitmap_new_for_data (ctx,
459 width, height,
460 format,
461 rowstride,
462 (uint8_t *) data);
463
464 ret = _cogl_texture_set_region_from_bitmap (texture,
465 0, 0,
466 width, height,
467 source_bmp,
468 dst_x, dst_y,
469 level,
470 error);
471
472 cogl_object_unref (source_bmp);
473
474 return ret;
475 }
476
477 CoglBool
cogl_texture_set_region(CoglTexture * texture,int src_x,int src_y,int dst_x,int dst_y,unsigned int dst_width,unsigned int dst_height,int width,int height,CoglPixelFormat format,unsigned int rowstride,const uint8_t * data)478 cogl_texture_set_region (CoglTexture *texture,
479 int src_x,
480 int src_y,
481 int dst_x,
482 int dst_y,
483 unsigned int dst_width,
484 unsigned int dst_height,
485 int width,
486 int height,
487 CoglPixelFormat format,
488 unsigned int rowstride,
489 const uint8_t *data)
490 {
491 CoglError *ignore_error = NULL;
492 const uint8_t *first_pixel;
493 int bytes_per_pixel = _cogl_pixel_format_get_bytes_per_pixel (format);
494 CoglBool status;
495
496 /* Rowstride from width if none specified */
497 if (rowstride == 0)
498 rowstride = bytes_per_pixel * width;
499
500 first_pixel = data + rowstride * src_y + bytes_per_pixel * src_x;
501
502 status = _cogl_texture_set_region (texture,
503 dst_width,
504 dst_height,
505 format,
506 rowstride,
507 first_pixel,
508 dst_x,
509 dst_y,
510 0,
511 &ignore_error);
512 if (!status)
513 cogl_error_free (ignore_error);
514 return status;
515 }
516
517 CoglBool
cogl_texture_set_data(CoglTexture * texture,CoglPixelFormat format,int rowstride,const uint8_t * data,int level,CoglError ** error)518 cogl_texture_set_data (CoglTexture *texture,
519 CoglPixelFormat format,
520 int rowstride,
521 const uint8_t *data,
522 int level,
523 CoglError **error)
524 {
525 int level_width;
526 int level_height;
527
528 _cogl_texture_get_level_size (texture,
529 level,
530 &level_width,
531 &level_height,
532 NULL);
533
534 return _cogl_texture_set_region (texture,
535 level_width,
536 level_height,
537 format,
538 rowstride,
539 data,
540 0, 0, /* dest x, y */
541 level,
542 error);
543 }
544
545 static CoglBool
get_texture_bits_via_offscreen(CoglTexture * meta_texture,CoglTexture * sub_texture,int x,int y,int width,int height,uint8_t * dst_bits,unsigned int dst_rowstride,CoglPixelFormat closest_format)546 get_texture_bits_via_offscreen (CoglTexture *meta_texture,
547 CoglTexture *sub_texture,
548 int x,
549 int y,
550 int width,
551 int height,
552 uint8_t *dst_bits,
553 unsigned int dst_rowstride,
554 CoglPixelFormat closest_format)
555 {
556 CoglContext *ctx = sub_texture->context;
557 CoglOffscreen *offscreen;
558 CoglFramebuffer *framebuffer;
559 CoglBitmap *bitmap;
560 CoglBool ret;
561 CoglError *ignore_error = NULL;
562 CoglPixelFormat real_format;
563
564 if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
565 return FALSE;
566
567 offscreen = _cogl_offscreen_new_with_texture_full
568 (sub_texture,
569 COGL_OFFSCREEN_DISABLE_DEPTH_AND_STENCIL,
570 0);
571
572 framebuffer = COGL_FRAMEBUFFER (offscreen);
573 if (!cogl_framebuffer_allocate (framebuffer, &ignore_error))
574 {
575 cogl_error_free (ignore_error);
576 return FALSE;
577 }
578
579 /* Currently the framebuffer's internal format corresponds to the
580 * internal format of @sub_texture but in the case of atlas textures
581 * it's possible that this format doesn't reflect the correct
582 * premultiplied alpha status or what components are valid since
583 * atlas textures are always stored in a shared texture with a
584 * format of _RGBA_8888.
585 *
586 * Here we override the internal format to make sure the
587 * framebuffer's internal format matches the internal format of the
588 * parent meta_texture instead.
589 */
590 real_format = _cogl_texture_get_format (meta_texture);
591 _cogl_framebuffer_set_internal_format (framebuffer, real_format);
592
593 bitmap = cogl_bitmap_new_for_data (ctx,
594 width, height,
595 closest_format,
596 dst_rowstride,
597 dst_bits);
598 ret = _cogl_framebuffer_read_pixels_into_bitmap (framebuffer,
599 x, y,
600 COGL_READ_PIXELS_COLOR_BUFFER,
601 bitmap,
602 &ignore_error);
603
604 if (!ret)
605 cogl_error_free (ignore_error);
606
607 cogl_object_unref (bitmap);
608
609 cogl_object_unref (framebuffer);
610
611 return ret;
612 }
613
614 static CoglBool
get_texture_bits_via_copy(CoglTexture * texture,int x,int y,int width,int height,uint8_t * dst_bits,unsigned int dst_rowstride,CoglPixelFormat dst_format)615 get_texture_bits_via_copy (CoglTexture *texture,
616 int x,
617 int y,
618 int width,
619 int height,
620 uint8_t *dst_bits,
621 unsigned int dst_rowstride,
622 CoglPixelFormat dst_format)
623 {
624 unsigned int full_rowstride;
625 uint8_t *full_bits;
626 CoglBool ret = TRUE;
627 int bpp;
628 int full_tex_width, full_tex_height;
629
630 full_tex_width = cogl_texture_get_width (texture);
631 full_tex_height = cogl_texture_get_height (texture);
632
633 bpp = _cogl_pixel_format_get_bytes_per_pixel (dst_format);
634
635 full_rowstride = bpp * full_tex_width;
636 full_bits = malloc (full_rowstride * full_tex_height);
637
638 if (texture->vtable->get_data (texture,
639 dst_format,
640 full_rowstride,
641 full_bits))
642 {
643 uint8_t *dst = dst_bits;
644 uint8_t *src = full_bits + x * bpp + y * full_rowstride;
645 int i;
646
647 for (i = 0; i < height; i++)
648 {
649 memcpy (dst, src, bpp * width);
650 dst += dst_rowstride;
651 src += full_rowstride;
652 }
653 }
654 else
655 ret = FALSE;
656
657 free (full_bits);
658
659 return ret;
660 }
661
662 typedef struct
663 {
664 CoglTexture *meta_texture;
665 int orig_width;
666 int orig_height;
667 CoglBitmap *target_bmp;
668 uint8_t *target_bits;
669 CoglBool success;
670 CoglError *error;
671 } CoglTextureGetData;
672
673 static void
texture_get_cb(CoglTexture * subtexture,const float * subtexture_coords,const float * virtual_coords,void * user_data)674 texture_get_cb (CoglTexture *subtexture,
675 const float *subtexture_coords,
676 const float *virtual_coords,
677 void *user_data)
678 {
679 CoglTextureGetData *tg_data = user_data;
680 CoglTexture *meta_texture = tg_data->meta_texture;
681 CoglPixelFormat closest_format = cogl_bitmap_get_format (tg_data->target_bmp);
682 int bpp = _cogl_pixel_format_get_bytes_per_pixel (closest_format);
683 unsigned int rowstride = cogl_bitmap_get_rowstride (tg_data->target_bmp);
684 int subtexture_width = cogl_texture_get_width (subtexture);
685 int subtexture_height = cogl_texture_get_height (subtexture);
686
687 int x_in_subtexture = (int) (0.5 + subtexture_width * subtexture_coords[0]);
688 int y_in_subtexture = (int) (0.5 + subtexture_height * subtexture_coords[1]);
689 int width = ((int) (0.5 + subtexture_width * subtexture_coords[2])
690 - x_in_subtexture);
691 int height = ((int) (0.5 + subtexture_height * subtexture_coords[3])
692 - y_in_subtexture);
693 int x_in_bitmap = (int) (0.5 + tg_data->orig_width * virtual_coords[0]);
694 int y_in_bitmap = (int) (0.5 + tg_data->orig_height * virtual_coords[1]);
695
696 uint8_t *dst_bits;
697
698 if (!tg_data->success)
699 return;
700
701 dst_bits = tg_data->target_bits + x_in_bitmap * bpp + y_in_bitmap * rowstride;
702
703 /* If we can read everything as a single slice, then go ahead and do that
704 * to avoid allocating an FBO. We'll leave it up to the GL implementation to
705 * do glGetTexImage as efficiently as possible. (GLES doesn't have that,
706 * so we'll fall through)
707 */
708 if (x_in_subtexture == 0 && y_in_subtexture == 0 &&
709 width == subtexture_width && height == subtexture_height)
710 {
711 if (subtexture->vtable->get_data (subtexture,
712 closest_format,
713 rowstride,
714 dst_bits))
715 return;
716 }
717
718 /* Next best option is a FBO and glReadPixels */
719 if (get_texture_bits_via_offscreen (meta_texture,
720 subtexture,
721 x_in_subtexture, y_in_subtexture,
722 width, height,
723 dst_bits,
724 rowstride,
725 closest_format))
726 return;
727
728 /* Getting ugly: read the entire texture, copy out the part we want */
729 if (get_texture_bits_via_copy (subtexture,
730 x_in_subtexture, y_in_subtexture,
731 width, height,
732 dst_bits,
733 rowstride,
734 closest_format))
735 return;
736
737 /* No luck, the caller will fall back to the draw-to-backbuffer and
738 * read implementation */
739 tg_data->success = FALSE;
740 }
741
742 int
cogl_texture_get_data(CoglTexture * texture,CoglPixelFormat format,unsigned int rowstride,uint8_t * data)743 cogl_texture_get_data (CoglTexture *texture,
744 CoglPixelFormat format,
745 unsigned int rowstride,
746 uint8_t *data)
747 {
748 CoglContext *ctx = texture->context;
749 int bpp;
750 int byte_size;
751 CoglPixelFormat closest_format;
752 GLenum closest_gl_format;
753 GLenum closest_gl_type;
754 CoglBitmap *target_bmp;
755 int tex_width;
756 int tex_height;
757 CoglPixelFormat texture_format;
758 CoglError *ignore_error = NULL;
759
760 CoglTextureGetData tg_data;
761
762 texture_format = _cogl_texture_get_format (texture);
763
764 /* Default to internal format if none specified */
765 if (format == COGL_PIXEL_FORMAT_ANY)
766 format = texture_format;
767
768 tex_width = cogl_texture_get_width (texture);
769 tex_height = cogl_texture_get_height (texture);
770
771 /* Rowstride from texture width if none specified */
772 bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
773 if (rowstride == 0)
774 rowstride = tex_width * bpp;
775
776 /* Return byte size if only that requested */
777 byte_size = tex_height * rowstride;
778 if (data == NULL)
779 return byte_size;
780
781 closest_format =
782 ctx->texture_driver->find_best_gl_get_data_format (ctx,
783 texture_format,
784 format,
785 &closest_gl_format,
786 &closest_gl_type);
787
788 /* We can assume that whatever data GL gives us will have the
789 premult status of the original texture */
790 if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (closest_format))
791 closest_format = ((closest_format & ~COGL_PREMULT_BIT) |
792 (texture_format & COGL_PREMULT_BIT));
793
794 /* If the application is requesting a conversion from a
795 * component-alpha texture and the driver doesn't support them
796 * natively then we can only read into an alpha-format buffer. In
797 * this case the driver will be faking the alpha textures with a
798 * red-component texture and it won't swizzle to the correct format
799 * while reading */
800 if (!_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_ALPHA_TEXTURES))
801 {
802 if (texture_format == COGL_PIXEL_FORMAT_A_8)
803 {
804 closest_format = COGL_PIXEL_FORMAT_A_8;
805 closest_gl_format = GL_RED;
806 closest_gl_type = GL_UNSIGNED_BYTE;
807 }
808 else if (format == COGL_PIXEL_FORMAT_A_8)
809 {
810 /* If we are converting to a component-alpha texture then we
811 * need to read all of the components to a temporary buffer
812 * because there is no way to get just the 4th component.
813 * Note: it doesn't matter whether the texture is
814 * pre-multiplied here because we're only going to look at
815 * the alpha component */
816 closest_format = COGL_PIXEL_FORMAT_RGBA_8888;
817 closest_gl_format = GL_RGBA;
818 closest_gl_type = GL_UNSIGNED_BYTE;
819 }
820 }
821
822 /* Is the requested format supported? */
823 if (closest_format == format)
824 /* Target user data directly */
825 target_bmp = cogl_bitmap_new_for_data (ctx,
826 tex_width,
827 tex_height,
828 format,
829 rowstride,
830 data);
831 else
832 {
833 target_bmp = _cogl_bitmap_new_with_malloc_buffer (ctx,
834 tex_width, tex_height,
835 closest_format,
836 &ignore_error);
837 if (!target_bmp)
838 {
839 cogl_error_free (ignore_error);
840 return 0;
841 }
842 }
843
844 tg_data.target_bits = _cogl_bitmap_map (target_bmp, COGL_BUFFER_ACCESS_WRITE,
845 COGL_BUFFER_MAP_HINT_DISCARD,
846 &ignore_error);
847 if (tg_data.target_bits)
848 {
849 tg_data.meta_texture = texture;
850 tg_data.orig_width = tex_width;
851 tg_data.orig_height = tex_height;
852 tg_data.target_bmp = target_bmp;
853 tg_data.error = NULL;
854 tg_data.success = TRUE;
855
856 /* If there are any dependent framebuffers on the texture then we
857 need to flush their journals so the texture contents will be
858 up-to-date */
859 _cogl_texture_flush_journal_rendering (texture);
860
861 /* Iterating through the subtextures allows piecing together
862 * the data for a sliced texture, and allows us to do the
863 * read-from-framebuffer logic here in a simple fashion rather than
864 * passing offsets down through the code. */
865 cogl_meta_texture_foreach_in_region (COGL_META_TEXTURE (texture),
866 0, 0, 1, 1,
867 COGL_PIPELINE_WRAP_MODE_REPEAT,
868 COGL_PIPELINE_WRAP_MODE_REPEAT,
869 texture_get_cb,
870 &tg_data);
871
872 _cogl_bitmap_unmap (target_bmp);
873 }
874 else
875 {
876 cogl_error_free (ignore_error);
877 tg_data.success = FALSE;
878 }
879
880 /* XXX: In some cases this api may fail to read back the texture
881 * data; such as for GLES which doesn't support glGetTexImage
882 */
883 if (!tg_data.success)
884 {
885 cogl_object_unref (target_bmp);
886 return 0;
887 }
888
889 /* Was intermediate used? */
890 if (closest_format != format)
891 {
892 CoglBitmap *new_bmp;
893 CoglBool result;
894 CoglError *error = NULL;
895
896 /* Convert to requested format directly into the user's buffer */
897 new_bmp = cogl_bitmap_new_for_data (ctx,
898 tex_width, tex_height,
899 format,
900 rowstride,
901 data);
902 result = _cogl_bitmap_convert_into_bitmap (target_bmp, new_bmp, &error);
903
904 if (!result)
905 {
906 cogl_error_free (error);
907 /* Return failure after cleaning up */
908 byte_size = 0;
909 }
910
911 cogl_object_unref (new_bmp);
912 }
913
914 cogl_object_unref (target_bmp);
915
916 return byte_size;
917 }
918
919 static void
_cogl_texture_framebuffer_destroy_cb(void * user_data,void * instance)920 _cogl_texture_framebuffer_destroy_cb (void *user_data,
921 void *instance)
922 {
923 CoglTexture *tex = user_data;
924 CoglFramebuffer *framebuffer = instance;
925
926 tex->framebuffers = g_list_remove (tex->framebuffers, framebuffer);
927 }
928
929 void
_cogl_texture_associate_framebuffer(CoglTexture * texture,CoglFramebuffer * framebuffer)930 _cogl_texture_associate_framebuffer (CoglTexture *texture,
931 CoglFramebuffer *framebuffer)
932 {
933 static CoglUserDataKey framebuffer_destroy_notify_key;
934
935 /* Note: we don't take a reference on the framebuffer here because
936 * that would introduce a circular reference. */
937 texture->framebuffers = g_list_prepend (texture->framebuffers, framebuffer);
938
939 /* Since we haven't taken a reference on the framebuffer we setup
940 * some private data so we will be notified if it is destroyed... */
941 _cogl_object_set_user_data (COGL_OBJECT (framebuffer),
942 &framebuffer_destroy_notify_key,
943 texture,
944 _cogl_texture_framebuffer_destroy_cb);
945 }
946
947 const GList *
_cogl_texture_get_associated_framebuffers(CoglTexture * texture)948 _cogl_texture_get_associated_framebuffers (CoglTexture *texture)
949 {
950 return texture->framebuffers;
951 }
952
953 void
_cogl_texture_flush_journal_rendering(CoglTexture * texture)954 _cogl_texture_flush_journal_rendering (CoglTexture *texture)
955 {
956 GList *l;
957
958 /* It could be that a referenced texture is part of a framebuffer
959 * which has an associated journal that must be flushed before it
960 * can be sampled from by the current primitive... */
961 for (l = texture->framebuffers; l; l = l->next)
962 _cogl_framebuffer_flush_journal (l->data);
963 }
964
965 /* This function lets you define a meta texture as a grid of textures
966 * whereby the x and y grid-lines are defined by an array of
967 * CoglSpans. With that grid based description this function can then
968 * iterate all the cells of the grid that lye within a region
969 * specified as virtual, meta-texture, coordinates. This function can
970 * also cope with regions that extend beyond the original meta-texture
971 * grid by iterating cells repeatedly according to the wrap_x/y
972 * arguments.
973 *
974 * To differentiate between texture coordinates of a specific, real,
975 * slice texture and the texture coordinates of a composite, meta
976 * texture, the coordinates of the meta texture are called "virtual"
977 * coordinates and the coordinates of spans are called "slice"
978 * coordinates.
979 *
980 * Note: no guarantee is given about the order in which the slices
981 * will be visited.
982 *
983 * Note: The slice coordinates passed to @callback are always
984 * normalized coordinates even if the span coordinates aren't
985 * normalized.
986 */
987 void
_cogl_texture_spans_foreach_in_region(CoglSpan * x_spans,int n_x_spans,CoglSpan * y_spans,int n_y_spans,CoglTexture ** textures,float * virtual_coords,float x_normalize_factor,float y_normalize_factor,CoglPipelineWrapMode wrap_x,CoglPipelineWrapMode wrap_y,CoglMetaTextureCallback callback,void * user_data)988 _cogl_texture_spans_foreach_in_region (CoglSpan *x_spans,
989 int n_x_spans,
990 CoglSpan *y_spans,
991 int n_y_spans,
992 CoglTexture **textures,
993 float *virtual_coords,
994 float x_normalize_factor,
995 float y_normalize_factor,
996 CoglPipelineWrapMode wrap_x,
997 CoglPipelineWrapMode wrap_y,
998 CoglMetaTextureCallback callback,
999 void *user_data)
1000 {
1001 CoglSpanIter iter_x;
1002 CoglSpanIter iter_y;
1003 float slice_coords[4];
1004 float span_virtual_coords[4];
1005
1006 /* Iterate the y axis of the virtual rectangle */
1007 for (_cogl_span_iter_begin (&iter_y,
1008 y_spans,
1009 n_y_spans,
1010 y_normalize_factor,
1011 virtual_coords[1],
1012 virtual_coords[3],
1013 wrap_y);
1014 !_cogl_span_iter_end (&iter_y);
1015 _cogl_span_iter_next (&iter_y))
1016 {
1017 if (iter_y.flipped)
1018 {
1019 slice_coords[1] = iter_y.intersect_end;
1020 slice_coords[3] = iter_y.intersect_start;
1021 span_virtual_coords[1] = iter_y.intersect_end;
1022 span_virtual_coords[3] = iter_y.intersect_start;
1023 }
1024 else
1025 {
1026 slice_coords[1] = iter_y.intersect_start;
1027 slice_coords[3] = iter_y.intersect_end;
1028 span_virtual_coords[1] = iter_y.intersect_start;
1029 span_virtual_coords[3] = iter_y.intersect_end;
1030 }
1031
1032 /* Map the current intersection to normalized slice coordinates */
1033 slice_coords[1] = (slice_coords[1] - iter_y.pos) / iter_y.span->size;
1034 slice_coords[3] = (slice_coords[3] - iter_y.pos) / iter_y.span->size;
1035
1036 /* Iterate the x axis of the virtual rectangle */
1037 for (_cogl_span_iter_begin (&iter_x,
1038 x_spans,
1039 n_x_spans,
1040 x_normalize_factor,
1041 virtual_coords[0],
1042 virtual_coords[2],
1043 wrap_x);
1044 !_cogl_span_iter_end (&iter_x);
1045 _cogl_span_iter_next (&iter_x))
1046 {
1047 CoglTexture *span_tex;
1048
1049 if (iter_x.flipped)
1050 {
1051 slice_coords[0] = iter_x.intersect_end;
1052 slice_coords[2] = iter_x.intersect_start;
1053 span_virtual_coords[0] = iter_x.intersect_end;
1054 span_virtual_coords[2] = iter_x.intersect_start;
1055 }
1056 else
1057 {
1058 slice_coords[0] = iter_x.intersect_start;
1059 slice_coords[2] = iter_x.intersect_end;
1060 span_virtual_coords[0] = iter_x.intersect_start;
1061 span_virtual_coords[2] = iter_x.intersect_end;
1062 }
1063
1064 /* Map the current intersection to normalized slice coordinates */
1065 slice_coords[0] = (slice_coords[0] - iter_x.pos) / iter_x.span->size;
1066 slice_coords[2] = (slice_coords[2] - iter_x.pos) / iter_x.span->size;
1067
1068 /* Pluck out the cogl texture for this span */
1069 span_tex = textures[iter_y.index * n_x_spans + iter_x.index];
1070
1071 callback (COGL_TEXTURE (span_tex),
1072 slice_coords,
1073 span_virtual_coords,
1074 user_data);
1075 }
1076 }
1077 }
1078
1079 void
_cogl_texture_set_allocated(CoglTexture * texture,CoglPixelFormat internal_format,int width,int height)1080 _cogl_texture_set_allocated (CoglTexture *texture,
1081 CoglPixelFormat internal_format,
1082 int width,
1083 int height)
1084 {
1085 _cogl_texture_set_internal_format (texture, internal_format);
1086
1087 texture->width = width;
1088 texture->height = height;
1089 texture->allocated = TRUE;
1090
1091 _cogl_texture_free_loader (texture);
1092 }
1093
1094 CoglBool
cogl_texture_allocate(CoglTexture * texture,CoglError ** error)1095 cogl_texture_allocate (CoglTexture *texture,
1096 CoglError **error)
1097 {
1098 if (texture->allocated)
1099 return TRUE;
1100
1101 if (texture->components == COGL_TEXTURE_COMPONENTS_RG &&
1102 !cogl_has_feature (texture->context, COGL_FEATURE_ID_TEXTURE_RG))
1103 _cogl_set_error (error,
1104 COGL_TEXTURE_ERROR,
1105 COGL_TEXTURE_ERROR_FORMAT,
1106 "A red-green texture was requested but the driver "
1107 "does not support them");
1108
1109 texture->allocated = texture->vtable->allocate (texture, error);
1110
1111 return texture->allocated;
1112 }
1113
1114 void
_cogl_texture_set_internal_format(CoglTexture * texture,CoglPixelFormat internal_format)1115 _cogl_texture_set_internal_format (CoglTexture *texture,
1116 CoglPixelFormat internal_format)
1117 {
1118 texture->premultiplied = FALSE;
1119
1120 if (internal_format == COGL_PIXEL_FORMAT_ANY)
1121 internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
1122
1123 if (internal_format == COGL_PIXEL_FORMAT_A_8)
1124 {
1125 texture->components = COGL_TEXTURE_COMPONENTS_A;
1126 return;
1127 }
1128 else if (internal_format == COGL_PIXEL_FORMAT_RG_88)
1129 {
1130 texture->components = COGL_TEXTURE_COMPONENTS_RG;
1131 return;
1132 }
1133 else if (internal_format & COGL_DEPTH_BIT)
1134 {
1135 texture->components = COGL_TEXTURE_COMPONENTS_DEPTH;
1136 return;
1137 }
1138 else if (internal_format & COGL_A_BIT)
1139 {
1140 texture->components = COGL_TEXTURE_COMPONENTS_RGBA;
1141 if (internal_format & COGL_PREMULT_BIT)
1142 texture->premultiplied = TRUE;
1143 return;
1144 }
1145 else
1146 texture->components = COGL_TEXTURE_COMPONENTS_RGB;
1147 }
1148
1149 CoglPixelFormat
_cogl_texture_determine_internal_format(CoglTexture * texture,CoglPixelFormat src_format)1150 _cogl_texture_determine_internal_format (CoglTexture *texture,
1151 CoglPixelFormat src_format)
1152 {
1153 switch (texture->components)
1154 {
1155 case COGL_TEXTURE_COMPONENTS_DEPTH:
1156 if (src_format & COGL_DEPTH_BIT)
1157 return src_format;
1158 else
1159 {
1160 CoglContext *ctx = texture->context;
1161
1162 if (_cogl_has_private_feature (ctx,
1163 COGL_PRIVATE_FEATURE_EXT_PACKED_DEPTH_STENCIL) ||
1164 _cogl_has_private_feature (ctx,
1165 COGL_PRIVATE_FEATURE_OES_PACKED_DEPTH_STENCIL))
1166 {
1167 return COGL_PIXEL_FORMAT_DEPTH_24_STENCIL_8;
1168 }
1169 else
1170 return COGL_PIXEL_FORMAT_DEPTH_16;
1171 }
1172 case COGL_TEXTURE_COMPONENTS_A:
1173 return COGL_PIXEL_FORMAT_A_8;
1174 case COGL_TEXTURE_COMPONENTS_RG:
1175 return COGL_PIXEL_FORMAT_RG_88;
1176 case COGL_TEXTURE_COMPONENTS_RGB:
1177 if (src_format != COGL_PIXEL_FORMAT_ANY &&
1178 !(src_format & COGL_A_BIT) && !(src_format & COGL_DEPTH_BIT))
1179 return src_format;
1180 else
1181 return COGL_PIXEL_FORMAT_RGB_888;
1182 case COGL_TEXTURE_COMPONENTS_RGBA:
1183 {
1184 CoglPixelFormat format;
1185
1186 if (src_format != COGL_PIXEL_FORMAT_ANY &&
1187 (src_format & COGL_A_BIT) && src_format != COGL_PIXEL_FORMAT_A_8)
1188 format = src_format;
1189 else
1190 format = COGL_PIXEL_FORMAT_RGBA_8888;
1191
1192 if (texture->premultiplied)
1193 {
1194 if (COGL_PIXEL_FORMAT_CAN_HAVE_PREMULT (format))
1195 return format |= COGL_PREMULT_BIT;
1196 else
1197 return COGL_PIXEL_FORMAT_RGBA_8888_PRE;
1198 }
1199 else
1200 return format & ~COGL_PREMULT_BIT;
1201 }
1202 }
1203
1204 g_return_val_if_reached (COGL_PIXEL_FORMAT_RGBA_8888_PRE);
1205 }
1206
1207 void
cogl_texture_set_components(CoglTexture * texture,CoglTextureComponents components)1208 cogl_texture_set_components (CoglTexture *texture,
1209 CoglTextureComponents components)
1210 {
1211 _COGL_RETURN_IF_FAIL (!texture->allocated);
1212
1213 if (texture->components == components)
1214 return;
1215
1216 texture->components = components;
1217 }
1218
1219 CoglTextureComponents
cogl_texture_get_components(CoglTexture * texture)1220 cogl_texture_get_components (CoglTexture *texture)
1221 {
1222 return texture->components;
1223 }
1224
1225 void
cogl_texture_set_premultiplied(CoglTexture * texture,CoglBool premultiplied)1226 cogl_texture_set_premultiplied (CoglTexture *texture,
1227 CoglBool premultiplied)
1228 {
1229 _COGL_RETURN_IF_FAIL (!texture->allocated);
1230
1231 premultiplied = !!premultiplied;
1232
1233 if (texture->premultiplied == premultiplied)
1234 return;
1235
1236 texture->premultiplied = premultiplied;
1237 }
1238
1239 CoglBool
cogl_texture_get_premultiplied(CoglTexture * texture)1240 cogl_texture_get_premultiplied (CoglTexture *texture)
1241 {
1242 return texture->premultiplied;
1243 }
1244
1245 void
_cogl_texture_copy_internal_format(CoglTexture * src,CoglTexture * dest)1246 _cogl_texture_copy_internal_format (CoglTexture *src,
1247 CoglTexture *dest)
1248 {
1249 cogl_texture_set_components (dest, src->components);
1250 cogl_texture_set_premultiplied (dest, src->premultiplied);
1251 }
1252