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