/** * glTextureView (ARB_texture_view) * If an error is found, record it with _mesa_error() * \return none. */ void GLAPIENTRY _mesa_TextureView(GLuint texture, GLenum target, GLuint origtexture, GLenum internalformat, GLuint minlevel, GLuint numlevels, GLuint minlayer, GLuint numlayers) { struct gl_texture_object *texObj; struct gl_texture_object *origTexObj; struct gl_texture_image *origTexImage; GLuint newViewMinLevel, newViewMinLayer; GLuint newViewNumLevels, newViewNumLayers; GLsizei width, height, depth; mesa_format texFormat; GLboolean sizeOK, dimensionsOK; GLenum faceTarget; GET_CURRENT_CONTEXT(ctx); if (MESA_VERBOSE & (VERBOSE_API | VERBOSE_TEXTURE)) _mesa_debug(ctx, "glTextureView %d %s %d %s %d %d %d %d\n", texture, _mesa_lookup_enum_by_nr(target), origtexture, _mesa_lookup_enum_by_nr(internalformat), minlevel, numlevels, minlayer, numlayers); if (origtexture == 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(origtexture = %u)", origtexture); return; } /* Need original texture information to validate arguments */ origTexObj = _mesa_lookup_texture(ctx, origtexture); /* If <origtexture> is not the name of a texture, INVALID_VALUE is generated. */ if (!origTexObj) { _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(origtexture = %u)", origtexture); return; } /* If <origtexture>'s TEXTURE_IMMUTABLE_FORMAT value is not TRUE, * INVALID_OPERATION is generated. */ if (!origTexObj->Immutable) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(origtexture not immutable)"); return; } /* If <texture> is 0, INVALID_VALUE is generated. */ if (texture == 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(texture = 0)"); return; } /* If <texture> is not a valid name returned by GenTextures, * the error INVALID_OPERATION is generated. */ texObj = _mesa_lookup_texture(ctx, texture); if (texObj == NULL) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(texture = %u non-gen name)", texture); return; } /* If <texture> has already been bound and given a target, then * the error INVALID_OPERATION is generated. */ if (texObj->Target) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(texture = %u already bound)", texture); return; } /* Check for compatible target */ if (!target_valid(ctx, origTexObj->Target, target)) { return; /* error was recorded */ } /* minlevel and minlayer are relative to the view of origtexture * If minlevel or minlayer is greater than level or layer, respectively, * of origtexture return INVALID_VALUE. */ newViewMinLevel = origTexObj->MinLevel + minlevel; newViewMinLayer = origTexObj->MinLayer + minlayer; if (newViewMinLevel >= (origTexObj->MinLevel + origTexObj->NumLevels)) { _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(new minlevel (%d) > orig minlevel (%d) + orig numlevels (%d))", newViewMinLevel, origTexObj->MinLevel, origTexObj->NumLevels); return; } if (newViewMinLayer >= (origTexObj->MinLayer + origTexObj->NumLayers)) { _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(new minlayer (%d) > orig minlayer (%d) + orig numlayers (%d))", newViewMinLayer, origTexObj->MinLayer, origTexObj->NumLayers); return; } if (!_mesa_texture_view_compatible_format(ctx, origTexObj->Image[0][0]->InternalFormat, internalformat)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(internalformat %s not compatible with origtexture %s)", _mesa_lookup_enum_by_nr(internalformat), _mesa_lookup_enum_by_nr(origTexObj->Image[0][0]->InternalFormat)); return; } texFormat = _mesa_choose_texture_format(ctx, texObj, target, 0, internalformat, GL_NONE, GL_NONE); assert(texFormat != MESA_FORMAT_NONE); if (texFormat == MESA_FORMAT_NONE) return; newViewNumLevels = MIN2(numlevels, origTexObj->NumLevels - minlevel); newViewNumLayers = MIN2(numlayers, origTexObj->NumLayers - minlayer); faceTarget = origTexObj->Target; if (faceTarget == GL_TEXTURE_CUBE_MAP) faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + minlayer; /* Get a reference to what will become this View's base level */ origTexImage = _mesa_select_tex_image(origTexObj, faceTarget, minlevel); width = origTexImage->Width; height = origTexImage->Height; depth = origTexImage->Depth; /* Adjust width, height, depth to be appropriate for new target */ switch (target) { case GL_TEXTURE_1D: height = 1; break; case GL_TEXTURE_3D: break; case GL_TEXTURE_1D_ARRAY: height = (GLsizei) newViewNumLayers; break; case GL_TEXTURE_2D: case GL_TEXTURE_2D_MULTISAMPLE: case GL_TEXTURE_RECTANGLE: case GL_TEXTURE_CUBE_MAP: depth = 1; break; case GL_TEXTURE_2D_ARRAY: case GL_TEXTURE_CUBE_MAP_ARRAY: case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: depth = newViewNumLayers; break; } /* If the dimensions of the original texture are larger than the maximum * supported dimensions of the new target, the error INVALID_OPERATION is * generated. For example, if the original texture has a TEXTURE_2D_ARRAY * target and its width is greater than MAX_CUBE_MAP_TEXTURE_SIZE, an error * will be generated if TextureView is called to create a TEXTURE_CUBE_MAP * view. */ dimensionsOK = _mesa_legal_texture_dimensions(ctx, target, 0, width, height, depth, 0); if (!dimensionsOK) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(invalid width or height or depth)"); return; } sizeOK = ctx->Driver.TestProxyTexImage(ctx, target, 0, texFormat, width, height, depth, 0); if (!sizeOK) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(invalid texture size)"); return; } /* If <target> is TEXTURE_1D, TEXTURE_2D, TEXTURE_3D, TEXTURE_RECTANGLE, * or TEXTURE_2D_MULTISAMPLE and <numlayers> does not equal 1, the error * INVALID_VALUE is generated. */ switch (target) { case GL_TEXTURE_1D: case GL_TEXTURE_2D: case GL_TEXTURE_3D: case GL_TEXTURE_RECTANGLE: case GL_TEXTURE_2D_MULTISAMPLE: if (numlayers != 1) { _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(numlayers %d != 1)", numlayers); return; } break; case GL_TEXTURE_CUBE_MAP: /* If the new texture's target is TEXTURE_CUBE_MAP, the clamped <numlayers> * must be equal to 6. */ if (newViewNumLayers != 6) { _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(clamped numlayers %d != 6)", newViewNumLayers); return; } break; case GL_TEXTURE_CUBE_MAP_ARRAY: /* If the new texture's target is TEXTURE_CUBE_MAP_ARRAY, * then <numlayers> counts layer-faces rather than layers, * and the clamped <numlayers> must be a multiple of 6. * Otherwise, the error INVALID_VALUE is generated. */ if ((newViewNumLayers % 6) != 0) { _mesa_error(ctx, GL_INVALID_VALUE, "glTextureView(clamped numlayers %d is not a multiple of 6)", newViewNumLayers); return; } break; } /* If the new texture's target is TEXTURE_CUBE_MAP or * TEXTURE_CUBE_MAP_ARRAY, the width and height of the original texture's * levels must be equal otherwise the error INVALID_OPERATION is generated. */ if ((target == GL_TEXTURE_CUBE_MAP || target == GL_TEXTURE_CUBE_MAP_ARRAY) && (origTexImage->Width != origTexImage->Height)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTextureView(origtexture width (%d) != height (%d))", origTexImage->Width, origTexImage->Height); return; } /* When the original texture's target is TEXTURE_CUBE_MAP, the layer * parameters are interpreted in the same order as if it were a * TEXTURE_CUBE_MAP_ARRAY with 6 layer-faces. */ /* If the internal format does not exactly match the internal format of the * original texture, the contents of the memory are reinterpreted in the * same manner as for image bindings described in * section 3.9.20 (Texture Image Loads and Stores). */ /* TEXTURE_BASE_LEVEL and TEXTURE_MAX_LEVEL are interpreted * relative to the view and not relative to the original data store. */ if (!initialize_texture_fields(ctx, target, texObj, newViewNumLevels, width, height, depth, internalformat, texFormat)) { return; /* Already recorded error */ } texObj->MinLevel = newViewMinLevel; texObj->MinLayer = newViewMinLayer; texObj->NumLevels = newViewNumLevels; texObj->NumLayers = newViewNumLayers; texObj->Immutable = GL_TRUE; texObj->ImmutableLevels = origTexObj->ImmutableLevels; texObj->Target = target; if (ctx->Driver.TextureView != NULL && !ctx->Driver.TextureView(ctx, texObj, origTexObj)) { return; /* driver recorded error */ } }
/** * Helper that does the storage allocation for _mesa_TexStorage1/2/3D() * and _mesa_TextureStorage1/2/3D(). */ static void texture_storage(struct gl_context *ctx, GLuint dims, struct gl_texture_object *texObj, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, bool dsa) { GLboolean sizeOK, dimensionsOK; mesa_format texFormat; const char* suffix = dsa ? "ture" : ""; assert(texObj); if (tex_storage_error_check(ctx, texObj, dims, target, levels, internalformat, width, height, depth, dsa)) { return; /* error was recorded */ } texFormat = _mesa_choose_texture_format(ctx, texObj, target, 0, internalformat, GL_NONE, GL_NONE); /* check that width, height, depth are legal for the mipmap level */ dimensionsOK = _mesa_legal_texture_dimensions(ctx, target, 0, width, height, depth, 0); sizeOK = ctx->Driver.TestProxyTexImage(ctx, target, levels, 0, texFormat, 1, width, height, depth); if (_mesa_is_proxy_texture(target)) { if (dimensionsOK && sizeOK) { initialize_texture_fields(ctx, texObj, levels, width, height, depth, internalformat, texFormat); } else { /* clear all image fields for [levels] */ clear_texture_fields(ctx, texObj); } } else { if (!dimensionsOK) { _mesa_error(ctx, GL_INVALID_VALUE, "glTex%sStorage%uD(invalid width, height or depth)", suffix, dims); return; } if (!sizeOK) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTex%sStorage%uD(texture too large)", suffix, dims); } assert(levels > 0); assert(width > 0); assert(height > 0); assert(depth > 0); if (!initialize_texture_fields(ctx, texObj, levels, width, height, depth, internalformat, texFormat)) { return; } /* Do actual texture memory allocation */ if (!ctx->Driver.AllocTextureStorage(ctx, texObj, levels, width, height, depth)) { /* Reset the texture images' info to zeros. * Strictly speaking, we probably don't have to do this since * generating GL_OUT_OF_MEMORY can leave things in an undefined * state but this puts things in a consistent state. */ clear_texture_fields(ctx, texObj); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTex%sStorage%uD", suffix, dims); return; } _mesa_set_texture_view_state(ctx, texObj, target, levels); update_fbo_texture(ctx, texObj); } }
/** * Helper used by _mesa_TexStorage1/2/3D(). */ static void texstorage(GLuint dims, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { struct gl_texture_object *texObj; GLboolean sizeOK, dimensionsOK; gl_format texFormat; GET_CURRENT_CONTEXT(ctx); if (tex_storage_error_check(ctx, dims, target, levels, internalformat, width, height, depth)) { return; /* error was recorded */ } texObj = _mesa_get_current_tex_object(ctx, target); assert(texObj); texFormat = _mesa_choose_texture_format(ctx, texObj, target, 0, internalformat, GL_NONE, GL_NONE); assert(texFormat != MESA_FORMAT_NONE); /* check that width, height, depth are legal for the mipmap level */ dimensionsOK = _mesa_legal_texture_dimensions(ctx, target, 0, width, height, depth, 0); sizeOK = ctx->Driver.TestProxyTexImage(ctx, target, 0, texFormat, width, height, depth, 0); if (_mesa_is_proxy_texture(texObj->Target)) { if (dimensionsOK && sizeOK) { initialize_texture_fields(ctx, texObj, levels, width, height, depth, internalformat, texFormat); } else { /* clear all image fields for [levels] */ clear_texture_fields(ctx, texObj); } } else { if (!dimensionsOK) { _mesa_error(ctx, GL_INVALID_VALUE, "glTexStorage%uD(invalid width, height or depth)", dims); return; } if (!sizeOK) { _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexStorage%uD(texture too large)", dims); } assert(levels > 0); assert(width > 0); assert(height > 0); assert(depth > 0); if (!initialize_texture_fields(ctx, texObj, levels, width, height, depth, internalformat, texFormat)) { return; } /* Do actual texture memory allocation */ if (!ctx->Driver.AllocTextureStorage(ctx, texObj, levels, width, height, depth)) { /* Reset the texture images' info to zeros. * Strictly speaking, we probably don't have to do this since * generating GL_OUT_OF_MEMORY can leave things in an undefined * state but this puts things in a consistent state. */ clear_texture_fields(ctx, texObj); _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexStorage%uD", dims); return; } texObj->Immutable = GL_TRUE; texObj->ImmutableLevels = levels; } }