X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fmesa%2Fmain%2Ftexobj.c;h=d650c75e4e711fe31aab39f5ce360b6e910afeaf;hb=c73245882c7ff1277b190b97f093f7b423a22f10;hp=078a43ab1534530d67eb223cfe1d4ca7bc1f245d;hpb=d6a0692f9dc055c5e5f0e7c806537ad24aa13709;p=mesa.git diff --git a/src/mesa/main/texobj.c b/src/mesa/main/texobj.c index 078a43ab153..d650c75e4e7 100644 --- a/src/mesa/main/texobj.c +++ b/src/mesa/main/texobj.c @@ -107,6 +107,8 @@ _mesa_initialize_texture_object( struct gl_texture_object *obj, target == GL_TEXTURE_RECTANGLE_NV || target == GL_TEXTURE_1D_ARRAY_EXT || target == GL_TEXTURE_2D_ARRAY_EXT || + target == GL_TEXTURE_EXTERNAL_OES || + target == GL_TEXTURE_CUBE_MAP_ARRAY || target == GL_TEXTURE_BUFFER); memset(obj, 0, sizeof(*obj)); @@ -119,8 +121,12 @@ _mesa_initialize_texture_object( struct gl_texture_object *obj, obj->BaseLevel = 0; obj->MaxLevel = 1000; + /* must be one; no support for (YUV) planes in separate buffers */ + obj->RequiredTextureImageUnits = 1; + /* sampler state */ - if (target == GL_TEXTURE_RECTANGLE_NV) { + if (target == GL_TEXTURE_RECTANGLE_NV || + target == GL_TEXTURE_EXTERNAL_OES) { obj->Sampler.WrapS = GL_CLAMP_TO_EDGE; obj->Sampler.WrapT = GL_CLAMP_TO_EDGE; obj->Sampler.WrapR = GL_CLAMP_TO_EDGE; @@ -139,8 +145,7 @@ _mesa_initialize_texture_object( struct gl_texture_object *obj, obj->Sampler.MaxAnisotropy = 1.0; obj->Sampler.CompareMode = GL_NONE; /* ARB_shadow */ obj->Sampler.CompareFunc = GL_LEQUAL; /* ARB_shadow */ - obj->Sampler.CompareFailValue = 0.0F; /* ARB_shadow_ambient */ - obj->Sampler.DepthMode = GL_LUMINANCE; /* ARB_depth_texture */ + obj->DepthMode = GL_LUMINANCE; obj->Sampler.CubeMapSeamless = GL_FALSE; obj->Swizzle[0] = GL_RED; obj->Swizzle[1] = GL_GREEN; @@ -148,6 +153,8 @@ _mesa_initialize_texture_object( struct gl_texture_object *obj, obj->Swizzle[3] = GL_ALPHA; obj->_Swizzle = SWIZZLE_NOOP; obj->Sampler.sRGBDecode = GL_DECODE_EXT; + obj->BufferObjectFormat = GL_LUMINANCE8; + obj->_BufferObjectFormat = MESA_FORMAT_L8; } @@ -161,7 +168,8 @@ finish_texture_init(struct gl_context *ctx, GLenum target, { assert(obj->Target == 0); - if (target == GL_TEXTURE_RECTANGLE_NV) { + if (target == GL_TEXTURE_RECTANGLE_NV || + target == GL_TEXTURE_EXTERNAL_OES) { /* have to init wrap and filter state here - kind of klunky */ obj->Sampler.WrapS = GL_CLAMP_TO_EDGE; obj->Sampler.WrapT = GL_CLAMP_TO_EDGE; @@ -198,13 +206,11 @@ _mesa_delete_texture_object(struct gl_context *ctx, */ texObj->Target = 0x99; - _mesa_free_colortable_data(&texObj->Palette); - /* free the texture images */ for (face = 0; face < 6; face++) { for (i = 0; i < MAX_TEXTURE_LEVELS; i++) { if (texObj->Image[face][i]) { - _mesa_delete_texture_image( ctx, texObj->Image[face][i] ); + ctx->Driver.DeleteTextureImage(ctx, texObj->Image[face][i]); } } } @@ -251,17 +257,18 @@ _mesa_copy_texture_object( struct gl_texture_object *dest, dest->Sampler.MaxAnisotropy = src->Sampler.MaxAnisotropy; dest->Sampler.CompareMode = src->Sampler.CompareMode; dest->Sampler.CompareFunc = src->Sampler.CompareFunc; - dest->Sampler.CompareFailValue = src->Sampler.CompareFailValue; dest->Sampler.CubeMapSeamless = src->Sampler.CubeMapSeamless; - dest->Sampler.DepthMode = src->Sampler.DepthMode; + dest->DepthMode = src->DepthMode; dest->Sampler.sRGBDecode = src->Sampler.sRGBDecode; dest->_MaxLevel = src->_MaxLevel; dest->_MaxLambda = src->_MaxLambda; dest->GenerateMipmap = src->GenerateMipmap; - dest->Palette = src->Palette; - dest->_Complete = src->_Complete; + dest->_BaseComplete = src->_BaseComplete; + dest->_MipmapComplete = src->_MipmapComplete; COPY_4V(dest->Swizzle, src->Swizzle); dest->_Swizzle = src->_Swizzle; + + dest->RequiredTextureImageUnits = src->RequiredTextureImageUnits; } @@ -309,6 +316,8 @@ valid_texture_object(const struct gl_texture_object *tex) case GL_TEXTURE_1D_ARRAY_EXT: case GL_TEXTURE_2D_ARRAY_EXT: case GL_TEXTURE_BUFFER: + case GL_TEXTURE_EXTERNAL_OES: + case GL_TEXTURE_CUBE_MAP_ARRAY: return GL_TRUE; case 0x99: _mesa_problem(NULL, "invalid reference to a deleted texture object"); @@ -380,26 +389,41 @@ _mesa_reference_texobj_(struct gl_texture_object **ptr, } +enum base_mipmap { BASE, MIPMAP }; + /** - * Mark a texture object as incomplete. + * Mark a texture object as incomplete. There are actually three kinds of + * (in)completeness: + * 1. "base incomplete": the base level of the texture is invalid so no + * texturing is possible. + * 2. "mipmap incomplete": a non-base level of the texture is invalid so + * mipmap filtering isn't possible, but non-mipmap filtering is. + * 3. "texture incompleteness": some combination of texture state and + * sampler state renders the texture incomplete. + * * \param t texture object + * \param bm either BASE or MIPMAP to indicate what's incomplete * \param fmt... string describing why it's incomplete (for debugging). */ static void -incomplete(struct gl_texture_object *t, const char *fmt, ...) +incomplete(struct gl_texture_object *t, enum base_mipmap bm, + const char *fmt, ...) { -#if 0 - va_list args; - char s[100]; + if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_TEXTURE) { + va_list args; + char s[100]; + + va_start(args, fmt); + vsnprintf(s, sizeof(s), fmt, args); + va_end(args); - va_start(args, fmt); - vsnprintf(s, sizeof(s), fmt, args); - va_end(args); + _mesa_debug(NULL, "Texture Obj %d incomplete because: %s\n", t->Name, s); + } - printf("Texture Obj %d incomplete because: %s\n", t->Name, s); -#endif - t->_Complete = GL_FALSE; + if (bm == BASE) + t->_BaseComplete = GL_FALSE; + t->_MipmapComplete = GL_FALSE; } @@ -420,262 +444,205 @@ _mesa_test_texobj_completeness( const struct gl_context *ctx, struct gl_texture_object *t ) { const GLint baseLevel = t->BaseLevel; - GLint maxLog2 = 0, maxLevels = 0; + const struct gl_texture_image *baseImage; + GLint maxLevels = 0; - t->_Complete = GL_TRUE; /* be optimistic */ + /* We'll set these to FALSE if tests fail below */ + t->_BaseComplete = GL_TRUE; + t->_MipmapComplete = GL_TRUE; + + if (t->Target == GL_TEXTURE_BUFFER) { + /* Buffer textures are always considered complete. The obvious case where + * they would be incomplete (no BO attached) is actually specced to be + * undefined rendering results. + */ + return; + } /* Detect cases where the application set the base level to an invalid * value. */ if ((baseLevel < 0) || (baseLevel >= MAX_TEXTURE_LEVELS)) { - incomplete(t, "base level = %d is invalid", baseLevel); + incomplete(t, BASE, "base level = %d is invalid", baseLevel); return; } + if (t->MaxLevel < baseLevel) { + incomplete(t, BASE, "MAX_LEVEL (%d) < BASE_LEVEL (%d)", + t->MaxLevel, baseLevel); + return; + } + + baseImage = t->Image[0][baseLevel]; + /* Always need the base level image */ - if (!t->Image[0][baseLevel]) { - incomplete(t, "Image[baseLevel=%d] == NULL", baseLevel); + if (!baseImage) { + incomplete(t, BASE, "Image[baseLevel=%d] == NULL", baseLevel); return; } /* Check width/height/depth for zero */ - if (t->Image[0][baseLevel]->Width == 0 || - t->Image[0][baseLevel]->Height == 0 || - t->Image[0][baseLevel]->Depth == 0) { - incomplete(t, "texture width = 0"); + if (baseImage->Width == 0 || + baseImage->Height == 0 || + baseImage->Depth == 0) { + incomplete(t, BASE, "texture width or height or depth = 0"); return; } - /* Compute _MaxLevel */ - if ((t->Target == GL_TEXTURE_1D) || - (t->Target == GL_TEXTURE_1D_ARRAY_EXT)) { - maxLog2 = t->Image[0][baseLevel]->WidthLog2; - maxLevels = ctx->Const.MaxTextureLevels; + /* Check if the texture values are integer */ + { + GLenum datatype = _mesa_get_format_datatype(baseImage->TexFormat); + t->_IsIntegerFormat = datatype == GL_INT || datatype == GL_UNSIGNED_INT; } - else if ((t->Target == GL_TEXTURE_2D) || - (t->Target == GL_TEXTURE_2D_ARRAY_EXT)) { - maxLog2 = MAX2(t->Image[0][baseLevel]->WidthLog2, - t->Image[0][baseLevel]->HeightLog2); + + /* Compute _MaxLevel (the maximum mipmap level we'll sample from given the + * mipmap image sizes and GL_TEXTURE_MAX_LEVEL state). + */ + switch (t->Target) { + case GL_TEXTURE_1D: + case GL_TEXTURE_1D_ARRAY_EXT: maxLevels = ctx->Const.MaxTextureLevels; - } - else if (t->Target == GL_TEXTURE_3D) { - GLint max = MAX2(t->Image[0][baseLevel]->WidthLog2, - t->Image[0][baseLevel]->HeightLog2); - maxLog2 = MAX2(max, (GLint)(t->Image[0][baseLevel]->DepthLog2)); + break; + case GL_TEXTURE_2D: + case GL_TEXTURE_2D_ARRAY_EXT: + maxLevels = ctx->Const.MaxTextureLevels; + break; + case GL_TEXTURE_3D: maxLevels = ctx->Const.Max3DTextureLevels; - } - else if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) { - maxLog2 = MAX2(t->Image[0][baseLevel]->WidthLog2, - t->Image[0][baseLevel]->HeightLog2); + break; + case GL_TEXTURE_CUBE_MAP_ARB: + case GL_TEXTURE_CUBE_MAP_ARRAY: maxLevels = ctx->Const.MaxCubeTextureLevels; - } - else if (t->Target == GL_TEXTURE_RECTANGLE_NV) { - maxLog2 = 0; /* not applicable */ + break; + case GL_TEXTURE_RECTANGLE_NV: + case GL_TEXTURE_BUFFER: + case GL_TEXTURE_EXTERNAL_OES: maxLevels = 1; /* no mipmapping */ - } - else { + break; + default: _mesa_problem(ctx, "Bad t->Target in _mesa_test_texobj_completeness"); return; } ASSERT(maxLevels > 0); - if (t->MaxLevel < t->BaseLevel) { - incomplete(t, "MAX_LEVEL (%d) < BASE_LEVEL (%d)", - t->MaxLevel, t->BaseLevel); - return; - } - - t->_MaxLevel = baseLevel + maxLog2; + t->_MaxLevel = + baseLevel + baseImage->MaxNumLevels - 1; /* 'p' in the GL spec */ t->_MaxLevel = MIN2(t->_MaxLevel, t->MaxLevel); - t->_MaxLevel = MIN2(t->_MaxLevel, maxLevels - 1); + t->_MaxLevel = MIN2(t->_MaxLevel, maxLevels - 1); /* 'q' in the GL spec */ /* Compute _MaxLambda = q - b (see the 1.2 spec) used during mipmapping */ - t->_MaxLambda = (GLfloat) (t->_MaxLevel - t->BaseLevel); + t->_MaxLambda = (GLfloat) (t->_MaxLevel - baseLevel); + + if (t->Immutable) { + /* This texture object was created with glTexStorage1/2/3D() so we + * know that all the mipmap levels are the right size and all cube + * map faces are the same size. + * We don't need to do any of the additional checks below. + */ + return; + } if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) { - /* make sure that all six cube map level 0 images are the same size */ - const GLuint w = t->Image[0][baseLevel]->Width2; - const GLuint h = t->Image[0][baseLevel]->Height2; + /* Make sure that all six cube map level 0 images are the same size. + * Note: we know that the image's width==height (we enforce that + * at glTexImage time) so we only need to test the width here. + */ GLuint face; + assert(baseImage->Width2 == baseImage->Height); for (face = 1; face < 6; face++) { + assert(t->Image[face][baseLevel] == NULL || + t->Image[face][baseLevel]->Width2 == + t->Image[face][baseLevel]->Height2); if (t->Image[face][baseLevel] == NULL || - t->Image[face][baseLevel]->Width2 != w || - t->Image[face][baseLevel]->Height2 != h) { - incomplete(t, "Cube face missing or mismatched size"); + t->Image[face][baseLevel]->Width2 != baseImage->Width2) { + incomplete(t, BASE, "Cube face missing or mismatched size"); return; } } } - /* extra checking for mipmaps */ - if (t->Sampler.MinFilter != GL_NEAREST && t->Sampler.MinFilter != GL_LINEAR) { - /* - * Mipmapping: determine if we have a complete set of mipmaps - */ + /* + * Do mipmap consistency checking. + * Note: we don't care about the current texture sampler state here. + * To determine texture completeness we'll either look at _BaseComplete + * or _MipmapComplete depending on the current minification filter mode. + */ + { GLint i; - GLint minLevel = baseLevel; - GLint maxLevel = t->_MaxLevel; + const GLint minLevel = baseLevel; + const GLint maxLevel = t->_MaxLevel; + const GLuint numFaces = _mesa_num_tex_faces(t->Target); + GLuint width, height, depth, face; if (minLevel > maxLevel) { - incomplete(t, "minLevel > maxLevel"); + incomplete(t, BASE, "minLevel > maxLevel"); return; } - /* Test dimension-independent attributes */ - for (i = minLevel; i <= maxLevel; i++) { - if (t->Image[0][i]) { - if (t->Image[0][i]->TexFormat != t->Image[0][baseLevel]->TexFormat) { - incomplete(t, "Format[i] != Format[baseLevel]"); - return; - } - if (t->Image[0][i]->Border != t->Image[0][baseLevel]->Border) { - incomplete(t, "Border[i] != Border[baseLevel]"); - return; - } - } - } + /* Get the base image's dimensions */ + width = baseImage->Width2; + height = baseImage->Height2; + depth = baseImage->Depth2; - /* Test things which depend on number of texture image dimensions */ - if ((t->Target == GL_TEXTURE_1D) || - (t->Target == GL_TEXTURE_1D_ARRAY_EXT)) { - /* Test 1-D mipmaps */ - GLuint width = t->Image[0][baseLevel]->Width2; - for (i = baseLevel + 1; i < maxLevels; i++) { - if (width > 1) { - width /= 2; - } - if (i >= minLevel && i <= maxLevel) { - if (!t->Image[0][i]) { - incomplete(t, "1D Image[0][i] == NULL"); - return; - } - if (t->Image[0][i]->Width2 != width ) { - incomplete(t, "1D Image[0][i] bad width"); - return; - } - } - if (width == 1) { - return; /* found smallest needed mipmap, all done! */ - } + /* Note: this loop will be a no-op for RECT, BUFFER, EXTERNAL textures */ + for (i = baseLevel + 1; i < maxLevels; i++) { + /* Compute the expected size of image at level[i] */ + if (width > 1) { + width /= 2; } - } - else if ((t->Target == GL_TEXTURE_2D) || - (t->Target == GL_TEXTURE_2D_ARRAY_EXT)) { - /* Test 2-D mipmaps */ - GLuint width = t->Image[0][baseLevel]->Width2; - GLuint height = t->Image[0][baseLevel]->Height2; - for (i = baseLevel + 1; i < maxLevels; i++) { - if (width > 1) { - width /= 2; - } - if (height > 1) { - height /= 2; - } + if (height > 1 && t->Target != GL_TEXTURE_1D_ARRAY) { + height /= 2; + } + if (depth > 1 && t->Target != GL_TEXTURE_2D_ARRAY && t->Target != GL_TEXTURE_CUBE_MAP_ARRAY) { + depth /= 2; + } + + /* loop over cube faces (or single face otherwise) */ + for (face = 0; face < numFaces; face++) { if (i >= minLevel && i <= maxLevel) { - if (!t->Image[0][i]) { - incomplete(t, "2D Image[0][i] == NULL"); - return; - } - if (t->Image[0][i]->Width2 != width) { - incomplete(t, "2D Image[0][i] bad width"); - return; - } - if (t->Image[0][i]->Height2 != height) { - incomplete(t, "2D Image[0][i] bad height"); + const struct gl_texture_image *img = t->Image[face][i]; + + if (!img) { + incomplete(t, MIPMAP, "TexImage[%d] is missing", i); return; } - if (width==1 && height==1) { - return; /* found smallest needed mipmap, all done! */ - } - } - } - } - else if (t->Target == GL_TEXTURE_3D) { - /* Test 3-D mipmaps */ - GLuint width = t->Image[0][baseLevel]->Width2; - GLuint height = t->Image[0][baseLevel]->Height2; - GLuint depth = t->Image[0][baseLevel]->Depth2; - for (i = baseLevel + 1; i < maxLevels; i++) { - if (width > 1) { - width /= 2; - } - if (height > 1) { - height /= 2; - } - if (depth > 1) { - depth /= 2; - } - if (i >= minLevel && i <= maxLevel) { - if (!t->Image[0][i]) { - incomplete(t, "3D Image[0][i] == NULL"); + if (img->TexFormat != baseImage->TexFormat) { + incomplete(t, MIPMAP, "Format[i] != Format[baseLevel]"); return; } - if (t->Image[0][i]->_BaseFormat == GL_DEPTH_COMPONENT) { - incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex"); + if (img->Border != baseImage->Border) { + incomplete(t, MIPMAP, "Border[i] != Border[baseLevel]"); return; } - if (t->Image[0][i]->Width2 != width) { - incomplete(t, "3D Image[0][i] bad width"); + if (img->Width2 != width) { + incomplete(t, MIPMAP, "TexImage[%d] bad width %u", i, img->Width2); return; } - if (t->Image[0][i]->Height2 != height) { - incomplete(t, "3D Image[0][i] bad height"); + if (img->Height2 != height) { + incomplete(t, MIPMAP, "TexImage[%d] bad height %u", i, img->Height2); return; } - if (t->Image[0][i]->Depth2 != depth) { - incomplete(t, "3D Image[0][i] bad depth"); + if (img->Depth2 != depth) { + incomplete(t, MIPMAP, "TexImage[%d] bad depth %u", i, img->Depth2); return; } - } - if (width == 1 && height == 1 && depth == 1) { - return; /* found smallest needed mipmap, all done! */ - } - } - } - else if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) { - /* make sure 6 cube faces are consistant */ - GLuint width = t->Image[0][baseLevel]->Width2; - GLuint height = t->Image[0][baseLevel]->Height2; - for (i = baseLevel + 1; i < maxLevels; i++) { - if (width > 1) { - width /= 2; - } - if (height > 1) { - height /= 2; - } - if (i >= minLevel && i <= maxLevel) { - GLuint face; - for (face = 0; face < 6; face++) { - /* check that we have images defined */ - if (!t->Image[face][i]) { - incomplete(t, "CubeMap Image[n][i] == NULL"); - return; - } - /* Don't support GL_DEPTH_COMPONENT for cube maps */ - if (t->Image[face][i]->_BaseFormat == GL_DEPTH_COMPONENT) { - incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex"); - return; - } - /* check that all six images have same size */ - if (t->Image[face][i]->Width2 != width || - t->Image[face][i]->Height2 != height) { - incomplete(t, "CubeMap Image[n][i] bad size"); + + /* Extra checks for cube textures */ + if (face > 0) { + /* check that cube faces are the same size */ + if (img->Width2 != t->Image[0][i]->Width2 || + img->Height2 != t->Image[0][i]->Height2) { + incomplete(t, MIPMAP, "CubeMap Image[n][i] bad size"); return; } - } - } - if (width == 1 && height == 1) { - return; /* found smallest needed mipmap, all done! */ + } } } - } - else if (t->Target == GL_TEXTURE_RECTANGLE_NV) { - /* XXX special checking? */ - } - else { - /* Target = ??? */ - _mesa_problem(ctx, "Bug in gl_test_texture_object_completeness\n"); + + if (width == 1 && height == 1 && depth == 1) { + return; /* found smallest needed mipmap, all done! */ + } } } } @@ -731,69 +698,241 @@ void _mesa_dirty_texobj(struct gl_context *ctx, struct gl_texture_object *texObj, GLboolean invalidate_state) { - texObj->_Complete = GL_FALSE; + texObj->_BaseComplete = GL_FALSE; + texObj->_MipmapComplete = GL_FALSE; if (invalidate_state) ctx->NewState |= _NEW_TEXTURE; } /** - * Return pointer to a default/fallback texture. - * The texture is a 2D 8x8 RGBA texture with all texels = (0,0,0,1). - * That's the value a sampler should get when sampling from an + * Return pointer to a default/fallback texture of the given type/target. + * The texture is an RGBA texture with all texels = (0,0,0,1). + * That's the value a GLSL sampler should get when sampling from an * incomplete texture. */ struct gl_texture_object * -_mesa_get_fallback_texture(struct gl_context *ctx) +_mesa_get_fallback_texture(struct gl_context *ctx, gl_texture_index tex) { - if (!ctx->Shared->FallbackTex) { + if (!ctx->Shared->FallbackTex[tex]) { /* create fallback texture now */ - static GLubyte texels[8 * 8][4]; + const GLsizei width = 1, height = 1, depth = 1; + GLubyte texel[4]; struct gl_texture_object *texObj; struct gl_texture_image *texImage; gl_format texFormat; - GLuint i; - - for (i = 0; i < 8 * 8; i++) { - texels[i][0] = - texels[i][1] = - texels[i][2] = 0x0; - texels[i][3] = 0xff; + GLuint dims, face, numFaces = 1; + GLenum target; + + texel[0] = + texel[1] = + texel[2] = 0x0; + texel[3] = 0xff; + + switch (tex) { + case TEXTURE_2D_ARRAY_INDEX: + dims = 3; + target = GL_TEXTURE_2D_ARRAY; + break; + case TEXTURE_1D_ARRAY_INDEX: + dims = 2; + target = GL_TEXTURE_1D_ARRAY; + break; + case TEXTURE_CUBE_INDEX: + dims = 2; + target = GL_TEXTURE_CUBE_MAP; + numFaces = 6; + break; + case TEXTURE_3D_INDEX: + dims = 3; + target = GL_TEXTURE_3D; + break; + case TEXTURE_RECT_INDEX: + dims = 2; + target = GL_TEXTURE_RECTANGLE; + break; + case TEXTURE_2D_INDEX: + dims = 2; + target = GL_TEXTURE_2D; + break; + case TEXTURE_1D_INDEX: + dims = 1; + target = GL_TEXTURE_1D; + break; + case TEXTURE_BUFFER_INDEX: + dims = 0; + target = GL_TEXTURE_BUFFER; + break; + case TEXTURE_CUBE_ARRAY_INDEX: + dims = 3; + target = GL_TEXTURE_CUBE_MAP_ARRAY; + break; + case TEXTURE_EXTERNAL_INDEX: + dims = 2; + target = GL_TEXTURE_EXTERNAL_OES; + break; + default: + /* no-op */ + return NULL; } /* create texture object */ - texObj = ctx->Driver.NewTextureObject(ctx, 0, GL_TEXTURE_2D); + texObj = ctx->Driver.NewTextureObject(ctx, 0, target); + if (!texObj) + return NULL; + assert(texObj->RefCount == 1); texObj->Sampler.MinFilter = GL_NEAREST; texObj->Sampler.MagFilter = GL_NEAREST; - /* create level[0] texture image */ - texImage = _mesa_get_tex_image(ctx, texObj, GL_TEXTURE_2D, 0); - - texFormat = ctx->Driver.ChooseTextureFormat(ctx, GL_RGBA, GL_RGBA, + texFormat = ctx->Driver.ChooseTextureFormat(ctx, target, + GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE); - /* init the image fields */ - _mesa_init_teximage_fields(ctx, GL_TEXTURE_2D, texImage, - 8, 8, 1, 0, GL_RGBA, texFormat); + /* need a loop here just for cube maps */ + for (face = 0; face < numFaces; face++) { + GLenum faceTarget; - ASSERT(texImage->TexFormat != MESA_FORMAT_NONE); + if (target == GL_TEXTURE_CUBE_MAP) + faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; + else + faceTarget = target; + + /* initialize level[0] texture image */ + texImage = _mesa_get_tex_image(ctx, texObj, faceTarget, 0); - /* set image data */ - ctx->Driver.TexImage2D(ctx, GL_TEXTURE_2D, 0, GL_RGBA, - 8, 8, 0, - GL_RGBA, GL_UNSIGNED_BYTE, texels, - &ctx->DefaultPacking, texObj, texImage); + _mesa_init_teximage_fields(ctx, texImage, + width, + (dims > 1) ? height : 1, + (dims > 2) ? depth : 1, + 0, /* border */ + GL_RGBA, texFormat); + + ctx->Driver.TexImage(ctx, dims, texImage, + GL_RGBA, GL_UNSIGNED_BYTE, texel, + &ctx->DefaultPacking); + } _mesa_test_texobj_completeness(ctx, texObj); - assert(texObj->_Complete); + assert(texObj->_BaseComplete); + assert(texObj->_MipmapComplete); - ctx->Shared->FallbackTex = texObj; + ctx->Shared->FallbackTex[tex] = texObj; } - return ctx->Shared->FallbackTex; + return ctx->Shared->FallbackTex[tex]; } +/** + * Compute the size of the given texture object, in bytes. + */ +static GLuint +texture_size(const struct gl_texture_object *texObj) +{ + const GLuint numFaces = _mesa_num_tex_faces(texObj->Target); + GLuint face, level, size = 0; + + for (face = 0; face < numFaces; face++) { + for (level = 0; level < MAX_TEXTURE_LEVELS; level++) { + const struct gl_texture_image *img = texObj->Image[face][level]; + if (img) { + GLuint sz = _mesa_format_image_size(img->TexFormat, img->Width, + img->Height, img->Depth); + size += sz; + } + } + } + + return size; +} + + +/** + * Callback called from _mesa_HashWalk() + */ +static void +count_tex_size(GLuint key, void *data, void *userData) +{ + const struct gl_texture_object *texObj = + (const struct gl_texture_object *) data; + GLuint *total = (GLuint *) userData; + + *total = *total + texture_size(texObj); +} + + +/** + * Compute total size (in bytes) of all textures for the given context. + * For debugging purposes. + */ +GLuint +_mesa_total_texture_memory(struct gl_context *ctx) +{ + GLuint tgt, total = 0; + + _mesa_HashWalk(ctx->Shared->TexObjects, count_tex_size, &total); + + /* plus, the default texture objects */ + for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { + total += texture_size(ctx->Shared->DefaultTex[tgt]); + } + + return total; +} + +static struct gl_texture_object * +invalidate_tex_image_error_check(struct gl_context *ctx, GLuint texture, + GLint level, const char *name) +{ + /* The GL_ARB_invalidate_subdata spec says: + * + * "If is zero or is not the name of a texture, the error + * INVALID_VALUE is generated." + * + * This performs the error check in a different order than listed in the + * spec. We have to get the texture object before we can validate the + * other parameters against values in the texture object. + */ + struct gl_texture_object *const t = _mesa_lookup_texture(ctx, texture); + if (texture == 0 || t == NULL) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(texture)", name); + return NULL; + } + + /* The GL_ARB_invalidate_subdata spec says: + * + * "If is less than zero or greater than the base 2 logarithm + * of the maximum texture width, height, or depth, the error + * INVALID_VALUE is generated." + */ + if (level < 0 || level > t->MaxLevel) { + _mesa_error(ctx, GL_INVALID_VALUE, "%s(level)", name); + return NULL; + } + + /* The GL_ARB_invalidate_subdata spec says: + * + * "If the target of is TEXTURE_RECTANGLE, TEXTURE_BUFFER, + * TEXTURE_2D_MULTISAMPLE, or TEXTURE_2D_MULTISAMPLE_ARRAY, and + * is not zero, the error INVALID_VALUE is generated." + */ + if (level != 0) { + switch (t->Target) { + case GL_TEXTURE_RECTANGLE: + case GL_TEXTURE_BUFFER: + case GL_TEXTURE_2D_MULTISAMPLE: + case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: + _mesa_error(ctx, GL_INVALID_VALUE, "%s(level)", name); + return NULL; + + default: + break; + } + } + + return t; +} + /*@}*/ @@ -872,7 +1011,7 @@ unbind_texobj_from_fbo(struct gl_context *ctx, for (i = 0; i < n; i++) { struct gl_framebuffer *fb = (i == 0) ? ctx->DrawBuffer : ctx->ReadBuffer; - if (fb->Name) { + if (_mesa_is_user_fbo(fb)) { GLuint j; for (j = 0; j < BUFFER_COUNT; j++) { if (fb->Attachment[j].Type == GL_TEXTURE && @@ -982,25 +1121,41 @@ _mesa_DeleteTextures( GLsizei n, const GLuint *textures) * \return TEXTURE_x_INDEX or -1 if target is invalid */ static GLint -target_enum_to_index(GLenum target) +target_enum_to_index(struct gl_context *ctx, GLenum target) { switch (target) { case GL_TEXTURE_1D: - return TEXTURE_1D_INDEX; + return _mesa_is_desktop_gl(ctx) ? TEXTURE_1D_INDEX : -1; case GL_TEXTURE_2D: return TEXTURE_2D_INDEX; case GL_TEXTURE_3D: return TEXTURE_3D_INDEX; case GL_TEXTURE_CUBE_MAP_ARB: - return TEXTURE_CUBE_INDEX; + return ctx->Extensions.ARB_texture_cube_map + ? TEXTURE_CUBE_INDEX : -1; case GL_TEXTURE_RECTANGLE_NV: - return TEXTURE_RECT_INDEX; + return _mesa_is_desktop_gl(ctx) && ctx->Extensions.NV_texture_rectangle + ? TEXTURE_RECT_INDEX : -1; case GL_TEXTURE_1D_ARRAY_EXT: - return TEXTURE_1D_ARRAY_INDEX; + return _mesa_is_desktop_gl(ctx) + && (ctx->Extensions.EXT_texture_array + || ctx->Extensions.MESA_texture_array) + ? TEXTURE_1D_ARRAY_INDEX : -1; case GL_TEXTURE_2D_ARRAY_EXT: - return TEXTURE_2D_ARRAY_INDEX; + return (_mesa_is_desktop_gl(ctx) + && (ctx->Extensions.EXT_texture_array + || ctx->Extensions.MESA_texture_array)) + || _mesa_is_gles3(ctx) + ? TEXTURE_2D_ARRAY_INDEX : -1; case GL_TEXTURE_BUFFER_ARB: - return TEXTURE_BUFFER_INDEX; + return _mesa_is_desktop_gl(ctx) + && ctx->Extensions.ARB_texture_buffer_object + ? TEXTURE_BUFFER_INDEX : -1; + case GL_TEXTURE_EXTERNAL_OES: + return _mesa_is_gles(ctx) && ctx->Extensions.OES_EGL_image_external + ? TEXTURE_EXTERNAL_INDEX : -1; + case GL_TEXTURE_CUBE_MAP_ARRAY: + return TEXTURE_CUBE_ARRAY_INDEX; default: return -1; } @@ -1035,7 +1190,7 @@ _mesa_BindTexture( GLenum target, GLuint texName ) _mesa_debug(ctx, "glBindTexture %s %d\n", _mesa_lookup_enum_by_nr(target), (GLint) texName); - targetIndex = target_enum_to_index(target); + targetIndex = target_enum_to_index(ctx, target); if (targetIndex < 0) { _mesa_error(ctx, GL_INVALID_ENUM, "glBindTexture(target)"); return; @@ -1065,6 +1220,11 @@ _mesa_BindTexture( GLenum target, GLuint texName ) } } else { + if (ctx->API == API_OPENGL_CORE) { + _mesa_error(ctx, GL_INVALID_OPERATION, "glBindTexture(non-gen name)"); + return; + } + /* if this is a new texture id, allocate a texture object now */ newTexObj = ctx->Driver.NewTextureObject(ctx, texName, target); if (!newTexObj) { @@ -1163,10 +1323,7 @@ _mesa_PrioritizeTextures( GLsizei n, const GLuint *texName, * * \return GL_TRUE if all textures are resident and \p residences is left unchanged, * - * \sa glAreTexturesResident(). - * - * Looks up each texture in the hash and calls - * dd_function_table::IsTextureResident. + * Note: we assume all textures are always resident */ GLboolean GLAPIENTRY _mesa_AreTexturesResident(GLsizei n, const GLuint *texName, @@ -1174,7 +1331,7 @@ _mesa_AreTexturesResident(GLsizei n, const GLuint *texName, { GET_CURRENT_CONTEXT(ctx); GLboolean allResident = GL_TRUE; - GLint i, j; + GLint i; ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); if (n < 0) { @@ -1185,6 +1342,7 @@ _mesa_AreTexturesResident(GLsizei n, const GLuint *texName, if (!texName || !residences) return GL_FALSE; + /* We only do error checking on the texture names */ for (i = 0; i < n; i++) { struct gl_texture_object *t; if (texName[i] == 0) { @@ -1196,21 +1354,6 @@ _mesa_AreTexturesResident(GLsizei n, const GLuint *texName, _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident"); return GL_FALSE; } - if (!ctx->Driver.IsTextureResident || - ctx->Driver.IsTextureResident(ctx, t)) { - /* The texture is resident */ - if (!allResident) - residences[i] = GL_TRUE; - } - else { - /* The texture is not resident */ - if (allResident) { - allResident = GL_FALSE; - for (j = 0; j < i; j++) - residences[j] = GL_TRUE; - } - residences[i] = GL_FALSE; - } } return allResident; @@ -1276,4 +1419,164 @@ _mesa_unlock_context_textures( struct gl_context *ctx ) _glthread_UNLOCK_MUTEX(ctx->Shared->TexMutex); } +void GLAPIENTRY +_mesa_InvalidateTexSubImage(GLuint texture, GLint level, GLint xoffset, + GLint yoffset, GLint zoffset, GLsizei width, + GLsizei height, GLsizei depth) +{ + struct gl_texture_object *t; + struct gl_texture_image *image; + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + t = invalidate_tex_image_error_check(ctx, texture, level, + "glInvalidateTexSubImage"); + + /* The GL_ARB_invalidate_subdata spec says: + * + * "...the specified subregion must be between - and + where + * is the size of the dimension of the texture image, and is + * the size of the border of that texture image, otherwise + * INVALID_VALUE is generated (border is not applied to dimensions that + * don't exist in a given texture target)." + */ + image = t->Image[0][level]; + if (image) { + int xBorder; + int yBorder; + int zBorder; + int imageWidth; + int imageHeight; + int imageDepth; + + /* The GL_ARB_invalidate_subdata spec says: + * + * "For texture targets that don't have certain dimensions, this + * command treats those dimensions as having a size of 1. For + * example, to invalidate a portion of a two-dimensional texture, + * the application would use equal to zero and + * equal to one." + */ + switch (t->Target) { + case GL_TEXTURE_BUFFER: + xBorder = 0; + yBorder = 0; + zBorder = 0; + imageWidth = 1; + imageHeight = 1; + imageDepth = 1; + break; + case GL_TEXTURE_1D: + xBorder = image->Border; + yBorder = 0; + zBorder = 0; + imageWidth = image->Width; + imageHeight = 1; + imageDepth = 1; + break; + case GL_TEXTURE_1D_ARRAY: + xBorder = image->Border; + yBorder = 0; + zBorder = 0; + imageWidth = image->Width; + imageHeight = image->Height; + imageDepth = 1; + break; + case GL_TEXTURE_2D: + case GL_TEXTURE_CUBE_MAP: + case GL_TEXTURE_RECTANGLE: + case GL_TEXTURE_2D_MULTISAMPLE: + xBorder = image->Border; + yBorder = image->Border; + zBorder = 0; + imageWidth = image->Width; + imageHeight = image->Height; + imageDepth = 1; + break; + case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_CUBE_MAP_ARRAY: + xBorder = image->Border; + yBorder = image->Border; + zBorder = 0; + imageWidth = image->Width; + imageHeight = image->Height; + imageDepth = image->Depth; + break; + case GL_TEXTURE_3D: + xBorder = image->Border; + yBorder = image->Border; + zBorder = image->Border; + imageWidth = image->Width; + imageHeight = image->Height; + imageDepth = image->Depth; + break; + default: + assert(!"Should not get here."); + xBorder = 0; + yBorder = 0; + zBorder = 0; + imageWidth = 0; + imageHeight = 0; + imageDepth = 0; + break; + } + + if (xoffset < -xBorder) { + _mesa_error(ctx, GL_INVALID_VALUE, "glInvalidateSubTexImage(xoffset)"); + return; + } + + if (xoffset + width > imageWidth + xBorder) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glInvalidateSubTexImage(xoffset+width)"); + return; + } + + if (yoffset < -yBorder) { + _mesa_error(ctx, GL_INVALID_VALUE, "glInvalidateSubTexImage(yoffset)"); + return; + } + + if (yoffset + height > imageHeight + yBorder) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glInvalidateSubTexImage(yoffset+height)"); + return; + } + + if (zoffset < -zBorder) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glInvalidateSubTexImage(zoffset)"); + return; + } + + if (zoffset + depth > imageDepth + zBorder) { + _mesa_error(ctx, GL_INVALID_VALUE, + "glInvalidateSubTexImage(zoffset+depth)"); + return; + } + } + + /* We don't actually do anything for this yet. Just return after + * validating the parameters and generating the required errors. + */ + return; +} + +void GLAPIENTRY +_mesa_InvalidateTexImage(GLuint texture, GLint level) +{ + GET_CURRENT_CONTEXT(ctx); + + ASSERT_OUTSIDE_BEGIN_END(ctx); + + invalidate_tex_image_error_check(ctx, texture, level, + "glInvalidateTexImage"); + + /* We don't actually do anything for this yet. Just return after + * validating the parameters and generating the required errors. + */ + return; +} + /*@}*/