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