shared.c revision 848b8605
1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 2009 VMware, Inc. All Rights Reserved. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included 14 * in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25/** 26 * \file shared.c 27 * Shared-context state 28 */ 29 30#include "imports.h" 31#include "mtypes.h" 32#include "hash.h" 33#include "atifragshader.h" 34#include "bufferobj.h" 35#include "shared.h" 36#include "program/program.h" 37#include "dlist.h" 38#include "samplerobj.h" 39#include "set.h" 40#include "shaderapi.h" 41#include "shaderobj.h" 42#include "syncobj.h" 43 44#include "util/hash_table.h" 45 46/** 47 * Allocate and initialize a shared context state structure. 48 * Initializes the display list, texture objects and vertex programs hash 49 * tables, allocates the texture objects. If it runs out of memory, frees 50 * everything already allocated before returning NULL. 51 * 52 * \return pointer to a gl_shared_state structure on success, or NULL on 53 * failure. 54 */ 55struct gl_shared_state * 56_mesa_alloc_shared_state(struct gl_context *ctx) 57{ 58 struct gl_shared_state *shared; 59 GLuint i; 60 61 shared = CALLOC_STRUCT(gl_shared_state); 62 if (!shared) 63 return NULL; 64 65 mtx_init(&shared->Mutex, mtx_plain); 66 67 shared->DisplayList = _mesa_NewHashTable(); 68 shared->TexObjects = _mesa_NewHashTable(); 69 shared->Programs = _mesa_NewHashTable(); 70 71 shared->DefaultVertexProgram = 72 gl_vertex_program(ctx->Driver.NewProgram(ctx, 73 GL_VERTEX_PROGRAM_ARB, 0)); 74 shared->DefaultFragmentProgram = 75 gl_fragment_program(ctx->Driver.NewProgram(ctx, 76 GL_FRAGMENT_PROGRAM_ARB, 0)); 77 78 shared->ATIShaders = _mesa_NewHashTable(); 79 shared->DefaultFragmentShader = _mesa_new_ati_fragment_shader(ctx, 0); 80 81 shared->ShaderObjects = _mesa_NewHashTable(); 82 83 shared->BufferObjects = _mesa_NewHashTable(); 84 85 /* GL_ARB_sampler_objects */ 86 shared->SamplerObjects = _mesa_NewHashTable(); 87 88 /* Allocate the default buffer object */ 89 shared->NullBufferObj = ctx->Driver.NewBufferObject(ctx, 0, 0); 90 91 /* Create default texture objects */ 92 for (i = 0; i < NUM_TEXTURE_TARGETS; i++) { 93 /* NOTE: the order of these enums matches the TEXTURE_x_INDEX values */ 94 static const GLenum targets[] = { 95 GL_TEXTURE_2D_MULTISAMPLE, 96 GL_TEXTURE_2D_MULTISAMPLE_ARRAY, 97 GL_TEXTURE_CUBE_MAP_ARRAY, 98 GL_TEXTURE_BUFFER, 99 GL_TEXTURE_2D_ARRAY_EXT, 100 GL_TEXTURE_1D_ARRAY_EXT, 101 GL_TEXTURE_EXTERNAL_OES, 102 GL_TEXTURE_CUBE_MAP, 103 GL_TEXTURE_3D, 104 GL_TEXTURE_RECTANGLE_NV, 105 GL_TEXTURE_2D, 106 GL_TEXTURE_1D 107 }; 108 STATIC_ASSERT(Elements(targets) == NUM_TEXTURE_TARGETS); 109 shared->DefaultTex[i] = ctx->Driver.NewTextureObject(ctx, 0, targets[i]); 110 } 111 112 /* sanity check */ 113 assert(shared->DefaultTex[TEXTURE_1D_INDEX]->RefCount == 1); 114 115 /* Mutex and timestamp for texobj state validation */ 116 mtx_init(&shared->TexMutex, mtx_recursive); 117 shared->TextureStateStamp = 0; 118 119 shared->FrameBuffers = _mesa_NewHashTable(); 120 shared->RenderBuffers = _mesa_NewHashTable(); 121 122 shared->SyncObjects = _mesa_set_create(NULL, _mesa_key_pointer_equal); 123 124 return shared; 125} 126 127 128/** 129 * Callback for deleting a display list. Called by _mesa_HashDeleteAll(). 130 */ 131static void 132delete_displaylist_cb(GLuint id, void *data, void *userData) 133{ 134 struct gl_display_list *list = (struct gl_display_list *) data; 135 struct gl_context *ctx = (struct gl_context *) userData; 136 _mesa_delete_list(ctx, list); 137} 138 139 140/** 141 * Callback for deleting a texture object. Called by _mesa_HashDeleteAll(). 142 */ 143static void 144delete_texture_cb(GLuint id, void *data, void *userData) 145{ 146 struct gl_texture_object *texObj = (struct gl_texture_object *) data; 147 struct gl_context *ctx = (struct gl_context *) userData; 148 ctx->Driver.DeleteTexture(ctx, texObj); 149} 150 151 152/** 153 * Callback for deleting a program object. Called by _mesa_HashDeleteAll(). 154 */ 155static void 156delete_program_cb(GLuint id, void *data, void *userData) 157{ 158 struct gl_program *prog = (struct gl_program *) data; 159 struct gl_context *ctx = (struct gl_context *) userData; 160 if(prog != &_mesa_DummyProgram) { 161 ASSERT(prog->RefCount == 1); /* should only be referenced by hash table */ 162 prog->RefCount = 0; /* now going away */ 163 ctx->Driver.DeleteProgram(ctx, prog); 164 } 165} 166 167 168/** 169 * Callback for deleting an ATI fragment shader object. 170 * Called by _mesa_HashDeleteAll(). 171 */ 172static void 173delete_fragshader_cb(GLuint id, void *data, void *userData) 174{ 175 struct ati_fragment_shader *shader = (struct ati_fragment_shader *) data; 176 struct gl_context *ctx = (struct gl_context *) userData; 177 _mesa_delete_ati_fragment_shader(ctx, shader); 178} 179 180 181/** 182 * Callback for deleting a buffer object. Called by _mesa_HashDeleteAll(). 183 */ 184static void 185delete_bufferobj_cb(GLuint id, void *data, void *userData) 186{ 187 struct gl_buffer_object *bufObj = (struct gl_buffer_object *) data; 188 struct gl_context *ctx = (struct gl_context *) userData; 189 190 _mesa_buffer_unmap_all_mappings(ctx, bufObj); 191 _mesa_reference_buffer_object(ctx, &bufObj, NULL); 192} 193 194 195/** 196 * Callback for freeing shader program data. Call it before delete_shader_cb 197 * to avoid memory access error. 198 */ 199static void 200free_shader_program_data_cb(GLuint id, void *data, void *userData) 201{ 202 struct gl_context *ctx = (struct gl_context *) userData; 203 struct gl_shader_program *shProg = (struct gl_shader_program *) data; 204 205 if (shProg->Type == GL_SHADER_PROGRAM_MESA) { 206 _mesa_free_shader_program_data(ctx, shProg); 207 } 208} 209 210 211/** 212 * Callback for deleting shader and shader programs objects. 213 * Called by _mesa_HashDeleteAll(). 214 */ 215static void 216delete_shader_cb(GLuint id, void *data, void *userData) 217{ 218 struct gl_context *ctx = (struct gl_context *) userData; 219 struct gl_shader *sh = (struct gl_shader *) data; 220 if (_mesa_validate_shader_target(ctx, sh->Type)) { 221 ctx->Driver.DeleteShader(ctx, sh); 222 } 223 else { 224 struct gl_shader_program *shProg = (struct gl_shader_program *) data; 225 ASSERT(shProg->Type == GL_SHADER_PROGRAM_MESA); 226 ctx->Driver.DeleteShaderProgram(ctx, shProg); 227 } 228} 229 230 231/** 232 * Callback for deleting a framebuffer object. Called by _mesa_HashDeleteAll() 233 */ 234static void 235delete_framebuffer_cb(GLuint id, void *data, void *userData) 236{ 237 struct gl_framebuffer *fb = (struct gl_framebuffer *) data; 238 /* The fact that the framebuffer is in the hashtable means its refcount 239 * is one, but we're removing from the hashtable now. So clear refcount. 240 */ 241 /*assert(fb->RefCount == 1);*/ 242 fb->RefCount = 0; 243 244 /* NOTE: Delete should always be defined but there are two reports 245 * of it being NULL (bugs 13507, 14293). Work-around for now. 246 */ 247 if (fb->Delete) 248 fb->Delete(fb); 249} 250 251 252/** 253 * Callback for deleting a renderbuffer object. Called by _mesa_HashDeleteAll() 254 */ 255static void 256delete_renderbuffer_cb(GLuint id, void *data, void *userData) 257{ 258 struct gl_context *ctx = (struct gl_context *) userData; 259 struct gl_renderbuffer *rb = (struct gl_renderbuffer *) data; 260 rb->RefCount = 0; /* see comment for FBOs above */ 261 if (rb->Delete) 262 rb->Delete(ctx, rb); 263} 264 265 266/** 267 * Callback for deleting a sampler object. Called by _mesa_HashDeleteAll() 268 */ 269static void 270delete_sampler_object_cb(GLuint id, void *data, void *userData) 271{ 272 struct gl_context *ctx = (struct gl_context *) userData; 273 struct gl_sampler_object *sampObj = (struct gl_sampler_object *) data; 274 _mesa_reference_sampler_object(ctx, &sampObj, NULL); 275} 276 277 278/** 279 * Deallocate a shared state object and all children structures. 280 * 281 * \param ctx GL context. 282 * \param shared shared state pointer. 283 * 284 * Frees the display lists, the texture objects (calling the driver texture 285 * deletion callback to free its private data) and the vertex programs, as well 286 * as their hash tables. 287 * 288 * \sa alloc_shared_state(). 289 */ 290static void 291free_shared_state(struct gl_context *ctx, struct gl_shared_state *shared) 292{ 293 GLuint i; 294 295 /* Free the dummy/fallback texture objects */ 296 for (i = 0; i < NUM_TEXTURE_TARGETS; i++) { 297 if (shared->FallbackTex[i]) 298 ctx->Driver.DeleteTexture(ctx, shared->FallbackTex[i]); 299 } 300 301 /* 302 * Free display lists 303 */ 304 _mesa_HashDeleteAll(shared->DisplayList, delete_displaylist_cb, ctx); 305 _mesa_DeleteHashTable(shared->DisplayList); 306 307 _mesa_HashWalk(shared->ShaderObjects, free_shader_program_data_cb, ctx); 308 _mesa_HashDeleteAll(shared->ShaderObjects, delete_shader_cb, ctx); 309 _mesa_DeleteHashTable(shared->ShaderObjects); 310 311 _mesa_HashDeleteAll(shared->Programs, delete_program_cb, ctx); 312 _mesa_DeleteHashTable(shared->Programs); 313 314 _mesa_reference_vertprog(ctx, &shared->DefaultVertexProgram, NULL); 315 _mesa_reference_geomprog(ctx, &shared->DefaultGeometryProgram, NULL); 316 _mesa_reference_fragprog(ctx, &shared->DefaultFragmentProgram, NULL); 317 318 _mesa_HashDeleteAll(shared->ATIShaders, delete_fragshader_cb, ctx); 319 _mesa_DeleteHashTable(shared->ATIShaders); 320 _mesa_delete_ati_fragment_shader(ctx, shared->DefaultFragmentShader); 321 322 _mesa_HashDeleteAll(shared->BufferObjects, delete_bufferobj_cb, ctx); 323 _mesa_DeleteHashTable(shared->BufferObjects); 324 325 _mesa_HashDeleteAll(shared->FrameBuffers, delete_framebuffer_cb, ctx); 326 _mesa_DeleteHashTable(shared->FrameBuffers); 327 _mesa_HashDeleteAll(shared->RenderBuffers, delete_renderbuffer_cb, ctx); 328 _mesa_DeleteHashTable(shared->RenderBuffers); 329 330 _mesa_reference_buffer_object(ctx, &shared->NullBufferObj, NULL); 331 332 { 333 struct set_entry *entry; 334 335 set_foreach(shared->SyncObjects, entry) { 336 _mesa_unref_sync_object(ctx, (struct gl_sync_object *) entry->key); 337 } 338 } 339 _mesa_set_destroy(shared->SyncObjects, NULL); 340 341 _mesa_HashDeleteAll(shared->SamplerObjects, delete_sampler_object_cb, ctx); 342 _mesa_DeleteHashTable(shared->SamplerObjects); 343 344 /* 345 * Free texture objects (after FBOs since some textures might have 346 * been bound to FBOs). 347 */ 348 ASSERT(ctx->Driver.DeleteTexture); 349 /* the default textures */ 350 for (i = 0; i < NUM_TEXTURE_TARGETS; i++) { 351 ctx->Driver.DeleteTexture(ctx, shared->DefaultTex[i]); 352 } 353 354 /* all other textures */ 355 _mesa_HashDeleteAll(shared->TexObjects, delete_texture_cb, ctx); 356 _mesa_DeleteHashTable(shared->TexObjects); 357 358 mtx_destroy(&shared->Mutex); 359 mtx_destroy(&shared->TexMutex); 360 361 free(shared); 362} 363 364 365/** 366 * gl_shared_state objects are ref counted. 367 * If ptr's refcount goes to zero, free the shared state. 368 */ 369void 370_mesa_reference_shared_state(struct gl_context *ctx, 371 struct gl_shared_state **ptr, 372 struct gl_shared_state *state) 373{ 374 if (*ptr == state) 375 return; 376 377 if (*ptr) { 378 /* unref old state */ 379 struct gl_shared_state *old = *ptr; 380 GLboolean delete; 381 382 mtx_lock(&old->Mutex); 383 assert(old->RefCount >= 1); 384 old->RefCount--; 385 delete = (old->RefCount == 0); 386 mtx_unlock(&old->Mutex); 387 388 if (delete) { 389 free_shared_state(ctx, old); 390 } 391 392 *ptr = NULL; 393 } 394 395 if (state) { 396 /* reference new state */ 397 mtx_lock(&state->Mutex); 398 state->RefCount++; 399 *ptr = state; 400 mtx_unlock(&state->Mutex); 401 } 402} 403