"Initial commit to Gerrit"
[profile/ivi/cogl.git] / cogl / cogl-texture-rectangle.c
1 /*
2  * Cogl
3  *
4  * An object oriented GL/GLES Abstraction/Utility Layer
5  *
6  * Copyright (C) 2010 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-rectangle-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
41 #include <string.h>
42 #include <math.h>
43
44 /* These aren't defined under GLES */
45 #ifndef GL_TEXTURE_RECTANGLE_ARB
46 #define GL_TEXTURE_RECTANGLE_ARB 0x84F5
47 #endif
48 #ifndef GL_CLAMP
49 #define GL_CLAMP                 0x2900
50 #endif
51 #ifndef GL_CLAMP_TO_BORDER
52 #define GL_CLAMP_TO_BORDER       0x812D
53 #endif
54
55 static void _cogl_texture_rectangle_free (CoglTextureRectangle *tex_rect);
56
57 COGL_TEXTURE_DEFINE (TextureRectangle, texture_rectangle);
58
59 static const CoglTextureVtable cogl_texture_rectangle_vtable;
60
61 static gboolean
62 can_use_wrap_mode (GLenum wrap_mode)
63 {
64   return (wrap_mode == GL_CLAMP ||
65           wrap_mode == GL_CLAMP_TO_EDGE ||
66           wrap_mode == GL_CLAMP_TO_BORDER);
67 }
68
69 static void
70 _cogl_texture_rectangle_set_wrap_mode_parameters (CoglTexture *tex,
71                                                   GLenum wrap_mode_s,
72                                                   GLenum wrap_mode_t,
73                                                   GLenum wrap_mode_p)
74 {
75   CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex);
76
77   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
78
79   /* Only set the wrap mode if it's different from the current value
80      to avoid too many GL calls. Texture rectangle doesn't make use of
81      the r coordinate so we can ignore its wrap mode */
82   if (tex_rect->wrap_mode_s != wrap_mode_s ||
83       tex_rect->wrap_mode_t != wrap_mode_t)
84     {
85       g_assert (can_use_wrap_mode (wrap_mode_s));
86       g_assert (can_use_wrap_mode (wrap_mode_t));
87
88       _cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB,
89                                        tex_rect->gl_texture,
90                                        tex_rect->is_foreign);
91       GE( ctx, glTexParameteri (GL_TEXTURE_RECTANGLE_ARB,
92                                 GL_TEXTURE_WRAP_S, wrap_mode_s) );
93       GE( ctx, glTexParameteri (GL_TEXTURE_RECTANGLE_ARB,
94                                 GL_TEXTURE_WRAP_T, wrap_mode_t) );
95
96       tex_rect->wrap_mode_s = wrap_mode_s;
97       tex_rect->wrap_mode_t = wrap_mode_t;
98     }
99 }
100
101 static void
102 _cogl_texture_rectangle_free (CoglTextureRectangle *tex_rect)
103 {
104   if (!tex_rect->is_foreign)
105     _cogl_delete_gl_texture (tex_rect->gl_texture);
106
107   /* Chain up */
108   _cogl_texture_free (COGL_TEXTURE (tex_rect));
109 }
110
111 static gboolean
112 _cogl_texture_rectangle_can_create (unsigned int width,
113                                     unsigned int height,
114                                     CoglPixelFormat internal_format,
115                                     GError **error)
116 {
117   GLenum gl_intformat;
118   GLenum gl_type;
119
120   _COGL_GET_CONTEXT (ctx, FALSE);
121
122   if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_RECTANGLE))
123     {
124       g_set_error (error,
125                    COGL_TEXTURE_ERROR,
126                    COGL_TEXTURE_ERROR_TYPE,
127                    "The CoglTextureRectangle feature isn't available");
128       return FALSE;
129     }
130
131   ctx->texture_driver->pixel_format_to_gl (internal_format,
132                                            &gl_intformat,
133                                            NULL,
134                                            &gl_type);
135
136   /* Check that the driver can create a texture with that size */
137   if (!ctx->texture_driver->size_supported (GL_TEXTURE_RECTANGLE_ARB,
138                                             gl_intformat,
139                                             gl_type,
140                                             width,
141                                             height))
142     {
143       g_set_error (error,
144                    COGL_TEXTURE_ERROR,
145                    COGL_TEXTURE_ERROR_SIZE,
146                    "The requested texture size + format is unsupported");
147       return FALSE;
148     }
149
150   return TRUE;
151 }
152
153 static CoglTextureRectangle *
154 _cogl_texture_rectangle_create_base (unsigned int     width,
155                                      unsigned int     height,
156                                      CoglPixelFormat  internal_format)
157 {
158   CoglTextureRectangle *tex_rect = g_new (CoglTextureRectangle, 1);
159   CoglTexture *tex = COGL_TEXTURE (tex_rect);
160
161   _cogl_texture_init (tex, &cogl_texture_rectangle_vtable);
162
163   tex_rect->width = width;
164   tex_rect->height = height;
165
166   /* We default to GL_LINEAR for both filters */
167   tex_rect->min_filter = GL_LINEAR;
168   tex_rect->mag_filter = GL_LINEAR;
169
170   /* Wrap mode not yet set */
171   tex_rect->wrap_mode_s = GL_FALSE;
172   tex_rect->wrap_mode_t = GL_FALSE;
173
174   tex_rect->format = internal_format;
175
176   return tex_rect;
177 }
178
179 CoglTextureRectangle *
180 cogl_texture_rectangle_new_with_size (CoglContext *ctx,
181                                       int width,
182                                       int height,
183                                       CoglPixelFormat internal_format,
184                                       GError **error)
185 {
186   CoglTextureRectangle *tex_rect;
187   GLenum                gl_intformat;
188   GLenum                gl_format;
189   GLenum                gl_type;
190
191   /* Since no data, we need some internal format */
192   if (internal_format == COGL_PIXEL_FORMAT_ANY)
193     internal_format = COGL_PIXEL_FORMAT_RGBA_8888_PRE;
194
195   if (!_cogl_texture_rectangle_can_create (width, height,
196                                            internal_format, error))
197     return NULL;
198
199   internal_format = ctx->texture_driver->pixel_format_to_gl (internal_format,
200                                                              &gl_intformat,
201                                                              &gl_format,
202                                                              &gl_type);
203
204   tex_rect = _cogl_texture_rectangle_create_base (width, height,
205                                                   internal_format);
206
207   ctx->texture_driver->gen (GL_TEXTURE_RECTANGLE_ARB, 1, &tex_rect->gl_texture);
208   _cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB,
209                                    tex_rect->gl_texture,
210                                    tex_rect->is_foreign);
211   GE( ctx, glTexImage2D (GL_TEXTURE_RECTANGLE_ARB, 0, gl_intformat,
212                          width, height, 0, gl_format, gl_type, NULL) );
213
214   return _cogl_texture_rectangle_object_new (tex_rect);
215 }
216
217 CoglTextureRectangle *
218 _cogl_texture_rectangle_new_from_bitmap (CoglBitmap      *bmp,
219                                          CoglTextureFlags flags,
220                                          CoglPixelFormat  internal_format)
221 {
222   CoglTextureRectangle *tex_rect;
223   CoglBitmap           *dst_bmp;
224   GLenum                gl_intformat;
225   GLenum                gl_format;
226   GLenum                gl_type;
227
228   _COGL_GET_CONTEXT (ctx, NULL);
229
230   _COGL_RETURN_VAL_IF_FAIL (cogl_is_bitmap (bmp), NULL);
231
232   internal_format =
233     _cogl_texture_determine_internal_format (cogl_bitmap_get_format (bmp),
234                                              internal_format);
235
236   if (!_cogl_texture_rectangle_can_create (cogl_bitmap_get_width (bmp),
237                                            cogl_bitmap_get_height (bmp),
238                                            internal_format,
239                                            NULL))
240     return NULL;
241
242   dst_bmp = _cogl_texture_prepare_for_upload (bmp,
243                                               internal_format,
244                                               &internal_format,
245                                               &gl_intformat,
246                                               &gl_format,
247                                               &gl_type);
248
249   if (dst_bmp == NULL)
250     return NULL;
251
252   tex_rect = _cogl_texture_rectangle_create_base (cogl_bitmap_get_width (bmp),
253                                                   cogl_bitmap_get_height (bmp),
254                                                   internal_format);
255
256   ctx->texture_driver->gen (GL_TEXTURE_RECTANGLE_ARB, 1, &tex_rect->gl_texture);
257   ctx->texture_driver->upload_to_gl (GL_TEXTURE_RECTANGLE_ARB,
258                                      tex_rect->gl_texture,
259                                      FALSE,
260                                      dst_bmp,
261                                      gl_intformat,
262                                      gl_format,
263                                      gl_type);
264
265   tex_rect->gl_format = gl_intformat;
266
267   cogl_object_unref (dst_bmp);
268
269   return _cogl_texture_rectangle_object_new (tex_rect);
270 }
271
272 CoglTextureRectangle *
273 _cogl_texture_rectangle_new_from_foreign (GLuint gl_handle,
274                                           GLuint width,
275                                           GLuint height,
276                                           CoglPixelFormat format)
277 {
278   /* NOTE: width, height and internal format are not queriable
279    * in GLES, hence such a function prototype.
280    */
281
282   GLenum                gl_error      = 0;
283   GLint                 gl_compressed = GL_FALSE;
284   GLenum                gl_int_format = 0;
285   CoglTextureRectangle *tex_rect;
286
287   _COGL_GET_CONTEXT (ctx, NULL);
288
289   if (!ctx->texture_driver->allows_foreign_gl_target (GL_TEXTURE_RECTANGLE_ARB))
290     return NULL;
291
292   /* Make sure it is a valid GL texture object */
293   if (!ctx->glIsTexture (gl_handle))
294     return NULL;
295
296   /* Make sure binding succeeds */
297   while ((gl_error = ctx->glGetError ()) != GL_NO_ERROR)
298     ;
299
300   _cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB, gl_handle, TRUE);
301   if (ctx->glGetError () != GL_NO_ERROR)
302     return NULL;
303
304   /* Obtain texture parameters */
305
306 #if HAVE_COGL_GL
307   if (ctx->driver == COGL_DRIVER_GL)
308     {
309       GLint val;
310
311       GE( ctx, glGetTexLevelParameteriv (GL_TEXTURE_RECTANGLE_ARB, 0,
312                                          GL_TEXTURE_COMPRESSED,
313                                          &gl_compressed) );
314
315       GE( ctx, glGetTexLevelParameteriv (GL_TEXTURE_RECTANGLE_ARB, 0,
316                                          GL_TEXTURE_INTERNAL_FORMAT,
317                                          &val) );
318
319       gl_int_format = val;
320
321       /* If we can query GL for the actual pixel format then we'll ignore
322          the passed in format and use that. */
323       if (!ctx->texture_driver->pixel_format_from_gl_internal (gl_int_format,
324                                                                &format))
325         return NULL;
326     }
327   else
328 #endif
329     {
330       /* Otherwise we'll assume we can derive the GL format from the
331          passed in format */
332       ctx->texture_driver->pixel_format_to_gl (format,
333                                                &gl_int_format,
334                                                NULL,
335                                                NULL);
336     }
337
338   /* Note: We always trust the given width and height without querying
339    * the texture object because the user may be creating a Cogl
340    * texture for a texture_from_pixmap object where glTexImage2D may
341    * not have been called and the texture_from_pixmap spec doesn't
342    * clarify that it is reliable to query back the size from OpenGL.
343    */
344
345   /* Validate width and height */
346   if (width <= 0 || height <= 0)
347     return NULL;
348
349   /* Compressed texture images not supported */
350   if (gl_compressed == GL_TRUE)
351     return NULL;
352
353   /* Create new texture */
354   tex_rect = _cogl_texture_rectangle_create_base (width, height, format);
355
356   /* Setup bitmap info */
357   tex_rect->is_foreign = TRUE;
358
359   tex_rect->format = format;
360
361   tex_rect->gl_texture = gl_handle;
362   tex_rect->gl_format = gl_int_format;
363
364   /* Unknown filter */
365   tex_rect->min_filter = GL_FALSE;
366   tex_rect->mag_filter = GL_FALSE;
367
368   return _cogl_texture_rectangle_handle_new (tex_rect);
369 }
370
371 static int
372 _cogl_texture_rectangle_get_max_waste (CoglTexture *tex)
373 {
374   return -1;
375 }
376
377 static gboolean
378 _cogl_texture_rectangle_is_sliced (CoglTexture *tex)
379 {
380   return FALSE;
381 }
382
383 static gboolean
384 _cogl_texture_rectangle_can_hardware_repeat (CoglTexture *tex)
385 {
386   return FALSE;
387 }
388
389 static void
390 _cogl_texture_rectangle_transform_coords_to_gl (CoglTexture *tex,
391                                                 float *s,
392                                                 float *t)
393 {
394   CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex);
395
396   *s *= tex_rect->width;
397   *t *= tex_rect->height;
398 }
399
400 static CoglTransformResult
401 _cogl_texture_rectangle_transform_quad_coords_to_gl (CoglTexture *tex,
402                                                      float *coords)
403 {
404   CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex);
405   gboolean need_repeat = FALSE;
406   int i;
407
408   for (i = 0; i < 4; i++)
409     {
410       if (coords[i] < 0.0f || coords[i] > 1.0f)
411         need_repeat = TRUE;
412       coords[i] *= (i & 1) ? tex_rect->height : tex_rect->width;
413     }
414
415   return (need_repeat ? COGL_TRANSFORM_SOFTWARE_REPEAT
416           : COGL_TRANSFORM_NO_REPEAT);
417 }
418
419 static gboolean
420 _cogl_texture_rectangle_get_gl_texture (CoglTexture *tex,
421                                         GLuint *out_gl_handle,
422                                         GLenum *out_gl_target)
423 {
424   CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex);
425
426   if (out_gl_handle)
427     *out_gl_handle = tex_rect->gl_texture;
428
429   if (out_gl_target)
430     *out_gl_target = GL_TEXTURE_RECTANGLE_ARB;
431
432   return TRUE;
433 }
434
435 static void
436 _cogl_texture_rectangle_set_filters (CoglTexture *tex,
437                                      GLenum       min_filter,
438                                      GLenum       mag_filter)
439 {
440   CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex);
441
442   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
443
444   if (min_filter == tex_rect->min_filter
445       && mag_filter == tex_rect->mag_filter)
446     return;
447
448   /* Rectangle textures don't support mipmapping */
449   g_assert (min_filter == GL_LINEAR || min_filter == GL_NEAREST);
450
451   /* Store new values */
452   tex_rect->min_filter = min_filter;
453   tex_rect->mag_filter = mag_filter;
454
455   /* Apply new filters to the texture */
456   _cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB,
457                                    tex_rect->gl_texture,
458                                    tex_rect->is_foreign);
459   GE( ctx, glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER,
460                             mag_filter) );
461   GE( ctx, glTexParameteri (GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER,
462                             min_filter) );
463 }
464
465 static void
466 _cogl_texture_rectangle_pre_paint (CoglTexture *tex,
467                                    CoglTexturePrePaintFlags flags)
468 {
469   _COGL_GET_CONTEXT (ctx, NO_RETVAL);
470
471   /* Rectangle textures don't support mipmaps */
472   g_assert ((flags & COGL_TEXTURE_NEEDS_MIPMAP) == 0);
473 }
474
475 static void
476 _cogl_texture_rectangle_ensure_non_quad_rendering (CoglTexture *tex)
477 {
478   /* Nothing needs to be done */
479 }
480
481 static gboolean
482 _cogl_texture_rectangle_set_region (CoglTexture    *tex,
483                                     int             src_x,
484                                     int             src_y,
485                                     int             dst_x,
486                                     int             dst_y,
487                                     unsigned int    dst_width,
488                                     unsigned int    dst_height,
489                                     CoglBitmap     *bmp)
490 {
491   CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex);
492   GLenum                gl_format;
493   GLenum                gl_type;
494
495   _COGL_GET_CONTEXT (ctx, FALSE);
496
497   bmp = _cogl_texture_prepare_for_upload (bmp,
498                                           cogl_texture_get_format (tex),
499                                           NULL,
500                                           NULL,
501                                           &gl_format,
502                                           &gl_type);
503
504   /* Send data to GL */
505   ctx->texture_driver->upload_subregion_to_gl (GL_TEXTURE_RECTANGLE_ARB,
506                                                tex_rect->gl_texture,
507                                                FALSE,
508                                                src_x, src_y,
509                                                dst_x, dst_y,
510                                                dst_width, dst_height,
511                                                bmp,
512                                                gl_format,
513                                                gl_type);
514
515   cogl_object_unref (bmp);
516
517   return TRUE;
518 }
519
520 static gboolean
521 _cogl_texture_rectangle_get_data (CoglTexture     *tex,
522                                   CoglPixelFormat  format,
523                                   unsigned int     rowstride,
524                                   guint8          *data)
525 {
526   CoglTextureRectangle *tex_rect = COGL_TEXTURE_RECTANGLE (tex);
527   int                   bpp;
528   GLenum                gl_format;
529   GLenum                gl_type;
530
531   _COGL_GET_CONTEXT (ctx, FALSE);
532
533   bpp = _cogl_pixel_format_get_bytes_per_pixel (format);
534
535   ctx->texture_driver->pixel_format_to_gl (format,
536                                            NULL, /* internal format */
537                                            &gl_format,
538                                            &gl_type);
539
540   ctx->texture_driver->prep_gl_for_pixels_download (rowstride, bpp);
541
542   _cogl_bind_gl_texture_transient (GL_TEXTURE_RECTANGLE_ARB,
543                                    tex_rect->gl_texture,
544                                    tex_rect->is_foreign);
545   return ctx->texture_driver->gl_get_tex_image (GL_TEXTURE_RECTANGLE_ARB,
546                                                 gl_format,
547                                                 gl_type,
548                                                 data);
549 }
550
551 static CoglPixelFormat
552 _cogl_texture_rectangle_get_format (CoglTexture *tex)
553 {
554   return COGL_TEXTURE_RECTANGLE (tex)->format;
555 }
556
557 static GLenum
558 _cogl_texture_rectangle_get_gl_format (CoglTexture *tex)
559 {
560   return COGL_TEXTURE_RECTANGLE (tex)->gl_format;
561 }
562
563 static int
564 _cogl_texture_rectangle_get_width (CoglTexture *tex)
565 {
566   return COGL_TEXTURE_RECTANGLE (tex)->width;
567 }
568
569 static int
570 _cogl_texture_rectangle_get_height (CoglTexture *tex)
571 {
572   return COGL_TEXTURE_RECTANGLE (tex)->height;
573 }
574
575 static gboolean
576 _cogl_texture_rectangle_is_foreign (CoglTexture *tex)
577 {
578   return COGL_TEXTURE_RECTANGLE (tex)->is_foreign;
579 }
580
581 static CoglTextureType
582 _cogl_texture_rectangle_get_type (CoglTexture *tex)
583 {
584   return COGL_TEXTURE_TYPE_RECTANGLE;
585 }
586
587 static const CoglTextureVtable
588 cogl_texture_rectangle_vtable =
589   {
590     _cogl_texture_rectangle_set_region,
591     _cogl_texture_rectangle_get_data,
592     NULL, /* foreach_sub_texture_in_region */
593     _cogl_texture_rectangle_get_max_waste,
594     _cogl_texture_rectangle_is_sliced,
595     _cogl_texture_rectangle_can_hardware_repeat,
596     _cogl_texture_rectangle_transform_coords_to_gl,
597     _cogl_texture_rectangle_transform_quad_coords_to_gl,
598     _cogl_texture_rectangle_get_gl_texture,
599     _cogl_texture_rectangle_set_filters,
600     _cogl_texture_rectangle_pre_paint,
601     _cogl_texture_rectangle_ensure_non_quad_rendering,
602     _cogl_texture_rectangle_set_wrap_mode_parameters,
603     _cogl_texture_rectangle_get_format,
604     _cogl_texture_rectangle_get_gl_format,
605     _cogl_texture_rectangle_get_width,
606     _cogl_texture_rectangle_get_height,
607     _cogl_texture_rectangle_get_type,
608     _cogl_texture_rectangle_is_foreign
609   };