X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Ftexstorage.c;h=9fd969fbc53408dba6cab9c3676424f0aac5dd26;hb=ffd9c7fd74622b3c4271ea31df9e09b4180d4a5a;hp=675fd745b7106233de5c2a45c0858124c581d6b6;hpb=12dc4be8a66c92ce04637abc54ed85ac7ff9aa13;p=mesa.git diff --git a/src/mesa/main/texstorage.c b/src/mesa/main/texstorage.c index 675fd745b71..9fd969fbc53 100644 --- a/src/mesa/main/texstorage.c +++ b/src/mesa/main/texstorage.c @@ -16,30 +16,30 @@ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. */ - /** * \file texstorage.c * GL_ARB_texture_storage functions */ - - #include "glheader.h" #include "context.h" #include "enums.h" #include "imports.h" #include "macros.h" -#include "mfeatures.h" #include "teximage.h" #include "texobj.h" +#include "mipmap.h" #include "texstorage.h" +#include "textureview.h" #include "mtypes.h" - +#include "glformats.h" +#include "hash.h" /** @@ -51,6 +51,13 @@ static GLboolean legal_texobj_target(struct gl_context *ctx, GLuint dims, GLenum target) { + if (_mesa_is_gles3(ctx) + && target != GL_TEXTURE_2D + && target != GL_TEXTURE_CUBE_MAP + && target != GL_TEXTURE_3D + && target != GL_TEXTURE_2D_ARRAY) + return GL_FALSE; + switch (dims) { case 1: switch (target) { @@ -73,8 +80,7 @@ legal_texobj_target(struct gl_context *ctx, GLuint dims, GLenum target) return ctx->Extensions.NV_texture_rectangle; case GL_TEXTURE_1D_ARRAY: case GL_PROXY_TEXTURE_1D_ARRAY: - return (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array); + return ctx->Extensions.EXT_texture_array; default: return GL_FALSE; } @@ -85,8 +91,7 @@ legal_texobj_target(struct gl_context *ctx, GLuint dims, GLenum target) return GL_TRUE; case GL_TEXTURE_2D_ARRAY: case GL_PROXY_TEXTURE_2D_ARRAY: - return (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array); + return ctx->Extensions.EXT_texture_array; case GL_TEXTURE_CUBE_MAP_ARRAY: case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY: return ctx->Extensions.ARB_texture_cube_map_array; @@ -100,30 +105,9 @@ legal_texobj_target(struct gl_context *ctx, GLuint dims, GLenum target) } -/** - * Compute the size of the next mipmap level. - */ -static void -next_mipmap_level_size(GLenum target, - GLint *width, GLint *height, GLint *depth) -{ - if (*width > 1) { - *width /= 2; - } - - if ((*height > 1) && (target != GL_TEXTURE_1D_ARRAY)) { - *height /= 2; - } - - if ((*depth > 1) && (target != GL_TEXTURE_2D_ARRAY)) { - *depth /= 2; - } -} - - /** Helper to get a particular texture image in a texture object */ static struct gl_texture_image * -get_tex_image(struct gl_context *ctx, +get_tex_image(struct gl_context *ctx, struct gl_texture_object *texObj, GLuint face, GLuint level) { @@ -141,7 +125,7 @@ initialize_texture_fields(struct gl_context *ctx, struct gl_texture_object *texObj, GLint levels, GLsizei width, GLsizei height, GLsizei depth, - GLenum internalFormat, gl_format texFormat) + GLenum internalFormat, mesa_format texFormat) { const GLenum target = texObj->Target; const GLuint numFaces = _mesa_num_tex_faces(target); @@ -164,16 +148,17 @@ initialize_texture_fields(struct gl_context *ctx, 0, internalFormat, texFormat); } - next_mipmap_level_size(target, &levelWidth, &levelHeight, &levelDepth); + _mesa_next_mipmap_level_size(target, 0, + levelWidth, levelHeight, levelDepth, + &levelWidth, &levelHeight, &levelDepth); } return GL_TRUE; } /** - * Clear all fields of texture object to zeros. Used for proxy texture tests. - * Used for proxy texture tests (and to clean up when a texture memory - * allocation fails). + * Clear all fields of texture object to zeros. Used for proxy texture tests + * and to clean up when a texture memory allocation fails. */ static void clear_texture_fields(struct gl_context *ctx, @@ -184,7 +169,7 @@ clear_texture_fields(struct gl_context *ctx, GLint level; GLuint face; - for (level = 0; level < Elements(texObj->Image[0]); level++) { + for (level = 0; level < ARRAY_SIZE(texObj->Image[0]); level++) { for (face = 0; face < numFaces; face++) { struct gl_texture_image *texImage = get_tex_image(ctx, texObj, face, level); @@ -203,19 +188,23 @@ clear_texture_fields(struct gl_context *ctx, /** - * Do error checking for calls to glTexStorage1/2/3D(). - * If an error is found, record it with _mesa_error(), unless the target - * is a proxy texture. - * \return GL_TRUE if any error, GL_FALSE otherwise. + * Update/re-validate framebuffer object. */ -static GLboolean -tex_storage_error_check(struct gl_context *ctx, GLuint dims, GLenum target, - GLsizei levels, GLenum internalformat, - GLsizei width, GLsizei height, GLsizei depth) +static void +update_fbo_texture(struct gl_context *ctx, struct gl_texture_object *texObj) { - struct gl_texture_object *texObj; - GLboolean legalFormat; + const unsigned numFaces = _mesa_num_tex_faces(texObj->Target); + for (int level = 0; level < ARRAY_SIZE(texObj->Image[0]); level++) { + for (unsigned face = 0; face < numFaces; face++) + _mesa_update_fbo_texture(ctx, texObj, face, level); + } +} + +GLboolean +_mesa_is_legal_tex_storage_format(const struct gl_context *ctx, + GLenum internalformat) +{ /* check internal format - note that only sized formats are allowed */ switch (internalformat) { case GL_ALPHA: @@ -250,96 +239,157 @@ tex_storage_error_check(struct gl_context *ctx, GLuint dims, GLenum target, case GL_LUMINANCE_INTEGER_EXT: case GL_LUMINANCE_ALPHA_INTEGER_EXT: /* these unsized formats are illegal */ - legalFormat = GL_FALSE; - break; + return GL_FALSE; default: - legalFormat = _mesa_base_tex_format(ctx, internalformat) > 0; + return _mesa_base_tex_format(ctx, internalformat) > 0; } +} - if (!legalFormat) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glTexStorage%uD(internalformat = %s)", dims, - _mesa_lookup_enum_by_nr(internalformat)); - return GL_TRUE; + +/** + * Default ctx->Driver.AllocTextureStorage() handler. + * + * The driver can override this with a more specific implementation if it + * desires, but this can be used to get the texture images allocated using the + * usual texture image handling code. The immutability of + * GL_ARB_texture_storage texture layouts is handled by texObj->Immutable + * checks at glTexImage* time. + */ +GLboolean +_mesa_AllocTextureStorage_sw(struct gl_context *ctx, + struct gl_texture_object *texObj, + GLsizei levels, GLsizei width, + GLsizei height, GLsizei depth) +{ + const int numFaces = _mesa_num_tex_faces(texObj->Target); + int face; + int level; + + (void) width; + (void) height; + (void) depth; + + for (face = 0; face < numFaces; face++) { + for (level = 0; level < levels; level++) { + struct gl_texture_image *const texImage = texObj->Image[face][level]; + if (!ctx->Driver.AllocTextureImageBuffer(ctx, texImage)) + return GL_FALSE; + } } + return GL_TRUE; +} + + +/** + * Do error checking for calls to glTexStorage1/2/3D(). + * If an error is found, record it with _mesa_error(), unless the target + * is a proxy texture. + * \return GL_TRUE if any error, GL_FALSE otherwise. + */ +static GLboolean +tex_storage_error_check(struct gl_context *ctx, + struct gl_texture_object *texObj, + GLuint dims, GLenum target, + GLsizei levels, GLenum internalformat, + GLsizei width, GLsizei height, GLsizei depth, + bool dsa) +{ + const char* suffix = dsa ? "ture" : ""; + + /* Legal format checking has been moved to texstorage and texturestorage in + * order to allow meta functions to use legacy formats. */ + /* size check */ - if (width < 1 || height < 1 || depth < 1) { + if (!_mesa_valid_tex_storage_dim(width, height, depth)) { _mesa_error(ctx, GL_INVALID_VALUE, - "glTexStorage%uD(width, height or depth < 1)", dims); + "glTex%sStorage%uD(width, height or depth < 1)", + suffix, dims); return GL_TRUE; - } + } - /* target check */ - if (!legal_texobj_target(ctx, dims, target)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glTexStorage%uD(illegal target=%s)", - dims, _mesa_lookup_enum_by_nr(target)); - return GL_TRUE; + if (_mesa_is_compressed_format(ctx, internalformat)) { + GLenum err; + if (!_mesa_target_can_be_compressed(ctx, target, internalformat, &err)) { + _mesa_error(ctx, err, + "glTex%sStorage%dD(internalformat = %s)", suffix, dims, + _mesa_enum_to_string(internalformat)); + return GL_TRUE; + } } /* levels check */ if (levels < 1) { - _mesa_error(ctx, GL_INVALID_VALUE, "glTexStorage%uD(levels < 1)", - dims); + _mesa_error(ctx, GL_INVALID_VALUE, "glTex%sStorage%uD(levels < 1)", + suffix, dims); return GL_TRUE; - } + } /* check levels against maximum (note different error than above) */ if (levels > (GLint) _mesa_max_texture_levels(ctx, target)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glTexStorage%uD(levels too large)", dims); + "glTex%sStorage%uD(levels too large)", + suffix, dims); return GL_TRUE; } /* check levels against width/height/depth */ if (levels > _mesa_get_tex_max_num_levels(target, width, height, depth)) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glTexStorage%uD(too many levels for max texture dimension)", - dims); + "glTex%sStorage%uD(too many levels" + " for max texture dimension)", + suffix, dims); return GL_TRUE; } /* non-default texture object check */ - texObj = _mesa_get_current_tex_object(ctx, target); - if (!texObj || (texObj->Name == 0)) { + if (!_mesa_is_proxy_texture(target) && (!texObj || (texObj->Name == 0))) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glTexStorage%uD(texture object 0)", dims); + "glTex%sStorage%uD(texture object 0)", + suffix, dims); return GL_TRUE; } /* Check if texObj->Immutable is set */ - if (texObj->Immutable) { - _mesa_error(ctx, GL_INVALID_OPERATION, "glTexStorage%uD(immutable)", - dims); + if (!_mesa_is_proxy_texture(target) && texObj->Immutable) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glTex%sStorage%uD(immutable)", + suffix, dims); return GL_TRUE; } + /* additional checks for depth textures */ + if (!_mesa_legal_texture_base_format_for_target(ctx, target, internalformat, + dims, dsa ? + "glTextureStorage" : + "glTexStorage")) + return GL_TRUE; + return GL_FALSE; } /** - * Helper used by _mesa_TexStorage1/2/3D(). + * Helper that does the storage allocation for _mesa_TexStorage1/2/3D() + * and _mesa_TextureStorage1/2/3D(). */ -static void -texstorage(GLuint dims, GLenum target, GLsizei levels, GLenum internalformat, - GLsizei width, GLsizei height, GLsizei depth) +void +_mesa_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) { - struct gl_texture_object *texObj; GLboolean sizeOK, dimensionsOK; - gl_format texFormat; + mesa_format texFormat; + const char* suffix = dsa ? "ture" : ""; - GET_CURRENT_CONTEXT(ctx); + assert(texObj); - if (tex_storage_error_check(ctx, dims, target, levels, - internalformat, width, height, depth)) { + if (tex_storage_error_check(ctx, texObj, dims, target, levels, + internalformat, width, height, depth, dsa)) { 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); @@ -351,7 +401,7 @@ texstorage(GLuint dims, GLenum target, GLsizei levels, GLenum internalformat, sizeOK = ctx->Driver.TestProxyTexImage(ctx, target, 0, texFormat, width, height, depth, 0); - if (_mesa_is_proxy_texture(texObj->Target)) { + if (_mesa_is_proxy_texture(target)) { if (dimensionsOK && sizeOK) { initialize_texture_fields(ctx, texObj, levels, width, height, depth, internalformat, texFormat); @@ -364,13 +414,15 @@ texstorage(GLuint dims, GLenum target, GLsizei levels, GLenum internalformat, else { if (!dimensionsOK) { _mesa_error(ctx, GL_INVALID_VALUE, - "glTexStorage%uD(invalid width, height or depth)", dims); + "glTex%sStorage%uD(invalid width, height or depth)", + suffix, dims); return; } if (!sizeOK) { _mesa_error(ctx, GL_OUT_OF_MEMORY, - "glTexStorage%uD(texture too large)", dims); + "glTex%sStorage%uD(texture too large)", + suffix, dims); } assert(levels > 0); @@ -392,13 +444,107 @@ texstorage(GLuint dims, GLenum target, GLsizei levels, GLenum internalformat, * state but this puts things in a consistent state. */ clear_texture_fields(ctx, texObj); - _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexStorage%uD", dims); + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTex%sStorage%uD", + suffix, dims); return; } - texObj->Immutable = GL_TRUE; - texObj->ImmutableLevels = levels; + _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; + GET_CURRENT_CONTEXT(ctx); + + /* Check target. This is done here so that _mesa_texture_storage + * can receive unsized formats. + */ + if (!legal_texobj_target(ctx, dims, target)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glTexStorage%uD(illegal target=%s)", + dims, _mesa_enum_to_string(target)); + return; + } + + if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) + _mesa_debug(ctx, "glTexStorage%uD %s %d %s %d %d %d\n", + dims, + _mesa_enum_to_string(target), levels, + _mesa_enum_to_string(internalformat), + width, height, depth); + + /* Check the format to make sure it is sized. */ + if (!_mesa_is_legal_tex_storage_format(ctx, internalformat)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glTexStorage%uD(internalformat = %s)", dims, + _mesa_enum_to_string(internalformat)); + return; + } + + texObj = _mesa_get_current_tex_object(ctx, target); + if (!texObj) + return; + + _mesa_texture_storage(ctx, dims, texObj, target, levels, + internalformat, width, height, depth, false); +} + + +/** + * Helper used by _mesa_TextureStorage1/2/3D(). + */ +static void +texturestorage(GLuint dims, GLuint texture, GLsizei levels, + GLenum internalformat, GLsizei width, GLsizei height, + GLsizei depth) +{ + struct gl_texture_object *texObj; + GET_CURRENT_CONTEXT(ctx); + + if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) + _mesa_debug(ctx, "glTextureStorage%uD %d %d %s %d %d %d\n", + dims, texture, levels, + _mesa_enum_to_string(internalformat), + width, height, depth); + + /* Check the format to make sure it is sized. */ + if (!_mesa_is_legal_tex_storage_format(ctx, internalformat)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glTextureStorage%uD(internalformat = %s)", dims, + _mesa_enum_to_string(internalformat)); + return; } + + /* Get the texture object by Name. */ + texObj = _mesa_lookup_texture(ctx, texture); + if (!texObj) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTextureStorage%uD(texture = %d)", dims, texture); + return; + } + + /* Check target. This is done here so that _mesa_texture_storage + * can receive unsized formats. + */ + if (!legal_texobj_target(ctx, dims, texObj->Target)) { + _mesa_error(ctx, GL_INVALID_ENUM, + "glTextureStorage%uD(illegal target=%s)", + dims, _mesa_enum_to_string(texObj->Target)); + return; + } + + _mesa_texture_storage(ctx, dims, texObj, texObj->Target, + levels, internalformat, width, height, depth, true); } @@ -426,6 +572,30 @@ _mesa_TexStorage3D(GLenum target, GLsizei levels, GLenum internalformat, } +void GLAPIENTRY +_mesa_TextureStorage1D(GLuint texture, GLsizei levels, GLenum internalformat, + GLsizei width) +{ + texturestorage(1, texture, levels, internalformat, width, 1, 1); +} + + +void GLAPIENTRY +_mesa_TextureStorage2D(GLuint texture, GLsizei levels, + GLenum internalformat, + GLsizei width, GLsizei height) +{ + texturestorage(2, texture, levels, internalformat, width, height, 1); +} + + +void GLAPIENTRY +_mesa_TextureStorage3D(GLuint texture, GLsizei levels, GLenum internalformat, + GLsizei width, GLsizei height, GLsizei depth) +{ + texturestorage(3, texture, levels, internalformat, width, height, depth); +} + /* * Note: we don't support GL_EXT_direct_state_access and the spec says @@ -440,7 +610,16 @@ _mesa_TextureStorage1DEXT(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width) { - /* no-op */ + GET_CURRENT_CONTEXT(ctx); + + (void) texture; + (void) target; + (void) levels; + (void) internalformat; + (void) width; + + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTextureStorage1DEXT not supported"); } @@ -449,9 +628,18 @@ _mesa_TextureStorage2DEXT(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height) { - /* no-op */ -} + GET_CURRENT_CONTEXT(ctx); + (void) texture; + (void) target; + (void) levels; + (void) internalformat; + (void) width; + (void) height; + + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTextureStorage2DEXT not supported"); +} void GLAPIENTRY @@ -459,5 +647,16 @@ _mesa_TextureStorage3DEXT(GLuint texture, GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth) { - /* no-op */ + GET_CURRENT_CONTEXT(ctx); + + (void) texture; + (void) target; + (void) levels; + (void) internalformat; + (void) width; + (void) height; + (void) depth; + + _mesa_error(ctx, GL_INVALID_OPERATION, + "glTextureStorage3DEXT not supported"); }