1 /*
2  * Cogl
3  *
4  * A Low Level GPU Graphics and Utilities API
5  *
6  * Copyright (C) 2010 Intel Corporation.
7  *
8  * Permission is hereby granted, free of charge, to any person
9  * obtaining a copy of this software and associated documentation
10  * files (the "Software"), to deal in the Software without
11  * restriction, including without limitation the rights to use, copy,
12  * modify, merge, publish, distribute, sublicense, and/or sell copies
13  * of the Software, and to permit persons to whom the Software is
14  * furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be
17  * included in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26  * SOFTWARE.
27  *
28  * Authors:
29  *  Neil Roberts   <neil@linux.intel.com>
30  */
31 
32 #ifdef HAVE_CONFIG_H
33 #include "cogl-config.h"
34 #endif
35 
36 #include "cogl-private.h"
37 #include "cogl-util.h"
38 #include "cogl-texture-private.h"
39 #include "cogl-texture-3d-private.h"
40 #include "cogl-texture-3d.h"
41 #include "cogl-texture-gl-private.h"
42 #include "cogl-texture-driver.h"
43 #include "cogl-context-private.h"
44 #include "cogl-object-private.h"
45 #include "cogl-journal-private.h"
46 #include "cogl-pipeline-private.h"
47 #include "cogl-pipeline-opengl-private.h"
48 #include "cogl-error-private.h"
49 #include "cogl-util-gl-private.h"
50 #include "cogl-gtype-private.h"
51 
52 #include <string.h>
53 #include <math.h>
54 
55 /* These might not be defined on GLES */
56 #ifndef GL_TEXTURE_3D
57 #define GL_TEXTURE_3D                           0x806F
58 #endif
59 #ifndef GL_TEXTURE_WRAP_R
60 #define GL_TEXTURE_WRAP_R                       0x8072
61 #endif
62 
63 static void _cogl_texture_3d_free (CoglTexture3D *tex_3d);
64 
65 COGL_TEXTURE_DEFINE (Texture3D, texture_3d);
66 COGL_GTYPE_DEFINE_CLASS (Texture3D, texture_3d,
67                          COGL_GTYPE_IMPLEMENT_INTERFACE (texture));
68 
69 static const CoglTextureVtable cogl_texture_3d_vtable;
70 
71 static void
_cogl_texture_3d_gl_flush_legacy_texobj_wrap_modes(CoglTexture * tex,GLenum wrap_mode_s,GLenum wrap_mode_t,GLenum wrap_mode_p)72 _cogl_texture_3d_gl_flush_legacy_texobj_wrap_modes (CoglTexture *tex,
73                                                     GLenum wrap_mode_s,
74                                                     GLenum wrap_mode_t,
75                                                     GLenum wrap_mode_p)
76 {
77   CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex);
78   CoglContext *ctx = tex->context;
79 
80   /* Only set the wrap mode if it's different from the current value
81      to avoid too many GL calls. */
82   if (tex_3d->gl_legacy_texobj_wrap_mode_s != wrap_mode_s ||
83       tex_3d->gl_legacy_texobj_wrap_mode_t != wrap_mode_t ||
84       tex_3d->gl_legacy_texobj_wrap_mode_p != wrap_mode_p)
85     {
86       _cogl_bind_gl_texture_transient (GL_TEXTURE_3D,
87                                        tex_3d->gl_texture,
88                                        FALSE);
89       GE( ctx, glTexParameteri (GL_TEXTURE_3D,
90                                 GL_TEXTURE_WRAP_S,
91                                 wrap_mode_s) );
92       GE( ctx, glTexParameteri (GL_TEXTURE_3D,
93                                 GL_TEXTURE_WRAP_T,
94                                 wrap_mode_t) );
95       GE( ctx, glTexParameteri (GL_TEXTURE_3D,
96                                 GL_TEXTURE_WRAP_R,
97                                 wrap_mode_p) );
98 
99       tex_3d->gl_legacy_texobj_wrap_mode_s = wrap_mode_s;
100       tex_3d->gl_legacy_texobj_wrap_mode_t = wrap_mode_t;
101       tex_3d->gl_legacy_texobj_wrap_mode_p = wrap_mode_p;
102     }
103 }
104 
105 static void
_cogl_texture_3d_free(CoglTexture3D * tex_3d)106 _cogl_texture_3d_free (CoglTexture3D *tex_3d)
107 {
108   if (tex_3d->gl_texture)
109     _cogl_delete_gl_texture (tex_3d->gl_texture);
110 
111   /* Chain up */
112   _cogl_texture_free (COGL_TEXTURE (tex_3d));
113 }
114 
115 static void
_cogl_texture_3d_set_auto_mipmap(CoglTexture * tex,CoglBool value)116 _cogl_texture_3d_set_auto_mipmap (CoglTexture *tex,
117                                   CoglBool value)
118 {
119   CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex);
120 
121   tex_3d->auto_mipmap = value;
122 }
123 
124 static CoglTexture3D *
_cogl_texture_3d_create_base(CoglContext * ctx,int width,int height,int depth,CoglPixelFormat internal_format,CoglTextureLoader * loader)125 _cogl_texture_3d_create_base (CoglContext *ctx,
126                               int width,
127                               int height,
128                               int depth,
129                               CoglPixelFormat internal_format,
130                               CoglTextureLoader *loader)
131 {
132   CoglTexture3D *tex_3d = g_new (CoglTexture3D, 1);
133   CoglTexture *tex = COGL_TEXTURE (tex_3d);
134 
135   _cogl_texture_init (tex, ctx, width, height,
136                       internal_format, loader, &cogl_texture_3d_vtable);
137 
138   tex_3d->gl_texture = 0;
139 
140   tex_3d->depth = depth;
141   tex_3d->mipmaps_dirty = TRUE;
142   tex_3d->auto_mipmap = TRUE;
143 
144   /* We default to GL_LINEAR for both filters */
145   tex_3d->gl_legacy_texobj_min_filter = GL_LINEAR;
146   tex_3d->gl_legacy_texobj_mag_filter = GL_LINEAR;
147 
148   /* Wrap mode not yet set */
149   tex_3d->gl_legacy_texobj_wrap_mode_s = GL_FALSE;
150   tex_3d->gl_legacy_texobj_wrap_mode_t = GL_FALSE;
151   tex_3d->gl_legacy_texobj_wrap_mode_p = GL_FALSE;
152 
153   return _cogl_texture_3d_object_new (tex_3d);
154 }
155 
156 CoglTexture3D *
cogl_texture_3d_new_with_size(CoglContext * ctx,int width,int height,int depth)157 cogl_texture_3d_new_with_size (CoglContext *ctx,
158                                int width,
159                                int height,
160                                int depth)
161 {
162   CoglTextureLoader *loader = _cogl_texture_create_loader ();
163   loader->src_type = COGL_TEXTURE_SOURCE_TYPE_SIZED;
164   loader->src.sized.width = width;
165   loader->src.sized.height = height;
166   loader->src.sized.depth = depth;
167 
168   return _cogl_texture_3d_create_base (ctx, width, height, depth,
169                                        COGL_PIXEL_FORMAT_RGBA_8888_PRE,
170                                        loader);
171 }
172 
173 CoglTexture3D *
cogl_texture_3d_new_from_bitmap(CoglBitmap * bmp,int height,int depth)174 cogl_texture_3d_new_from_bitmap (CoglBitmap *bmp,
175                                  int height,
176                                  int depth)
177 {
178   CoglTextureLoader *loader;
179 
180   _COGL_RETURN_VAL_IF_FAIL (bmp, NULL);
181 
182   loader = _cogl_texture_create_loader ();
183   loader->src_type = COGL_TEXTURE_SOURCE_TYPE_BITMAP;
184   loader->src.bitmap.bitmap = cogl_object_ref (bmp);
185   loader->src.bitmap.height = height;
186   loader->src.bitmap.depth = depth;
187   loader->src.bitmap.can_convert_in_place = FALSE; /* TODO add api for this */
188 
189   return _cogl_texture_3d_create_base (_cogl_bitmap_get_context (bmp),
190                                        cogl_bitmap_get_width (bmp),
191                                        height,
192                                        depth,
193                                        cogl_bitmap_get_format (bmp),
194                                        loader);
195 }
196 
197 CoglTexture3D *
cogl_texture_3d_new_from_data(CoglContext * context,int width,int height,int depth,CoglPixelFormat format,int rowstride,int image_stride,const uint8_t * data,CoglError ** error)198 cogl_texture_3d_new_from_data (CoglContext *context,
199                                int width,
200                                int height,
201                                int depth,
202                                CoglPixelFormat format,
203                                int rowstride,
204                                int image_stride,
205                                const uint8_t *data,
206                                CoglError **error)
207 {
208   CoglBitmap *bitmap;
209   CoglTexture3D *ret;
210 
211   _COGL_RETURN_VAL_IF_FAIL (data, NULL);
212   _COGL_RETURN_VAL_IF_FAIL (format != COGL_PIXEL_FORMAT_ANY, NULL);
213 
214   /* Rowstride from width if not given */
215   if (rowstride == 0)
216     rowstride = width * _cogl_pixel_format_get_bytes_per_pixel (format);
217   /* Image stride from height and rowstride if not given */
218   if (image_stride == 0)
219     image_stride = height * rowstride;
220 
221   if (image_stride < rowstride * height)
222     return NULL;
223 
224   /* GL doesn't support uploading when the image_stride isn't a
225      multiple of the rowstride. If this happens we'll just pack the
226      image into a new bitmap. The documentation for this function
227      recommends avoiding this situation. */
228   if (image_stride % rowstride != 0)
229     {
230       uint8_t *bmp_data;
231       int bmp_rowstride;
232       int z, y;
233 
234       bitmap = _cogl_bitmap_new_with_malloc_buffer (context,
235                                                     width,
236                                                     depth * height,
237                                                     format,
238                                                     error);
239       if (!bitmap)
240         return NULL;
241 
242       bmp_data = _cogl_bitmap_map (bitmap,
243                                    COGL_BUFFER_ACCESS_WRITE,
244                                    COGL_BUFFER_MAP_HINT_DISCARD,
245                                    error);
246 
247       if (bmp_data == NULL)
248         {
249           cogl_object_unref (bitmap);
250           return NULL;
251         }
252 
253       bmp_rowstride = cogl_bitmap_get_rowstride (bitmap);
254 
255       /* Copy all of the images in */
256       for (z = 0; z < depth; z++)
257         for (y = 0; y < height; y++)
258           memcpy (bmp_data + (z * bmp_rowstride * height +
259                               bmp_rowstride * y),
260                   data + z * image_stride + rowstride * y,
261                   bmp_rowstride);
262 
263       _cogl_bitmap_unmap (bitmap);
264     }
265   else
266     bitmap = cogl_bitmap_new_for_data (context,
267                                        width,
268                                        image_stride / rowstride * depth,
269                                        format,
270                                        rowstride,
271                                        (uint8_t *) data);
272 
273   ret = cogl_texture_3d_new_from_bitmap (bitmap,
274                                          height,
275                                          depth);
276 
277   cogl_object_unref (bitmap);
278 
279   if (ret &&
280       !cogl_texture_allocate (COGL_TEXTURE (ret), error))
281     {
282       cogl_object_unref (ret);
283       return NULL;
284     }
285 
286   return ret;
287 }
288 
289 static CoglBool
_cogl_texture_3d_can_create(CoglContext * ctx,int width,int height,int depth,CoglPixelFormat internal_format,CoglError ** error)290 _cogl_texture_3d_can_create (CoglContext *ctx,
291                              int width,
292                              int height,
293                              int depth,
294                              CoglPixelFormat internal_format,
295                              CoglError **error)
296 {
297   GLenum gl_intformat;
298   GLenum gl_type;
299 
300   /* This should only happen on GLES */
301   if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_3D))
302     {
303       _cogl_set_error (error,
304                        COGL_SYSTEM_ERROR,
305                        COGL_SYSTEM_ERROR_UNSUPPORTED,
306                        "3D textures are not supported by the GPU");
307       return FALSE;
308     }
309 
310   /* If NPOT textures aren't supported then the size must be a power
311      of two */
312   if (!cogl_has_feature (ctx, COGL_FEATURE_ID_TEXTURE_NPOT) &&
313       (!_cogl_util_is_pot (width) ||
314        !_cogl_util_is_pot (height) ||
315        !_cogl_util_is_pot (depth)))
316     {
317       _cogl_set_error (error,
318                        COGL_SYSTEM_ERROR,
319                        COGL_SYSTEM_ERROR_UNSUPPORTED,
320                        "A non-power-of-two size was requested but this is not "
321                        "supported by the GPU");
322       return FALSE;
323     }
324 
325   ctx->driver_vtable->pixel_format_to_gl (ctx,
326                                           internal_format,
327                                           &gl_intformat,
328                                           NULL,
329                                           &gl_type);
330 
331   /* Check that the driver can create a texture with that size */
332   if (!ctx->texture_driver->size_supported_3d (ctx,
333                                                GL_TEXTURE_3D,
334                                                gl_intformat,
335                                                gl_type,
336                                                width,
337                                                height,
338                                                depth))
339     {
340       _cogl_set_error (error,
341                        COGL_SYSTEM_ERROR,
342                        COGL_SYSTEM_ERROR_UNSUPPORTED,
343                        "The requested dimensions are not supported by the GPU");
344       return FALSE;
345     }
346 
347   return TRUE;
348 }
349 
350 static CoglBool
allocate_with_size(CoglTexture3D * tex_3d,CoglTextureLoader * loader,CoglError ** error)351 allocate_with_size (CoglTexture3D *tex_3d,
352                     CoglTextureLoader *loader,
353                     CoglError **error)
354 {
355   CoglTexture *tex = COGL_TEXTURE (tex_3d);
356   CoglContext *ctx = tex->context;
357   CoglPixelFormat internal_format;
358   int width = loader->src.sized.width;
359   int height = loader->src.sized.height;
360   int depth = loader->src.sized.depth;
361   GLenum gl_intformat;
362   GLenum gl_format;
363   GLenum gl_type;
364   GLenum gl_texture;
365 
366   internal_format =
367     _cogl_texture_determine_internal_format (tex, COGL_PIXEL_FORMAT_ANY);
368 
369   if (!_cogl_texture_3d_can_create (ctx,
370                                     width,
371                                     height,
372                                     depth,
373                                     internal_format,
374                                     error))
375     return FALSE;
376 
377   ctx->driver_vtable->pixel_format_to_gl (ctx,
378                                           internal_format,
379                                           &gl_intformat,
380                                           &gl_format,
381                                           &gl_type);
382 
383   gl_texture =
384     ctx->texture_driver->gen (ctx, GL_TEXTURE_3D, internal_format);
385   _cogl_bind_gl_texture_transient (GL_TEXTURE_3D,
386                                    gl_texture,
387                                    FALSE);
388   /* Clear any GL errors */
389   _cogl_gl_util_clear_gl_errors (ctx);
390 
391   ctx->glTexImage3D (GL_TEXTURE_3D, 0, gl_intformat,
392                      width, height, depth,
393                      0, gl_format, gl_type, NULL);
394 
395   if (_cogl_gl_util_catch_out_of_memory (ctx, error))
396     {
397       GE( ctx, glDeleteTextures (1, &gl_texture) );
398       return FALSE;
399     }
400 
401   tex_3d->gl_texture = gl_texture;
402   tex_3d->gl_format = gl_intformat;
403 
404   tex_3d->depth = depth;
405 
406   tex_3d->internal_format = internal_format;
407 
408   _cogl_texture_set_allocated (tex, internal_format, width, height);
409 
410   return TRUE;
411 }
412 
413 static CoglBool
allocate_from_bitmap(CoglTexture3D * tex_3d,CoglTextureLoader * loader,CoglError ** error)414 allocate_from_bitmap (CoglTexture3D *tex_3d,
415                       CoglTextureLoader *loader,
416                       CoglError **error)
417 {
418   CoglTexture *tex = COGL_TEXTURE (tex_3d);
419   CoglContext *ctx = tex->context;
420   CoglPixelFormat internal_format;
421   CoglBitmap *bmp = loader->src.bitmap.bitmap;
422   int bmp_width = cogl_bitmap_get_width (bmp);
423   int height = loader->src.bitmap.height;
424   int depth = loader->src.bitmap.depth;
425   CoglPixelFormat bmp_format = cogl_bitmap_get_format (bmp);
426   CoglBool can_convert_in_place = loader->src.bitmap.can_convert_in_place;
427   CoglBitmap *upload_bmp;
428   CoglPixelFormat upload_format;
429   GLenum gl_intformat;
430   GLenum gl_format;
431   GLenum gl_type;
432 
433   internal_format = _cogl_texture_determine_internal_format (tex, bmp_format);
434 
435   if (!_cogl_texture_3d_can_create (ctx,
436                                     bmp_width, height, depth,
437                                     internal_format,
438                                     error))
439     return FALSE;
440 
441   upload_bmp = _cogl_bitmap_convert_for_upload (bmp,
442                                                 internal_format,
443                                                 can_convert_in_place,
444                                                 error);
445   if (upload_bmp == NULL)
446     return FALSE;
447 
448   upload_format = cogl_bitmap_get_format (upload_bmp);
449 
450   ctx->driver_vtable->pixel_format_to_gl (ctx,
451                                           upload_format,
452                                           NULL, /* internal format */
453                                           &gl_format,
454                                           &gl_type);
455   ctx->driver_vtable->pixel_format_to_gl (ctx,
456                                           internal_format,
457                                           &gl_intformat,
458                                           NULL,
459                                           NULL);
460 
461   /* Keep a copy of the first pixel so that if glGenerateMipmap isn't
462      supported we can fallback to using GL_GENERATE_MIPMAP */
463   if (!cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
464     {
465       CoglError *ignore = NULL;
466       uint8_t *data = _cogl_bitmap_map (upload_bmp,
467                                         COGL_BUFFER_ACCESS_READ, 0,
468                                         &ignore);
469 
470       tex_3d->first_pixel.gl_format = gl_format;
471       tex_3d->first_pixel.gl_type = gl_type;
472 
473       if (data)
474         {
475           memcpy (tex_3d->first_pixel.data, data,
476                   _cogl_pixel_format_get_bytes_per_pixel (upload_format));
477           _cogl_bitmap_unmap (upload_bmp);
478         }
479       else
480         {
481           g_warning ("Failed to read first pixel of bitmap for "
482                      "glGenerateMipmap fallback");
483           cogl_error_free (ignore);
484           memset (tex_3d->first_pixel.data, 0,
485                   _cogl_pixel_format_get_bytes_per_pixel (upload_format));
486         }
487     }
488 
489   tex_3d->gl_texture =
490     ctx->texture_driver->gen (ctx, GL_TEXTURE_3D, internal_format);
491 
492   if (!ctx->texture_driver->upload_to_gl_3d (ctx,
493                                              GL_TEXTURE_3D,
494                                              tex_3d->gl_texture,
495                                              FALSE, /* is_foreign */
496                                              height,
497                                              depth,
498                                              upload_bmp,
499                                              gl_intformat,
500                                              gl_format,
501                                              gl_type,
502                                              error))
503     {
504       cogl_object_unref (upload_bmp);
505       return FALSE;
506     }
507 
508   tex_3d->gl_format = gl_intformat;
509 
510   cogl_object_unref (upload_bmp);
511 
512   tex_3d->depth = loader->src.bitmap.depth;
513 
514   tex_3d->internal_format = internal_format;
515 
516   _cogl_texture_set_allocated (tex, internal_format,
517                                bmp_width, loader->src.bitmap.height);
518 
519   return TRUE;
520 }
521 
522 static CoglBool
_cogl_texture_3d_allocate(CoglTexture * tex,CoglError ** error)523 _cogl_texture_3d_allocate (CoglTexture *tex,
524                            CoglError **error)
525 {
526   CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex);
527   CoglTextureLoader *loader = tex->loader;
528 
529   _COGL_RETURN_VAL_IF_FAIL (loader, FALSE);
530 
531   switch (loader->src_type)
532     {
533     case COGL_TEXTURE_SOURCE_TYPE_SIZED:
534       return allocate_with_size (tex_3d, loader, error);
535     case COGL_TEXTURE_SOURCE_TYPE_BITMAP:
536       return allocate_from_bitmap (tex_3d, loader, error);
537     default:
538       break;
539     }
540 
541   g_return_val_if_reached (FALSE);
542 }
543 
544 static int
_cogl_texture_3d_get_max_waste(CoglTexture * tex)545 _cogl_texture_3d_get_max_waste (CoglTexture *tex)
546 {
547   return -1;
548 }
549 
550 static CoglBool
_cogl_texture_3d_is_sliced(CoglTexture * tex)551 _cogl_texture_3d_is_sliced (CoglTexture *tex)
552 {
553   return FALSE;
554 }
555 
556 static CoglBool
_cogl_texture_3d_can_hardware_repeat(CoglTexture * tex)557 _cogl_texture_3d_can_hardware_repeat (CoglTexture *tex)
558 {
559   return TRUE;
560 }
561 
562 static void
_cogl_texture_3d_transform_coords_to_gl(CoglTexture * tex,float * s,float * t)563 _cogl_texture_3d_transform_coords_to_gl (CoglTexture *tex,
564                                          float *s,
565                                          float *t)
566 {
567   /* The texture coordinates map directly so we don't need to do
568      anything */
569 }
570 
571 static CoglTransformResult
_cogl_texture_3d_transform_quad_coords_to_gl(CoglTexture * tex,float * coords)572 _cogl_texture_3d_transform_quad_coords_to_gl (CoglTexture *tex,
573                                               float *coords)
574 {
575   /* The texture coordinates map directly so we don't need to do
576      anything other than check for repeats */
577 
578   CoglBool need_repeat = FALSE;
579   int i;
580 
581   for (i = 0; i < 4; i++)
582     if (coords[i] < 0.0f || coords[i] > 1.0f)
583       need_repeat = TRUE;
584 
585   return (need_repeat ? COGL_TRANSFORM_HARDWARE_REPEAT
586           : COGL_TRANSFORM_NO_REPEAT);
587 }
588 
589 static CoglBool
_cogl_texture_3d_get_gl_texture(CoglTexture * tex,GLuint * out_gl_handle,GLenum * out_gl_target)590 _cogl_texture_3d_get_gl_texture (CoglTexture *tex,
591                                  GLuint *out_gl_handle,
592                                  GLenum *out_gl_target)
593 {
594   CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex);
595 
596   if (out_gl_handle)
597     *out_gl_handle = tex_3d->gl_texture;
598 
599   if (out_gl_target)
600     *out_gl_target = GL_TEXTURE_3D;
601 
602   return TRUE;
603 }
604 
605 static void
_cogl_texture_3d_gl_flush_legacy_texobj_filters(CoglTexture * tex,GLenum min_filter,GLenum mag_filter)606 _cogl_texture_3d_gl_flush_legacy_texobj_filters (CoglTexture *tex,
607                                                  GLenum min_filter,
608                                                  GLenum mag_filter)
609 {
610   CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex);
611   CoglContext *ctx = tex->context;
612 
613   if (min_filter == tex_3d->gl_legacy_texobj_min_filter
614       && mag_filter == tex_3d->gl_legacy_texobj_mag_filter)
615     return;
616 
617   /* Store new values */
618   tex_3d->gl_legacy_texobj_min_filter = min_filter;
619   tex_3d->gl_legacy_texobj_mag_filter = mag_filter;
620 
621   /* Apply new filters to the texture */
622   _cogl_bind_gl_texture_transient (GL_TEXTURE_3D,
623                                    tex_3d->gl_texture,
624                                    FALSE);
625   GE( ctx, glTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, mag_filter) );
626   GE( ctx, glTexParameteri (GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, min_filter) );
627 }
628 
629 static void
_cogl_texture_3d_pre_paint(CoglTexture * tex,CoglTexturePrePaintFlags flags)630 _cogl_texture_3d_pre_paint (CoglTexture *tex, CoglTexturePrePaintFlags flags)
631 {
632   CoglTexture3D *tex_3d = COGL_TEXTURE_3D (tex);
633   CoglContext *ctx = tex->context;
634 
635   /* Only update if the mipmaps are dirty */
636   if ((flags & COGL_TEXTURE_NEEDS_MIPMAP) &&
637       tex_3d->auto_mipmap && tex_3d->mipmaps_dirty)
638     {
639       /* glGenerateMipmap is defined in the FBO extension. If it's not
640          available we'll fallback to temporarily enabling
641          GL_GENERATE_MIPMAP and reuploading the first pixel */
642       if (cogl_has_feature (ctx, COGL_FEATURE_ID_OFFSCREEN))
643         _cogl_texture_gl_generate_mipmaps (tex);
644 #if defined (HAVE_COGL_GL) || defined (HAVE_COGL_GLES)
645       else if (_cogl_has_private_feature (ctx, COGL_PRIVATE_FEATURE_GL_FIXED))
646         {
647           _cogl_bind_gl_texture_transient (GL_TEXTURE_3D,
648                                            tex_3d->gl_texture,
649                                            FALSE);
650 
651           GE( ctx, glTexParameteri (GL_TEXTURE_3D,
652                                     GL_GENERATE_MIPMAP,
653                                     GL_TRUE) );
654           GE( ctx, glTexSubImage3D (GL_TEXTURE_3D,
655                                     0, /* level */
656                                     0, /* xoffset */
657                                     0, /* yoffset */
658                                     0, /* zoffset */
659                                     1, /* width */
660                                     1, /* height */
661                                     1, /* depth */
662                                     tex_3d->first_pixel.gl_format,
663                                     tex_3d->first_pixel.gl_type,
664                                     tex_3d->first_pixel.data) );
665           GE( ctx, glTexParameteri (GL_TEXTURE_3D,
666                                     GL_GENERATE_MIPMAP,
667                                     GL_FALSE) );
668         }
669 #endif
670 
671       tex_3d->mipmaps_dirty = FALSE;
672     }
673 }
674 
675 static void
_cogl_texture_3d_ensure_non_quad_rendering(CoglTexture * tex)676 _cogl_texture_3d_ensure_non_quad_rendering (CoglTexture *tex)
677 {
678   /* Nothing needs to be done */
679 }
680 
681 static CoglBool
_cogl_texture_3d_set_region(CoglTexture * tex,int src_x,int src_y,int dst_x,int dst_y,int dst_width,int dst_height,int level,CoglBitmap * bmp,CoglError ** error)682 _cogl_texture_3d_set_region (CoglTexture *tex,
683                              int src_x,
684                              int src_y,
685                              int dst_x,
686                              int dst_y,
687                              int dst_width,
688                              int dst_height,
689                              int level,
690                              CoglBitmap *bmp,
691                              CoglError **error)
692 {
693   /* This function doesn't really make sense for 3D textures because
694      it can't specify which image to upload to */
695   _cogl_set_error (error,
696                    COGL_SYSTEM_ERROR,
697                    COGL_SYSTEM_ERROR_UNSUPPORTED,
698                    "Setting a 2D region on a 3D texture isn't "
699                    "currently supported");
700 
701   return FALSE;
702 }
703 
704 static int
_cogl_texture_3d_get_data(CoglTexture * tex,CoglPixelFormat format,int rowstride,uint8_t * data)705 _cogl_texture_3d_get_data (CoglTexture *tex,
706                            CoglPixelFormat format,
707                            int rowstride,
708                            uint8_t *data)
709 {
710   /* FIXME: we could probably implement this by assuming the data is
711      big enough to hold all of the images and that there is no stride
712      between the images. However it would be better to have an API
713      that can provide an image stride and this function probably isn't
714      particularly useful anyway so for now it just reports failure */
715   return 0;
716 }
717 
718 static CoglPixelFormat
_cogl_texture_3d_get_format(CoglTexture * tex)719 _cogl_texture_3d_get_format (CoglTexture *tex)
720 {
721   return COGL_TEXTURE_3D (tex)->internal_format;
722 }
723 
724 static GLenum
_cogl_texture_3d_get_gl_format(CoglTexture * tex)725 _cogl_texture_3d_get_gl_format (CoglTexture *tex)
726 {
727   return COGL_TEXTURE_3D (tex)->gl_format;
728 }
729 
730 static CoglTextureType
_cogl_texture_3d_get_type(CoglTexture * tex)731 _cogl_texture_3d_get_type (CoglTexture *tex)
732 {
733   return COGL_TEXTURE_TYPE_3D;
734 }
735 
736 static const CoglTextureVtable
737 cogl_texture_3d_vtable =
738   {
739     TRUE, /* primitive */
740     _cogl_texture_3d_allocate,
741     _cogl_texture_3d_set_region,
742     _cogl_texture_3d_get_data,
743     NULL, /* foreach_sub_texture_in_region */
744     _cogl_texture_3d_get_max_waste,
745     _cogl_texture_3d_is_sliced,
746     _cogl_texture_3d_can_hardware_repeat,
747     _cogl_texture_3d_transform_coords_to_gl,
748     _cogl_texture_3d_transform_quad_coords_to_gl,
749     _cogl_texture_3d_get_gl_texture,
750     _cogl_texture_3d_gl_flush_legacy_texobj_filters,
751     _cogl_texture_3d_pre_paint,
752     _cogl_texture_3d_ensure_non_quad_rendering,
753     _cogl_texture_3d_gl_flush_legacy_texobj_wrap_modes,
754     _cogl_texture_3d_get_format,
755     _cogl_texture_3d_get_gl_format,
756     _cogl_texture_3d_get_type,
757     NULL, /* is_foreign */
758     _cogl_texture_3d_set_auto_mipmap
759   };
760