texobj.c revision 848b8605
1848b8605Smrg/** 2848b8605Smrg * \file texobj.c 3848b8605Smrg * Texture object management. 4848b8605Smrg */ 5848b8605Smrg 6848b8605Smrg/* 7848b8605Smrg * Mesa 3-D graphics library 8848b8605Smrg * 9848b8605Smrg * Copyright (C) 1999-2007 Brian Paul All Rights Reserved. 10848b8605Smrg * 11848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a 12848b8605Smrg * copy of this software and associated documentation files (the "Software"), 13848b8605Smrg * to deal in the Software without restriction, including without limitation 14848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 15848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the 16848b8605Smrg * Software is furnished to do so, subject to the following conditions: 17848b8605Smrg * 18848b8605Smrg * The above copyright notice and this permission notice shall be included 19848b8605Smrg * in all copies or substantial portions of the Software. 20848b8605Smrg * 21848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 22848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 24848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 25848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 26848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 27848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE. 28848b8605Smrg */ 29848b8605Smrg 30848b8605Smrg 31848b8605Smrg#include "bufferobj.h" 32848b8605Smrg#include "colortab.h" 33848b8605Smrg#include "context.h" 34848b8605Smrg#include "enums.h" 35848b8605Smrg#include "fbobject.h" 36848b8605Smrg#include "formats.h" 37848b8605Smrg#include "hash.h" 38848b8605Smrg#include "imports.h" 39848b8605Smrg#include "macros.h" 40848b8605Smrg#include "teximage.h" 41848b8605Smrg#include "texobj.h" 42848b8605Smrg#include "texstate.h" 43848b8605Smrg#include "mtypes.h" 44848b8605Smrg#include "program/prog_instruction.h" 45848b8605Smrg 46848b8605Smrg 47848b8605Smrg 48848b8605Smrg/**********************************************************************/ 49848b8605Smrg/** \name Internal functions */ 50848b8605Smrg/*@{*/ 51848b8605Smrg 52848b8605Smrg 53848b8605Smrg/** 54848b8605Smrg * Return the gl_texture_object for a given ID. 55848b8605Smrg */ 56848b8605Smrgstruct gl_texture_object * 57848b8605Smrg_mesa_lookup_texture(struct gl_context *ctx, GLuint id) 58848b8605Smrg{ 59848b8605Smrg return (struct gl_texture_object *) 60848b8605Smrg _mesa_HashLookup(ctx->Shared->TexObjects, id); 61848b8605Smrg} 62848b8605Smrg 63848b8605Smrg 64848b8605Smrgvoid 65848b8605Smrg_mesa_begin_texture_lookups(struct gl_context *ctx) 66848b8605Smrg{ 67848b8605Smrg _mesa_HashLockMutex(ctx->Shared->TexObjects); 68848b8605Smrg} 69848b8605Smrg 70848b8605Smrg 71848b8605Smrgvoid 72848b8605Smrg_mesa_end_texture_lookups(struct gl_context *ctx) 73848b8605Smrg{ 74848b8605Smrg _mesa_HashUnlockMutex(ctx->Shared->TexObjects); 75848b8605Smrg} 76848b8605Smrg 77848b8605Smrg 78848b8605Smrgstruct gl_texture_object * 79848b8605Smrg_mesa_lookup_texture_locked(struct gl_context *ctx, GLuint id) 80848b8605Smrg{ 81848b8605Smrg return (struct gl_texture_object *) 82848b8605Smrg _mesa_HashLookupLocked(ctx->Shared->TexObjects, id); 83848b8605Smrg} 84848b8605Smrg 85848b8605Smrg 86848b8605Smrg/** 87848b8605Smrg * Allocate and initialize a new texture object. But don't put it into the 88848b8605Smrg * texture object hash table. 89848b8605Smrg * 90848b8605Smrg * Called via ctx->Driver.NewTextureObject, unless overridden by a device 91848b8605Smrg * driver. 92848b8605Smrg * 93848b8605Smrg * \param shared the shared GL state structure to contain the texture object 94848b8605Smrg * \param name integer name for the texture object 95848b8605Smrg * \param target either GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D, 96848b8605Smrg * GL_TEXTURE_CUBE_MAP_ARB or GL_TEXTURE_RECTANGLE_NV. zero is ok for the sake 97848b8605Smrg * of GenTextures() 98848b8605Smrg * 99848b8605Smrg * \return pointer to new texture object. 100848b8605Smrg */ 101848b8605Smrgstruct gl_texture_object * 102848b8605Smrg_mesa_new_texture_object( struct gl_context *ctx, GLuint name, GLenum target ) 103848b8605Smrg{ 104848b8605Smrg struct gl_texture_object *obj; 105848b8605Smrg (void) ctx; 106848b8605Smrg obj = MALLOC_STRUCT(gl_texture_object); 107848b8605Smrg _mesa_initialize_texture_object(ctx, obj, name, target); 108848b8605Smrg return obj; 109848b8605Smrg} 110848b8605Smrg 111848b8605Smrg 112848b8605Smrg/** 113848b8605Smrg * Initialize a new texture object to default values. 114848b8605Smrg * \param obj the texture object 115848b8605Smrg * \param name the texture name 116848b8605Smrg * \param target the texture target 117848b8605Smrg */ 118848b8605Smrgvoid 119848b8605Smrg_mesa_initialize_texture_object( struct gl_context *ctx, 120848b8605Smrg struct gl_texture_object *obj, 121848b8605Smrg GLuint name, GLenum target ) 122848b8605Smrg{ 123848b8605Smrg ASSERT(target == 0 || 124848b8605Smrg target == GL_TEXTURE_1D || 125848b8605Smrg target == GL_TEXTURE_2D || 126848b8605Smrg target == GL_TEXTURE_3D || 127848b8605Smrg target == GL_TEXTURE_CUBE_MAP_ARB || 128848b8605Smrg target == GL_TEXTURE_RECTANGLE_NV || 129848b8605Smrg target == GL_TEXTURE_1D_ARRAY_EXT || 130848b8605Smrg target == GL_TEXTURE_2D_ARRAY_EXT || 131848b8605Smrg target == GL_TEXTURE_EXTERNAL_OES || 132848b8605Smrg target == GL_TEXTURE_CUBE_MAP_ARRAY || 133848b8605Smrg target == GL_TEXTURE_BUFFER || 134848b8605Smrg target == GL_TEXTURE_2D_MULTISAMPLE || 135848b8605Smrg target == GL_TEXTURE_2D_MULTISAMPLE_ARRAY); 136848b8605Smrg 137848b8605Smrg memset(obj, 0, sizeof(*obj)); 138848b8605Smrg /* init the non-zero fields */ 139848b8605Smrg mtx_init(&obj->Mutex, mtx_plain); 140848b8605Smrg obj->RefCount = 1; 141848b8605Smrg obj->Name = name; 142848b8605Smrg obj->Target = target; 143848b8605Smrg obj->Priority = 1.0F; 144848b8605Smrg obj->BaseLevel = 0; 145848b8605Smrg obj->MaxLevel = 1000; 146848b8605Smrg 147848b8605Smrg /* must be one; no support for (YUV) planes in separate buffers */ 148848b8605Smrg obj->RequiredTextureImageUnits = 1; 149848b8605Smrg 150848b8605Smrg /* sampler state */ 151848b8605Smrg if (target == GL_TEXTURE_RECTANGLE_NV || 152848b8605Smrg target == GL_TEXTURE_EXTERNAL_OES) { 153848b8605Smrg obj->Sampler.WrapS = GL_CLAMP_TO_EDGE; 154848b8605Smrg obj->Sampler.WrapT = GL_CLAMP_TO_EDGE; 155848b8605Smrg obj->Sampler.WrapR = GL_CLAMP_TO_EDGE; 156848b8605Smrg obj->Sampler.MinFilter = GL_LINEAR; 157848b8605Smrg } 158848b8605Smrg else { 159848b8605Smrg obj->Sampler.WrapS = GL_REPEAT; 160848b8605Smrg obj->Sampler.WrapT = GL_REPEAT; 161848b8605Smrg obj->Sampler.WrapR = GL_REPEAT; 162848b8605Smrg obj->Sampler.MinFilter = GL_NEAREST_MIPMAP_LINEAR; 163848b8605Smrg } 164848b8605Smrg obj->Sampler.MagFilter = GL_LINEAR; 165848b8605Smrg obj->Sampler.MinLod = -1000.0; 166848b8605Smrg obj->Sampler.MaxLod = 1000.0; 167848b8605Smrg obj->Sampler.LodBias = 0.0; 168848b8605Smrg obj->Sampler.MaxAnisotropy = 1.0; 169848b8605Smrg obj->Sampler.CompareMode = GL_NONE; /* ARB_shadow */ 170848b8605Smrg obj->Sampler.CompareFunc = GL_LEQUAL; /* ARB_shadow */ 171848b8605Smrg obj->DepthMode = ctx->API == API_OPENGL_CORE ? GL_RED : GL_LUMINANCE; 172848b8605Smrg obj->StencilSampling = false; 173848b8605Smrg obj->Sampler.CubeMapSeamless = GL_FALSE; 174848b8605Smrg obj->Swizzle[0] = GL_RED; 175848b8605Smrg obj->Swizzle[1] = GL_GREEN; 176848b8605Smrg obj->Swizzle[2] = GL_BLUE; 177848b8605Smrg obj->Swizzle[3] = GL_ALPHA; 178848b8605Smrg obj->_Swizzle = SWIZZLE_NOOP; 179848b8605Smrg obj->Sampler.sRGBDecode = GL_DECODE_EXT; 180848b8605Smrg obj->BufferObjectFormat = GL_R8; 181848b8605Smrg obj->_BufferObjectFormat = MESA_FORMAT_R_UNORM8; 182848b8605Smrg obj->ImageFormatCompatibilityType = GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE; 183848b8605Smrg} 184848b8605Smrg 185848b8605Smrg 186848b8605Smrg/** 187848b8605Smrg * Some texture initialization can't be finished until we know which 188848b8605Smrg * target it's getting bound to (GL_TEXTURE_1D/2D/etc). 189848b8605Smrg */ 190848b8605Smrgstatic void 191848b8605Smrgfinish_texture_init(struct gl_context *ctx, GLenum target, 192848b8605Smrg struct gl_texture_object *obj) 193848b8605Smrg{ 194848b8605Smrg GLenum filter = GL_LINEAR; 195848b8605Smrg assert(obj->Target == 0); 196848b8605Smrg 197848b8605Smrg switch (target) { 198848b8605Smrg case GL_TEXTURE_2D_MULTISAMPLE: 199848b8605Smrg case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 200848b8605Smrg filter = GL_NEAREST; 201848b8605Smrg /* fallthrough */ 202848b8605Smrg 203848b8605Smrg case GL_TEXTURE_RECTANGLE_NV: 204848b8605Smrg case GL_TEXTURE_EXTERNAL_OES: 205848b8605Smrg /* have to init wrap and filter state here - kind of klunky */ 206848b8605Smrg obj->Sampler.WrapS = GL_CLAMP_TO_EDGE; 207848b8605Smrg obj->Sampler.WrapT = GL_CLAMP_TO_EDGE; 208848b8605Smrg obj->Sampler.WrapR = GL_CLAMP_TO_EDGE; 209848b8605Smrg obj->Sampler.MinFilter = filter; 210848b8605Smrg obj->Sampler.MagFilter = filter; 211848b8605Smrg if (ctx->Driver.TexParameter) { 212848b8605Smrg static const GLfloat fparam_wrap[1] = {(GLfloat) GL_CLAMP_TO_EDGE}; 213848b8605Smrg const GLfloat fparam_filter[1] = {(GLfloat) filter}; 214848b8605Smrg ctx->Driver.TexParameter(ctx, obj, GL_TEXTURE_WRAP_S, fparam_wrap); 215848b8605Smrg ctx->Driver.TexParameter(ctx, obj, GL_TEXTURE_WRAP_T, fparam_wrap); 216848b8605Smrg ctx->Driver.TexParameter(ctx, obj, GL_TEXTURE_WRAP_R, fparam_wrap); 217848b8605Smrg ctx->Driver.TexParameter(ctx, obj, 218848b8605Smrg GL_TEXTURE_MIN_FILTER, fparam_filter); 219848b8605Smrg ctx->Driver.TexParameter(ctx, obj, 220848b8605Smrg GL_TEXTURE_MAG_FILTER, fparam_filter); 221848b8605Smrg } 222848b8605Smrg break; 223848b8605Smrg 224848b8605Smrg default: 225848b8605Smrg /* nothing needs done */ 226848b8605Smrg break; 227848b8605Smrg } 228848b8605Smrg} 229848b8605Smrg 230848b8605Smrg 231848b8605Smrg/** 232848b8605Smrg * Deallocate a texture object struct. It should have already been 233848b8605Smrg * removed from the texture object pool. 234848b8605Smrg * Called via ctx->Driver.DeleteTexture() if not overriden by a driver. 235848b8605Smrg * 236848b8605Smrg * \param shared the shared GL state to which the object belongs. 237848b8605Smrg * \param texObj the texture object to delete. 238848b8605Smrg */ 239848b8605Smrgvoid 240848b8605Smrg_mesa_delete_texture_object(struct gl_context *ctx, 241848b8605Smrg struct gl_texture_object *texObj) 242848b8605Smrg{ 243848b8605Smrg GLuint i, face; 244848b8605Smrg 245848b8605Smrg /* Set Target to an invalid value. With some assertions elsewhere 246848b8605Smrg * we can try to detect possible use of deleted textures. 247848b8605Smrg */ 248848b8605Smrg texObj->Target = 0x99; 249848b8605Smrg 250848b8605Smrg /* free the texture images */ 251848b8605Smrg for (face = 0; face < 6; face++) { 252848b8605Smrg for (i = 0; i < MAX_TEXTURE_LEVELS; i++) { 253848b8605Smrg if (texObj->Image[face][i]) { 254848b8605Smrg ctx->Driver.DeleteTextureImage(ctx, texObj->Image[face][i]); 255848b8605Smrg } 256848b8605Smrg } 257848b8605Smrg } 258848b8605Smrg 259848b8605Smrg _mesa_reference_buffer_object(ctx, &texObj->BufferObject, NULL); 260848b8605Smrg 261848b8605Smrg /* destroy the mutex -- it may have allocated memory (eg on bsd) */ 262848b8605Smrg mtx_destroy(&texObj->Mutex); 263848b8605Smrg 264848b8605Smrg free(texObj->Label); 265848b8605Smrg 266848b8605Smrg /* free this object */ 267848b8605Smrg free(texObj); 268848b8605Smrg} 269848b8605Smrg 270848b8605Smrg 271848b8605Smrg 272848b8605Smrg/** 273848b8605Smrg * Copy texture object state from one texture object to another. 274848b8605Smrg * Use for glPush/PopAttrib. 275848b8605Smrg * 276848b8605Smrg * \param dest destination texture object. 277848b8605Smrg * \param src source texture object. 278848b8605Smrg */ 279848b8605Smrgvoid 280848b8605Smrg_mesa_copy_texture_object( struct gl_texture_object *dest, 281848b8605Smrg const struct gl_texture_object *src ) 282848b8605Smrg{ 283848b8605Smrg dest->Target = src->Target; 284848b8605Smrg dest->TargetIndex = src->TargetIndex; 285848b8605Smrg dest->Name = src->Name; 286848b8605Smrg dest->Priority = src->Priority; 287848b8605Smrg dest->Sampler.BorderColor.f[0] = src->Sampler.BorderColor.f[0]; 288848b8605Smrg dest->Sampler.BorderColor.f[1] = src->Sampler.BorderColor.f[1]; 289848b8605Smrg dest->Sampler.BorderColor.f[2] = src->Sampler.BorderColor.f[2]; 290848b8605Smrg dest->Sampler.BorderColor.f[3] = src->Sampler.BorderColor.f[3]; 291848b8605Smrg dest->Sampler.WrapS = src->Sampler.WrapS; 292848b8605Smrg dest->Sampler.WrapT = src->Sampler.WrapT; 293848b8605Smrg dest->Sampler.WrapR = src->Sampler.WrapR; 294848b8605Smrg dest->Sampler.MinFilter = src->Sampler.MinFilter; 295848b8605Smrg dest->Sampler.MagFilter = src->Sampler.MagFilter; 296848b8605Smrg dest->Sampler.MinLod = src->Sampler.MinLod; 297848b8605Smrg dest->Sampler.MaxLod = src->Sampler.MaxLod; 298848b8605Smrg dest->Sampler.LodBias = src->Sampler.LodBias; 299848b8605Smrg dest->BaseLevel = src->BaseLevel; 300848b8605Smrg dest->MaxLevel = src->MaxLevel; 301848b8605Smrg dest->Sampler.MaxAnisotropy = src->Sampler.MaxAnisotropy; 302848b8605Smrg dest->Sampler.CompareMode = src->Sampler.CompareMode; 303848b8605Smrg dest->Sampler.CompareFunc = src->Sampler.CompareFunc; 304848b8605Smrg dest->Sampler.CubeMapSeamless = src->Sampler.CubeMapSeamless; 305848b8605Smrg dest->DepthMode = src->DepthMode; 306848b8605Smrg dest->StencilSampling = src->StencilSampling; 307848b8605Smrg dest->Sampler.sRGBDecode = src->Sampler.sRGBDecode; 308848b8605Smrg dest->_MaxLevel = src->_MaxLevel; 309848b8605Smrg dest->_MaxLambda = src->_MaxLambda; 310848b8605Smrg dest->GenerateMipmap = src->GenerateMipmap; 311848b8605Smrg dest->_BaseComplete = src->_BaseComplete; 312848b8605Smrg dest->_MipmapComplete = src->_MipmapComplete; 313848b8605Smrg COPY_4V(dest->Swizzle, src->Swizzle); 314848b8605Smrg dest->_Swizzle = src->_Swizzle; 315848b8605Smrg 316848b8605Smrg dest->RequiredTextureImageUnits = src->RequiredTextureImageUnits; 317848b8605Smrg} 318848b8605Smrg 319848b8605Smrg 320848b8605Smrg/** 321848b8605Smrg * Free all texture images of the given texture object. 322848b8605Smrg * 323848b8605Smrg * \param ctx GL context. 324848b8605Smrg * \param t texture object. 325848b8605Smrg * 326848b8605Smrg * \sa _mesa_clear_texture_image(). 327848b8605Smrg */ 328848b8605Smrgvoid 329848b8605Smrg_mesa_clear_texture_object(struct gl_context *ctx, 330848b8605Smrg struct gl_texture_object *texObj) 331848b8605Smrg{ 332848b8605Smrg GLuint i, j; 333848b8605Smrg 334848b8605Smrg if (texObj->Target == 0) 335848b8605Smrg return; 336848b8605Smrg 337848b8605Smrg for (i = 0; i < MAX_FACES; i++) { 338848b8605Smrg for (j = 0; j < MAX_TEXTURE_LEVELS; j++) { 339848b8605Smrg struct gl_texture_image *texImage = texObj->Image[i][j]; 340848b8605Smrg if (texImage) 341848b8605Smrg _mesa_clear_texture_image(ctx, texImage); 342848b8605Smrg } 343848b8605Smrg } 344848b8605Smrg} 345848b8605Smrg 346848b8605Smrg 347848b8605Smrg/** 348848b8605Smrg * Check if the given texture object is valid by examining its Target field. 349848b8605Smrg * For debugging only. 350848b8605Smrg */ 351848b8605Smrgstatic GLboolean 352848b8605Smrgvalid_texture_object(const struct gl_texture_object *tex) 353848b8605Smrg{ 354848b8605Smrg switch (tex->Target) { 355848b8605Smrg case 0: 356848b8605Smrg case GL_TEXTURE_1D: 357848b8605Smrg case GL_TEXTURE_2D: 358848b8605Smrg case GL_TEXTURE_3D: 359848b8605Smrg case GL_TEXTURE_CUBE_MAP_ARB: 360848b8605Smrg case GL_TEXTURE_RECTANGLE_NV: 361848b8605Smrg case GL_TEXTURE_1D_ARRAY_EXT: 362848b8605Smrg case GL_TEXTURE_2D_ARRAY_EXT: 363848b8605Smrg case GL_TEXTURE_BUFFER: 364848b8605Smrg case GL_TEXTURE_EXTERNAL_OES: 365848b8605Smrg case GL_TEXTURE_CUBE_MAP_ARRAY: 366848b8605Smrg case GL_TEXTURE_2D_MULTISAMPLE: 367848b8605Smrg case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 368848b8605Smrg return GL_TRUE; 369848b8605Smrg case 0x99: 370848b8605Smrg _mesa_problem(NULL, "invalid reference to a deleted texture object"); 371848b8605Smrg return GL_FALSE; 372848b8605Smrg default: 373848b8605Smrg _mesa_problem(NULL, "invalid texture object Target 0x%x, Id = %u", 374848b8605Smrg tex->Target, tex->Name); 375848b8605Smrg return GL_FALSE; 376848b8605Smrg } 377848b8605Smrg} 378848b8605Smrg 379848b8605Smrg 380848b8605Smrg/** 381848b8605Smrg * Reference (or unreference) a texture object. 382848b8605Smrg * If '*ptr', decrement *ptr's refcount (and delete if it becomes zero). 383848b8605Smrg * If 'tex' is non-null, increment its refcount. 384848b8605Smrg * This is normally only called from the _mesa_reference_texobj() macro 385848b8605Smrg * when there's a real pointer change. 386848b8605Smrg */ 387848b8605Smrgvoid 388848b8605Smrg_mesa_reference_texobj_(struct gl_texture_object **ptr, 389848b8605Smrg struct gl_texture_object *tex) 390848b8605Smrg{ 391848b8605Smrg assert(ptr); 392848b8605Smrg 393848b8605Smrg if (*ptr) { 394848b8605Smrg /* Unreference the old texture */ 395848b8605Smrg GLboolean deleteFlag = GL_FALSE; 396848b8605Smrg struct gl_texture_object *oldTex = *ptr; 397848b8605Smrg 398848b8605Smrg ASSERT(valid_texture_object(oldTex)); 399848b8605Smrg (void) valid_texture_object; /* silence warning in release builds */ 400848b8605Smrg 401848b8605Smrg mtx_lock(&oldTex->Mutex); 402848b8605Smrg ASSERT(oldTex->RefCount > 0); 403848b8605Smrg oldTex->RefCount--; 404848b8605Smrg 405848b8605Smrg deleteFlag = (oldTex->RefCount == 0); 406848b8605Smrg mtx_unlock(&oldTex->Mutex); 407848b8605Smrg 408848b8605Smrg if (deleteFlag) { 409848b8605Smrg GET_CURRENT_CONTEXT(ctx); 410848b8605Smrg if (ctx) 411848b8605Smrg ctx->Driver.DeleteTexture(ctx, oldTex); 412848b8605Smrg else 413848b8605Smrg _mesa_problem(NULL, "Unable to delete texture, no context"); 414848b8605Smrg } 415848b8605Smrg 416848b8605Smrg *ptr = NULL; 417848b8605Smrg } 418848b8605Smrg assert(!*ptr); 419848b8605Smrg 420848b8605Smrg if (tex) { 421848b8605Smrg /* reference new texture */ 422848b8605Smrg ASSERT(valid_texture_object(tex)); 423848b8605Smrg mtx_lock(&tex->Mutex); 424848b8605Smrg if (tex->RefCount == 0) { 425848b8605Smrg /* this texture's being deleted (look just above) */ 426848b8605Smrg /* Not sure this can every really happen. Warn if it does. */ 427848b8605Smrg _mesa_problem(NULL, "referencing deleted texture object"); 428848b8605Smrg *ptr = NULL; 429848b8605Smrg } 430848b8605Smrg else { 431848b8605Smrg tex->RefCount++; 432848b8605Smrg *ptr = tex; 433848b8605Smrg } 434848b8605Smrg mtx_unlock(&tex->Mutex); 435848b8605Smrg } 436848b8605Smrg} 437848b8605Smrg 438848b8605Smrg 439848b8605Smrgenum base_mipmap { BASE, MIPMAP }; 440848b8605Smrg 441848b8605Smrg 442848b8605Smrg/** 443848b8605Smrg * Mark a texture object as incomplete. There are actually three kinds of 444848b8605Smrg * (in)completeness: 445848b8605Smrg * 1. "base incomplete": the base level of the texture is invalid so no 446848b8605Smrg * texturing is possible. 447848b8605Smrg * 2. "mipmap incomplete": a non-base level of the texture is invalid so 448848b8605Smrg * mipmap filtering isn't possible, but non-mipmap filtering is. 449848b8605Smrg * 3. "texture incompleteness": some combination of texture state and 450848b8605Smrg * sampler state renders the texture incomplete. 451848b8605Smrg * 452848b8605Smrg * \param t texture object 453848b8605Smrg * \param bm either BASE or MIPMAP to indicate what's incomplete 454848b8605Smrg * \param fmt... string describing why it's incomplete (for debugging). 455848b8605Smrg */ 456848b8605Smrgstatic void 457848b8605Smrgincomplete(struct gl_texture_object *t, enum base_mipmap bm, 458848b8605Smrg const char *fmt, ...) 459848b8605Smrg{ 460848b8605Smrg if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_TEXTURE) { 461848b8605Smrg va_list args; 462848b8605Smrg char s[100]; 463848b8605Smrg 464848b8605Smrg va_start(args, fmt); 465848b8605Smrg vsnprintf(s, sizeof(s), fmt, args); 466848b8605Smrg va_end(args); 467848b8605Smrg 468848b8605Smrg _mesa_debug(NULL, "Texture Obj %d incomplete because: %s\n", t->Name, s); 469848b8605Smrg } 470848b8605Smrg 471848b8605Smrg if (bm == BASE) 472848b8605Smrg t->_BaseComplete = GL_FALSE; 473848b8605Smrg t->_MipmapComplete = GL_FALSE; 474848b8605Smrg} 475848b8605Smrg 476848b8605Smrg 477848b8605Smrg/** 478848b8605Smrg * Examine a texture object to determine if it is complete. 479848b8605Smrg * 480848b8605Smrg * The gl_texture_object::Complete flag will be set to GL_TRUE or GL_FALSE 481848b8605Smrg * accordingly. 482848b8605Smrg * 483848b8605Smrg * \param ctx GL context. 484848b8605Smrg * \param t texture object. 485848b8605Smrg * 486848b8605Smrg * According to the texture target, verifies that each of the mipmaps is 487848b8605Smrg * present and has the expected size. 488848b8605Smrg */ 489848b8605Smrgvoid 490848b8605Smrg_mesa_test_texobj_completeness( const struct gl_context *ctx, 491848b8605Smrg struct gl_texture_object *t ) 492848b8605Smrg{ 493848b8605Smrg const GLint baseLevel = t->BaseLevel; 494848b8605Smrg const struct gl_texture_image *baseImage; 495848b8605Smrg GLint maxLevels = 0; 496848b8605Smrg 497848b8605Smrg /* We'll set these to FALSE if tests fail below */ 498848b8605Smrg t->_BaseComplete = GL_TRUE; 499848b8605Smrg t->_MipmapComplete = GL_TRUE; 500848b8605Smrg 501848b8605Smrg if (t->Target == GL_TEXTURE_BUFFER) { 502848b8605Smrg /* Buffer textures are always considered complete. The obvious case where 503848b8605Smrg * they would be incomplete (no BO attached) is actually specced to be 504848b8605Smrg * undefined rendering results. 505848b8605Smrg */ 506848b8605Smrg return; 507848b8605Smrg } 508848b8605Smrg 509848b8605Smrg /* Detect cases where the application set the base level to an invalid 510848b8605Smrg * value. 511848b8605Smrg */ 512848b8605Smrg if ((baseLevel < 0) || (baseLevel >= MAX_TEXTURE_LEVELS)) { 513848b8605Smrg incomplete(t, BASE, "base level = %d is invalid", baseLevel); 514848b8605Smrg return; 515848b8605Smrg } 516848b8605Smrg 517848b8605Smrg if (t->MaxLevel < baseLevel) { 518848b8605Smrg incomplete(t, MIPMAP, "MAX_LEVEL (%d) < BASE_LEVEL (%d)", 519848b8605Smrg t->MaxLevel, baseLevel); 520848b8605Smrg return; 521848b8605Smrg } 522848b8605Smrg 523848b8605Smrg baseImage = t->Image[0][baseLevel]; 524848b8605Smrg 525848b8605Smrg /* Always need the base level image */ 526848b8605Smrg if (!baseImage) { 527848b8605Smrg incomplete(t, BASE, "Image[baseLevel=%d] == NULL", baseLevel); 528848b8605Smrg return; 529848b8605Smrg } 530848b8605Smrg 531848b8605Smrg /* Check width/height/depth for zero */ 532848b8605Smrg if (baseImage->Width == 0 || 533848b8605Smrg baseImage->Height == 0 || 534848b8605Smrg baseImage->Depth == 0) { 535848b8605Smrg incomplete(t, BASE, "texture width or height or depth = 0"); 536848b8605Smrg return; 537848b8605Smrg } 538848b8605Smrg 539848b8605Smrg /* Check if the texture values are integer */ 540848b8605Smrg { 541848b8605Smrg GLenum datatype = _mesa_get_format_datatype(baseImage->TexFormat); 542848b8605Smrg t->_IsIntegerFormat = datatype == GL_INT || datatype == GL_UNSIGNED_INT; 543848b8605Smrg } 544848b8605Smrg 545848b8605Smrg /* Compute _MaxLevel (the maximum mipmap level we'll sample from given the 546848b8605Smrg * mipmap image sizes and GL_TEXTURE_MAX_LEVEL state). 547848b8605Smrg */ 548848b8605Smrg switch (t->Target) { 549848b8605Smrg case GL_TEXTURE_1D: 550848b8605Smrg case GL_TEXTURE_1D_ARRAY_EXT: 551848b8605Smrg maxLevels = ctx->Const.MaxTextureLevels; 552848b8605Smrg break; 553848b8605Smrg case GL_TEXTURE_2D: 554848b8605Smrg case GL_TEXTURE_2D_ARRAY_EXT: 555848b8605Smrg maxLevels = ctx->Const.MaxTextureLevels; 556848b8605Smrg break; 557848b8605Smrg case GL_TEXTURE_3D: 558848b8605Smrg maxLevels = ctx->Const.Max3DTextureLevels; 559848b8605Smrg break; 560848b8605Smrg case GL_TEXTURE_CUBE_MAP_ARB: 561848b8605Smrg case GL_TEXTURE_CUBE_MAP_ARRAY: 562848b8605Smrg maxLevels = ctx->Const.MaxCubeTextureLevels; 563848b8605Smrg break; 564848b8605Smrg case GL_TEXTURE_RECTANGLE_NV: 565848b8605Smrg case GL_TEXTURE_BUFFER: 566848b8605Smrg case GL_TEXTURE_EXTERNAL_OES: 567848b8605Smrg case GL_TEXTURE_2D_MULTISAMPLE: 568848b8605Smrg case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 569848b8605Smrg maxLevels = 1; /* no mipmapping */ 570848b8605Smrg break; 571848b8605Smrg default: 572848b8605Smrg _mesa_problem(ctx, "Bad t->Target in _mesa_test_texobj_completeness"); 573848b8605Smrg return; 574848b8605Smrg } 575848b8605Smrg 576848b8605Smrg ASSERT(maxLevels > 0); 577848b8605Smrg 578848b8605Smrg t->_MaxLevel = MIN3(t->MaxLevel, 579848b8605Smrg /* 'p' in the GL spec */ 580848b8605Smrg (int) (baseLevel + baseImage->MaxNumLevels - 1), 581848b8605Smrg /* 'q' in the GL spec */ 582848b8605Smrg maxLevels - 1); 583848b8605Smrg 584848b8605Smrg if (t->Immutable) { 585848b8605Smrg /* Adjust max level for views: the data store may have more levels than 586848b8605Smrg * the view exposes. 587848b8605Smrg */ 588848b8605Smrg t->_MaxLevel = MIN2(t->_MaxLevel, t->NumLevels - 1); 589848b8605Smrg } 590848b8605Smrg 591848b8605Smrg /* Compute _MaxLambda = q - p in the spec used during mipmapping */ 592848b8605Smrg t->_MaxLambda = (GLfloat) (t->_MaxLevel - baseLevel); 593848b8605Smrg 594848b8605Smrg if (t->Immutable) { 595848b8605Smrg /* This texture object was created with glTexStorage1/2/3D() so we 596848b8605Smrg * know that all the mipmap levels are the right size and all cube 597848b8605Smrg * map faces are the same size. 598848b8605Smrg * We don't need to do any of the additional checks below. 599848b8605Smrg */ 600848b8605Smrg return; 601848b8605Smrg } 602848b8605Smrg 603848b8605Smrg if (t->Target == GL_TEXTURE_CUBE_MAP_ARB) { 604848b8605Smrg /* Make sure that all six cube map level 0 images are the same size. 605848b8605Smrg * Note: we know that the image's width==height (we enforce that 606848b8605Smrg * at glTexImage time) so we only need to test the width here. 607848b8605Smrg */ 608848b8605Smrg GLuint face; 609848b8605Smrg assert(baseImage->Width2 == baseImage->Height); 610848b8605Smrg for (face = 1; face < 6; face++) { 611848b8605Smrg assert(t->Image[face][baseLevel] == NULL || 612848b8605Smrg t->Image[face][baseLevel]->Width2 == 613848b8605Smrg t->Image[face][baseLevel]->Height2); 614848b8605Smrg if (t->Image[face][baseLevel] == NULL || 615848b8605Smrg t->Image[face][baseLevel]->Width2 != baseImage->Width2) { 616848b8605Smrg incomplete(t, BASE, "Cube face missing or mismatched size"); 617848b8605Smrg return; 618848b8605Smrg } 619848b8605Smrg } 620848b8605Smrg } 621848b8605Smrg 622848b8605Smrg /* 623848b8605Smrg * Do mipmap consistency checking. 624848b8605Smrg * Note: we don't care about the current texture sampler state here. 625848b8605Smrg * To determine texture completeness we'll either look at _BaseComplete 626848b8605Smrg * or _MipmapComplete depending on the current minification filter mode. 627848b8605Smrg */ 628848b8605Smrg { 629848b8605Smrg GLint i; 630848b8605Smrg const GLint minLevel = baseLevel; 631848b8605Smrg const GLint maxLevel = t->_MaxLevel; 632848b8605Smrg const GLuint numFaces = _mesa_num_tex_faces(t->Target); 633848b8605Smrg GLuint width, height, depth, face; 634848b8605Smrg 635848b8605Smrg if (minLevel > maxLevel) { 636848b8605Smrg incomplete(t, MIPMAP, "minLevel > maxLevel"); 637848b8605Smrg return; 638848b8605Smrg } 639848b8605Smrg 640848b8605Smrg /* Get the base image's dimensions */ 641848b8605Smrg width = baseImage->Width2; 642848b8605Smrg height = baseImage->Height2; 643848b8605Smrg depth = baseImage->Depth2; 644848b8605Smrg 645848b8605Smrg /* Note: this loop will be a no-op for RECT, BUFFER, EXTERNAL, 646848b8605Smrg * MULTISAMPLE and MULTISAMPLE_ARRAY textures 647848b8605Smrg */ 648848b8605Smrg for (i = baseLevel + 1; i < maxLevels; i++) { 649848b8605Smrg /* Compute the expected size of image at level[i] */ 650848b8605Smrg if (width > 1) { 651848b8605Smrg width /= 2; 652848b8605Smrg } 653848b8605Smrg if (height > 1 && t->Target != GL_TEXTURE_1D_ARRAY) { 654848b8605Smrg height /= 2; 655848b8605Smrg } 656848b8605Smrg if (depth > 1 && t->Target != GL_TEXTURE_2D_ARRAY && t->Target != GL_TEXTURE_CUBE_MAP_ARRAY) { 657848b8605Smrg depth /= 2; 658848b8605Smrg } 659848b8605Smrg 660848b8605Smrg /* loop over cube faces (or single face otherwise) */ 661848b8605Smrg for (face = 0; face < numFaces; face++) { 662848b8605Smrg if (i >= minLevel && i <= maxLevel) { 663848b8605Smrg const struct gl_texture_image *img = t->Image[face][i]; 664848b8605Smrg 665848b8605Smrg if (!img) { 666848b8605Smrg incomplete(t, MIPMAP, "TexImage[%d] is missing", i); 667848b8605Smrg return; 668848b8605Smrg } 669848b8605Smrg if (img->TexFormat != baseImage->TexFormat) { 670848b8605Smrg incomplete(t, MIPMAP, "Format[i] != Format[baseLevel]"); 671848b8605Smrg return; 672848b8605Smrg } 673848b8605Smrg if (img->Border != baseImage->Border) { 674848b8605Smrg incomplete(t, MIPMAP, "Border[i] != Border[baseLevel]"); 675848b8605Smrg return; 676848b8605Smrg } 677848b8605Smrg if (img->Width2 != width) { 678848b8605Smrg incomplete(t, MIPMAP, "TexImage[%d] bad width %u", i, img->Width2); 679848b8605Smrg return; 680848b8605Smrg } 681848b8605Smrg if (img->Height2 != height) { 682848b8605Smrg incomplete(t, MIPMAP, "TexImage[%d] bad height %u", i, img->Height2); 683848b8605Smrg return; 684848b8605Smrg } 685848b8605Smrg if (img->Depth2 != depth) { 686848b8605Smrg incomplete(t, MIPMAP, "TexImage[%d] bad depth %u", i, img->Depth2); 687848b8605Smrg return; 688848b8605Smrg } 689848b8605Smrg 690848b8605Smrg /* Extra checks for cube textures */ 691848b8605Smrg if (face > 0) { 692848b8605Smrg /* check that cube faces are the same size */ 693848b8605Smrg if (img->Width2 != t->Image[0][i]->Width2 || 694848b8605Smrg img->Height2 != t->Image[0][i]->Height2) { 695848b8605Smrg incomplete(t, MIPMAP, "CubeMap Image[n][i] bad size"); 696848b8605Smrg return; 697848b8605Smrg } 698848b8605Smrg } 699848b8605Smrg } 700848b8605Smrg } 701848b8605Smrg 702848b8605Smrg if (width == 1 && height == 1 && depth == 1) { 703848b8605Smrg return; /* found smallest needed mipmap, all done! */ 704848b8605Smrg } 705848b8605Smrg } 706848b8605Smrg } 707848b8605Smrg} 708848b8605Smrg 709848b8605Smrg 710848b8605Smrg/** 711848b8605Smrg * Check if the given cube map texture is "cube complete" as defined in 712848b8605Smrg * the OpenGL specification. 713848b8605Smrg */ 714848b8605SmrgGLboolean 715848b8605Smrg_mesa_cube_complete(const struct gl_texture_object *texObj) 716848b8605Smrg{ 717848b8605Smrg const GLint baseLevel = texObj->BaseLevel; 718848b8605Smrg const struct gl_texture_image *img0, *img; 719848b8605Smrg GLuint face; 720848b8605Smrg 721848b8605Smrg if (texObj->Target != GL_TEXTURE_CUBE_MAP) 722848b8605Smrg return GL_FALSE; 723848b8605Smrg 724848b8605Smrg if ((baseLevel < 0) || (baseLevel >= MAX_TEXTURE_LEVELS)) 725848b8605Smrg return GL_FALSE; 726848b8605Smrg 727848b8605Smrg /* check first face */ 728848b8605Smrg img0 = texObj->Image[0][baseLevel]; 729848b8605Smrg if (!img0 || 730848b8605Smrg img0->Width < 1 || 731848b8605Smrg img0->Width != img0->Height) 732848b8605Smrg return GL_FALSE; 733848b8605Smrg 734848b8605Smrg /* check remaining faces vs. first face */ 735848b8605Smrg for (face = 1; face < 6; face++) { 736848b8605Smrg img = texObj->Image[face][baseLevel]; 737848b8605Smrg if (!img || 738848b8605Smrg img->Width != img0->Width || 739848b8605Smrg img->Height != img0->Height || 740848b8605Smrg img->TexFormat != img0->TexFormat) 741848b8605Smrg return GL_FALSE; 742848b8605Smrg } 743848b8605Smrg 744848b8605Smrg return GL_TRUE; 745848b8605Smrg} 746848b8605Smrg 747848b8605Smrg 748848b8605Smrg/** 749848b8605Smrg * Mark a texture object dirty. It forces the object to be incomplete 750848b8605Smrg * and forces the context to re-validate its state. 751848b8605Smrg * 752848b8605Smrg * \param ctx GL context. 753848b8605Smrg * \param texObj texture object. 754848b8605Smrg */ 755848b8605Smrgvoid 756848b8605Smrg_mesa_dirty_texobj(struct gl_context *ctx, struct gl_texture_object *texObj) 757848b8605Smrg{ 758848b8605Smrg texObj->_BaseComplete = GL_FALSE; 759848b8605Smrg texObj->_MipmapComplete = GL_FALSE; 760848b8605Smrg ctx->NewState |= _NEW_TEXTURE; 761848b8605Smrg} 762848b8605Smrg 763848b8605Smrg 764848b8605Smrg/** 765848b8605Smrg * Return pointer to a default/fallback texture of the given type/target. 766848b8605Smrg * The texture is an RGBA texture with all texels = (0,0,0,1). 767848b8605Smrg * That's the value a GLSL sampler should get when sampling from an 768848b8605Smrg * incomplete texture. 769848b8605Smrg */ 770848b8605Smrgstruct gl_texture_object * 771848b8605Smrg_mesa_get_fallback_texture(struct gl_context *ctx, gl_texture_index tex) 772848b8605Smrg{ 773848b8605Smrg if (!ctx->Shared->FallbackTex[tex]) { 774848b8605Smrg /* create fallback texture now */ 775848b8605Smrg const GLsizei width = 1, height = 1, depth = 1; 776848b8605Smrg GLubyte texel[4]; 777848b8605Smrg struct gl_texture_object *texObj; 778848b8605Smrg struct gl_texture_image *texImage; 779848b8605Smrg mesa_format texFormat; 780848b8605Smrg GLuint dims, face, numFaces = 1; 781848b8605Smrg GLenum target; 782848b8605Smrg 783848b8605Smrg texel[0] = 784848b8605Smrg texel[1] = 785848b8605Smrg texel[2] = 0x0; 786848b8605Smrg texel[3] = 0xff; 787848b8605Smrg 788848b8605Smrg switch (tex) { 789848b8605Smrg case TEXTURE_2D_ARRAY_INDEX: 790848b8605Smrg dims = 3; 791848b8605Smrg target = GL_TEXTURE_2D_ARRAY; 792848b8605Smrg break; 793848b8605Smrg case TEXTURE_1D_ARRAY_INDEX: 794848b8605Smrg dims = 2; 795848b8605Smrg target = GL_TEXTURE_1D_ARRAY; 796848b8605Smrg break; 797848b8605Smrg case TEXTURE_CUBE_INDEX: 798848b8605Smrg dims = 2; 799848b8605Smrg target = GL_TEXTURE_CUBE_MAP; 800848b8605Smrg numFaces = 6; 801848b8605Smrg break; 802848b8605Smrg case TEXTURE_3D_INDEX: 803848b8605Smrg dims = 3; 804848b8605Smrg target = GL_TEXTURE_3D; 805848b8605Smrg break; 806848b8605Smrg case TEXTURE_RECT_INDEX: 807848b8605Smrg dims = 2; 808848b8605Smrg target = GL_TEXTURE_RECTANGLE; 809848b8605Smrg break; 810848b8605Smrg case TEXTURE_2D_INDEX: 811848b8605Smrg dims = 2; 812848b8605Smrg target = GL_TEXTURE_2D; 813848b8605Smrg break; 814848b8605Smrg case TEXTURE_1D_INDEX: 815848b8605Smrg dims = 1; 816848b8605Smrg target = GL_TEXTURE_1D; 817848b8605Smrg break; 818848b8605Smrg case TEXTURE_BUFFER_INDEX: 819848b8605Smrg dims = 0; 820848b8605Smrg target = GL_TEXTURE_BUFFER; 821848b8605Smrg break; 822848b8605Smrg case TEXTURE_CUBE_ARRAY_INDEX: 823848b8605Smrg dims = 3; 824848b8605Smrg target = GL_TEXTURE_CUBE_MAP_ARRAY; 825848b8605Smrg break; 826848b8605Smrg case TEXTURE_EXTERNAL_INDEX: 827848b8605Smrg dims = 2; 828848b8605Smrg target = GL_TEXTURE_EXTERNAL_OES; 829848b8605Smrg break; 830848b8605Smrg case TEXTURE_2D_MULTISAMPLE_INDEX: 831848b8605Smrg dims = 2; 832848b8605Smrg target = GL_TEXTURE_2D_MULTISAMPLE; 833848b8605Smrg break; 834848b8605Smrg case TEXTURE_2D_MULTISAMPLE_ARRAY_INDEX: 835848b8605Smrg dims = 3; 836848b8605Smrg target = GL_TEXTURE_2D_MULTISAMPLE_ARRAY; 837848b8605Smrg break; 838848b8605Smrg default: 839848b8605Smrg /* no-op */ 840848b8605Smrg return NULL; 841848b8605Smrg } 842848b8605Smrg 843848b8605Smrg /* create texture object */ 844848b8605Smrg texObj = ctx->Driver.NewTextureObject(ctx, 0, target); 845848b8605Smrg if (!texObj) 846848b8605Smrg return NULL; 847848b8605Smrg 848848b8605Smrg assert(texObj->RefCount == 1); 849848b8605Smrg texObj->Sampler.MinFilter = GL_NEAREST; 850848b8605Smrg texObj->Sampler.MagFilter = GL_NEAREST; 851848b8605Smrg 852848b8605Smrg texFormat = ctx->Driver.ChooseTextureFormat(ctx, target, 853848b8605Smrg GL_RGBA, GL_RGBA, 854848b8605Smrg GL_UNSIGNED_BYTE); 855848b8605Smrg 856848b8605Smrg /* need a loop here just for cube maps */ 857848b8605Smrg for (face = 0; face < numFaces; face++) { 858848b8605Smrg GLenum faceTarget; 859848b8605Smrg 860848b8605Smrg if (target == GL_TEXTURE_CUBE_MAP) 861848b8605Smrg faceTarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + face; 862848b8605Smrg else 863848b8605Smrg faceTarget = target; 864848b8605Smrg 865848b8605Smrg /* initialize level[0] texture image */ 866848b8605Smrg texImage = _mesa_get_tex_image(ctx, texObj, faceTarget, 0); 867848b8605Smrg 868848b8605Smrg _mesa_init_teximage_fields(ctx, texImage, 869848b8605Smrg width, 870848b8605Smrg (dims > 1) ? height : 1, 871848b8605Smrg (dims > 2) ? depth : 1, 872848b8605Smrg 0, /* border */ 873848b8605Smrg GL_RGBA, texFormat); 874848b8605Smrg 875848b8605Smrg ctx->Driver.TexImage(ctx, dims, texImage, 876848b8605Smrg GL_RGBA, GL_UNSIGNED_BYTE, texel, 877848b8605Smrg &ctx->DefaultPacking); 878848b8605Smrg } 879848b8605Smrg 880848b8605Smrg _mesa_test_texobj_completeness(ctx, texObj); 881848b8605Smrg assert(texObj->_BaseComplete); 882848b8605Smrg assert(texObj->_MipmapComplete); 883848b8605Smrg 884848b8605Smrg ctx->Shared->FallbackTex[tex] = texObj; 885848b8605Smrg } 886848b8605Smrg return ctx->Shared->FallbackTex[tex]; 887848b8605Smrg} 888848b8605Smrg 889848b8605Smrg 890848b8605Smrg/** 891848b8605Smrg * Compute the size of the given texture object, in bytes. 892848b8605Smrg */ 893848b8605Smrgstatic GLuint 894848b8605Smrgtexture_size(const struct gl_texture_object *texObj) 895848b8605Smrg{ 896848b8605Smrg const GLuint numFaces = _mesa_num_tex_faces(texObj->Target); 897848b8605Smrg GLuint face, level, size = 0; 898848b8605Smrg 899848b8605Smrg for (face = 0; face < numFaces; face++) { 900848b8605Smrg for (level = 0; level < MAX_TEXTURE_LEVELS; level++) { 901848b8605Smrg const struct gl_texture_image *img = texObj->Image[face][level]; 902848b8605Smrg if (img) { 903848b8605Smrg GLuint sz = _mesa_format_image_size(img->TexFormat, img->Width, 904848b8605Smrg img->Height, img->Depth); 905848b8605Smrg size += sz; 906848b8605Smrg } 907848b8605Smrg } 908848b8605Smrg } 909848b8605Smrg 910848b8605Smrg return size; 911848b8605Smrg} 912848b8605Smrg 913848b8605Smrg 914848b8605Smrg/** 915848b8605Smrg * Callback called from _mesa_HashWalk() 916848b8605Smrg */ 917848b8605Smrgstatic void 918848b8605Smrgcount_tex_size(GLuint key, void *data, void *userData) 919848b8605Smrg{ 920848b8605Smrg const struct gl_texture_object *texObj = 921848b8605Smrg (const struct gl_texture_object *) data; 922848b8605Smrg GLuint *total = (GLuint *) userData; 923848b8605Smrg 924848b8605Smrg (void) key; 925848b8605Smrg 926848b8605Smrg *total = *total + texture_size(texObj); 927848b8605Smrg} 928848b8605Smrg 929848b8605Smrg 930848b8605Smrg/** 931848b8605Smrg * Compute total size (in bytes) of all textures for the given context. 932848b8605Smrg * For debugging purposes. 933848b8605Smrg */ 934848b8605SmrgGLuint 935848b8605Smrg_mesa_total_texture_memory(struct gl_context *ctx) 936848b8605Smrg{ 937848b8605Smrg GLuint tgt, total = 0; 938848b8605Smrg 939848b8605Smrg _mesa_HashWalk(ctx->Shared->TexObjects, count_tex_size, &total); 940848b8605Smrg 941848b8605Smrg /* plus, the default texture objects */ 942848b8605Smrg for (tgt = 0; tgt < NUM_TEXTURE_TARGETS; tgt++) { 943848b8605Smrg total += texture_size(ctx->Shared->DefaultTex[tgt]); 944848b8605Smrg } 945848b8605Smrg 946848b8605Smrg return total; 947848b8605Smrg} 948848b8605Smrg 949848b8605Smrgstatic struct gl_texture_object * 950848b8605Smrginvalidate_tex_image_error_check(struct gl_context *ctx, GLuint texture, 951848b8605Smrg GLint level, const char *name) 952848b8605Smrg{ 953848b8605Smrg /* The GL_ARB_invalidate_subdata spec says: 954848b8605Smrg * 955848b8605Smrg * "If <texture> is zero or is not the name of a texture, the error 956848b8605Smrg * INVALID_VALUE is generated." 957848b8605Smrg * 958848b8605Smrg * This performs the error check in a different order than listed in the 959848b8605Smrg * spec. We have to get the texture object before we can validate the 960848b8605Smrg * other parameters against values in the texture object. 961848b8605Smrg */ 962848b8605Smrg struct gl_texture_object *const t = _mesa_lookup_texture(ctx, texture); 963848b8605Smrg if (texture == 0 || t == NULL) { 964848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(texture)", name); 965848b8605Smrg return NULL; 966848b8605Smrg } 967848b8605Smrg 968848b8605Smrg /* The GL_ARB_invalidate_subdata spec says: 969848b8605Smrg * 970848b8605Smrg * "If <level> is less than zero or greater than the base 2 logarithm 971848b8605Smrg * of the maximum texture width, height, or depth, the error 972848b8605Smrg * INVALID_VALUE is generated." 973848b8605Smrg */ 974848b8605Smrg if (level < 0 || level > t->MaxLevel) { 975848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(level)", name); 976848b8605Smrg return NULL; 977848b8605Smrg } 978848b8605Smrg 979848b8605Smrg /* The GL_ARB_invalidate_subdata spec says: 980848b8605Smrg * 981848b8605Smrg * "If the target of <texture> is TEXTURE_RECTANGLE, TEXTURE_BUFFER, 982848b8605Smrg * TEXTURE_2D_MULTISAMPLE, or TEXTURE_2D_MULTISAMPLE_ARRAY, and <level> 983848b8605Smrg * is not zero, the error INVALID_VALUE is generated." 984848b8605Smrg */ 985848b8605Smrg if (level != 0) { 986848b8605Smrg switch (t->Target) { 987848b8605Smrg case GL_TEXTURE_RECTANGLE: 988848b8605Smrg case GL_TEXTURE_BUFFER: 989848b8605Smrg case GL_TEXTURE_2D_MULTISAMPLE: 990848b8605Smrg case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 991848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "%s(level)", name); 992848b8605Smrg return NULL; 993848b8605Smrg 994848b8605Smrg default: 995848b8605Smrg break; 996848b8605Smrg } 997848b8605Smrg } 998848b8605Smrg 999848b8605Smrg return t; 1000848b8605Smrg} 1001848b8605Smrg 1002848b8605Smrg/*@}*/ 1003848b8605Smrg 1004848b8605Smrg 1005848b8605Smrg/***********************************************************************/ 1006848b8605Smrg/** \name API functions */ 1007848b8605Smrg/*@{*/ 1008848b8605Smrg 1009848b8605Smrg 1010848b8605Smrg/** 1011848b8605Smrg * Generate texture names. 1012848b8605Smrg * 1013848b8605Smrg * \param n number of texture names to be generated. 1014848b8605Smrg * \param textures an array in which will hold the generated texture names. 1015848b8605Smrg * 1016848b8605Smrg * \sa glGenTextures(). 1017848b8605Smrg * 1018848b8605Smrg * Calls _mesa_HashFindFreeKeyBlock() to find a block of free texture 1019848b8605Smrg * IDs which are stored in \p textures. Corresponding empty texture 1020848b8605Smrg * objects are also generated. 1021848b8605Smrg */ 1022848b8605Smrgvoid GLAPIENTRY 1023848b8605Smrg_mesa_GenTextures( GLsizei n, GLuint *textures ) 1024848b8605Smrg{ 1025848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1026848b8605Smrg GLuint first; 1027848b8605Smrg GLint i; 1028848b8605Smrg 1029848b8605Smrg if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 1030848b8605Smrg _mesa_debug(ctx, "glGenTextures %d\n", n); 1031848b8605Smrg 1032848b8605Smrg if (n < 0) { 1033848b8605Smrg _mesa_error( ctx, GL_INVALID_VALUE, "glGenTextures" ); 1034848b8605Smrg return; 1035848b8605Smrg } 1036848b8605Smrg 1037848b8605Smrg if (!textures) 1038848b8605Smrg return; 1039848b8605Smrg 1040848b8605Smrg /* 1041848b8605Smrg * This must be atomic (generation and allocation of texture IDs) 1042848b8605Smrg */ 1043848b8605Smrg mtx_lock(&ctx->Shared->Mutex); 1044848b8605Smrg 1045848b8605Smrg first = _mesa_HashFindFreeKeyBlock(ctx->Shared->TexObjects, n); 1046848b8605Smrg 1047848b8605Smrg /* Allocate new, empty texture objects */ 1048848b8605Smrg for (i = 0; i < n; i++) { 1049848b8605Smrg struct gl_texture_object *texObj; 1050848b8605Smrg GLuint name = first + i; 1051848b8605Smrg GLenum target = 0; 1052848b8605Smrg texObj = ctx->Driver.NewTextureObject(ctx, name, target); 1053848b8605Smrg if (!texObj) { 1054848b8605Smrg mtx_unlock(&ctx->Shared->Mutex); 1055848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glGenTextures"); 1056848b8605Smrg return; 1057848b8605Smrg } 1058848b8605Smrg 1059848b8605Smrg /* insert into hash table */ 1060848b8605Smrg _mesa_HashInsert(ctx->Shared->TexObjects, texObj->Name, texObj); 1061848b8605Smrg 1062848b8605Smrg textures[i] = name; 1063848b8605Smrg } 1064848b8605Smrg 1065848b8605Smrg mtx_unlock(&ctx->Shared->Mutex); 1066848b8605Smrg} 1067848b8605Smrg 1068848b8605Smrg 1069848b8605Smrg/** 1070848b8605Smrg * Check if the given texture object is bound to the current draw or 1071848b8605Smrg * read framebuffer. If so, Unbind it. 1072848b8605Smrg */ 1073848b8605Smrgstatic void 1074848b8605Smrgunbind_texobj_from_fbo(struct gl_context *ctx, 1075848b8605Smrg struct gl_texture_object *texObj) 1076848b8605Smrg{ 1077848b8605Smrg bool progress = false; 1078848b8605Smrg 1079848b8605Smrg /* Section 4.4.2 (Attaching Images to Framebuffer Objects), subsection 1080848b8605Smrg * "Attaching Texture Images to a Framebuffer," of the OpenGL 3.1 spec 1081848b8605Smrg * says: 1082848b8605Smrg * 1083848b8605Smrg * "If a texture object is deleted while its image is attached to one 1084848b8605Smrg * or more attachment points in the currently bound framebuffer, then 1085848b8605Smrg * it is as if FramebufferTexture* had been called, with a texture of 1086848b8605Smrg * zero, for each attachment point to which this image was attached in 1087848b8605Smrg * the currently bound framebuffer. In other words, this texture image 1088848b8605Smrg * is first detached from all attachment points in the currently bound 1089848b8605Smrg * framebuffer. Note that the texture image is specifically not 1090848b8605Smrg * detached from any other framebuffer objects. Detaching the texture 1091848b8605Smrg * image from any other framebuffer objects is the responsibility of 1092848b8605Smrg * the application." 1093848b8605Smrg */ 1094848b8605Smrg if (_mesa_is_user_fbo(ctx->DrawBuffer)) { 1095848b8605Smrg progress = _mesa_detach_renderbuffer(ctx, ctx->DrawBuffer, texObj); 1096848b8605Smrg } 1097848b8605Smrg if (_mesa_is_user_fbo(ctx->ReadBuffer) 1098848b8605Smrg && ctx->ReadBuffer != ctx->DrawBuffer) { 1099848b8605Smrg progress = _mesa_detach_renderbuffer(ctx, ctx->ReadBuffer, texObj) 1100848b8605Smrg || progress; 1101848b8605Smrg } 1102848b8605Smrg 1103848b8605Smrg if (progress) 1104848b8605Smrg /* Vertices are already flushed by _mesa_DeleteTextures */ 1105848b8605Smrg ctx->NewState |= _NEW_BUFFERS; 1106848b8605Smrg} 1107848b8605Smrg 1108848b8605Smrg 1109848b8605Smrg/** 1110848b8605Smrg * Check if the given texture object is bound to any texture image units and 1111848b8605Smrg * unbind it if so (revert to default textures). 1112848b8605Smrg */ 1113848b8605Smrgstatic void 1114848b8605Smrgunbind_texobj_from_texunits(struct gl_context *ctx, 1115848b8605Smrg struct gl_texture_object *texObj) 1116848b8605Smrg{ 1117848b8605Smrg const gl_texture_index index = texObj->TargetIndex; 1118848b8605Smrg GLuint u; 1119848b8605Smrg 1120848b8605Smrg if (texObj->Target == 0) 1121848b8605Smrg return; 1122848b8605Smrg 1123848b8605Smrg for (u = 0; u < ctx->Texture.NumCurrentTexUsed; u++) { 1124848b8605Smrg struct gl_texture_unit *unit = &ctx->Texture.Unit[u]; 1125848b8605Smrg 1126848b8605Smrg if (texObj == unit->CurrentTex[index]) { 1127848b8605Smrg /* Bind the default texture for this unit/target */ 1128848b8605Smrg _mesa_reference_texobj(&unit->CurrentTex[index], 1129848b8605Smrg ctx->Shared->DefaultTex[index]); 1130848b8605Smrg unit->_BoundTextures &= ~(1 << index); 1131848b8605Smrg } 1132848b8605Smrg } 1133848b8605Smrg} 1134848b8605Smrg 1135848b8605Smrg 1136848b8605Smrg/** 1137848b8605Smrg * Check if the given texture object is bound to any shader image unit 1138848b8605Smrg * and unbind it if that's the case. 1139848b8605Smrg */ 1140848b8605Smrgstatic void 1141848b8605Smrgunbind_texobj_from_image_units(struct gl_context *ctx, 1142848b8605Smrg struct gl_texture_object *texObj) 1143848b8605Smrg{ 1144848b8605Smrg GLuint i; 1145848b8605Smrg 1146848b8605Smrg for (i = 0; i < ctx->Const.MaxImageUnits; i++) { 1147848b8605Smrg struct gl_image_unit *unit = &ctx->ImageUnits[i]; 1148848b8605Smrg 1149848b8605Smrg if (texObj == unit->TexObj) 1150848b8605Smrg _mesa_reference_texobj(&unit->TexObj, NULL); 1151848b8605Smrg } 1152848b8605Smrg} 1153848b8605Smrg 1154848b8605Smrg/** 1155848b8605Smrg * Unbinds all textures bound to the given texture image unit. 1156848b8605Smrg */ 1157848b8605Smrgstatic void 1158848b8605Smrgunbind_textures_from_unit(struct gl_context *ctx, GLuint unit) 1159848b8605Smrg{ 1160848b8605Smrg struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; 1161848b8605Smrg 1162848b8605Smrg while (texUnit->_BoundTextures) { 1163848b8605Smrg const GLuint index = ffs(texUnit->_BoundTextures) - 1; 1164848b8605Smrg struct gl_texture_object *texObj = ctx->Shared->DefaultTex[index]; 1165848b8605Smrg 1166848b8605Smrg _mesa_reference_texobj(&texUnit->CurrentTex[index], texObj); 1167848b8605Smrg 1168848b8605Smrg /* Pass BindTexture call to device driver */ 1169848b8605Smrg if (ctx->Driver.BindTexture) 1170848b8605Smrg ctx->Driver.BindTexture(ctx, unit, 0, texObj); 1171848b8605Smrg 1172848b8605Smrg texUnit->_BoundTextures &= ~(1 << index); 1173848b8605Smrg ctx->NewState |= _NEW_TEXTURE; 1174848b8605Smrg } 1175848b8605Smrg} 1176848b8605Smrg 1177848b8605Smrg/** 1178848b8605Smrg * Delete named textures. 1179848b8605Smrg * 1180848b8605Smrg * \param n number of textures to be deleted. 1181848b8605Smrg * \param textures array of texture IDs to be deleted. 1182848b8605Smrg * 1183848b8605Smrg * \sa glDeleteTextures(). 1184848b8605Smrg * 1185848b8605Smrg * If we're about to delete a texture that's currently bound to any 1186848b8605Smrg * texture unit, unbind the texture first. Decrement the reference 1187848b8605Smrg * count on the texture object and delete it if it's zero. 1188848b8605Smrg * Recall that texture objects can be shared among several rendering 1189848b8605Smrg * contexts. 1190848b8605Smrg */ 1191848b8605Smrgvoid GLAPIENTRY 1192848b8605Smrg_mesa_DeleteTextures( GLsizei n, const GLuint *textures) 1193848b8605Smrg{ 1194848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1195848b8605Smrg GLint i; 1196848b8605Smrg 1197848b8605Smrg if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 1198848b8605Smrg _mesa_debug(ctx, "glDeleteTextures %d\n", n); 1199848b8605Smrg 1200848b8605Smrg FLUSH_VERTICES(ctx, 0); /* too complex */ 1201848b8605Smrg 1202848b8605Smrg if (!textures) 1203848b8605Smrg return; 1204848b8605Smrg 1205848b8605Smrg for (i = 0; i < n; i++) { 1206848b8605Smrg if (textures[i] > 0) { 1207848b8605Smrg struct gl_texture_object *delObj 1208848b8605Smrg = _mesa_lookup_texture(ctx, textures[i]); 1209848b8605Smrg 1210848b8605Smrg if (delObj) { 1211848b8605Smrg _mesa_lock_texture(ctx, delObj); 1212848b8605Smrg 1213848b8605Smrg /* Check if texture is bound to any framebuffer objects. 1214848b8605Smrg * If so, unbind. 1215848b8605Smrg * See section 4.4.2.3 of GL_EXT_framebuffer_object. 1216848b8605Smrg */ 1217848b8605Smrg unbind_texobj_from_fbo(ctx, delObj); 1218848b8605Smrg 1219848b8605Smrg /* Check if this texture is currently bound to any texture units. 1220848b8605Smrg * If so, unbind it. 1221848b8605Smrg */ 1222848b8605Smrg unbind_texobj_from_texunits(ctx, delObj); 1223848b8605Smrg 1224848b8605Smrg /* Check if this texture is currently bound to any shader 1225848b8605Smrg * image unit. If so, unbind it. 1226848b8605Smrg * See section 3.9.X of GL_ARB_shader_image_load_store. 1227848b8605Smrg */ 1228848b8605Smrg unbind_texobj_from_image_units(ctx, delObj); 1229848b8605Smrg 1230848b8605Smrg _mesa_unlock_texture(ctx, delObj); 1231848b8605Smrg 1232848b8605Smrg ctx->NewState |= _NEW_TEXTURE; 1233848b8605Smrg 1234848b8605Smrg /* The texture _name_ is now free for re-use. 1235848b8605Smrg * Remove it from the hash table now. 1236848b8605Smrg */ 1237848b8605Smrg mtx_lock(&ctx->Shared->Mutex); 1238848b8605Smrg _mesa_HashRemove(ctx->Shared->TexObjects, delObj->Name); 1239848b8605Smrg mtx_unlock(&ctx->Shared->Mutex); 1240848b8605Smrg 1241848b8605Smrg /* Unreference the texobj. If refcount hits zero, the texture 1242848b8605Smrg * will be deleted. 1243848b8605Smrg */ 1244848b8605Smrg _mesa_reference_texobj(&delObj, NULL); 1245848b8605Smrg } 1246848b8605Smrg } 1247848b8605Smrg } 1248848b8605Smrg} 1249848b8605Smrg 1250848b8605Smrg 1251848b8605Smrg/** 1252848b8605Smrg * Convert a GL texture target enum such as GL_TEXTURE_2D or GL_TEXTURE_3D 1253848b8605Smrg * into the corresponding Mesa texture target index. 1254848b8605Smrg * Note that proxy targets are not valid here. 1255848b8605Smrg * \return TEXTURE_x_INDEX or -1 if target is invalid 1256848b8605Smrg */ 1257848b8605Smrgint 1258848b8605Smrg_mesa_tex_target_to_index(const struct gl_context *ctx, GLenum target) 1259848b8605Smrg{ 1260848b8605Smrg switch (target) { 1261848b8605Smrg case GL_TEXTURE_1D: 1262848b8605Smrg return _mesa_is_desktop_gl(ctx) ? TEXTURE_1D_INDEX : -1; 1263848b8605Smrg case GL_TEXTURE_2D: 1264848b8605Smrg return TEXTURE_2D_INDEX; 1265848b8605Smrg case GL_TEXTURE_3D: 1266848b8605Smrg return ctx->API != API_OPENGLES ? TEXTURE_3D_INDEX : -1; 1267848b8605Smrg case GL_TEXTURE_CUBE_MAP: 1268848b8605Smrg return ctx->Extensions.ARB_texture_cube_map 1269848b8605Smrg ? TEXTURE_CUBE_INDEX : -1; 1270848b8605Smrg case GL_TEXTURE_RECTANGLE: 1271848b8605Smrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.NV_texture_rectangle 1272848b8605Smrg ? TEXTURE_RECT_INDEX : -1; 1273848b8605Smrg case GL_TEXTURE_1D_ARRAY: 1274848b8605Smrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_array 1275848b8605Smrg ? TEXTURE_1D_ARRAY_INDEX : -1; 1276848b8605Smrg case GL_TEXTURE_2D_ARRAY: 1277848b8605Smrg return (_mesa_is_desktop_gl(ctx) && ctx->Extensions.EXT_texture_array) 1278848b8605Smrg || _mesa_is_gles3(ctx) 1279848b8605Smrg ? TEXTURE_2D_ARRAY_INDEX : -1; 1280848b8605Smrg case GL_TEXTURE_BUFFER: 1281848b8605Smrg return ctx->API == API_OPENGL_CORE && 1282848b8605Smrg ctx->Extensions.ARB_texture_buffer_object ? 1283848b8605Smrg TEXTURE_BUFFER_INDEX : -1; 1284848b8605Smrg case GL_TEXTURE_EXTERNAL_OES: 1285848b8605Smrg return _mesa_is_gles(ctx) && ctx->Extensions.OES_EGL_image_external 1286848b8605Smrg ? TEXTURE_EXTERNAL_INDEX : -1; 1287848b8605Smrg case GL_TEXTURE_CUBE_MAP_ARRAY: 1288848b8605Smrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_cube_map_array 1289848b8605Smrg ? TEXTURE_CUBE_ARRAY_INDEX : -1; 1290848b8605Smrg case GL_TEXTURE_2D_MULTISAMPLE: 1291848b8605Smrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_multisample 1292848b8605Smrg ? TEXTURE_2D_MULTISAMPLE_INDEX: -1; 1293848b8605Smrg case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 1294848b8605Smrg return _mesa_is_desktop_gl(ctx) && ctx->Extensions.ARB_texture_multisample 1295848b8605Smrg ? TEXTURE_2D_MULTISAMPLE_ARRAY_INDEX: -1; 1296848b8605Smrg default: 1297848b8605Smrg return -1; 1298848b8605Smrg } 1299848b8605Smrg} 1300848b8605Smrg 1301848b8605Smrg 1302848b8605Smrg/** 1303848b8605Smrg * Bind a named texture to a texturing target. 1304848b8605Smrg * 1305848b8605Smrg * \param target texture target. 1306848b8605Smrg * \param texName texture name. 1307848b8605Smrg * 1308848b8605Smrg * \sa glBindTexture(). 1309848b8605Smrg * 1310848b8605Smrg * Determines the old texture object bound and returns immediately if rebinding 1311848b8605Smrg * the same texture. Get the current texture which is either a default texture 1312848b8605Smrg * if name is null, a named texture from the hash, or a new texture if the 1313848b8605Smrg * given texture name is new. Increments its reference count, binds it, and 1314848b8605Smrg * calls dd_function_table::BindTexture. Decrements the old texture reference 1315848b8605Smrg * count and deletes it if it reaches zero. 1316848b8605Smrg */ 1317848b8605Smrgvoid GLAPIENTRY 1318848b8605Smrg_mesa_BindTexture( GLenum target, GLuint texName ) 1319848b8605Smrg{ 1320848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1321848b8605Smrg struct gl_texture_unit *texUnit = _mesa_get_current_tex_unit(ctx); 1322848b8605Smrg struct gl_texture_object *newTexObj = NULL; 1323848b8605Smrg GLint targetIndex; 1324848b8605Smrg 1325848b8605Smrg if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 1326848b8605Smrg _mesa_debug(ctx, "glBindTexture %s %d\n", 1327848b8605Smrg _mesa_lookup_enum_by_nr(target), (GLint) texName); 1328848b8605Smrg 1329848b8605Smrg targetIndex = _mesa_tex_target_to_index(ctx, target); 1330848b8605Smrg if (targetIndex < 0) { 1331848b8605Smrg _mesa_error(ctx, GL_INVALID_ENUM, "glBindTexture(target)"); 1332848b8605Smrg return; 1333848b8605Smrg } 1334848b8605Smrg assert(targetIndex < NUM_TEXTURE_TARGETS); 1335848b8605Smrg 1336848b8605Smrg /* 1337848b8605Smrg * Get pointer to new texture object (newTexObj) 1338848b8605Smrg */ 1339848b8605Smrg if (texName == 0) { 1340848b8605Smrg /* Use a default texture object */ 1341848b8605Smrg newTexObj = ctx->Shared->DefaultTex[targetIndex]; 1342848b8605Smrg } 1343848b8605Smrg else { 1344848b8605Smrg /* non-default texture object */ 1345848b8605Smrg newTexObj = _mesa_lookup_texture(ctx, texName); 1346848b8605Smrg if (newTexObj) { 1347848b8605Smrg /* error checking */ 1348848b8605Smrg if (newTexObj->Target != 0 && newTexObj->Target != target) { 1349848b8605Smrg /* the named texture object's target doesn't match the given target */ 1350848b8605Smrg _mesa_error( ctx, GL_INVALID_OPERATION, 1351848b8605Smrg "glBindTexture(target mismatch)" ); 1352848b8605Smrg return; 1353848b8605Smrg } 1354848b8605Smrg if (newTexObj->Target == 0) { 1355848b8605Smrg finish_texture_init(ctx, target, newTexObj); 1356848b8605Smrg } 1357848b8605Smrg } 1358848b8605Smrg else { 1359848b8605Smrg if (ctx->API == API_OPENGL_CORE) { 1360848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, "glBindTexture(non-gen name)"); 1361848b8605Smrg return; 1362848b8605Smrg } 1363848b8605Smrg 1364848b8605Smrg /* if this is a new texture id, allocate a texture object now */ 1365848b8605Smrg newTexObj = ctx->Driver.NewTextureObject(ctx, texName, target); 1366848b8605Smrg if (!newTexObj) { 1367848b8605Smrg _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindTexture"); 1368848b8605Smrg return; 1369848b8605Smrg } 1370848b8605Smrg 1371848b8605Smrg /* and insert it into hash table */ 1372848b8605Smrg mtx_lock(&ctx->Shared->Mutex); 1373848b8605Smrg _mesa_HashInsert(ctx->Shared->TexObjects, texName, newTexObj); 1374848b8605Smrg mtx_unlock(&ctx->Shared->Mutex); 1375848b8605Smrg } 1376848b8605Smrg newTexObj->Target = target; 1377848b8605Smrg newTexObj->TargetIndex = targetIndex; 1378848b8605Smrg } 1379848b8605Smrg 1380848b8605Smrg assert(valid_texture_object(newTexObj)); 1381848b8605Smrg 1382848b8605Smrg /* Check if this texture is only used by this context and is already bound. 1383848b8605Smrg * If so, just return. 1384848b8605Smrg */ 1385848b8605Smrg { 1386848b8605Smrg GLboolean early_out; 1387848b8605Smrg mtx_lock(&ctx->Shared->Mutex); 1388848b8605Smrg early_out = ((ctx->Shared->RefCount == 1) 1389848b8605Smrg && (newTexObj == texUnit->CurrentTex[targetIndex])); 1390848b8605Smrg mtx_unlock(&ctx->Shared->Mutex); 1391848b8605Smrg if (early_out) { 1392848b8605Smrg return; 1393848b8605Smrg } 1394848b8605Smrg } 1395848b8605Smrg 1396848b8605Smrg /* flush before changing binding */ 1397848b8605Smrg FLUSH_VERTICES(ctx, _NEW_TEXTURE); 1398848b8605Smrg 1399848b8605Smrg /* Do the actual binding. The refcount on the previously bound 1400848b8605Smrg * texture object will be decremented. It'll be deleted if the 1401848b8605Smrg * count hits zero. 1402848b8605Smrg */ 1403848b8605Smrg _mesa_reference_texobj(&texUnit->CurrentTex[targetIndex], newTexObj); 1404848b8605Smrg ctx->Texture.NumCurrentTexUsed = MAX2(ctx->Texture.NumCurrentTexUsed, 1405848b8605Smrg ctx->Texture.CurrentUnit + 1); 1406848b8605Smrg ASSERT(texUnit->CurrentTex[targetIndex]); 1407848b8605Smrg 1408848b8605Smrg if (texName != 0) 1409848b8605Smrg texUnit->_BoundTextures |= (1 << targetIndex); 1410848b8605Smrg else 1411848b8605Smrg texUnit->_BoundTextures &= ~(1 << targetIndex); 1412848b8605Smrg 1413848b8605Smrg /* Pass BindTexture call to device driver */ 1414848b8605Smrg if (ctx->Driver.BindTexture) 1415848b8605Smrg ctx->Driver.BindTexture(ctx, ctx->Texture.CurrentUnit, target, newTexObj); 1416848b8605Smrg} 1417848b8605Smrg 1418848b8605Smrg 1419848b8605Smrgvoid GLAPIENTRY 1420848b8605Smrg_mesa_BindTextures(GLuint first, GLsizei count, const GLuint *textures) 1421848b8605Smrg{ 1422848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1423848b8605Smrg GLint i; 1424848b8605Smrg 1425848b8605Smrg /* The ARB_multi_bind spec says: 1426848b8605Smrg * 1427848b8605Smrg * "An INVALID_OPERATION error is generated if <first> + <count> 1428848b8605Smrg * is greater than the number of texture image units supported 1429848b8605Smrg * by the implementation." 1430848b8605Smrg */ 1431848b8605Smrg if (first + count > ctx->Const.MaxCombinedTextureImageUnits) { 1432848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 1433848b8605Smrg "glBindTextures(first=%u + count=%d > the value of " 1434848b8605Smrg "GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS=%u)", 1435848b8605Smrg first, count, ctx->Const.MaxCombinedTextureImageUnits); 1436848b8605Smrg return; 1437848b8605Smrg } 1438848b8605Smrg 1439848b8605Smrg /* Flush before changing bindings */ 1440848b8605Smrg FLUSH_VERTICES(ctx, 0); 1441848b8605Smrg 1442848b8605Smrg ctx->Texture.NumCurrentTexUsed = MAX2(ctx->Texture.NumCurrentTexUsed, 1443848b8605Smrg first + count); 1444848b8605Smrg 1445848b8605Smrg if (textures) { 1446848b8605Smrg /* Note that the error semantics for multi-bind commands differ from 1447848b8605Smrg * those of other GL commands. 1448848b8605Smrg * 1449848b8605Smrg * The issues section in the ARB_multi_bind spec says: 1450848b8605Smrg * 1451848b8605Smrg * "(11) Typically, OpenGL specifies that if an error is generated by 1452848b8605Smrg * a command, that command has no effect. This is somewhat 1453848b8605Smrg * unfortunate for multi-bind commands, because it would require 1454848b8605Smrg * a first pass to scan the entire list of bound objects for 1455848b8605Smrg * errors and then a second pass to actually perform the 1456848b8605Smrg * bindings. Should we have different error semantics? 1457848b8605Smrg * 1458848b8605Smrg * RESOLVED: Yes. In this specification, when the parameters for 1459848b8605Smrg * one of the <count> binding points are invalid, that binding 1460848b8605Smrg * point is not updated and an error will be generated. However, 1461848b8605Smrg * other binding points in the same command will be updated if 1462848b8605Smrg * their parameters are valid and no other error occurs." 1463848b8605Smrg */ 1464848b8605Smrg 1465848b8605Smrg _mesa_begin_texture_lookups(ctx); 1466848b8605Smrg 1467848b8605Smrg for (i = 0; i < count; i++) { 1468848b8605Smrg if (textures[i] != 0) { 1469848b8605Smrg struct gl_texture_unit *texUnit = &ctx->Texture.Unit[first + i]; 1470848b8605Smrg struct gl_texture_object *current = texUnit->_Current; 1471848b8605Smrg struct gl_texture_object *texObj; 1472848b8605Smrg 1473848b8605Smrg if (current && current->Name == textures[i]) 1474848b8605Smrg texObj = current; 1475848b8605Smrg else 1476848b8605Smrg texObj = _mesa_lookup_texture_locked(ctx, textures[i]); 1477848b8605Smrg 1478848b8605Smrg if (texObj && texObj->Target != 0) { 1479848b8605Smrg const gl_texture_index targetIndex = texObj->TargetIndex; 1480848b8605Smrg 1481848b8605Smrg if (texUnit->CurrentTex[targetIndex] != texObj) { 1482848b8605Smrg /* Do the actual binding. The refcount on the previously 1483848b8605Smrg * bound texture object will be decremented. It will be 1484848b8605Smrg * deleted if the count hits zero. 1485848b8605Smrg */ 1486848b8605Smrg _mesa_reference_texobj(&texUnit->CurrentTex[targetIndex], 1487848b8605Smrg texObj); 1488848b8605Smrg 1489848b8605Smrg texUnit->_BoundTextures |= (1 << targetIndex); 1490848b8605Smrg ctx->NewState |= _NEW_TEXTURE; 1491848b8605Smrg 1492848b8605Smrg /* Pass the BindTexture call to the device driver */ 1493848b8605Smrg if (ctx->Driver.BindTexture) 1494848b8605Smrg ctx->Driver.BindTexture(ctx, first + i, 1495848b8605Smrg texObj->Target, texObj); 1496848b8605Smrg } 1497848b8605Smrg } else { 1498848b8605Smrg /* The ARB_multi_bind spec says: 1499848b8605Smrg * 1500848b8605Smrg * "An INVALID_OPERATION error is generated if any value 1501848b8605Smrg * in <textures> is not zero or the name of an existing 1502848b8605Smrg * texture object (per binding)." 1503848b8605Smrg */ 1504848b8605Smrg _mesa_error(ctx, GL_INVALID_OPERATION, 1505848b8605Smrg "glBindTextures(textures[%d]=%u is not zero " 1506848b8605Smrg "or the name of an existing texture object)", 1507848b8605Smrg i, textures[i]); 1508848b8605Smrg } 1509848b8605Smrg } else { 1510848b8605Smrg unbind_textures_from_unit(ctx, first + i); 1511848b8605Smrg } 1512848b8605Smrg } 1513848b8605Smrg 1514848b8605Smrg _mesa_end_texture_lookups(ctx); 1515848b8605Smrg } else { 1516848b8605Smrg /* Unbind all textures in the range <first> through <first>+<count>-1 */ 1517848b8605Smrg for (i = 0; i < count; i++) 1518848b8605Smrg unbind_textures_from_unit(ctx, first + i); 1519848b8605Smrg } 1520848b8605Smrg} 1521848b8605Smrg 1522848b8605Smrg 1523848b8605Smrg/** 1524848b8605Smrg * Set texture priorities. 1525848b8605Smrg * 1526848b8605Smrg * \param n number of textures. 1527848b8605Smrg * \param texName texture names. 1528848b8605Smrg * \param priorities corresponding texture priorities. 1529848b8605Smrg * 1530848b8605Smrg * \sa glPrioritizeTextures(). 1531848b8605Smrg * 1532848b8605Smrg * Looks up each texture in the hash, clamps the corresponding priority between 1533848b8605Smrg * 0.0 and 1.0, and calls dd_function_table::PrioritizeTexture. 1534848b8605Smrg */ 1535848b8605Smrgvoid GLAPIENTRY 1536848b8605Smrg_mesa_PrioritizeTextures( GLsizei n, const GLuint *texName, 1537848b8605Smrg const GLclampf *priorities ) 1538848b8605Smrg{ 1539848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1540848b8605Smrg GLint i; 1541848b8605Smrg 1542848b8605Smrg if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 1543848b8605Smrg _mesa_debug(ctx, "glPrioritizeTextures %d\n", n); 1544848b8605Smrg 1545848b8605Smrg FLUSH_VERTICES(ctx, 0); 1546848b8605Smrg 1547848b8605Smrg if (n < 0) { 1548848b8605Smrg _mesa_error( ctx, GL_INVALID_VALUE, "glPrioritizeTextures" ); 1549848b8605Smrg return; 1550848b8605Smrg } 1551848b8605Smrg 1552848b8605Smrg if (!priorities) 1553848b8605Smrg return; 1554848b8605Smrg 1555848b8605Smrg for (i = 0; i < n; i++) { 1556848b8605Smrg if (texName[i] > 0) { 1557848b8605Smrg struct gl_texture_object *t = _mesa_lookup_texture(ctx, texName[i]); 1558848b8605Smrg if (t) { 1559848b8605Smrg t->Priority = CLAMP( priorities[i], 0.0F, 1.0F ); 1560848b8605Smrg } 1561848b8605Smrg } 1562848b8605Smrg } 1563848b8605Smrg 1564848b8605Smrg ctx->NewState |= _NEW_TEXTURE; 1565848b8605Smrg} 1566848b8605Smrg 1567848b8605Smrg 1568848b8605Smrg 1569848b8605Smrg/** 1570848b8605Smrg * See if textures are loaded in texture memory. 1571848b8605Smrg * 1572848b8605Smrg * \param n number of textures to query. 1573848b8605Smrg * \param texName array with the texture names. 1574848b8605Smrg * \param residences array which will hold the residence status. 1575848b8605Smrg * 1576848b8605Smrg * \return GL_TRUE if all textures are resident and \p residences is left unchanged, 1577848b8605Smrg * 1578848b8605Smrg * Note: we assume all textures are always resident 1579848b8605Smrg */ 1580848b8605SmrgGLboolean GLAPIENTRY 1581848b8605Smrg_mesa_AreTexturesResident(GLsizei n, const GLuint *texName, 1582848b8605Smrg GLboolean *residences) 1583848b8605Smrg{ 1584848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1585848b8605Smrg GLboolean allResident = GL_TRUE; 1586848b8605Smrg GLint i; 1587848b8605Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 1588848b8605Smrg 1589848b8605Smrg if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 1590848b8605Smrg _mesa_debug(ctx, "glAreTexturesResident %d\n", n); 1591848b8605Smrg 1592848b8605Smrg if (n < 0) { 1593848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident(n)"); 1594848b8605Smrg return GL_FALSE; 1595848b8605Smrg } 1596848b8605Smrg 1597848b8605Smrg if (!texName || !residences) 1598848b8605Smrg return GL_FALSE; 1599848b8605Smrg 1600848b8605Smrg /* We only do error checking on the texture names */ 1601848b8605Smrg for (i = 0; i < n; i++) { 1602848b8605Smrg struct gl_texture_object *t; 1603848b8605Smrg if (texName[i] == 0) { 1604848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident"); 1605848b8605Smrg return GL_FALSE; 1606848b8605Smrg } 1607848b8605Smrg t = _mesa_lookup_texture(ctx, texName[i]); 1608848b8605Smrg if (!t) { 1609848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glAreTexturesResident"); 1610848b8605Smrg return GL_FALSE; 1611848b8605Smrg } 1612848b8605Smrg } 1613848b8605Smrg 1614848b8605Smrg return allResident; 1615848b8605Smrg} 1616848b8605Smrg 1617848b8605Smrg 1618848b8605Smrg/** 1619848b8605Smrg * See if a name corresponds to a texture. 1620848b8605Smrg * 1621848b8605Smrg * \param texture texture name. 1622848b8605Smrg * 1623848b8605Smrg * \return GL_TRUE if texture name corresponds to a texture, or GL_FALSE 1624848b8605Smrg * otherwise. 1625848b8605Smrg * 1626848b8605Smrg * \sa glIsTexture(). 1627848b8605Smrg * 1628848b8605Smrg * Calls _mesa_HashLookup(). 1629848b8605Smrg */ 1630848b8605SmrgGLboolean GLAPIENTRY 1631848b8605Smrg_mesa_IsTexture( GLuint texture ) 1632848b8605Smrg{ 1633848b8605Smrg struct gl_texture_object *t; 1634848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1635848b8605Smrg ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE); 1636848b8605Smrg 1637848b8605Smrg if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 1638848b8605Smrg _mesa_debug(ctx, "glIsTexture %d\n", texture); 1639848b8605Smrg 1640848b8605Smrg if (!texture) 1641848b8605Smrg return GL_FALSE; 1642848b8605Smrg 1643848b8605Smrg t = _mesa_lookup_texture(ctx, texture); 1644848b8605Smrg 1645848b8605Smrg /* IsTexture is true only after object has been bound once. */ 1646848b8605Smrg return t && t->Target; 1647848b8605Smrg} 1648848b8605Smrg 1649848b8605Smrg 1650848b8605Smrg/** 1651848b8605Smrg * Simplest implementation of texture locking: grab the shared tex 1652848b8605Smrg * mutex. Examine the shared context state timestamp and if there has 1653848b8605Smrg * been a change, set the appropriate bits in ctx->NewState. 1654848b8605Smrg * 1655848b8605Smrg * This is used to deal with synchronizing things when a texture object 1656848b8605Smrg * is used/modified by different contexts (or threads) which are sharing 1657848b8605Smrg * the texture. 1658848b8605Smrg * 1659848b8605Smrg * See also _mesa_lock/unlock_texture() in teximage.h 1660848b8605Smrg */ 1661848b8605Smrgvoid 1662848b8605Smrg_mesa_lock_context_textures( struct gl_context *ctx ) 1663848b8605Smrg{ 1664848b8605Smrg mtx_lock(&ctx->Shared->TexMutex); 1665848b8605Smrg 1666848b8605Smrg if (ctx->Shared->TextureStateStamp != ctx->TextureStateTimestamp) { 1667848b8605Smrg ctx->NewState |= _NEW_TEXTURE; 1668848b8605Smrg ctx->TextureStateTimestamp = ctx->Shared->TextureStateStamp; 1669848b8605Smrg } 1670848b8605Smrg} 1671848b8605Smrg 1672848b8605Smrg 1673848b8605Smrgvoid 1674848b8605Smrg_mesa_unlock_context_textures( struct gl_context *ctx ) 1675848b8605Smrg{ 1676848b8605Smrg assert(ctx->Shared->TextureStateStamp == ctx->TextureStateTimestamp); 1677848b8605Smrg mtx_unlock(&ctx->Shared->TexMutex); 1678848b8605Smrg} 1679848b8605Smrg 1680848b8605Smrgvoid GLAPIENTRY 1681848b8605Smrg_mesa_InvalidateTexSubImage(GLuint texture, GLint level, GLint xoffset, 1682848b8605Smrg GLint yoffset, GLint zoffset, GLsizei width, 1683848b8605Smrg GLsizei height, GLsizei depth) 1684848b8605Smrg{ 1685848b8605Smrg struct gl_texture_object *t; 1686848b8605Smrg struct gl_texture_image *image; 1687848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1688848b8605Smrg 1689848b8605Smrg if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 1690848b8605Smrg _mesa_debug(ctx, "glInvalidateTexSubImage %d\n", texture); 1691848b8605Smrg 1692848b8605Smrg t = invalidate_tex_image_error_check(ctx, texture, level, 1693848b8605Smrg "glInvalidateTexSubImage"); 1694848b8605Smrg 1695848b8605Smrg /* The GL_ARB_invalidate_subdata spec says: 1696848b8605Smrg * 1697848b8605Smrg * "...the specified subregion must be between -<b> and <dim>+<b> where 1698848b8605Smrg * <dim> is the size of the dimension of the texture image, and <b> is 1699848b8605Smrg * the size of the border of that texture image, otherwise 1700848b8605Smrg * INVALID_VALUE is generated (border is not applied to dimensions that 1701848b8605Smrg * don't exist in a given texture target)." 1702848b8605Smrg */ 1703848b8605Smrg image = t->Image[0][level]; 1704848b8605Smrg if (image) { 1705848b8605Smrg int xBorder; 1706848b8605Smrg int yBorder; 1707848b8605Smrg int zBorder; 1708848b8605Smrg int imageWidth; 1709848b8605Smrg int imageHeight; 1710848b8605Smrg int imageDepth; 1711848b8605Smrg 1712848b8605Smrg /* The GL_ARB_invalidate_subdata spec says: 1713848b8605Smrg * 1714848b8605Smrg * "For texture targets that don't have certain dimensions, this 1715848b8605Smrg * command treats those dimensions as having a size of 1. For 1716848b8605Smrg * example, to invalidate a portion of a two-dimensional texture, 1717848b8605Smrg * the application would use <zoffset> equal to zero and <depth> 1718848b8605Smrg * equal to one." 1719848b8605Smrg */ 1720848b8605Smrg switch (t->Target) { 1721848b8605Smrg case GL_TEXTURE_BUFFER: 1722848b8605Smrg xBorder = 0; 1723848b8605Smrg yBorder = 0; 1724848b8605Smrg zBorder = 0; 1725848b8605Smrg imageWidth = 1; 1726848b8605Smrg imageHeight = 1; 1727848b8605Smrg imageDepth = 1; 1728848b8605Smrg break; 1729848b8605Smrg case GL_TEXTURE_1D: 1730848b8605Smrg xBorder = image->Border; 1731848b8605Smrg yBorder = 0; 1732848b8605Smrg zBorder = 0; 1733848b8605Smrg imageWidth = image->Width; 1734848b8605Smrg imageHeight = 1; 1735848b8605Smrg imageDepth = 1; 1736848b8605Smrg break; 1737848b8605Smrg case GL_TEXTURE_1D_ARRAY: 1738848b8605Smrg xBorder = image->Border; 1739848b8605Smrg yBorder = 0; 1740848b8605Smrg zBorder = 0; 1741848b8605Smrg imageWidth = image->Width; 1742848b8605Smrg imageHeight = image->Height; 1743848b8605Smrg imageDepth = 1; 1744848b8605Smrg break; 1745848b8605Smrg case GL_TEXTURE_2D: 1746848b8605Smrg case GL_TEXTURE_CUBE_MAP: 1747848b8605Smrg case GL_TEXTURE_RECTANGLE: 1748848b8605Smrg case GL_TEXTURE_2D_MULTISAMPLE: 1749848b8605Smrg xBorder = image->Border; 1750848b8605Smrg yBorder = image->Border; 1751848b8605Smrg zBorder = 0; 1752848b8605Smrg imageWidth = image->Width; 1753848b8605Smrg imageHeight = image->Height; 1754848b8605Smrg imageDepth = 1; 1755848b8605Smrg break; 1756848b8605Smrg case GL_TEXTURE_2D_ARRAY: 1757848b8605Smrg case GL_TEXTURE_CUBE_MAP_ARRAY: 1758848b8605Smrg case GL_TEXTURE_2D_MULTISAMPLE_ARRAY: 1759848b8605Smrg xBorder = image->Border; 1760848b8605Smrg yBorder = image->Border; 1761848b8605Smrg zBorder = 0; 1762848b8605Smrg imageWidth = image->Width; 1763848b8605Smrg imageHeight = image->Height; 1764848b8605Smrg imageDepth = image->Depth; 1765848b8605Smrg break; 1766848b8605Smrg case GL_TEXTURE_3D: 1767848b8605Smrg xBorder = image->Border; 1768848b8605Smrg yBorder = image->Border; 1769848b8605Smrg zBorder = image->Border; 1770848b8605Smrg imageWidth = image->Width; 1771848b8605Smrg imageHeight = image->Height; 1772848b8605Smrg imageDepth = image->Depth; 1773848b8605Smrg break; 1774848b8605Smrg default: 1775848b8605Smrg assert(!"Should not get here."); 1776848b8605Smrg xBorder = 0; 1777848b8605Smrg yBorder = 0; 1778848b8605Smrg zBorder = 0; 1779848b8605Smrg imageWidth = 0; 1780848b8605Smrg imageHeight = 0; 1781848b8605Smrg imageDepth = 0; 1782848b8605Smrg break; 1783848b8605Smrg } 1784848b8605Smrg 1785848b8605Smrg if (xoffset < -xBorder) { 1786848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glInvalidateSubTexImage(xoffset)"); 1787848b8605Smrg return; 1788848b8605Smrg } 1789848b8605Smrg 1790848b8605Smrg if (xoffset + width > imageWidth + xBorder) { 1791848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 1792848b8605Smrg "glInvalidateSubTexImage(xoffset+width)"); 1793848b8605Smrg return; 1794848b8605Smrg } 1795848b8605Smrg 1796848b8605Smrg if (yoffset < -yBorder) { 1797848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, "glInvalidateSubTexImage(yoffset)"); 1798848b8605Smrg return; 1799848b8605Smrg } 1800848b8605Smrg 1801848b8605Smrg if (yoffset + height > imageHeight + yBorder) { 1802848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 1803848b8605Smrg "glInvalidateSubTexImage(yoffset+height)"); 1804848b8605Smrg return; 1805848b8605Smrg } 1806848b8605Smrg 1807848b8605Smrg if (zoffset < -zBorder) { 1808848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 1809848b8605Smrg "glInvalidateSubTexImage(zoffset)"); 1810848b8605Smrg return; 1811848b8605Smrg } 1812848b8605Smrg 1813848b8605Smrg if (zoffset + depth > imageDepth + zBorder) { 1814848b8605Smrg _mesa_error(ctx, GL_INVALID_VALUE, 1815848b8605Smrg "glInvalidateSubTexImage(zoffset+depth)"); 1816848b8605Smrg return; 1817848b8605Smrg } 1818848b8605Smrg } 1819848b8605Smrg 1820848b8605Smrg /* We don't actually do anything for this yet. Just return after 1821848b8605Smrg * validating the parameters and generating the required errors. 1822848b8605Smrg */ 1823848b8605Smrg return; 1824848b8605Smrg} 1825848b8605Smrg 1826848b8605Smrgvoid GLAPIENTRY 1827848b8605Smrg_mesa_InvalidateTexImage(GLuint texture, GLint level) 1828848b8605Smrg{ 1829848b8605Smrg GET_CURRENT_CONTEXT(ctx); 1830848b8605Smrg 1831848b8605Smrg if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE)) 1832848b8605Smrg _mesa_debug(ctx, "glInvalidateTexImage(%d, %d)\n", texture, level); 1833848b8605Smrg 1834848b8605Smrg invalidate_tex_image_error_check(ctx, texture, level, 1835848b8605Smrg "glInvalidateTexImage"); 1836848b8605Smrg 1837848b8605Smrg /* We don't actually do anything for this yet. Just return after 1838848b8605Smrg * validating the parameters and generating the required errors. 1839848b8605Smrg */ 1840848b8605Smrg return; 1841848b8605Smrg} 1842848b8605Smrg 1843848b8605Smrg/*@}*/ 1844