cleanup specfile for packaging
[profile/ivi/cogl.git] / cogl / cogl-texture-2d.c
1 /*
2  * Cogl
3  *
4  * An object oriented GL/GLES Abstraction/Utility Layer
5  *
6  * Copyright (C) 2009 Intel Corporation.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20  *
21  *
22  *
23  * Authors:
24  *  Neil Roberts   <neil@linux.intel.com>
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include "cogl-private.h"
32 #include "cogl-util.h"
33 #include "cogl-texture-private.h"
34 #include "cogl-texture-2d-private.h"
35 #include "cogl-texture-driver.h"
36 #include "cogl-context-private.h"
37 #include "cogl-handle.h"
38 #include "cogl-journal-private.h"
39 #include "cogl-pipeline-opengl-private.h"
40 #include "cogl-framebuffer-private.h"
41 #ifdef COGL_HAS_EGL_SUPPORT
42 #include "cogl-winsys-egl-private.h"
43 #endif
44
45 #include <string.h>
46 #include <math.h>
47
48 #ifdef COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT
49 #include "cogl-wayland-server.h"
50 #endif
51
52 static void _cogl_texture_2d_free (CoglTexture2D *tex_2d);
53
54 COGL_TEXTURE_DEFINE (Texture2D, texture_2d);
55
56 static const CoglTextureVtable cogl_texture_2d_vtable;
57
58 typedef struct _CoglTexture2DManualRepeatData
59 {
60   CoglTexture2D *tex_2d;
61   CoglMetaTextureCallback callback;
62   void *user_data;
63 } CoglTexture2DManualRepeatData;
64
65 static void
66 _cogl_texture_2d_set_wrap_mode_parameters (CoglTexture *tex,
67                                            GLenum wrap_mode_s,
68                                            GLenum wrap_mode_t,
69                                            GLenum wrap_mode_p)
70 {
71   CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
72
73   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
74
75   /* Only set the wrap mode if it's different from the current value
76      to avoid too many GL calls. Texture 2D doesn't make use of the r
77      coordinate so we can ignore its wrap mode */
78   if (tex_2d->wrap_mode_s != wrap_mode_s ||
79       tex_2d->wrap_mode_t != wrap_mode_t)
80     {
81       _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
82                                        tex_2d->gl_texture,
83                                        tex_2d->is_foreign);
84       GE( ctx, glTexParameteri (GL_TEXTURE_2D,
85                                 GL_TEXTURE_WRAP_S,
86                                 wrap_mode_s) );
87       GE( ctx, glTexParameteri (GL_TEXTURE_2D,
88                                 GL_TEXTURE_WRAP_T,
89                                 wrap_mode_t) );
90
91       tex_2d->wrap_mode_s = wrap_mode_s;
92       tex_2d->wrap_mode_t = wrap_mode_t;
93     }
94 }
95
96 static void
97 _cogl_texture_2d_free (CoglTexture2D *tex_2d)
98 {
99   if (!tex_2d->is_foreign)
100     _cogl_delete_gl_texture (tex_2d->gl_texture);
101
102   /* Chain up */
103   _cogl_texture_free (COGL_TEXTURE (tex_2d));
104 }
105
106 static gboolean
107 _cogl_texture_2d_can_create (unsigned int width,
108                              unsigned int height,
109                              CoglPixelFormat internal_format)
110 {
111   GLenum gl_intformat;
112   GLenum gl_type;
113
114   _COGL_GET_CONTEXT (ctx, FALSE);
115
116   /* If NPOT textures aren't supported then the size must be a power
117      of two */
118   if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT) &&
119       (!_cogl_util_is_pot (width) ||
120        !_cogl_util_is_pot (height)))
121     return FALSE;
122
123   ctx->texture_driver->pixel_format_to_gl (internal_format,
124                                            &gl_intformat,
125                                            NULL,
126                                            &gl_type);
127
128   /* Check that the driver can create a texture with that size */
129   if (!ctx->texture_driver->size_supported (GL_TEXTURE_2D,
130                                             gl_intformat,
131                                             gl_type,
132                                             width,
133                                             height))
134     return FALSE;
135
136   return TRUE;
137 }
138
139 static CoglTexture2D *
140 _cogl_texture_2d_create_base (unsigned int     width,
141                               unsigned int     height,
142                               CoglTextureFlags flags,
143                               CoglPixelFormat  internal_format)
144 {
145   CoglTexture2D *tex_2d = g_new (CoglTexture2D, 1);
146   CoglTexture *tex = COGL_TEXTURE (tex_2d);
147
148   _cogl_texture_init (tex, &cogl_texture_2d_vtable);
149
150   tex_2d->width = width;
151   tex_2d->height = height;
152   tex_2d->mipmaps_dirty = TRUE;
153   tex_2d->auto_mipmap = (flags & COGL_TEXTURE_NO_AUTO_MIPMAP) == 0;
154
155   /* We default to GL_LINEAR for both filters */
156   tex_2d->min_filter = GL_LINEAR;
157   tex_2d->mag_filter = GL_LINEAR;
158
159   /* Wrap mode not yet set */
160   tex_2d->wrap_mode_s = GL_FALSE;
161   tex_2d->wrap_mode_t = GL_FALSE;
162
163   tex_2d->is_foreign = FALSE;
164
165   tex_2d->format = internal_format;
166
167   return tex_2d;
168 }
169
170 CoglTexture2D *
171 cogl_texture_2d_new_with_size (CoglContext *ctx,
172                                int width,
173                                int height,
174                                CoglPixelFormat internal_format,
175                                GError **error)
176 {
177   CoglTexture2D         *tex_2d;
178   GLenum                 gl_intformat;
179   GLenum                 gl_format;
180   GLenum                 gl_type;
181
182   /* Since no data, we need some internal format */
183   if (internal_format == COGL_PIXEL_FORMAT_ANY)
184     internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
185
186   if (!_cogl_texture_2d_can_create (width, height, internal_format))
187     {
188       g_set_error (error, COGL_TEXTURE_ERROR,
189                    COGL_TEXTURE_ERROR_SIZE,
190                    "Failed to create texture 2d due to size/format"
191                    " constraints");
192       return NULL;
193     }
194
195   internal_format = ctx->texture_driver->pixel_format_to_gl (internal_format,
196                                                              &gl_intformat,
197                                                              &gl_format,
198                                                              &gl_type);
199
200   tex_2d = _cogl_texture_2d_create_base (width, height, COGL_TEXTURE_NONE,
201                                          internal_format);
202
203   ctx->texture_driver->gen (GL_TEXTURE_2D, 1, &tex_2d->gl_texture);
204   _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
205                                    tex_2d->gl_texture,
206                                    tex_2d->is_foreign);
207   GE( ctx, glTexImage2D (GL_TEXTURE_2D, 0, gl_intformat,
208                          width, height, 0, gl_format, gl_type, NULL) );
209
210   return _cogl_texture_2d_handle_new (tex_2d);
211 }
212
213 CoglHandle
214 _cogl_texture_2d_new_from_bitmap (CoglBitmap      *bmp,
215                                   CoglTextureFlags flags,
216                                   CoglPixelFormat  internal_format,
217                                   GError         **error)
218 {
219   CoglTexture2D *tex_2d;
220   CoglBitmap    *dst_bmp;
221   GLenum         gl_intformat;
222   GLenum         gl_format;
223   GLenum         gl_type;
224   guint8        *data;
225
226   _COGL_GET_CONTEXT (ctx, COGL_INVALID_HANDLE);
227
228   _COGL_RETURN_VAL_IF_FAIL (bmp != NULL, COGL_INVALID_HANDLE);
229
230   internal_format =
231     _cogl_texture_determine_internal_format (cogl_bitmap_get_format (bmp),
232                                              internal_format);
233
234   if (!_cogl_texture_2d_can_create (cogl_bitmap_get_width (bmp),
235                                     cogl_bitmap_get_height (bmp),
236                                     internal_format))
237     {
238       g_set_error (error, COGL_TEXTURE_ERROR,
239                    COGL_TEXTURE_ERROR_SIZE,
240                    "Failed to create texture 2d due to size/format"
241                    " constraints");
242       return NULL;
243
244     }
245
246   if ((dst_bmp = _cogl_texture_prepare_for_upload (bmp,
247                                                    internal_format,
248                                                    &internal_format,
249                                                    &gl_intformat,
250                                                    &gl_format,
251                                                    &gl_type)) == NULL)
252     {
253       g_set_error (error, COGL_TEXTURE_ERROR,
254                    COGL_TEXTURE_ERROR_FORMAT,
255                    "Failed to prepare texture upload due to format");
256       return NULL;
257     }
258
259   tex_2d = _cogl_texture_2d_create_base (cogl_bitmap_get_width (bmp),
260                                          cogl_bitmap_get_height (bmp),
261                                          flags,
262                                          internal_format);
263
264   /* Keep a copy of the first pixel so that if glGenerateMipmap isn't
265      supported we can fallback to using GL_GENERATE_MIPMAP */
266   if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) &&
267       (data = _cogl_bitmap_map (dst_bmp,
268                                 COGL_BUFFER_ACCESS_READ, 0)))
269     {
270       CoglPixelFormat format = cogl_bitmap_get_format (dst_bmp);
271       tex_2d->first_pixel.gl_format = gl_format;
272       tex_2d->first_pixel.gl_type = gl_type;
273       memcpy (tex_2d->first_pixel.data, data,
274               _cogl_pixel_format_get_bytes_per_pixel (format));
275
276       _cogl_bitmap_unmap (dst_bmp);
277     }
278
279   ctx->texture_driver->gen (GL_TEXTURE_2D, 1, &tex_2d->gl_texture);
280   ctx->texture_driver->upload_to_gl (GL_TEXTURE_2D,
281                                      tex_2d->gl_texture,
282                                      FALSE,
283                                      dst_bmp,
284                                      gl_intformat,
285                                      gl_format,
286                                      gl_type);
287
288   tex_2d->gl_format = gl_intformat;
289
290   cogl_object_unref (dst_bmp);
291
292   return _cogl_texture_2d_handle_new (tex_2d);
293 }
294
295 CoglTexture2D *
296 cogl_texture_2d_new_from_data (CoglContext *ctx,
297                                int width,
298                                int height,
299                                CoglPixelFormat format,
300                                CoglPixelFormat internal_format,
301                                int rowstride,
302                                const guint8 *data,
303                                GError **error)
304 {
305   CoglBitmap *bmp;
306   CoglHandle tex;
307
308   _COGL_RETURN_VAL_IF_FAIL (format != COGL_PIXEL_FORMAT_ANY, NULL);
309   _COGL_RETURN_VAL_IF_FAIL (data != NULL, NULL);
310
311   /* Rowstride from width if not given */
312   if (rowstride == 0)
313     rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format);
314
315   /* Wrap the data into a bitmap */
316   bmp = cogl_bitmap_new_for_data (ctx,
317                                   width, height,
318                                   format,
319                                   rowstride,
320                                   (guint8 *) data);
321
322   tex =_cogl_texture_2d_new_from_bitmap (bmp, COGL_TEXTURE_NONE,
323                                          internal_format,
324                                          error);
325
326   cogl_object_unref (bmp);
327
328   return tex;
329 }
330
331 CoglTexture2D *
332 cogl_texture_2d_new_from_foreign (CoglContext *ctx,
333                                   GLuint gl_handle,
334                                   int width,
335                                   int height,
336                                   CoglPixelFormat format,
337                                   GError **error)
338 {
339   /* NOTE: width, height and internal format are not queriable
340    * in GLES, hence such a function prototype.
341    */
342
343   GLenum         gl_error      = 0;
344   GLint          gl_compressed = GL_FALSE;
345   GLenum         gl_int_format = 0;
346   CoglTexture2D *tex_2d;
347
348   if (!ctx->texture_driver->allows_foreign_gl_target (GL_TEXTURE_2D))
349     return COGL_INVALID_HANDLE;
350
351   /* Make sure it is a valid GL texture object */
352   if (!ctx->glIsTexture (gl_handle))
353     return COGL_INVALID_HANDLE;
354
355   /* Make sure binding succeeds */
356   while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
357     ;
358
359   _cogl_bind_gl_texture_transient (GL_TEXTURE_2D, gl_handle, TRUE);
360   if (ctx->glGetError () != GL_NO_ERROR)
361     return COGL_INVALID_HANDLE;
362
363   /* Obtain texture parameters
364      (only level 0 we are interested in) */
365
366 #if HAVE_COGL_GL
367   if (ctx->driver == COGL_DRIVER_GL)
368     {
369       GE( ctx, glGetTexLevelParameteriv (GL_TEXTURE_2D, 0,
370                                          GL_TEXTURE_COMPRESSED,
371                                          &gl_compressed) );
372
373       {
374         GLint val;
375
376         GE( ctx, glGetTexLevelParameteriv (GL_TEXTURE_2D, 0,
377                                            GL_TEXTURE_INTERNAL_FORMAT,
378                                            &val) );
379
380         gl_int_format = val;
381       }
382
383       /* If we can query GL for the actual pixel format then we'll ignore
384          the passed in format and use that. */
385       if (!ctx->texture_driver->pixel_format_from_gl_internal (gl_int_format,
386                                                                &format))
387         return COGL_INVALID_HANDLE;
388     }
389   else
390 #endif
391     {
392       /* Otherwise we'll assume we can derive the GL format from the
393          passed in format */
394       ctx->texture_driver->pixel_format_to_gl (format,
395                                                &gl_int_format,
396                                                NULL,
397                                                NULL);
398     }
399
400   /* Note: We always trust the given width and height without querying
401    * the texture object because the user may be creating a Cogl
402    * texture for a texture_from_pixmap object where glTexImage2D may
403    * not have been called and the texture_from_pixmap spec doesn't
404    * clarify that it is reliable to query back the size from OpenGL.
405    */
406
407   /* Validate width and height */
408   if (width <= 0 || height <= 0)
409     return COGL_INVALID_HANDLE;
410
411   /* Compressed texture images not supported */
412   if (gl_compressed == GL_TRUE)
413     return COGL_INVALID_HANDLE;
414
415   /* Note: previously this code would query the texture object for
416      whether it has GL_GENERATE_MIPMAP enabled to determine whether to
417      auto-generate the mipmap. This doesn't make much sense any more
418      since Cogl switch to using glGenerateMipmap. Ideally I think
419      cogl_texture_new_from_foreign should take a flags parameter so
420      that the application can decide whether it wants
421      auto-mipmapping. To be compatible with existing code, Cogl now
422      disables its own auto-mipmapping but leaves the value of
423      GL_GENERATE_MIPMAP alone so that it would still work but without
424      the dirtiness tracking that Cogl would do. */
425
426   /* Create new texture */
427   tex_2d = _cogl_texture_2d_create_base (width, height,
428                                          COGL_TEXTURE_NO_AUTO_MIPMAP,
429                                          format);
430
431   /* Setup bitmap info */
432   tex_2d->is_foreign = TRUE;
433   tex_2d->mipmaps_dirty = TRUE;
434
435   tex_2d->format = format;
436
437   tex_2d->gl_texture = gl_handle;
438   tex_2d->gl_format = gl_int_format;
439
440   /* Unknown filter */
441   tex_2d->min_filter = GL_FALSE;
442   tex_2d->mag_filter = GL_FALSE;
443
444   return _cogl_texture_2d_handle_new (tex_2d);
445 }
446
447 #if defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base)
448 /* NB: The reason we require the width, height and format to be passed
449  * even though they may seem redundant is because GLES 1/2 don't
450  * provide a way to query these properties. */
451 CoglTexture2D *
452 _cogl_egl_texture_2d_new_from_image (CoglContext *ctx,
453                                      int width,
454                                      int height,
455                                      CoglPixelFormat format,
456                                      EGLImageKHR image,
457                                      GError **error)
458 {
459   CoglTexture2D *tex_2d;
460   GLenum gl_error;
461
462   _COGL_RETURN_VAL_IF_FAIL (_cogl_context_get_winsys (ctx)->constraints &
463                             COGL_RENDERER_CONSTRAINT_USES_EGL,
464                             NULL);
465
466   _COGL_RETURN_VAL_IF_FAIL (ctx->private_feature_flags &
467                         COGL_PRIVATE_FEATURE_TEXTURE_2D_FROM_EGL_IMAGE,
468                         NULL);
469
470   tex_2d = _cogl_texture_2d_create_base (width, height, COGL_TEXTURE_NONE,
471                                          format);
472
473   ctx->texture_driver->gen (GL_TEXTURE_2D, 1, &tex_2d->gl_texture);
474   _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
475                                    tex_2d->gl_texture,
476                                    FALSE);
477
478   while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
479     ;
480   ctx->glEGLImageTargetTexture2D (GL_TEXTURE_2D, image);
481   if (ctx->glGetError () != GL_NO_ERROR)
482     {
483       g_set_error (error,
484                    COGL_TEXTURE_ERROR,
485                    COGL_TEXTURE_ERROR_BAD_PARAMETER,
486                    "Could not create a CoglTexture2D from a given EGLImage");
487       return NULL;
488     }
489
490   return _cogl_texture_2d_handle_new (tex_2d);
491 }
492 #endif /* defined (COGL_HAS_EGL_SUPPORT) && defined (EGL_KHR_image_base) */
493
494 #ifdef COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT
495 CoglTexture2D *
496 cogl_wayland_texture_2d_new_from_buffer (CoglContext *ctx,
497                                          struct wl_buffer *buffer,
498                                          GError **error)
499 {
500   if (wl_buffer_is_shm (buffer))
501     {
502       int stride = wl_shm_buffer_get_stride (buffer);
503       CoglPixelFormat format;
504       CoglPixelFormat internal_format = COGL_PIXEL_FORMAT_ANY;
505
506       switch (wl_shm_buffer_get_format (buffer))
507         {
508 #if G_BYTE_ORDER == G_BIG_ENDIAN
509           case WL_SHM_FORMAT_ARGB8888:
510             format = COGL_PIXEL_FORMAT_ARGB_8888_PRE;
511             break;
512           case WL_SHM_FORMAT_XRGB32:
513             format = COGL_PIXEL_FORMAT_ARGB_8888;
514             internal_format = COGL_PIXEL_FORMAT_RGB_888;
515             break;
516 #elif G_BYTE_ORDER == G_LITTLE_ENDIAN
517           case WL_SHM_FORMAT_ARGB8888:
518             format = COGL_PIXEL_FORMAT_BGRA_8888_PRE;
519             break;
520           case WL_SHM_FORMAT_XRGB8888:
521             format = COGL_PIXEL_FORMAT_BGRA_8888;
522             internal_format = COGL_PIXEL_FORMAT_BGR_888;
523             break;
524 #endif
525           default:
526             g_warn_if_reached ();
527             format = COGL_PIXEL_FORMAT_ARGB_8888;
528         }
529
530       return cogl_texture_2d_new_from_data (ctx,
531                                             buffer->width,
532                                             buffer->height,
533                                             format,
534                                             internal_format,
535                                             stride,
536                                             wl_shm_buffer_get_data (buffer),
537                                             error);
538     }
539   else
540     {
541       EGLImageKHR image;
542       CoglTexture2D *tex;
543
544       _COGL_RETURN_VAL_IF_FAIL (_cogl_context_get_winsys (ctx)->constraints &
545                                 COGL_RENDERER_CONSTRAINT_USES_EGL,
546                                 NULL);
547       image = _cogl_egl_create_image (ctx,
548                                       EGL_WAYLAND_BUFFER_WL,
549                                       buffer,
550                                       NULL);
551       tex = _cogl_egl_texture_2d_new_from_image (ctx,
552                                                  buffer->width,
553                                                  buffer->height,
554                                                  COGL_PIXEL_FORMAT_ARGB_8888_PRE,
555                                                  image,
556                                                  error);
557       _cogl_egl_destroy_image (ctx, image);
558       return tex;
559     }
560 }
561 #endif /* COGL_HAS_WAYLAND_EGL_SERVER_SUPPORT */
562
563 void
564 _cogl_texture_2d_externally_modified (CoglHandle handle)
565 {
566   if (!cogl_is_texture_2d (handle))
567     return;
568
569   COGL_TEXTURE_2D (handle)->mipmaps_dirty = TRUE;
570 }
571
572 void
573 _cogl_texture_2d_copy_from_framebuffer (CoglHandle handle,
574                                         int dst_x,
575                                         int dst_y,
576                                         int src_x,
577                                         int src_y,
578                                         int width,
579                                         int height)
580 {
581   CoglTexture2D *tex_2d;
582
583   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
584
585   _COGL_RETURN_IF_FAIL (cogl_is_texture_2d (handle));
586
587   tex_2d = COGL_TEXTURE_2D (handle);
588
589   /* Make sure the current framebuffers are bound, though we don't need to
590    * flush the clip state here since we aren't going to draw to the
591    * framebuffer. */
592   _cogl_framebuffer_flush_state (cogl_get_draw_framebuffer (),
593                                  _cogl_get_read_framebuffer (),
594                                  COGL_FRAMEBUFFER_STATE_ALL &
595                                  ~COGL_FRAMEBUFFER_STATE_CLIP);
596
597   _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
598                                    tex_2d->gl_texture,
599                                    tex_2d->is_foreign);
600
601   ctx->glCopyTexSubImage2D (GL_TEXTURE_2D,
602                             0, /* level */
603                             dst_x, dst_y,
604                             src_x, src_y,
605                             width, height);
606
607   tex_2d->mipmaps_dirty = TRUE;
608 }
609
610 static int
611 _cogl_texture_2d_get_max_waste (CoglTexture *tex)
612 {
613   return -1;
614 }
615
616 static gboolean
617 _cogl_texture_2d_is_sliced (CoglTexture *tex)
618 {
619   return FALSE;
620 }
621
622 static gboolean
623 _cogl_texture_2d_can_hardware_repeat (CoglTexture *tex)
624 {
625   return TRUE;
626 }
627
628 static void
629 _cogl_texture_2d_transform_coords_to_gl (CoglTexture *tex,
630                                          float *s,
631                                          float *t)
632 {
633   /* The texture coordinates map directly so we don't need to do
634      anything */
635 }
636
637 static CoglTransformResult
638 _cogl_texture_2d_transform_quad_coords_to_gl (CoglTexture *tex,
639                                               float *coords)
640 {
641   /* The texture coordinates map directly so we don't need to do
642      anything other than check for repeats */
643
644   gboolean need_repeat = FALSE;
645   int i;
646
647   for (i = 0; i < 4; i++)
648     if (coords[i] < 0.0f || coords[i] > 1.0f)
649       need_repeat = TRUE;
650
651   return (need_repeat ? COGL_TRANSFORM_HARDWARE_REPEAT
652           : COGL_TRANSFORM_NO_REPEAT);
653 }
654
655 static gboolean
656 _cogl_texture_2d_get_gl_texture (CoglTexture *tex,
657                                  GLuint *out_gl_handle,
658                                  GLenum *out_gl_target)
659 {
660   CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
661
662   if (out_gl_handle)
663     *out_gl_handle = tex_2d->gl_texture;
664
665   if (out_gl_target)
666     *out_gl_target = GL_TEXTURE_2D;
667
668   return TRUE;
669 }
670
671 static void
672 _cogl_texture_2d_set_filters (CoglTexture *tex,
673                               GLenum       min_filter,
674                               GLenum       mag_filter)
675 {
676   CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
677
678   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
679
680   if (min_filter == tex_2d->min_filter
681       && mag_filter == tex_2d->mag_filter)
682     return;
683
684   /* Store new values */
685   tex_2d->min_filter = min_filter;
686   tex_2d->mag_filter = mag_filter;
687
688   /* Apply new filters to the texture */
689   _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
690                                    tex_2d->gl_texture,
691                                    tex_2d->is_foreign);
692   GE( ctx, glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, mag_filter) );
693   GE( ctx, glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, min_filter) );
694 }
695
696 static void
697 _cogl_texture_2d_pre_paint (CoglTexture *tex, CoglTexturePrePaintFlags flags)
698 {
699   CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
700
701   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
702
703   /* Only update if the mipmaps are dirty */
704   if ((flags & COGL_TEXTURE_NEEDS_MIPMAP) &&
705       tex_2d->auto_mipmap && tex_2d->mipmaps_dirty)
706     {
707       _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
708                                        tex_2d->gl_texture,
709                                        tex_2d->is_foreign);
710
711       /* glGenerateMipmap is defined in the FBO extension. If it's not
712          available we'll fallback to temporarily enabling
713          GL_GENERATE_MIPMAP and reuploading the first pixel */
714       if (cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
715         ctx->texture_driver->gl_generate_mipmaps (GL_TEXTURE_2D);
716 #if defined(HAVE_COGL_GLES) || defined(HAVE_COGL_GL)
717       else
718         {
719           GE( ctx, glTexParameteri (GL_TEXTURE_2D,
720                                     GL_GENERATE_MIPMAP,
721                                     GL_TRUE) );
722           GE( ctx, glTexSubImage2D (GL_TEXTURE_2D, 0, 0, 0, 1, 1,
723                                     tex_2d->first_pixel.gl_format,
724                                     tex_2d->first_pixel.gl_type,
725                                     tex_2d->first_pixel.data) );
726           GE( ctx, glTexParameteri (GL_TEXTURE_2D,
727                                     GL_GENERATE_MIPMAP,
728                                     GL_FALSE) );
729         }
730 #endif
731
732       tex_2d->mipmaps_dirty = FALSE;
733     }
734 }
735
736 static void
737 _cogl_texture_2d_ensure_non_quad_rendering (CoglTexture *tex)
738 {
739   /* Nothing needs to be done */
740 }
741
742 static gboolean
743 _cogl_texture_2d_set_region (CoglTexture    *tex,
744                              int             src_x,
745                              int             src_y,
746                              int             dst_x,
747                              int             dst_y,
748                              unsigned int    dst_width,
749                              unsigned int    dst_height,
750                              CoglBitmap     *bmp)
751 {
752   CoglTexture2D *tex_2d = COGL_TEXTURE_2D (tex);
753   GLenum         gl_format;
754   GLenum         gl_type;
755   guint8        *data;
756
757   _COGL_GET_CONTEXT (ctx, FALSE);
758
759   bmp = _cogl_texture_prepare_for_upload (bmp,
760                                           cogl_texture_get_format (tex),
761                                           NULL,
762                                           NULL,
763                                           &gl_format,
764                                           &gl_type);
765
766   /* If this touches the first pixel then we'll update our copy */
767   if (dst_x == 0 && dst_y == 0 &&
768       !cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN) &&
769       (data = _cogl_bitmap_map (bmp, COGL_BUFFER_ACCESS_READ, 0)))
770     {
771       CoglPixelFormat bpp =
772         _cogl_pixel_format_get_bytes_per_pixel (cogl_bitmap_get_format (bmp));
773       tex_2d->first_pixel.gl_format = gl_format;
774       tex_2d->first_pixel.gl_type = gl_type;
775       memcpy (tex_2d->first_pixel.data,
776               data + cogl_bitmap_get_rowstride (bmp) * src_y + bpp * src_x,
777               bpp);
778
779       _cogl_bitmap_unmap (bmp);
780     }
781
782   /* Send data to GL */
783   ctx->texture_driver->upload_subregion_to_gl (GL_TEXTURE_2D,
784                                                tex_2d->gl_texture,
785                                                FALSE,
786                                                src_x, src_y,
787                                                dst_x, dst_y,
788                                                dst_width, dst_height,
789                                                bmp,
790                                                gl_format,
791                                                gl_type);
792
793   tex_2d->mipmaps_dirty = TRUE;
794
795   cogl_object_unref (bmp);
796
797   return TRUE;
798 }
799
800 static gboolean
801 _cogl_texture_2d_get_data (CoglTexture     *tex,
802                            CoglPixelFormat  format,
803                            unsigned int     rowstride,
804                            guint8          *data)
805 {
806   CoglTexture2D   *tex_2d = COGL_TEXTURE_2D (tex);
807   int              bpp;
808   GLenum           gl_format;
809   GLenum           gl_type;
810
811   _COGL_GET_CONTEXT (ctx, FALSE);
812
813   bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
814
815   ctx->texture_driver->pixel_format_to_gl (format,
816                                            NULL, /* internal format */
817                                            &gl_format,
818                                            &gl_type);
819
820   ctx->texture_driver->prep_gl_for_pixels_download (rowstride, bpp);
821
822   _cogl_bind_gl_texture_transient (GL_TEXTURE_2D,
823                                    tex_2d->gl_texture,
824                                    tex_2d->is_foreign);
825   return ctx->texture_driver->gl_get_tex_image (GL_TEXTURE_2D,
826                                                 gl_format,
827                                                 gl_type,
828                                                 data);
829 }
830
831 static CoglPixelFormat
832 _cogl_texture_2d_get_format (CoglTexture *tex)
833 {
834   return COGL_TEXTURE_2D (tex)->format;
835 }
836
837 static GLenum
838 _cogl_texture_2d_get_gl_format (CoglTexture *tex)
839 {
840   return COGL_TEXTURE_2D (tex)->gl_format;
841 }
842
843 static int
844 _cogl_texture_2d_get_width (CoglTexture *tex)
845 {
846   return COGL_TEXTURE_2D (tex)->width;
847 }
848
849 static int
850 _cogl_texture_2d_get_height (CoglTexture *tex)
851 {
852   return COGL_TEXTURE_2D (tex)->height;
853 }
854
855 static gboolean
856 _cogl_texture_2d_is_foreign (CoglTexture *tex)
857 {
858   return COGL_TEXTURE_2D (tex)->is_foreign;
859 }
860
861 static CoglTextureType
862 _cogl_texture_2d_get_type (CoglTexture *tex)
863 {
864   return COGL_TEXTURE_TYPE_2D;
865 }
866
867 static const CoglTextureVtable
868 cogl_texture_2d_vtable =
869   {
870     _cogl_texture_2d_set_region,
871     _cogl_texture_2d_get_data,
872     NULL, /* foreach_sub_texture_in_region */
873     _cogl_texture_2d_get_max_waste,
874     _cogl_texture_2d_is_sliced,
875     _cogl_texture_2d_can_hardware_repeat,
876     _cogl_texture_2d_transform_coords_to_gl,
877     _cogl_texture_2d_transform_quad_coords_to_gl,
878     _cogl_texture_2d_get_gl_texture,
879     _cogl_texture_2d_set_filters,
880     _cogl_texture_2d_pre_paint,
881     _cogl_texture_2d_ensure_non_quad_rendering,
882     _cogl_texture_2d_set_wrap_mode_parameters,
883     _cogl_texture_2d_get_format,
884     _cogl_texture_2d_get_gl_format,
885     _cogl_texture_2d_get_width,
886     _cogl_texture_2d_get_height,
887     _cogl_texture_2d_get_type,
888     _cogl_texture_2d_is_foreign
889   };