mesa: Cosmetic changes in legal_texobj_target
[mesa.git] / src / mesa / main / texstorage.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2011 VMware, Inc. All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25 /**
26 * \file texstorage.c
27 * GL_ARB_texture_storage functions
28 */
29
30 #include "glheader.h"
31 #include "context.h"
32 #include "enums.h"
33 #include "imports.h"
34 #include "macros.h"
35 #include "teximage.h"
36 #include "texobj.h"
37 #include "mipmap.h"
38 #include "texstorage.h"
39 #include "textureview.h"
40 #include "mtypes.h"
41 #include "glformats.h"
42 #include "hash.h"
43
44
45 /**
46 * Check if the given texture target is a legal texture object target
47 * for a glTexStorage() command.
48 * This is a bit different than legal_teximage_target() when it comes
49 * to cube maps.
50 */
51 static bool
52 legal_texobj_target(const struct gl_context *ctx, GLuint dims, GLenum target)
53 {
54 if (dims < 1 || dims > 3) {
55 _mesa_problem(ctx, "invalid dims=%u in legal_texobj_target()", dims);
56 return false;
57 }
58
59 switch (dims) {
60 case 2:
61 switch (target) {
62 case GL_TEXTURE_2D:
63 return true;
64 case GL_TEXTURE_CUBE_MAP:
65 return ctx->Extensions.ARB_texture_cube_map;
66 }
67 break;
68 case 3:
69 switch (target) {
70 case GL_TEXTURE_3D:
71 return true;
72 case GL_TEXTURE_2D_ARRAY:
73 return ctx->Extensions.EXT_texture_array;
74 }
75 break;
76 }
77
78 if (!_mesa_is_desktop_gl(ctx))
79 return false;
80
81 switch (dims) {
82 case 1:
83 switch (target) {
84 case GL_TEXTURE_1D:
85 case GL_PROXY_TEXTURE_1D:
86 return true;
87 default:
88 return false;
89 }
90 case 2:
91 switch (target) {
92 case GL_PROXY_TEXTURE_2D:
93 return true;
94 case GL_PROXY_TEXTURE_CUBE_MAP:
95 return ctx->Extensions.ARB_texture_cube_map;
96 case GL_TEXTURE_RECTANGLE:
97 case GL_PROXY_TEXTURE_RECTANGLE:
98 return ctx->Extensions.NV_texture_rectangle;
99 case GL_TEXTURE_1D_ARRAY:
100 case GL_PROXY_TEXTURE_1D_ARRAY:
101 return ctx->Extensions.EXT_texture_array;
102 default:
103 return false;
104 }
105 case 3:
106 switch (target) {
107 case GL_PROXY_TEXTURE_3D:
108 return true;
109 case GL_PROXY_TEXTURE_2D_ARRAY:
110 return ctx->Extensions.EXT_texture_array;
111 case GL_TEXTURE_CUBE_MAP_ARRAY:
112 case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY:
113 return ctx->Extensions.ARB_texture_cube_map_array;
114 default:
115 return false;
116 }
117 default:
118 unreachable("impossible dimensions");
119 }
120 }
121
122
123 /** Helper to get a particular texture image in a texture object */
124 static struct gl_texture_image *
125 get_tex_image(struct gl_context *ctx,
126 struct gl_texture_object *texObj,
127 GLuint face, GLuint level)
128 {
129 const GLenum faceTarget =
130 (texObj->Target == GL_TEXTURE_CUBE_MAP ||
131 texObj->Target == GL_PROXY_TEXTURE_CUBE_MAP)
132 ? GL_TEXTURE_CUBE_MAP_POSITIVE_X + face : texObj->Target;
133 return _mesa_get_tex_image(ctx, texObj, faceTarget, level);
134 }
135
136
137
138 static GLboolean
139 initialize_texture_fields(struct gl_context *ctx,
140 struct gl_texture_object *texObj,
141 GLint levels,
142 GLsizei width, GLsizei height, GLsizei depth,
143 GLenum internalFormat, mesa_format texFormat)
144 {
145 const GLenum target = texObj->Target;
146 const GLuint numFaces = _mesa_num_tex_faces(target);
147 GLint level, levelWidth = width, levelHeight = height, levelDepth = depth;
148 GLuint face;
149
150 /* Set up all the texture object's gl_texture_images */
151 for (level = 0; level < levels; level++) {
152 for (face = 0; face < numFaces; face++) {
153 struct gl_texture_image *texImage =
154 get_tex_image(ctx, texObj, face, level);
155
156 if (!texImage) {
157 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexStorage");
158 return GL_FALSE;
159 }
160
161 _mesa_init_teximage_fields(ctx, texImage,
162 levelWidth, levelHeight, levelDepth,
163 0, internalFormat, texFormat);
164 }
165
166 _mesa_next_mipmap_level_size(target, 0,
167 levelWidth, levelHeight, levelDepth,
168 &levelWidth, &levelHeight, &levelDepth);
169 }
170 return GL_TRUE;
171 }
172
173
174 /**
175 * Clear all fields of texture object to zeros. Used for proxy texture tests
176 * and to clean up when a texture memory allocation fails.
177 */
178 static void
179 clear_texture_fields(struct gl_context *ctx,
180 struct gl_texture_object *texObj)
181 {
182 const GLenum target = texObj->Target;
183 const GLuint numFaces = _mesa_num_tex_faces(target);
184 GLint level;
185 GLuint face;
186
187 for (level = 0; level < ARRAY_SIZE(texObj->Image[0]); level++) {
188 for (face = 0; face < numFaces; face++) {
189 struct gl_texture_image *texImage =
190 get_tex_image(ctx, texObj, face, level);
191
192 if (!texImage) {
193 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexStorage");
194 return;
195 }
196
197 _mesa_clear_texture_image(ctx, texImage);
198 }
199 }
200 }
201
202
203 /**
204 * Update/re-validate framebuffer object.
205 */
206 static void
207 update_fbo_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
208 {
209 const unsigned numFaces = _mesa_num_tex_faces(texObj->Target);
210 for (int level = 0; level < ARRAY_SIZE(texObj->Image[0]); level++) {
211 for (unsigned face = 0; face < numFaces; face++)
212 _mesa_update_fbo_texture(ctx, texObj, face, level);
213 }
214 }
215
216
217 GLboolean
218 _mesa_is_legal_tex_storage_format(const struct gl_context *ctx,
219 GLenum internalformat)
220 {
221 /* check internal format - note that only sized formats are allowed */
222 switch (internalformat) {
223 case GL_ALPHA:
224 case GL_LUMINANCE:
225 case GL_LUMINANCE_ALPHA:
226 case GL_INTENSITY:
227 case GL_RED:
228 case GL_RG:
229 case GL_RGB:
230 case GL_RGBA:
231 case GL_BGRA:
232 case GL_DEPTH_COMPONENT:
233 case GL_DEPTH_STENCIL:
234 case GL_COMPRESSED_ALPHA:
235 case GL_COMPRESSED_LUMINANCE_ALPHA:
236 case GL_COMPRESSED_LUMINANCE:
237 case GL_COMPRESSED_INTENSITY:
238 case GL_COMPRESSED_RGB:
239 case GL_COMPRESSED_RGBA:
240 case GL_COMPRESSED_SRGB:
241 case GL_COMPRESSED_SRGB_ALPHA:
242 case GL_COMPRESSED_SLUMINANCE:
243 case GL_COMPRESSED_SLUMINANCE_ALPHA:
244 case GL_RED_INTEGER:
245 case GL_GREEN_INTEGER:
246 case GL_BLUE_INTEGER:
247 case GL_ALPHA_INTEGER:
248 case GL_RGB_INTEGER:
249 case GL_RGBA_INTEGER:
250 case GL_BGR_INTEGER:
251 case GL_BGRA_INTEGER:
252 case GL_LUMINANCE_INTEGER_EXT:
253 case GL_LUMINANCE_ALPHA_INTEGER_EXT:
254 /* these unsized formats are illegal */
255 return GL_FALSE;
256 default:
257 return _mesa_base_tex_format(ctx, internalformat) > 0;
258 }
259 }
260
261
262 /**
263 * Default ctx->Driver.AllocTextureStorage() handler.
264 *
265 * The driver can override this with a more specific implementation if it
266 * desires, but this can be used to get the texture images allocated using the
267 * usual texture image handling code. The immutability of
268 * GL_ARB_texture_storage texture layouts is handled by texObj->Immutable
269 * checks at glTexImage* time.
270 */
271 GLboolean
272 _mesa_AllocTextureStorage_sw(struct gl_context *ctx,
273 struct gl_texture_object *texObj,
274 GLsizei levels, GLsizei width,
275 GLsizei height, GLsizei depth)
276 {
277 const int numFaces = _mesa_num_tex_faces(texObj->Target);
278 int face;
279 int level;
280
281 (void) width;
282 (void) height;
283 (void) depth;
284
285 for (face = 0; face < numFaces; face++) {
286 for (level = 0; level < levels; level++) {
287 struct gl_texture_image *const texImage = texObj->Image[face][level];
288 if (!ctx->Driver.AllocTextureImageBuffer(ctx, texImage))
289 return GL_FALSE;
290 }
291 }
292
293 return GL_TRUE;
294 }
295
296
297 /**
298 * Do error checking for calls to glTexStorage1/2/3D().
299 * If an error is found, record it with _mesa_error(), unless the target
300 * is a proxy texture.
301 * \return GL_TRUE if any error, GL_FALSE otherwise.
302 */
303 static GLboolean
304 tex_storage_error_check(struct gl_context *ctx,
305 struct gl_texture_object *texObj,
306 GLuint dims, GLenum target,
307 GLsizei levels, GLenum internalformat,
308 GLsizei width, GLsizei height, GLsizei depth,
309 bool dsa)
310 {
311 const char* suffix = dsa ? "ture" : "";
312
313 /* Legal format checking has been moved to texstorage and texturestorage in
314 * order to allow meta functions to use legacy formats. */
315
316 /* size check */
317 if (!_mesa_valid_tex_storage_dim(width, height, depth)) {
318 _mesa_error(ctx, GL_INVALID_VALUE,
319 "glTex%sStorage%uD(width, height or depth < 1)",
320 suffix, dims);
321 return GL_TRUE;
322 }
323
324 if (_mesa_is_compressed_format(ctx, internalformat)) {
325 GLenum err;
326 if (!_mesa_target_can_be_compressed(ctx, target, internalformat, &err)) {
327 _mesa_error(ctx, err,
328 "glTex%sStorage%dD(internalformat = %s)", suffix, dims,
329 _mesa_enum_to_string(internalformat));
330 return GL_TRUE;
331 }
332 }
333
334 /* levels check */
335 if (levels < 1) {
336 _mesa_error(ctx, GL_INVALID_VALUE, "glTex%sStorage%uD(levels < 1)",
337 suffix, dims);
338 return GL_TRUE;
339 }
340
341 /* check levels against maximum (note different error than above) */
342 if (levels > (GLint) _mesa_max_texture_levels(ctx, target)) {
343 _mesa_error(ctx, GL_INVALID_OPERATION,
344 "glTex%sStorage%uD(levels too large)",
345 suffix, dims);
346 return GL_TRUE;
347 }
348
349 /* check levels against width/height/depth */
350 if (levels > _mesa_get_tex_max_num_levels(target, width, height, depth)) {
351 _mesa_error(ctx, GL_INVALID_OPERATION,
352 "glTex%sStorage%uD(too many levels"
353 " for max texture dimension)",
354 suffix, dims);
355 return GL_TRUE;
356 }
357
358 /* non-default texture object check */
359 if (!_mesa_is_proxy_texture(target) && (!texObj || (texObj->Name == 0))) {
360 _mesa_error(ctx, GL_INVALID_OPERATION,
361 "glTex%sStorage%uD(texture object 0)",
362 suffix, dims);
363 return GL_TRUE;
364 }
365
366 /* Check if texObj->Immutable is set */
367 if (!_mesa_is_proxy_texture(target) && texObj->Immutable) {
368 _mesa_error(ctx, GL_INVALID_OPERATION, "glTex%sStorage%uD(immutable)",
369 suffix, dims);
370 return GL_TRUE;
371 }
372
373 /* additional checks for depth textures */
374 if (!_mesa_legal_texture_base_format_for_target(ctx, target, internalformat)) {
375 _mesa_error(ctx, GL_INVALID_OPERATION, "glTex%sStorage%uD(bad target for texture)",
376 suffix, dims);
377 return GL_TRUE;
378 }
379
380 return GL_FALSE;
381 }
382
383
384 /**
385 * Helper that does the storage allocation for _mesa_TexStorage1/2/3D()
386 * and _mesa_TextureStorage1/2/3D().
387 */
388 void
389 _mesa_texture_storage(struct gl_context *ctx, GLuint dims,
390 struct gl_texture_object *texObj,
391 GLenum target, GLsizei levels,
392 GLenum internalformat, GLsizei width,
393 GLsizei height, GLsizei depth, bool dsa)
394 {
395 GLboolean sizeOK, dimensionsOK;
396 mesa_format texFormat;
397 const char* suffix = dsa ? "ture" : "";
398
399 assert(texObj);
400
401 if (tex_storage_error_check(ctx, texObj, dims, target, levels,
402 internalformat, width, height, depth, dsa)) {
403 return; /* error was recorded */
404 }
405
406 texFormat = _mesa_choose_texture_format(ctx, texObj, target, 0,
407 internalformat, GL_NONE, GL_NONE);
408 assert(texFormat != MESA_FORMAT_NONE);
409
410 /* check that width, height, depth are legal for the mipmap level */
411 dimensionsOK = _mesa_legal_texture_dimensions(ctx, target, 0,
412 width, height, depth, 0);
413
414 sizeOK = ctx->Driver.TestProxyTexImage(ctx, target, levels, 0, texFormat,
415 1, width, height, depth);
416
417 if (_mesa_is_proxy_texture(target)) {
418 if (dimensionsOK && sizeOK) {
419 initialize_texture_fields(ctx, texObj, levels, width, height, depth,
420 internalformat, texFormat);
421 }
422 else {
423 /* clear all image fields for [levels] */
424 clear_texture_fields(ctx, texObj);
425 }
426 }
427 else {
428 if (!dimensionsOK) {
429 _mesa_error(ctx, GL_INVALID_VALUE,
430 "glTex%sStorage%uD(invalid width, height or depth)",
431 suffix, dims);
432 return;
433 }
434
435 if (!sizeOK) {
436 _mesa_error(ctx, GL_OUT_OF_MEMORY,
437 "glTex%sStorage%uD(texture too large)",
438 suffix, dims);
439 }
440
441 assert(levels > 0);
442 assert(width > 0);
443 assert(height > 0);
444 assert(depth > 0);
445
446 if (!initialize_texture_fields(ctx, texObj, levels, width, height, depth,
447 internalformat, texFormat)) {
448 return;
449 }
450
451 /* Do actual texture memory allocation */
452 if (!ctx->Driver.AllocTextureStorage(ctx, texObj, levels,
453 width, height, depth)) {
454 /* Reset the texture images' info to zeros.
455 * Strictly speaking, we probably don't have to do this since
456 * generating GL_OUT_OF_MEMORY can leave things in an undefined
457 * state but this puts things in a consistent state.
458 */
459 clear_texture_fields(ctx, texObj);
460 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTex%sStorage%uD",
461 suffix, dims);
462 return;
463 }
464
465 _mesa_set_texture_view_state(ctx, texObj, target, levels);
466
467 update_fbo_texture(ctx, texObj);
468 }
469 }
470
471
472 /**
473 * Helper used by _mesa_TexStorage1/2/3D().
474 */
475 static void
476 texstorage(GLuint dims, GLenum target, GLsizei levels, GLenum internalformat,
477 GLsizei width, GLsizei height, GLsizei depth)
478 {
479 struct gl_texture_object *texObj;
480 GET_CURRENT_CONTEXT(ctx);
481
482 /* Check target. This is done here so that _mesa_texture_storage
483 * can receive unsized formats.
484 */
485 if (!legal_texobj_target(ctx, dims, target)) {
486 _mesa_error(ctx, GL_INVALID_ENUM,
487 "glTexStorage%uD(illegal target=%s)",
488 dims, _mesa_enum_to_string(target));
489 return;
490 }
491
492 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
493 _mesa_debug(ctx, "glTexStorage%uD %s %d %s %d %d %d\n",
494 dims,
495 _mesa_enum_to_string(target), levels,
496 _mesa_enum_to_string(internalformat),
497 width, height, depth);
498
499 /* Check the format to make sure it is sized. */
500 if (!_mesa_is_legal_tex_storage_format(ctx, internalformat)) {
501 _mesa_error(ctx, GL_INVALID_ENUM,
502 "glTexStorage%uD(internalformat = %s)", dims,
503 _mesa_enum_to_string(internalformat));
504 return;
505 }
506
507 texObj = _mesa_get_current_tex_object(ctx, target);
508 if (!texObj)
509 return;
510
511 _mesa_texture_storage(ctx, dims, texObj, target, levels,
512 internalformat, width, height, depth, false);
513 }
514
515
516 /**
517 * Helper used by _mesa_TextureStorage1/2/3D().
518 */
519 static void
520 texturestorage(GLuint dims, GLuint texture, GLsizei levels,
521 GLenum internalformat, GLsizei width, GLsizei height,
522 GLsizei depth)
523 {
524 struct gl_texture_object *texObj;
525 GET_CURRENT_CONTEXT(ctx);
526
527 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
528 _mesa_debug(ctx, "glTextureStorage%uD %d %d %s %d %d %d\n",
529 dims, texture, levels,
530 _mesa_enum_to_string(internalformat),
531 width, height, depth);
532
533 /* Check the format to make sure it is sized. */
534 if (!_mesa_is_legal_tex_storage_format(ctx, internalformat)) {
535 _mesa_error(ctx, GL_INVALID_ENUM,
536 "glTextureStorage%uD(internalformat = %s)", dims,
537 _mesa_enum_to_string(internalformat));
538 return;
539 }
540
541 /* Get the texture object by Name. */
542 texObj = _mesa_lookup_texture(ctx, texture);
543 if (!texObj) {
544 _mesa_error(ctx, GL_INVALID_OPERATION,
545 "glTextureStorage%uD(texture = %d)", dims, texture);
546 return;
547 }
548
549 /* Check target. This is done here so that _mesa_texture_storage
550 * can receive unsized formats.
551 */
552 if (!legal_texobj_target(ctx, dims, texObj->Target)) {
553 _mesa_error(ctx, GL_INVALID_ENUM,
554 "glTextureStorage%uD(illegal target=%s)",
555 dims, _mesa_enum_to_string(texObj->Target));
556 return;
557 }
558
559 _mesa_texture_storage(ctx, dims, texObj, texObj->Target,
560 levels, internalformat, width, height, depth, true);
561 }
562
563
564 void GLAPIENTRY
565 _mesa_TexStorage1D(GLenum target, GLsizei levels, GLenum internalformat,
566 GLsizei width)
567 {
568 texstorage(1, target, levels, internalformat, width, 1, 1);
569 }
570
571
572 void GLAPIENTRY
573 _mesa_TexStorage2D(GLenum target, GLsizei levels, GLenum internalformat,
574 GLsizei width, GLsizei height)
575 {
576 texstorage(2, target, levels, internalformat, width, height, 1);
577 }
578
579
580 void GLAPIENTRY
581 _mesa_TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat,
582 GLsizei width, GLsizei height, GLsizei depth)
583 {
584 texstorage(3, target, levels, internalformat, width, height, depth);
585 }
586
587
588 void GLAPIENTRY
589 _mesa_TextureStorage1D(GLuint texture, GLsizei levels, GLenum internalformat,
590 GLsizei width)
591 {
592 texturestorage(1, texture, levels, internalformat, width, 1, 1);
593 }
594
595
596 void GLAPIENTRY
597 _mesa_TextureStorage2D(GLuint texture, GLsizei levels,
598 GLenum internalformat,
599 GLsizei width, GLsizei height)
600 {
601 texturestorage(2, texture, levels, internalformat, width, height, 1);
602 }
603
604
605 void GLAPIENTRY
606 _mesa_TextureStorage3D(GLuint texture, GLsizei levels, GLenum internalformat,
607 GLsizei width, GLsizei height, GLsizei depth)
608 {
609 texturestorage(3, texture, levels, internalformat, width, height, depth);
610 }
611
612
613 /*
614 * Note: we don't support GL_EXT_direct_state_access and the spec says
615 * we don't need the following functions. However, glew checks for the
616 * presence of all six functions and will say that GL_ARB_texture_storage
617 * is not supported if these functions are missing.
618 */
619
620
621 void GLAPIENTRY
622 _mesa_TextureStorage1DEXT(GLuint texture, GLenum target, GLsizei levels,
623 GLenum internalformat,
624 GLsizei width)
625 {
626 GET_CURRENT_CONTEXT(ctx);
627
628 (void) texture;
629 (void) target;
630 (void) levels;
631 (void) internalformat;
632 (void) width;
633
634 _mesa_error(ctx, GL_INVALID_OPERATION,
635 "glTextureStorage1DEXT not supported");
636 }
637
638
639 void GLAPIENTRY
640 _mesa_TextureStorage2DEXT(GLuint texture, GLenum target, GLsizei levels,
641 GLenum internalformat,
642 GLsizei width, GLsizei height)
643 {
644 GET_CURRENT_CONTEXT(ctx);
645
646 (void) texture;
647 (void) target;
648 (void) levels;
649 (void) internalformat;
650 (void) width;
651 (void) height;
652
653 _mesa_error(ctx, GL_INVALID_OPERATION,
654 "glTextureStorage2DEXT not supported");
655 }
656
657
658 void GLAPIENTRY
659 _mesa_TextureStorage3DEXT(GLuint texture, GLenum target, GLsizei levels,
660 GLenum internalformat,
661 GLsizei width, GLsizei height, GLsizei depth)
662 {
663 GET_CURRENT_CONTEXT(ctx);
664
665 (void) texture;
666 (void) target;
667 (void) levels;
668 (void) internalformat;
669 (void) width;
670 (void) height;
671 (void) depth;
672
673 _mesa_error(ctx, GL_INVALID_OPERATION,
674 "glTextureStorage3DEXT not supported");
675 }