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