X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fmesa%2Fmain%2Fteximage.c;h=fb2dee7d85f0440a0752de8f93b1920a3e060786;hb=76b11d15d36db9e83b36efe469c27d68389bb627;hp=d0e31ac0a286a3b87dc1dfe915fcb4045e9a7522;hpb=fb1785197f26a76ff3b9b98dd178d0a9c378f979;p=mesa.git diff --git a/src/mesa/main/teximage.c b/src/mesa/main/teximage.c index d0e31ac0a28..fb2dee7d85f 100644 --- a/src/mesa/main/teximage.c +++ b/src/mesa/main/teximage.c @@ -48,8 +48,10 @@ #include "texobj.h" #include "texstate.h" #include "texstorage.h" +#include "textureview.h" #include "mtypes.h" #include "glformats.h" +#include "texstore.h" /** @@ -159,6 +161,9 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat ) case GL_DEPTH_COMPONENT24: case GL_DEPTH_COMPONENT32: return GL_DEPTH_COMPONENT; + case GL_DEPTH_STENCIL: + case GL_DEPTH24_STENCIL8: + return GL_DEPTH_STENCIL; default: ; /* fallthrough */ } @@ -251,16 +256,6 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat ) } } - if (ctx->Extensions.ATI_envmap_bumpmap) { - switch (internalFormat) { - case GL_DUDV_ATI: - case GL_DU8DV8_ATI: - return GL_DUDV_ATI; - default: - ; /* fallthrough */ - } - } - if (ctx->Extensions.EXT_texture_snorm) { switch (internalFormat) { case GL_RED_SNORM: @@ -300,30 +295,22 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat ) } } - if (ctx->Extensions.EXT_packed_depth_stencil) { - switch (internalFormat) { - case GL_DEPTH_STENCIL_EXT: - case GL_DEPTH24_STENCIL8_EXT: - return GL_DEPTH_STENCIL_EXT; - default: - ; /* fallthrough */ - } - } - if (ctx->Extensions.EXT_texture_sRGB) { switch (internalFormat) { case GL_SRGB_EXT: case GL_SRGB8_EXT: case GL_COMPRESSED_SRGB_EXT: - case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: return GL_RGB; + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: + return ctx->Extensions.EXT_texture_compression_s3tc ? GL_RGB : -1; case GL_SRGB_ALPHA_EXT: case GL_SRGB8_ALPHA8_EXT: case GL_COMPRESSED_SRGB_ALPHA_EXT: + return GL_RGBA; case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: - return GL_RGBA; + return ctx->Extensions.EXT_texture_compression_s3tc ? GL_RGBA : -1; case GL_SLUMINANCE_ALPHA_EXT: case GL_SLUMINANCE8_ALPHA8_EXT: case GL_COMPRESSED_SLUMINANCE_ALPHA_EXT: @@ -396,11 +383,6 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat ) if (ctx->Extensions.ARB_texture_rg) { switch (internalFormat) { case GL_R16F: - /* R16F depends on both ARB_half_float_pixel and ARB_texture_float. - */ - if (!ctx->Extensions.ARB_half_float_pixel) - break; - /* FALLTHROUGH */ case GL_R32F: if (!ctx->Extensions.ARB_texture_float) break; @@ -421,11 +403,6 @@ _mesa_base_tex_format( struct gl_context *ctx, GLint internalFormat ) return GL_RED; case GL_RG16F: - /* RG16F depends on both ARB_half_float_pixel and ARB_texture_float. - */ - if (!ctx->Extensions.ARB_half_float_pixel) - break; - /* FALLTHROUGH */ case GL_RG32F: if (!ctx->Extensions.ARB_texture_float) break; @@ -659,30 +636,37 @@ _mesa_delete_texture_image(struct gl_context *ctx, GLboolean _mesa_is_proxy_texture(GLenum target) { + unsigned i; + static const GLenum targets[] = { + GL_PROXY_TEXTURE_1D, + GL_PROXY_TEXTURE_2D, + GL_PROXY_TEXTURE_3D, + GL_PROXY_TEXTURE_CUBE_MAP, + GL_PROXY_TEXTURE_RECTANGLE, + GL_PROXY_TEXTURE_1D_ARRAY, + GL_PROXY_TEXTURE_2D_ARRAY, + GL_PROXY_TEXTURE_CUBE_MAP_ARRAY, + GL_PROXY_TEXTURE_2D_MULTISAMPLE, + GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY + }; /* - * NUM_TEXTURE_TARGETS should match number of terms below, except there's no + * NUM_TEXTURE_TARGETS should match number of terms above, except there's no * proxy for GL_TEXTURE_BUFFER and GL_TEXTURE_EXTERNAL_OES. */ - assert(NUM_TEXTURE_TARGETS == 10 + 2); - - return (target == GL_PROXY_TEXTURE_1D || - target == GL_PROXY_TEXTURE_2D || - target == GL_PROXY_TEXTURE_3D || - target == GL_PROXY_TEXTURE_CUBE_MAP_ARB || - target == GL_PROXY_TEXTURE_RECTANGLE_NV || - target == GL_PROXY_TEXTURE_1D_ARRAY_EXT || - target == GL_PROXY_TEXTURE_2D_ARRAY_EXT || - target == GL_PROXY_TEXTURE_CUBE_MAP_ARRAY || - target == GL_PROXY_TEXTURE_2D_MULTISAMPLE || - target == GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY); + STATIC_ASSERT(NUM_TEXTURE_TARGETS == Elements(targets) + 2); + + for (i = 0; i < Elements(targets); ++i) + if (target == targets[i]) + return GL_TRUE; + return GL_FALSE; } /** * Return the proxy target which corresponds to the given texture target */ -GLenum -_mesa_get_proxy_target(GLenum target) +static GLenum +proxy_target(GLenum target) { switch (target) { case GL_TEXTURE_1D: @@ -722,29 +706,22 @@ _mesa_get_proxy_target(GLenum target) case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY: return GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY; default: - _mesa_problem(NULL, "unexpected target in _mesa_get_proxy_target()"); + _mesa_problem(NULL, "unexpected target in proxy_target()"); return 0; } } /** - * Get the texture object that corresponds to the target of the given - * texture unit. The target should have already been checked for validity. - * - * \param ctx GL context. - * \param texUnit texture unit. - * \param target texture target. - * - * \return pointer to the texture object on success, or NULL on failure. + * Return a pointer to the current texture object for the given target + * on the current texture unit. + * Note: all error checking should have been done by this point. */ struct gl_texture_object * -_mesa_select_tex_object(struct gl_context *ctx, - const struct gl_texture_unit *texUnit, - GLenum target) +_mesa_get_current_tex_object(struct gl_context *ctx, GLenum target) { - const GLboolean arrayTex = (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array); + struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); + const GLboolean arrayTex = ctx->Extensions.EXT_texture_array; switch (target) { case GL_TEXTURE_1D: @@ -796,7 +773,7 @@ _mesa_select_tex_object(struct gl_context *ctx, ctx->Extensions.ARB_texture_buffer_object ? texUnit->CurrentTex[TEXTURE_BUFFER_INDEX] : NULL; case GL_TEXTURE_EXTERNAL_OES: - return ctx->Extensions.OES_EGL_image_external + return _mesa_is_gles(ctx) && ctx->Extensions.OES_EGL_image_external ? texUnit->CurrentTex[TEXTURE_EXTERNAL_INDEX] : NULL; case GL_TEXTURE_2D_MULTISAMPLE: return ctx->Extensions.ARB_texture_multisample @@ -811,22 +788,12 @@ _mesa_select_tex_object(struct gl_context *ctx, return ctx->Extensions.ARB_texture_multisample ? ctx->Texture.ProxyTex[TEXTURE_2D_MULTISAMPLE_ARRAY_INDEX] : NULL; default: - _mesa_problem(NULL, "bad target in _mesa_select_tex_object()"); + _mesa_problem(NULL, "bad target in _mesa_get_current_tex_object()"); return NULL; } } -/** - * Return pointer to texture object for given target on current texture unit. - */ -struct gl_texture_object * -_mesa_get_current_tex_object(struct gl_context *ctx, GLenum target) -{ - struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); - return _mesa_select_tex_object(ctx, texUnit, target); -} - /** * Get a texture image pointer from a texture object, given a texture @@ -1009,8 +976,7 @@ _mesa_max_texture_levels(struct gl_context *ctx, GLenum target) case GL_PROXY_TEXTURE_1D_ARRAY_EXT: case GL_TEXTURE_2D_ARRAY_EXT: case GL_PROXY_TEXTURE_2D_ARRAY_EXT: - return (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array) + return ctx->Extensions.EXT_texture_array ? ctx->Const.MaxTextureLevels : 0; case GL_TEXTURE_CUBE_MAP_ARRAY: case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY: @@ -1081,6 +1047,93 @@ _mesa_get_texture_dimensions(GLenum target) } +/** + * Check if a texture target can have more than one layer. + */ +GLboolean +_mesa_tex_target_is_layered(GLenum target) +{ + switch (target) { + case GL_TEXTURE_1D: + case GL_PROXY_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_PROXY_TEXTURE_2D: + case GL_TEXTURE_RECTANGLE: + case GL_PROXY_TEXTURE_RECTANGLE: + case GL_TEXTURE_2D_MULTISAMPLE: + case GL_PROXY_TEXTURE_2D_MULTISAMPLE: + case GL_TEXTURE_BUFFER: + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + case GL_TEXTURE_EXTERNAL_OES: + return GL_FALSE; + + case GL_TEXTURE_3D: + case GL_PROXY_TEXTURE_3D: + case GL_TEXTURE_CUBE_MAP: + case GL_PROXY_TEXTURE_CUBE_MAP: + case GL_TEXTURE_1D_ARRAY: + case GL_PROXY_TEXTURE_1D_ARRAY: + case GL_TEXTURE_2D_ARRAY: + case GL_PROXY_TEXTURE_2D_ARRAY: + case GL_TEXTURE_CUBE_MAP_ARRAY: + case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY: + case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: + case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY: + return GL_TRUE; + + default: + assert(!"Invalid texture target."); + return GL_FALSE; + } +} + + +/** + * Return the number of layers present in the given level of an array, + * cubemap or 3D texture. If the texture is not layered return zero. + */ +GLuint +_mesa_get_texture_layers(const struct gl_texture_object *texObj, GLint level) +{ + assert(level >= 0 && level < MAX_TEXTURE_LEVELS); + + switch (texObj->Target) { + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_TEXTURE_RECTANGLE: + case GL_TEXTURE_2D_MULTISAMPLE: + case GL_TEXTURE_BUFFER: + case GL_TEXTURE_EXTERNAL_OES: + return 0; + + case GL_TEXTURE_CUBE_MAP: + return 6; + + case GL_TEXTURE_1D_ARRAY: { + struct gl_texture_image *img = texObj->Image[0][level]; + return img ? img->Height : 0; + } + + case GL_TEXTURE_3D: + case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_CUBE_MAP_ARRAY: + case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: { + struct gl_texture_image *img = texObj->Image[0][level]; + return img ? img->Depth : 0; + } + + default: + assert(!"Invalid texture target."); + return 0; + } +} + + /** * Return the maximum number of mipmap levels for the given target * and the dimensions. @@ -1095,24 +1148,33 @@ _mesa_get_tex_max_num_levels(GLenum target, GLsizei width, GLsizei height, switch (target) { case GL_TEXTURE_1D: case GL_TEXTURE_1D_ARRAY: + case GL_PROXY_TEXTURE_1D: + case GL_PROXY_TEXTURE_1D_ARRAY: size = width; break; case GL_TEXTURE_CUBE_MAP: case GL_TEXTURE_CUBE_MAP_ARRAY: - ASSERT(width == height); + case GL_PROXY_TEXTURE_CUBE_MAP: + case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY: size = width; break; case GL_TEXTURE_2D: case GL_TEXTURE_2D_ARRAY: + case GL_PROXY_TEXTURE_2D: + case GL_PROXY_TEXTURE_2D_ARRAY: size = MAX2(width, height); break; case GL_TEXTURE_3D: + case GL_PROXY_TEXTURE_3D: size = MAX3(width, height, depth); break; case GL_TEXTURE_RECTANGLE: case GL_TEXTURE_EXTERNAL_OES: case GL_TEXTURE_2D_MULTISAMPLE: case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: + case GL_PROXY_TEXTURE_RECTANGLE: + case GL_PROXY_TEXTURE_2D_MULTISAMPLE: + case GL_PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY: return 1; default: assert(0); @@ -1214,16 +1276,19 @@ clear_teximage_fields(struct gl_texture_image *img) * \param border image border. * \param internalFormat internal format. * \param format the actual hardware format (one of MESA_FORMAT_*) + * \param numSamples number of samples per texel, or zero for non-MS. + * \param fixedSampleLocations are sample locations fixed? * * Fills in the fields of \p img with the given information. * Note: width, height and depth include the border. */ -void -_mesa_init_teximage_fields(struct gl_context *ctx, - struct gl_texture_image *img, - GLsizei width, GLsizei height, GLsizei depth, - GLint border, GLenum internalFormat, - gl_format format) +static void +init_teximage_fields_ms(struct gl_context *ctx, + struct gl_texture_image *img, + GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum internalFormat, + mesa_format format, + GLuint numSamples, GLboolean fixedSampleLocations) { GLenum target; ASSERT(img); @@ -1321,6 +1386,20 @@ _mesa_init_teximage_fields(struct gl_context *ctx, _mesa_get_tex_max_num_levels(target, img->Width2, img->Height2, img->Depth2); img->TexFormat = format; + img->NumSamples = numSamples; + img->FixedSampleLocations = fixedSampleLocations; +} + + +void +_mesa_init_teximage_fields(struct gl_context *ctx, + struct gl_texture_image *img, + GLsizei width, GLsizei height, GLsizei depth, + GLint border, GLenum internalFormat, + mesa_format format) +{ + init_teximage_fields_ms(ctx, img, width, height, depth, border, + internalFormat, format, 0, GL_TRUE); } @@ -1428,6 +1507,8 @@ _mesa_legal_texture_dimensions(struct gl_context *ctx, GLenum target, case GL_PROXY_TEXTURE_CUBE_MAP_ARB: maxSize = 1 << (ctx->Const.MaxCubeTextureLevels - 1); maxSize >>= level; + if (width != height) + return GL_FALSE; if (width < 2 * border || width > 2 * border + maxSize) return GL_FALSE; if (height < 2 * border || height > 2 * border + maxSize) @@ -1464,7 +1545,7 @@ _mesa_legal_texture_dimensions(struct gl_context *ctx, GLenum target, return GL_FALSE; if (height < 2 * border || height > 2 * border + maxSize) return GL_FALSE; - if (depth < 1 || depth > ctx->Const.MaxArrayTextureLayers) + if (depth < 0 || depth > ctx->Const.MaxArrayTextureLayers) return GL_FALSE; if (!ctx->Extensions.ARB_texture_non_power_of_two) { if (width > 0 && !_mesa_is_pow_two(width - 2 * border)) @@ -1481,7 +1562,9 @@ _mesa_legal_texture_dimensions(struct gl_context *ctx, GLenum target, return GL_FALSE; if (height < 2 * border || height > 2 * border + maxSize) return GL_FALSE; - if (depth < 1 || depth > ctx->Const.MaxArrayTextureLayers) + if (depth < 0 || depth > ctx->Const.MaxArrayTextureLayers || depth % 6) + return GL_FALSE; + if (width != height) return GL_FALSE; if (level >= ctx->Const.MaxCubeTextureLevels) return GL_FALSE; @@ -1565,7 +1648,10 @@ error_check_subtexture_dimensions(struct gl_context *ctx, /* check zoffset and depth */ if (dims > 2) { - GLint zBorder = (target == GL_TEXTURE_2D_ARRAY) ? 0 : destImage->Border; + GLint zBorder = (target == GL_TEXTURE_2D_ARRAY || + target == GL_TEXTURE_CUBE_MAP_ARRAY) ? + 0 : destImage->Border; + if (zoffset < -zBorder) { _mesa_error(ctx, GL_INVALID_VALUE, "%s3D(zoffset)", function); return GL_TRUE; @@ -1642,7 +1728,7 @@ error_check_subtexture_dimensions(struct gl_context *ctx, */ GLboolean _mesa_test_proxy_teximage(struct gl_context *ctx, GLenum target, GLint level, - gl_format format, + mesa_format format, GLint width, GLint height, GLint depth, GLint border) { /* We just check if the image size is less than MaxTextureMbytes. @@ -1704,8 +1790,7 @@ target_can_be_compressed(const struct gl_context *ctx, GLenum target, return ctx->Extensions.ARB_texture_cube_map; case GL_PROXY_TEXTURE_2D_ARRAY_EXT: case GL_TEXTURE_2D_ARRAY_EXT: - return (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array); + return ctx->Extensions.EXT_texture_array; case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY: case GL_TEXTURE_CUBE_MAP_ARRAY: return ctx->Extensions.ARB_texture_cube_map_array; @@ -1753,9 +1838,7 @@ legal_teximage_target(struct gl_context *ctx, GLuint dims, GLenum target) && ctx->Extensions.NV_texture_rectangle; case GL_TEXTURE_1D_ARRAY_EXT: case GL_PROXY_TEXTURE_1D_ARRAY_EXT: - return _mesa_is_desktop_gl(ctx) - && (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array); + return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_array; default: return GL_FALSE; } @@ -1766,14 +1849,10 @@ legal_teximage_target(struct gl_context *ctx, GLuint dims, GLenum target) case GL_PROXY_TEXTURE_3D: return _mesa_is_desktop_gl(ctx); case GL_TEXTURE_2D_ARRAY_EXT: - return (_mesa_is_desktop_gl(ctx) - && (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array)) + return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_array) || _mesa_is_gles3(ctx); case GL_PROXY_TEXTURE_2D_ARRAY_EXT: - return _mesa_is_desktop_gl(ctx) - && (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array); + return _mesa_is_desktop_gl(ctx) && 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; @@ -1814,9 +1893,7 @@ legal_texsubimage_target(struct gl_context *ctx, GLuint dims, GLenum target) return _mesa_is_desktop_gl(ctx) && ctx->Extensions.NV_texture_rectangle; case GL_TEXTURE_1D_ARRAY_EXT: - return _mesa_is_desktop_gl(ctx) - && (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array); + return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_array; default: return GL_FALSE; } @@ -1825,9 +1902,7 @@ legal_texsubimage_target(struct gl_context *ctx, GLuint dims, GLenum target) case GL_TEXTURE_3D: return GL_TRUE; case GL_TEXTURE_2D_ARRAY_EXT: - return (_mesa_is_desktop_gl(ctx) - && (ctx->Extensions.MESA_texture_array || - ctx->Extensions.EXT_texture_array)) + return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_array) || _mesa_is_gles3(ctx); case GL_TEXTURE_CUBE_MAP_ARRAY: case GL_PROXY_TEXTURE_CUBE_MAP_ARRAY: @@ -1850,12 +1925,8 @@ legal_texsubimage_target(struct gl_context *ctx, GLuint dims, GLenum target) static GLboolean mutable_tex_object(struct gl_context *ctx, GLenum target) { - if (ctx->Extensions.ARB_texture_storage) { - struct gl_texture_object *texObj = - _mesa_get_current_tex_object(ctx, target); - return !texObj->Immutable; - } - return GL_TRUE; + struct gl_texture_object *texObj = _mesa_get_current_tex_object(ctx, target); + return !texObj->Immutable; } @@ -1866,10 +1937,116 @@ static GLuint compressed_tex_size(GLsizei width, GLsizei height, GLsizei depth, GLenum glformat) { - gl_format mesaFormat = _mesa_glenum_to_compressed_format(glformat); + mesa_format mesaFormat = _mesa_glenum_to_compressed_format(glformat); return _mesa_format_image_size(mesaFormat, width, height, depth); } +/** + * Verify that a texture format is valid with a particular target + * + * In particular, textures with base format of \c GL_DEPTH_COMPONENT or + * \c GL_DEPTH_STENCIL are only valid with certain, context dependent texture + * targets. + * + * \param ctx GL context + * \param target Texture target + * \param internalFormat Internal format of the texture image + * \param dimensions Dimensionality at the caller. This is \b not used + * in the validation. It is only used when logging + * error messages. + * \param caller Base name of the calling function (e.g., + * "glTexImage" or "glTexStorage"). + * + * \returns true if the combination is legal, false otherwise. + */ +bool +_mesa_legal_texture_base_format_for_target(struct gl_context *ctx, + GLenum target, GLenum internalFormat, + unsigned dimensions, + const char *caller) +{ + if (_mesa_base_tex_format(ctx, internalFormat) == GL_DEPTH_COMPONENT + || _mesa_base_tex_format(ctx, internalFormat) == GL_DEPTH_STENCIL) { + /* Section 3.8.3 (Texture Image Specification) of the OpenGL 3.3 Core + * Profile spec says: + * + * "Textures with a base internal format of DEPTH_COMPONENT or + * DEPTH_STENCIL are supported by texture image specification + * commands only if target is TEXTURE_1D, TEXTURE_2D, + * TEXTURE_1D_ARRAY, TEXTURE_2D_ARRAY, TEXTURE_RECTANGLE, + * TEXTURE_CUBE_MAP, PROXY_TEXTURE_1D, PROXY_TEXTURE_2D, + * PROXY_TEXTURE_1D_ARRAY, PROXY_TEXTURE_2D_ARRAY, + * PROXY_TEXTURE_RECTANGLE, or PROXY_TEXTURE_CUBE_MAP. Using these + * formats in conjunction with any other target will result in an + * INVALID_OPERATION error." + * + * Cubemaps are only supported with desktop OpenGL version >= 3.0, + * EXT_gpu_shader4, or, on OpenGL ES 2.0+, OES_depth_texture_cube_map. + */ + if (target != GL_TEXTURE_1D && + target != GL_PROXY_TEXTURE_1D && + target != GL_TEXTURE_2D && + target != GL_PROXY_TEXTURE_2D && + target != GL_TEXTURE_1D_ARRAY && + target != GL_PROXY_TEXTURE_1D_ARRAY && + target != GL_TEXTURE_2D_ARRAY && + target != GL_PROXY_TEXTURE_2D_ARRAY && + target != GL_TEXTURE_RECTANGLE_ARB && + target != GL_PROXY_TEXTURE_RECTANGLE_ARB && + !((_mesa_is_cube_face(target) || + target == GL_TEXTURE_CUBE_MAP || + target == GL_PROXY_TEXTURE_CUBE_MAP) && + (ctx->Version >= 30 || ctx->Extensions.EXT_gpu_shader4 + || (ctx->API == API_OPENGLES2 && ctx->Extensions.OES_depth_texture_cube_map))) && + !((target == GL_TEXTURE_CUBE_MAP_ARRAY || + target == GL_PROXY_TEXTURE_CUBE_MAP_ARRAY) && + ctx->Extensions.ARB_texture_cube_map_array)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s%dD(bad target for depth texture)", + caller, dimensions); + return false; + } + } + + return true; +} + +static bool +texture_formats_agree(GLenum internalFormat, + GLenum format) +{ + GLboolean colorFormat; + GLboolean is_format_depth_or_depthstencil; + GLboolean is_internalFormat_depth_or_depthstencil; + + /* Even though there are no color-index textures, we still have to support + * uploading color-index data and remapping it to RGB via the + * GL_PIXEL_MAP_I_TO_[RGBA] tables. + */ + const GLboolean indexFormat = (format == GL_COLOR_INDEX); + + is_internalFormat_depth_or_depthstencil = + _mesa_is_depth_format(internalFormat) || + _mesa_is_depthstencil_format(internalFormat); + + is_format_depth_or_depthstencil = + _mesa_is_depth_format(format) || + _mesa_is_depthstencil_format(format); + + colorFormat = _mesa_is_color_format(format); + + if (_mesa_is_color_format(internalFormat) && !colorFormat && !indexFormat) + return false; + + if (is_internalFormat_depth_or_depthstencil != + is_format_depth_or_depthstencil) + return false; + + if (_mesa_is_ycbcr_format(internalFormat) != _mesa_is_ycbcr_format(format)) + return false; + + return true; +} /** * Test the glTexImage[123]D() parameters for errors. @@ -1904,15 +2081,8 @@ texture_error_check( struct gl_context *ctx, GLint width, GLint height, GLint depth, GLint border ) { - GLboolean colorFormat; GLenum err; - /* Even though there are no color-index textures, we still have to support - * uploading color-index data and remapping it to RGB via the - * GL_PIXEL_MAP_I_TO_[RGBA] tables. - */ - const GLboolean indexFormat = (format == GL_COLOR_INDEX); - /* Note: for proxy textures, some error conditions immediately generate * a GL error in the usual way. But others do not generate a GL error. * Instead, they cause the width, height, depth, format fields of the @@ -1976,27 +2146,6 @@ texture_error_check( struct gl_context *ctx, } } - if ((target == GL_PROXY_TEXTURE_CUBE_MAP_ARB || - _mesa_is_cube_face(target)) && width != height) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glTexImage2D(cube width != height)"); - return GL_TRUE; - } - - if ((target == GL_PROXY_TEXTURE_CUBE_MAP_ARRAY || - target == GL_TEXTURE_CUBE_MAP_ARRAY) && width != height) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glTexImage3D(cube array width != height)"); - return GL_TRUE; - } - - if ((target == GL_PROXY_TEXTURE_CUBE_MAP_ARRAY || - target == GL_TEXTURE_CUBE_MAP_ARRAY) && (depth % 6)) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glTexImage3D(cube array depth not multiple of 6)"); - return GL_TRUE; - } - /* Check internalFormat */ if (_mesa_base_tex_format(ctx, internalFormat) < 0) { _mesa_error(ctx, GL_INVALID_VALUE, @@ -2016,12 +2165,7 @@ texture_error_check( struct gl_context *ctx, } /* make sure internal format and format basically agree */ - colorFormat = _mesa_is_color_format(format); - if ((_mesa_is_color_format(internalFormat) && !colorFormat && !indexFormat) || - (_mesa_is_depth_format(internalFormat) != _mesa_is_depth_format(format)) || - (_mesa_is_ycbcr_format(internalFormat) != _mesa_is_ycbcr_format(format)) || - (_mesa_is_depthstencil_format(internalFormat) != _mesa_is_depthstencil_format(format)) || - (_mesa_is_dudv_format(internalFormat) != _mesa_is_dudv_format(format))) { + if (!texture_formats_agree(internalFormat, format)) { _mesa_error(ctx, GL_INVALID_OPERATION, "glTexImage%dD(incompatible internalFormat = %s, format = %s)", dimensions, _mesa_lookup_enum_by_nr(internalFormat), @@ -2061,32 +2205,9 @@ texture_error_check( struct gl_context *ctx, } /* additional checks for depth textures */ - if (_mesa_base_tex_format(ctx, internalFormat) == GL_DEPTH_COMPONENT - || _mesa_base_tex_format(ctx, internalFormat) == GL_DEPTH_STENCIL) { - /* Only 1D, 2D, rect, array and cube textures supported, not 3D - * Cubemaps are only supported for GL version > 3.0 or with EXT_gpu_shader4 */ - if (target != GL_TEXTURE_1D && - target != GL_PROXY_TEXTURE_1D && - target != GL_TEXTURE_2D && - target != GL_PROXY_TEXTURE_2D && - target != GL_TEXTURE_1D_ARRAY && - target != GL_PROXY_TEXTURE_1D_ARRAY && - target != GL_TEXTURE_2D_ARRAY && - target != GL_PROXY_TEXTURE_2D_ARRAY && - target != GL_TEXTURE_RECTANGLE_ARB && - target != GL_PROXY_TEXTURE_RECTANGLE_ARB && - !((_mesa_is_cube_face(target) || target == GL_PROXY_TEXTURE_CUBE_MAP) && - (ctx->Version >= 30 || ctx->Extensions.EXT_gpu_shader4 - || (ctx->API == API_OPENGLES2 && ctx->Extensions.OES_depth_texture_cube_map))) && - !((target == GL_TEXTURE_CUBE_MAP_ARRAY || - target == GL_PROXY_TEXTURE_CUBE_MAP_ARRAY) && - ctx->Extensions.ARB_texture_cube_map_array)) { - _mesa_error(ctx, GL_INVALID_ENUM, - "glTexImage%dD(bad target for depth texture)", - dimensions); - return GL_TRUE; - } - } + if (!_mesa_legal_texture_base_format_for_target(ctx, target, internalFormat, + dimensions, "glTexImage")) + return GL_TRUE; /* additional checks for compressed textures */ if (_mesa_is_compressed_format(ctx, internalFormat)) { @@ -2128,6 +2249,36 @@ texture_error_check( struct gl_context *ctx, } +bool +_mesa_compressed_texture_pixel_storage_error_check(struct gl_context *ctx, + GLint dimensions, + struct gl_pixelstore_attrib *packing, + const char *caller) +{ + if (!_mesa_is_desktop_gl(ctx) || !packing->CompressedBlockSize) + return true; + + if (packing->CompressedBlockWidth && packing->SkipPixels % packing->CompressedBlockWidth) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(skip-pixels %% block-width)", caller); + return false; + } + + if (dimensions > 1 && packing->CompressedBlockHeight && packing->SkipRows % packing->CompressedBlockHeight) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(skip-rows %% block-height)", caller); + return false; + } + + if (dimensions > 2 && packing->CompressedBlockDepth && packing->SkipImages % packing->CompressedBlockDepth) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(skip-images %% block-depth)", caller); + return false; + } + + return true; +} + /** * Error checking for glCompressedTexImage[123]D(). * Note that the width, height and depth values are not fully error checked @@ -2154,9 +2305,10 @@ compressed_texture_error_check(struct gl_context *ctx, GLint dimensions, /* This will detect any invalid internalFormat value */ if (!_mesa_is_compressed_format(ctx, internalFormat)) { - reason = "internalFormat"; - error = GL_INVALID_ENUM; - goto error; + _mesa_error(ctx, GL_INVALID_ENUM, + "glCompressedTexImage%dD(internalFormat=%s)", + dimensions, _mesa_lookup_enum_by_nr(internalFormat)); + return GL_TRUE; } switch (internalFormat) { @@ -2228,12 +2380,11 @@ compressed_texture_error_check(struct gl_context *ctx, GLint dimensions, goto error; } - /* For cube map, width must equal height */ - if ((target == GL_PROXY_TEXTURE_CUBE_MAP_ARB || - _mesa_is_cube_face(target)) && width != height) { - reason = "width != height"; - error = GL_INVALID_VALUE; - goto error; + /* Check for invalid pixel storage modes */ + if (!_mesa_compressed_texture_pixel_storage_error_check(ctx, dimensions, + &ctx->Unpack, + "glCompressedTexImage")) { + return GL_FALSE; } /* check image size in bytes */ @@ -2256,6 +2407,7 @@ compressed_texture_error_check(struct gl_context *ctx, GLint dimensions, return GL_FALSE; error: + /* Note: not all error paths exit through here. */ _mesa_error(ctx, error, "glCompressedTexImage%dD(%s)", dimensions, reason); return GL_TRUE; } @@ -2471,7 +2623,8 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions, break; default: _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyTexImage%dD(internalFormat)", dimensions); + "glCopyTexImage%dD(internalFormat=%s)", dimensions, + _mesa_lookup_enum_by_nr(internalFormat)); return GL_TRUE; } } @@ -2479,7 +2632,8 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions, baseFormat = _mesa_base_tex_format(ctx, internalFormat); if (baseFormat < 0) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyTexImage%dD(internalFormat)", dimensions); + "glCopyTexImage%dD(internalFormat=%s)", dimensions, + _mesa_lookup_enum_by_nr(internalFormat)); return GL_TRUE; } @@ -2488,7 +2642,8 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions, if (_mesa_is_color_format(internalFormat)) { if (rb_base_format < 0) { _mesa_error(ctx, GL_INVALID_VALUE, - "glCopyTexImage%dD(internalFormat)", dimensions); + "glCopyTexImage%dD(internalFormat=%s)", dimensions, + _mesa_lookup_enum_by_nr(internalFormat)); return GL_TRUE; } } @@ -2514,7 +2669,8 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions, } if (!valid) { _mesa_error(ctx, GL_INVALID_OPERATION, - "glCopyTexImage%dD(internalFormat)", dimensions); + "glCopyTexImage%dD(internalFormat=%s)", dimensions, + _mesa_lookup_enum_by_nr(internalFormat)); return GL_TRUE; } } @@ -2581,13 +2737,6 @@ copytexture_error_check( struct gl_context *ctx, GLuint dimensions, } } - if ((target == GL_PROXY_TEXTURE_CUBE_MAP_ARB || - _mesa_is_cube_face(target)) && width != height) { - _mesa_error(ctx, GL_INVALID_VALUE, - "glTexImage2D(cube width != height)"); - return GL_TRUE; - } - if (_mesa_is_compressed_format(ctx, internalFormat)) { if (!target_can_be_compressed(ctx, target, internalFormat)) { _mesa_error(ctx, GL_INVALID_ENUM, @@ -2863,13 +3012,13 @@ override_internal_format(GLenum internalFormat, GLint width, GLint height) * for efficient texture memory layout/allocation. In particular, this * comes up during automatic mipmap generation. */ -gl_format +mesa_format _mesa_choose_texture_format(struct gl_context *ctx, struct gl_texture_object *texObj, GLenum target, GLint level, GLenum internalFormat, GLenum format, GLenum type) { - gl_format f; + mesa_format f; /* see if we've already chosen a format for the previous level */ if (level > 0) { @@ -2888,7 +3037,7 @@ _mesa_choose_texture_format(struct gl_context *ctx, } /* If the application requested compression to an S3TC format but we don't - * have the DTXn library, force a generic compressed format instead. + * have the DXTn library, force a generic compressed format instead. */ if (internalFormat != format && format != GL_NONE) { const GLenum before = internalFormat; @@ -2919,7 +3068,7 @@ _mesa_choose_texture_format(struct gl_context *ctx, } /* choose format from scratch */ - f = ctx->Driver.ChooseTextureFormat(ctx, texObj->Target, internalFormat, + f = ctx->Driver.ChooseTextureFormat(ctx, target, internalFormat, format, type); ASSERT(f != MESA_FORMAT_NONE); return f; @@ -2991,7 +3140,7 @@ teximage(struct gl_context *ctx, GLboolean compressed, GLuint dims, struct gl_pixelstore_attrib unpack_no_border; const struct gl_pixelstore_attrib *unpack = &ctx->Unpack; struct gl_texture_object *texObj; - gl_format texFormat; + mesa_format texFormat; GLboolean dimensionsOK, sizeOK; FLUSH_VERTICES(ctx, 0); @@ -3082,7 +3231,7 @@ teximage(struct gl_context *ctx, GLboolean compressed, GLuint dims, height, depth, border); /* check that the texture won't take too much memory, etc */ - sizeOK = ctx->Driver.TestProxyTexImage(ctx, _mesa_get_proxy_target(target), + sizeOK = ctx->Driver.TestProxyTexImage(ctx, proxy_target(target), level, texFormat, width, height, depth, border); @@ -3164,7 +3313,7 @@ teximage(struct gl_context *ctx, GLboolean compressed, GLuint dims, _mesa_update_fbo_texture(ctx, texObj, face, level); - _mesa_dirty_texobj(ctx, texObj, GL_TRUE); + _mesa_dirty_texobj(ctx, texObj); } } _mesa_unlock_texture(ctx, texObj); @@ -3241,7 +3390,8 @@ _mesa_EGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image) valid_target = ctx->Extensions.OES_EGL_image; break; case GL_TEXTURE_EXTERNAL_OES: - valid_target = ctx->Extensions.OES_EGL_image_external; + valid_target = + _mesa_is_gles(ctx) ? ctx->Extensions.OES_EGL_image_external : false; break; default: valid_target = false; @@ -3282,7 +3432,7 @@ _mesa_EGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image) ctx->Driver.EGLImageTargetTexture2D(ctx, target, texObj, texImage, image); - _mesa_dirty_texobj(ctx, texObj, GL_TRUE); + _mesa_dirty_texobj(ctx, texObj); } _mesa_unlock_texture(ctx, texObj); @@ -3356,7 +3506,9 @@ texsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level, check_gen_mipmap(ctx, target, texObj, level); - ctx->NewState |= _NEW_TEXTURE; + /* NOTE: Don't signal _NEW_TEXTURE since we've only changed + * the texel data, not the texture format, size, etc. + */ } } _mesa_unlock_texture(ctx, texObj); @@ -3414,7 +3566,7 @@ _mesa_TexSubImage3D( GLenum target, GLint level, * from. This depends on whether the texture contains color or depth values. */ static struct gl_renderbuffer * -get_copy_tex_image_source(struct gl_context *ctx, gl_format texFormat) +get_copy_tex_image_source(struct gl_context *ctx, mesa_format texFormat) { if (_mesa_get_format_bits(texFormat, GL_DEPTH_BITS) > 0) { /* reading from depth/stencil buffer */ @@ -3426,6 +3578,35 @@ get_copy_tex_image_source(struct gl_context *ctx, gl_format texFormat) } } +static void +copytexsubimage_by_slice(struct gl_context *ctx, + struct gl_texture_image *texImage, + GLuint dims, + GLint xoffset, GLint yoffset, GLint zoffset, + struct gl_renderbuffer *rb, + GLint x, GLint y, + GLsizei width, GLsizei height) +{ + if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY) { + int slice; + + /* For 1D arrays, we copy each scanline of the source rectangle into the + * next array slice. + */ + assert(zoffset == 0); + + for (slice = 0; slice < height; slice++) { + assert(yoffset + slice < texImage->Height); + ctx->Driver.CopyTexSubImage(ctx, 2, texImage, + xoffset, 0, yoffset + slice, + rb, x, y + slice, width, 1); + } + } else { + ctx->Driver.CopyTexSubImage(ctx, dims, texImage, + xoffset, yoffset, zoffset, + rb, x, y, width, height); + } +} /** @@ -3439,7 +3620,7 @@ copyteximage(struct gl_context *ctx, GLuint dims, struct gl_texture_object *texObj; struct gl_texture_image *texImage; const GLuint face = _mesa_tex_target_to_face(target); - gl_format texFormat; + mesa_format texFormat; FLUSH_VERTICES(ctx, 0); @@ -3471,7 +3652,7 @@ copyteximage(struct gl_context *ctx, GLuint dims, internalFormat, GL_NONE, GL_NONE); assert(texFormat != MESA_FORMAT_NONE); - if (!ctx->Driver.TestProxyTexImage(ctx, _mesa_get_proxy_target(target), + if (!ctx->Driver.TestProxyTexImage(ctx, proxy_target(target), level, texFormat, width, height, 1, border)) { _mesa_error(ctx, GL_OUT_OF_MEMORY, @@ -3514,8 +3695,9 @@ copyteximage(struct gl_context *ctx, GLuint dims, struct gl_renderbuffer *srcRb = get_copy_tex_image_source(ctx, texImage->TexFormat); - ctx->Driver.CopyTexSubImage(ctx, dims, texImage, dstX, dstY, dstZ, - srcRb, srcX, srcY, width, height); + copytexsubimage_by_slice(ctx, texImage, dims, + dstX, dstY, dstZ, + srcRb, srcX, srcY, width, height); } check_gen_mipmap(ctx, target, texObj, level); @@ -3523,7 +3705,7 @@ copyteximage(struct gl_context *ctx, GLuint dims, _mesa_update_fbo_texture(ctx, texObj, face, level); - _mesa_dirty_texobj(ctx, texObj, GL_TRUE); + _mesa_dirty_texobj(ctx, texObj); } } _mesa_unlock_texture(ctx, texObj); @@ -3607,13 +3789,15 @@ copytexsubimage(struct gl_context *ctx, GLuint dims, GLenum target, GLint level, struct gl_renderbuffer *srcRb = get_copy_tex_image_source(ctx, texImage->TexFormat); - ctx->Driver.CopyTexSubImage(ctx, dims, texImage, - xoffset, yoffset, zoffset, - srcRb, x, y, width, height); + copytexsubimage_by_slice(ctx, texImage, dims, + xoffset, yoffset, zoffset, + srcRb, x, y, width, height); check_gen_mipmap(ctx, target, texObj, level); - ctx->NewState |= _NEW_TEXTURE; + /* NOTE: Don't signal _NEW_TEXTURE since we've only changed + * the texel data, not the texture format, size, etc. + */ } } _mesa_unlock_texture(ctx, texObj); @@ -3652,6 +3836,266 @@ _mesa_CopyTexSubImage3D( GLenum target, GLint level, x, y, width, height); } +static bool +check_clear_tex_image(struct gl_context *ctx, + const char *function, + struct gl_texture_image *texImage, + GLenum format, GLenum type, + const void *data, + GLubyte *clearValue) +{ + struct gl_texture_object *texObj = texImage->TexObject; + static const GLubyte zeroData[MAX_PIXEL_BYTES]; + GLenum internalFormat = texImage->InternalFormat; + GLenum err; + + if (texObj->Target == GL_TEXTURE_BUFFER) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(buffer texture)", function); + return false; + } + + if (_mesa_is_compressed_format(ctx, internalFormat)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(compressed texture)", function); + return false; + } + + err = _mesa_error_check_format_and_type(ctx, format, type); + if (err != GL_NO_ERROR) { + _mesa_error(ctx, err, + "%s(incompatible format = %s, type = %s)", + function, + _mesa_lookup_enum_by_nr(format), + _mesa_lookup_enum_by_nr(type)); + return false; + } + + /* make sure internal format and format basically agree */ + if (!texture_formats_agree(internalFormat, format)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(incompatible internalFormat = %s, format = %s)", + function, + _mesa_lookup_enum_by_nr(internalFormat), + _mesa_lookup_enum_by_nr(format)); + return false; + } + + if (ctx->Version >= 30 || ctx->Extensions.EXT_texture_integer) { + /* both source and dest must be integer-valued, or neither */ + if (_mesa_is_format_integer_color(texImage->TexFormat) != + _mesa_is_enum_format_integer(format)) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(integer/non-integer format mismatch)", + function); + return false; + } + } + + if (!_mesa_texstore(ctx, + 1, /* dims */ + texImage->_BaseFormat, + texImage->TexFormat, + 0, /* dstRowStride */ + &clearValue, + 1, 1, 1, /* srcWidth/Height/Depth */ + format, type, + data ? data : zeroData, + &ctx->DefaultPacking)) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid format)", function); + return false; + } + + return true; +} + +static struct gl_texture_object * +get_tex_obj_for_clear(struct gl_context *ctx, + const char *function, + GLuint texture) +{ + struct gl_texture_object *texObj; + + if (texture == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(zero texture)", function); + return NULL; + } + + texObj = _mesa_lookup_texture(ctx, texture); + + if (texObj == NULL) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(non-gen name)", function); + return NULL; + } + + if (texObj->Target == 0) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(unbound tex)", function); + return NULL; + } + + return texObj; +} + +static int +get_tex_images_for_clear(struct gl_context *ctx, + const char *function, + struct gl_texture_object *texObj, + GLint level, + struct gl_texture_image **texImages) +{ + GLenum target; + int i; + + if (level < 0 || level >= MAX_TEXTURE_LEVELS) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid level)", function); + return 0; + } + + if (texObj->Target == GL_TEXTURE_CUBE_MAP) { + for (i = 0; i < MAX_FACES; i++) { + target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + i; + + texImages[i] = _mesa_select_tex_image(ctx, texObj, target, level); + if (texImages[i] == NULL) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "%s(invalid level)", function); + return 0; + } + } + + return MAX_FACES; + } + + texImages[0] = _mesa_select_tex_image(ctx, texObj, texObj->Target, level); + + if (texImages[0] == NULL) { + _mesa_error(ctx, GL_INVALID_OPERATION, "%s(invalid level)", function); + return 0; + } + + return 1; +} + +void GLAPIENTRY +_mesa_ClearTexSubImage( GLuint texture, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, const void *data ) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_texture_object *texObj; + struct gl_texture_image *texImages[MAX_FACES]; + GLubyte clearValue[MAX_FACES][MAX_PIXEL_BYTES]; + int i, numImages; + int minDepth, maxDepth; + + texObj = get_tex_obj_for_clear(ctx, "glClearTexSubImage", texture); + + if (texObj == NULL) + return; + + _mesa_lock_texture(ctx, texObj); + + numImages = get_tex_images_for_clear(ctx, "glClearTexSubImage", + texObj, level, texImages); + if (numImages == 0) + goto out; + + if (numImages == 1) { + minDepth = -(int) texImages[0]->Border; + maxDepth = texImages[0]->Depth; + } else { + minDepth = 0; + maxDepth = numImages; + } + + if (xoffset < -(GLint) texImages[0]->Border || + yoffset < -(GLint) texImages[0]->Border || + zoffset < minDepth || + width < 0 || + height < 0 || + depth < 0 || + xoffset + width > texImages[0]->Width || + yoffset + height > texImages[0]->Height || + zoffset + depth > maxDepth) { + _mesa_error(ctx, GL_INVALID_OPERATION, + "glClearSubTexImage(invalid dimensions)"); + goto out; + } + + if (numImages == 1) { + if (check_clear_tex_image(ctx, "glClearTexSubImage", + texImages[0], + format, type, data, clearValue[0])) { + ctx->Driver.ClearTexSubImage(ctx, + texImages[0], + xoffset, yoffset, zoffset, + width, height, depth, + data ? clearValue[0] : NULL); + } + } else { + for (i = zoffset; i < zoffset + depth; i++) { + if (!check_clear_tex_image(ctx, "glClearTexSubImage", + texImages[i], + format, type, data, clearValue[i])) + goto out; + } + for (i = zoffset; i < zoffset + depth; i++) { + ctx->Driver.ClearTexSubImage(ctx, + texImages[i], + xoffset, yoffset, 0, + width, height, 1, + data ? clearValue[i] : NULL); + } + } + + out: + _mesa_unlock_texture(ctx, texObj); +} + +void GLAPIENTRY +_mesa_ClearTexImage( GLuint texture, GLint level, + GLenum format, GLenum type, const void *data ) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_texture_object *texObj; + struct gl_texture_image *texImages[MAX_FACES]; + GLubyte clearValue[MAX_FACES][MAX_PIXEL_BYTES]; + int i, numImages; + + texObj = get_tex_obj_for_clear(ctx, "glClearTexImage", texture); + + if (texObj == NULL) + return; + + _mesa_lock_texture(ctx, texObj); + + numImages = get_tex_images_for_clear(ctx, "glClearTexImage", + texObj, level, texImages); + + for (i = 0; i < numImages; i++) { + if (!check_clear_tex_image(ctx, "glClearTexImage", + texImages[i], + format, type, data, + clearValue[i])) + goto out; + } + + for (i = 0; i < numImages; i++) { + ctx->Driver.ClearTexSubImage(ctx, texImages[i], + -(GLint) texImages[i]->Border, /* xoffset */ + -(GLint) texImages[i]->Border, /* yoffset */ + -(GLint) texImages[i]->Border, /* zoffset */ + texImages[i]->Width, + texImages[i]->Height, + texImages[i]->Depth, + data ? clearValue[i] : NULL); + } + +out: + _mesa_unlock_texture(ctx, texObj); +} + @@ -3704,7 +4148,7 @@ compressed_subtexture_error_check(struct gl_context *ctx, GLint dims, } if (!targetOK) { - _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexImage%uD(target)", + _mesa_error(ctx, GL_INVALID_ENUM, "glCompressedTexSubImage%uD(target)", dims); return GL_TRUE; } @@ -3717,14 +4161,22 @@ compressed_subtexture_error_check(struct gl_context *ctx, GLint dims, } if (level < 0 || level >= _mesa_max_texture_levels(ctx, target)) { - _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexImage%uD(level=%d)", + _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage%uD(level=%d)", dims, level); return GL_TRUE; } + /* Check for invalid pixel storage modes */ + if (!_mesa_compressed_texture_pixel_storage_error_check(ctx, dims, + &ctx->Unpack, + "glCompressedTexSubImage")) { + return GL_FALSE; + } + + expectedSize = compressed_tex_size(width, height, depth, format); if (expectedSize != imageSize) { - _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexImage%uD(size=%d)", + _mesa_error(ctx, GL_INVALID_VALUE, "glCompressedTexSubImage%uD(size=%d)", dims, imageSize); return GL_TRUE; } @@ -3838,7 +4290,9 @@ compressed_tex_sub_image(GLuint dims, GLenum target, GLint level, check_gen_mipmap(ctx, target, texObj, level); - ctx->NewState |= _NEW_TEXTURE; + /* NOTE: Don't signal _NEW_TEXTURE since we've only changed + * the texel data, not the texture format, size, etc. + */ } } _mesa_unlock_texture(ctx, texObj); @@ -3876,104 +4330,125 @@ _mesa_CompressedTexSubImage3D(GLenum target, GLint level, GLint xoffset, width, height, depth, format, imageSize, data); } -static gl_format +static mesa_format get_texbuffer_format(const struct gl_context *ctx, GLenum internalFormat) { + if (ctx->API != API_OPENGL_CORE) { + switch (internalFormat) { + case GL_ALPHA8: + return MESA_FORMAT_A_UNORM8; + case GL_ALPHA16: + return MESA_FORMAT_A_UNORM16; + case GL_ALPHA16F_ARB: + return MESA_FORMAT_A_FLOAT16; + case GL_ALPHA32F_ARB: + return MESA_FORMAT_A_FLOAT32; + case GL_ALPHA8I_EXT: + return MESA_FORMAT_A_SINT8; + case GL_ALPHA16I_EXT: + return MESA_FORMAT_A_SINT16; + case GL_ALPHA32I_EXT: + return MESA_FORMAT_A_SINT32; + case GL_ALPHA8UI_EXT: + return MESA_FORMAT_A_UINT8; + case GL_ALPHA16UI_EXT: + return MESA_FORMAT_A_UINT16; + case GL_ALPHA32UI_EXT: + return MESA_FORMAT_A_UINT32; + case GL_LUMINANCE8: + return MESA_FORMAT_L_UNORM8; + case GL_LUMINANCE16: + return MESA_FORMAT_L_UNORM16; + case GL_LUMINANCE16F_ARB: + return MESA_FORMAT_L_FLOAT16; + case GL_LUMINANCE32F_ARB: + return MESA_FORMAT_L_FLOAT32; + case GL_LUMINANCE8I_EXT: + return MESA_FORMAT_L_SINT8; + case GL_LUMINANCE16I_EXT: + return MESA_FORMAT_L_SINT16; + case GL_LUMINANCE32I_EXT: + return MESA_FORMAT_L_SINT32; + case GL_LUMINANCE8UI_EXT: + return MESA_FORMAT_L_UINT8; + case GL_LUMINANCE16UI_EXT: + return MESA_FORMAT_L_UINT16; + case GL_LUMINANCE32UI_EXT: + return MESA_FORMAT_L_UINT32; + case GL_LUMINANCE8_ALPHA8: + return MESA_FORMAT_L8A8_UNORM; + case GL_LUMINANCE16_ALPHA16: + return MESA_FORMAT_L16A16_UNORM; + case GL_LUMINANCE_ALPHA16F_ARB: + return MESA_FORMAT_LA_FLOAT16; + case GL_LUMINANCE_ALPHA32F_ARB: + return MESA_FORMAT_LA_FLOAT32; + case GL_LUMINANCE_ALPHA8I_EXT: + return MESA_FORMAT_LA_SINT8; + case GL_LUMINANCE_ALPHA16I_EXT: + return MESA_FORMAT_LA_SINT8; + case GL_LUMINANCE_ALPHA32I_EXT: + return MESA_FORMAT_LA_SINT16; + case GL_LUMINANCE_ALPHA8UI_EXT: + return MESA_FORMAT_LA_UINT8; + case GL_LUMINANCE_ALPHA16UI_EXT: + return MESA_FORMAT_LA_UINT16; + case GL_LUMINANCE_ALPHA32UI_EXT: + return MESA_FORMAT_LA_UINT32; + case GL_INTENSITY8: + return MESA_FORMAT_I_UNORM8; + case GL_INTENSITY16: + return MESA_FORMAT_I_UNORM16; + case GL_INTENSITY16F_ARB: + return MESA_FORMAT_I_FLOAT16; + case GL_INTENSITY32F_ARB: + return MESA_FORMAT_I_FLOAT32; + case GL_INTENSITY8I_EXT: + return MESA_FORMAT_I_SINT8; + case GL_INTENSITY16I_EXT: + return MESA_FORMAT_I_SINT16; + case GL_INTENSITY32I_EXT: + return MESA_FORMAT_I_SINT32; + case GL_INTENSITY8UI_EXT: + return MESA_FORMAT_I_UINT8; + case GL_INTENSITY16UI_EXT: + return MESA_FORMAT_I_UINT16; + case GL_INTENSITY32UI_EXT: + return MESA_FORMAT_I_UINT32; + default: + break; + } + } + + if (ctx->API == API_OPENGL_CORE && + ctx->Extensions.ARB_texture_buffer_object_rgb32) { + switch (internalFormat) { + case GL_RGB32F: + return MESA_FORMAT_RGB_FLOAT32; + case GL_RGB32UI: + return MESA_FORMAT_RGB_UINT32; + case GL_RGB32I: + return MESA_FORMAT_RGB_SINT32; + default: + break; + } + } + switch (internalFormat) { - case GL_ALPHA8: - return MESA_FORMAT_A8; - case GL_ALPHA16: - return MESA_FORMAT_A16; - case GL_ALPHA16F_ARB: - return MESA_FORMAT_ALPHA_FLOAT16; - case GL_ALPHA32F_ARB: - return MESA_FORMAT_ALPHA_FLOAT32; - case GL_ALPHA8I_EXT: - return MESA_FORMAT_ALPHA_INT8; - case GL_ALPHA16I_EXT: - return MESA_FORMAT_ALPHA_INT16; - case GL_ALPHA32I_EXT: - return MESA_FORMAT_ALPHA_INT32; - case GL_ALPHA8UI_EXT: - return MESA_FORMAT_ALPHA_UINT8; - case GL_ALPHA16UI_EXT: - return MESA_FORMAT_ALPHA_UINT16; - case GL_ALPHA32UI_EXT: - return MESA_FORMAT_ALPHA_UINT32; - case GL_LUMINANCE8: - return MESA_FORMAT_L8; - case GL_LUMINANCE16: - return MESA_FORMAT_L16; - case GL_LUMINANCE16F_ARB: - return MESA_FORMAT_LUMINANCE_FLOAT16; - case GL_LUMINANCE32F_ARB: - return MESA_FORMAT_LUMINANCE_FLOAT32; - case GL_LUMINANCE8I_EXT: - return MESA_FORMAT_LUMINANCE_INT8; - case GL_LUMINANCE16I_EXT: - return MESA_FORMAT_LUMINANCE_INT16; - case GL_LUMINANCE32I_EXT: - return MESA_FORMAT_LUMINANCE_INT32; - case GL_LUMINANCE8UI_EXT: - return MESA_FORMAT_LUMINANCE_UINT8; - case GL_LUMINANCE16UI_EXT: - return MESA_FORMAT_LUMINANCE_UINT16; - case GL_LUMINANCE32UI_EXT: - return MESA_FORMAT_LUMINANCE_UINT32; - case GL_LUMINANCE8_ALPHA8: - return MESA_FORMAT_AL88; - case GL_LUMINANCE16_ALPHA16: - return MESA_FORMAT_AL1616; - case GL_LUMINANCE_ALPHA16F_ARB: - return MESA_FORMAT_LUMINANCE_ALPHA_FLOAT16; - case GL_LUMINANCE_ALPHA32F_ARB: - return MESA_FORMAT_LUMINANCE_ALPHA_FLOAT32; - case GL_LUMINANCE_ALPHA8I_EXT: - return MESA_FORMAT_LUMINANCE_ALPHA_INT8; - case GL_LUMINANCE_ALPHA16I_EXT: - return MESA_FORMAT_LUMINANCE_ALPHA_INT8; - case GL_LUMINANCE_ALPHA32I_EXT: - return MESA_FORMAT_LUMINANCE_ALPHA_INT16; - case GL_LUMINANCE_ALPHA8UI_EXT: - return MESA_FORMAT_LUMINANCE_ALPHA_UINT8; - case GL_LUMINANCE_ALPHA16UI_EXT: - return MESA_FORMAT_LUMINANCE_ALPHA_UINT16; - case GL_LUMINANCE_ALPHA32UI_EXT: - return MESA_FORMAT_LUMINANCE_ALPHA_UINT32; - case GL_INTENSITY8: - return MESA_FORMAT_I8; - case GL_INTENSITY16: - return MESA_FORMAT_I16; - case GL_INTENSITY16F_ARB: - return MESA_FORMAT_INTENSITY_FLOAT16; - case GL_INTENSITY32F_ARB: - return MESA_FORMAT_INTENSITY_FLOAT32; - case GL_INTENSITY8I_EXT: - return MESA_FORMAT_INTENSITY_INT8; - case GL_INTENSITY16I_EXT: - return MESA_FORMAT_INTENSITY_INT16; - case GL_INTENSITY32I_EXT: - return MESA_FORMAT_INTENSITY_INT32; - case GL_INTENSITY8UI_EXT: - return MESA_FORMAT_INTENSITY_UINT8; - case GL_INTENSITY16UI_EXT: - return MESA_FORMAT_INTENSITY_UINT16; - case GL_INTENSITY32UI_EXT: - return MESA_FORMAT_INTENSITY_UINT32; case GL_RGBA8: - return MESA_FORMAT_RGBA8888_REV; + return MESA_FORMAT_R8G8B8A8_UNORM; case GL_RGBA16: - return MESA_FORMAT_RGBA_16; + return MESA_FORMAT_RGBA_UNORM16; case GL_RGBA16F_ARB: return MESA_FORMAT_RGBA_FLOAT16; case GL_RGBA32F_ARB: return MESA_FORMAT_RGBA_FLOAT32; case GL_RGBA8I_EXT: - return MESA_FORMAT_RGBA_INT8; + return MESA_FORMAT_RGBA_SINT8; case GL_RGBA16I_EXT: - return MESA_FORMAT_RGBA_INT16; + return MESA_FORMAT_RGBA_SINT16; case GL_RGBA32I_EXT: - return MESA_FORMAT_RGBA_INT32; + return MESA_FORMAT_RGBA_SINT32; case GL_RGBA8UI_EXT: return MESA_FORMAT_RGBA_UINT8; case GL_RGBA16UI_EXT: @@ -3982,19 +4457,19 @@ get_texbuffer_format(const struct gl_context *ctx, GLenum internalFormat) return MESA_FORMAT_RGBA_UINT32; case GL_RG8: - return MESA_FORMAT_GR88; + return MESA_FORMAT_R8G8_UNORM; case GL_RG16: - return MESA_FORMAT_GR1616; + return MESA_FORMAT_R16G16_UNORM; case GL_RG16F: return MESA_FORMAT_RG_FLOAT16; case GL_RG32F: return MESA_FORMAT_RG_FLOAT32; case GL_RG8I: - return MESA_FORMAT_RG_INT8; + return MESA_FORMAT_RG_SINT8; case GL_RG16I: - return MESA_FORMAT_RG_INT16; + return MESA_FORMAT_RG_SINT16; case GL_RG32I: - return MESA_FORMAT_RG_INT32; + return MESA_FORMAT_RG_SINT32; case GL_RG8UI: return MESA_FORMAT_RG_UINT8; case GL_RG16UI: @@ -4003,19 +4478,19 @@ get_texbuffer_format(const struct gl_context *ctx, GLenum internalFormat) return MESA_FORMAT_RG_UINT32; case GL_R8: - return MESA_FORMAT_R8; + return MESA_FORMAT_R_UNORM8; case GL_R16: - return MESA_FORMAT_R16; + return MESA_FORMAT_R_UNORM16; case GL_R16F: return MESA_FORMAT_R_FLOAT16; case GL_R32F: return MESA_FORMAT_R_FLOAT32; case GL_R8I: - return MESA_FORMAT_R_INT8; + return MESA_FORMAT_R_SINT8; case GL_R16I: - return MESA_FORMAT_R_INT16; + return MESA_FORMAT_R_SINT16; case GL_R32I: - return MESA_FORMAT_R_INT32; + return MESA_FORMAT_R_SINT32; case GL_R8UI: return MESA_FORMAT_R_UINT8; case GL_R16UI: @@ -4023,44 +4498,41 @@ get_texbuffer_format(const struct gl_context *ctx, GLenum internalFormat) case GL_R32UI: return MESA_FORMAT_R_UINT32; - case GL_RGB32F: - return MESA_FORMAT_RGB_FLOAT32; - case GL_RGB32UI: - return MESA_FORMAT_RGB_UINT32; - case GL_RGB32I: - return MESA_FORMAT_RGB_INT32; - default: return MESA_FORMAT_NONE; } } -static gl_format -validate_texbuffer_format(const struct gl_context *ctx, GLenum internalFormat) +mesa_format +_mesa_validate_texbuffer_format(const struct gl_context *ctx, + GLenum internalFormat) { - gl_format format = get_texbuffer_format(ctx, internalFormat); + mesa_format format = get_texbuffer_format(ctx, internalFormat); GLenum datatype; if (format == MESA_FORMAT_NONE) return MESA_FORMAT_NONE; datatype = _mesa_get_format_datatype(format); - if (datatype == GL_FLOAT && !ctx->Extensions.ARB_texture_float) - return MESA_FORMAT_NONE; - if (datatype == GL_HALF_FLOAT && !ctx->Extensions.ARB_half_float_pixel) + /* The GL_ARB_texture_buffer_object spec says: + * + * "If ARB_texture_float is not supported, references to the + * floating-point internal formats provided by that extension should be + * removed, and such formats may not be passed to TexBufferARB." + * + * As a result, GL_HALF_FLOAT internal format depends on both + * GL_ARB_texture_float and GL_ARB_half_float_pixel. + */ + if ((datatype == GL_FLOAT || datatype == GL_HALF_FLOAT) && + !ctx->Extensions.ARB_texture_float) return MESA_FORMAT_NONE; - /* The GL_ARB_texture_rg and GL_ARB_texture_buffer_object specs don't make - * any mention of R/RG formats, but they appear in the GL 3.1 core - * specification. - */ - if (ctx->Version <= 30) { + if (!ctx->Extensions.ARB_texture_rg) { GLenum base_format = _mesa_get_format_base_format(format); - if (base_format == GL_R || base_format == GL_RG) - return MESA_FORMAT_NONE; + return MESA_FORMAT_NONE; } if (!ctx->Extensions.ARB_texture_buffer_object_rgb32) { @@ -4078,7 +4550,7 @@ texbufferrange(struct gl_context *ctx, GLenum target, GLenum internalFormat, GLintptr offset, GLsizeiptr size) { struct gl_texture_object *texObj; - gl_format format; + mesa_format format; FLUSH_VERTICES(ctx, 0); @@ -4087,7 +4559,7 @@ texbufferrange(struct gl_context *ctx, GLenum target, GLenum internalFormat, return; } - format = validate_texbuffer_format(ctx, internalFormat); + format = _mesa_validate_texbuffer_format(ctx, internalFormat); if (format == MESA_FORMAT_NONE) { _mesa_error(ctx, GL_INVALID_ENUM, "glTexBuffer(internalFormat 0x%x)", internalFormat); @@ -4214,8 +4686,8 @@ teximagemultisample(GLuint dims, GLenum target, GLsizei samples, { struct gl_texture_object *texObj; struct gl_texture_image *texImage; - GLboolean sizeOK, dimensionsOK; - gl_format texFormat; + GLboolean sizeOK, dimensionsOK, samplesOK; + mesa_format texFormat; GLenum sample_count_error; GET_CURRENT_CONTEXT(ctx); @@ -4251,7 +4723,17 @@ teximagemultisample(GLuint dims, GLenum target, GLsizei samples, sample_count_error = _mesa_check_sample_count(ctx, target, internalformat, samples); - if (sample_count_error != GL_NO_ERROR) { + samplesOK = sample_count_error == GL_NO_ERROR; + + /* Page 254 of OpenGL 4.4 spec says: + * "Proxy arrays for two-dimensional multisample and two-dimensional + * multisample array textures are operated on in the same way when + * TexImage2DMultisample is called with target specified as + * PROXY_TEXTURE_2D_MULTISAMPLE, or TexImage3DMultisample is called + * with target specified as PROXY_TEXTURE_2D_MULTISAMPLE_ARRAY. + * However, if samples is not supported, then no error is generated. + */ + if (!samplesOK && !_mesa_is_proxy_texture(target)) { _mesa_error(ctx, sample_count_error, "%s(samples)", func); return; } @@ -4283,16 +4765,14 @@ teximagemultisample(GLuint dims, GLenum target, GLsizei samples, width, height, depth, 0); if (_mesa_is_proxy_texture(target)) { - if (dimensionsOK && sizeOK) { - _mesa_init_teximage_fields(ctx, texImage, - width, height, depth, 0, internalformat, texFormat); - texImage->NumSamples = samples; - texImage->FixedSampleLocations = fixedsamplelocations; + if (samplesOK && dimensionsOK && sizeOK) { + init_teximage_fields_ms(ctx, texImage, width, height, depth, 0, + internalformat, texFormat, + samples, fixedsamplelocations); } else { /* clear all image fields */ - _mesa_init_teximage_fields(ctx, texImage, - 0, 0, 0, 0, GL_NONE, MESA_FORMAT_NONE); + clear_teximage_fields(texImage); } } else { @@ -4316,11 +4796,9 @@ teximagemultisample(GLuint dims, GLenum target, GLsizei samples, ctx->Driver.FreeTextureImageBuffer(ctx, texImage); - _mesa_init_teximage_fields(ctx, texImage, - width, height, depth, 0, internalformat, texFormat); - - texImage->NumSamples = samples; - texImage->FixedSampleLocations = fixedsamplelocations; + init_teximage_fields_ms(ctx, texImage, width, height, depth, 0, + internalformat, texFormat, + samples, fixedsamplelocations); if (width > 0 && height > 0 && depth > 0) { if (!ctx->Driver.AllocTextureStorage(ctx, texObj, 1, @@ -4335,6 +4813,11 @@ teximagemultisample(GLuint dims, GLenum target, GLsizei samples, } texObj->Immutable = immutable; + + if (immutable) { + _mesa_set_texture_view_state(ctx, texObj, target, 1); + } + _mesa_update_fbo_texture(ctx, texObj, 0, 0); } } @@ -4342,7 +4825,7 @@ teximagemultisample(GLuint dims, GLenum target, GLsizei samples, void GLAPIENTRY _mesa_TexImage2DMultisample(GLenum target, GLsizei samples, - GLint internalformat, GLsizei width, + GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations) { teximagemultisample(2, target, samples, internalformat, @@ -4353,7 +4836,7 @@ _mesa_TexImage2DMultisample(GLenum target, GLsizei samples, void GLAPIENTRY _mesa_TexImage3DMultisample(GLenum target, GLsizei samples, - GLint internalformat, GLsizei width, + GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations) { @@ -4373,7 +4856,6 @@ _mesa_TexStorage2DMultisample(GLenum target, GLsizei samples, "glTexStorage2DMultisample"); } - void GLAPIENTRY _mesa_TexStorage3DMultisample(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width,