shared.c revision af69d88d
14a49301eSmrg/*
24a49301eSmrg * Mesa 3-D graphics library
34a49301eSmrg *
44a49301eSmrg * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
54a49301eSmrg *
64a49301eSmrg * Permission is hereby granted, free of charge, to any person obtaining a
74a49301eSmrg * copy of this software and associated documentation files (the "Software"),
84a49301eSmrg * to deal in the Software without restriction, including without limitation
94a49301eSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
104a49301eSmrg * and/or sell copies of the Software, and to permit persons to whom the
114a49301eSmrg * Software is furnished to do so, subject to the following conditions:
124a49301eSmrg *
134a49301eSmrg * The above copyright notice and this permission notice shall be included
144a49301eSmrg * in all copies or substantial portions of the Software.
154a49301eSmrg *
164a49301eSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
174a49301eSmrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
184a49301eSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
234a49301eSmrg */
244a49301eSmrg
254a49301eSmrg/**
264a49301eSmrg * \file shared.c
274a49301eSmrg * Shared-context state
284a49301eSmrg */
294a49301eSmrg
304a49301eSmrg#include "imports.h"
314a49301eSmrg#include "mtypes.h"
324a49301eSmrg#include "hash.h"
333464ebd5Sriastradh#include "atifragshader.h"
344a49301eSmrg#include "bufferobj.h"
354a49301eSmrg#include "shared.h"
363464ebd5Sriastradh#include "program/program.h"
374a49301eSmrg#include "dlist.h"
383464ebd5Sriastradh#include "samplerobj.h"
39af69d88dSmrg#include "set.h"
40af69d88dSmrg#include "shaderapi.h"
413464ebd5Sriastradh#include "shaderobj.h"
424a49301eSmrg#include "syncobj.h"
433464ebd5Sriastradh
44af69d88dSmrg#include "util/hash_table.h"
454a49301eSmrg
464a49301eSmrg/**
474a49301eSmrg * Allocate and initialize a shared context state structure.
484a49301eSmrg * Initializes the display list, texture objects and vertex programs hash
494a49301eSmrg * tables, allocates the texture objects. If it runs out of memory, frees
504a49301eSmrg * everything already allocated before returning NULL.
514a49301eSmrg *
524a49301eSmrg * \return pointer to a gl_shared_state structure on success, or NULL on
534a49301eSmrg * failure.
544a49301eSmrg */
554a49301eSmrgstruct gl_shared_state *
563464ebd5Sriastradh_mesa_alloc_shared_state(struct gl_context *ctx)
574a49301eSmrg{
584a49301eSmrg   struct gl_shared_state *shared;
594a49301eSmrg   GLuint i;
604a49301eSmrg
614a49301eSmrg   shared = CALLOC_STRUCT(gl_shared_state);
624a49301eSmrg   if (!shared)
634a49301eSmrg      return NULL;
644a49301eSmrg
65af69d88dSmrg   mtx_init(&shared->Mutex, mtx_plain);
664a49301eSmrg
674a49301eSmrg   shared->DisplayList = _mesa_NewHashTable();
684a49301eSmrg   shared->TexObjects = _mesa_NewHashTable();
694a49301eSmrg   shared->Programs = _mesa_NewHashTable();
704a49301eSmrg
71af69d88dSmrg   shared->DefaultVertexProgram =
72af69d88dSmrg      gl_vertex_program(ctx->Driver.NewProgram(ctx,
73af69d88dSmrg                                               GL_VERTEX_PROGRAM_ARB, 0));
74af69d88dSmrg   shared->DefaultFragmentProgram =
75af69d88dSmrg      gl_fragment_program(ctx->Driver.NewProgram(ctx,
76af69d88dSmrg                                                 GL_FRAGMENT_PROGRAM_ARB, 0));
774a49301eSmrg
784a49301eSmrg   shared->ATIShaders = _mesa_NewHashTable();
794a49301eSmrg   shared->DefaultFragmentShader = _mesa_new_ati_fragment_shader(ctx, 0);
804a49301eSmrg
814a49301eSmrg   shared->ShaderObjects = _mesa_NewHashTable();
824a49301eSmrg
834a49301eSmrg   shared->BufferObjects = _mesa_NewHashTable();
844a49301eSmrg
853464ebd5Sriastradh   /* GL_ARB_sampler_objects */
863464ebd5Sriastradh   shared->SamplerObjects = _mesa_NewHashTable();
873464ebd5Sriastradh
884a49301eSmrg   /* Allocate the default buffer object */
894a49301eSmrg   shared->NullBufferObj = ctx->Driver.NewBufferObject(ctx, 0, 0);
904a49301eSmrg
914a49301eSmrg   /* Create default texture objects */
924a49301eSmrg   for (i = 0; i < NUM_TEXTURE_TARGETS; i++) {
934a49301eSmrg      /* NOTE: the order of these enums matches the TEXTURE_x_INDEX values */
94af69d88dSmrg      static const GLenum targets[] = {
95af69d88dSmrg         GL_TEXTURE_2D_MULTISAMPLE,
96af69d88dSmrg         GL_TEXTURE_2D_MULTISAMPLE_ARRAY,
97af69d88dSmrg         GL_TEXTURE_CUBE_MAP_ARRAY,
983464ebd5Sriastradh         GL_TEXTURE_BUFFER,
994a49301eSmrg         GL_TEXTURE_2D_ARRAY_EXT,
1004a49301eSmrg         GL_TEXTURE_1D_ARRAY_EXT,
101af69d88dSmrg         GL_TEXTURE_EXTERNAL_OES,
1024a49301eSmrg         GL_TEXTURE_CUBE_MAP,
1034a49301eSmrg         GL_TEXTURE_3D,
1044a49301eSmrg         GL_TEXTURE_RECTANGLE_NV,
1054a49301eSmrg         GL_TEXTURE_2D,
1064a49301eSmrg         GL_TEXTURE_1D
1074a49301eSmrg      };
108af69d88dSmrg      STATIC_ASSERT(Elements(targets) == NUM_TEXTURE_TARGETS);
1094a49301eSmrg      shared->DefaultTex[i] = ctx->Driver.NewTextureObject(ctx, 0, targets[i]);
1104a49301eSmrg   }
1114a49301eSmrg
1124a49301eSmrg   /* sanity check */
1134a49301eSmrg   assert(shared->DefaultTex[TEXTURE_1D_INDEX]->RefCount == 1);
1144a49301eSmrg
1154a49301eSmrg   /* Mutex and timestamp for texobj state validation */
116af69d88dSmrg   mtx_init(&shared->TexMutex, mtx_recursive);
1174a49301eSmrg   shared->TextureStateStamp = 0;
1184a49301eSmrg
1194a49301eSmrg   shared->FrameBuffers = _mesa_NewHashTable();
1204a49301eSmrg   shared->RenderBuffers = _mesa_NewHashTable();
1214a49301eSmrg
122af69d88dSmrg   shared->SyncObjects = _mesa_set_create(NULL, _mesa_key_pointer_equal);
1234a49301eSmrg
1244a49301eSmrg   return shared;
1254a49301eSmrg}
1264a49301eSmrg
1274a49301eSmrg
1284a49301eSmrg/**
1294a49301eSmrg * Callback for deleting a display list.  Called by _mesa_HashDeleteAll().
1304a49301eSmrg */
1314a49301eSmrgstatic void
1324a49301eSmrgdelete_displaylist_cb(GLuint id, void *data, void *userData)
1334a49301eSmrg{
1344a49301eSmrg   struct gl_display_list *list = (struct gl_display_list *) data;
1353464ebd5Sriastradh   struct gl_context *ctx = (struct gl_context *) userData;
1364a49301eSmrg   _mesa_delete_list(ctx, list);
1374a49301eSmrg}
1384a49301eSmrg
1394a49301eSmrg
1404a49301eSmrg/**
1414a49301eSmrg * Callback for deleting a texture object.  Called by _mesa_HashDeleteAll().
1424a49301eSmrg */
1434a49301eSmrgstatic void
1444a49301eSmrgdelete_texture_cb(GLuint id, void *data, void *userData)
1454a49301eSmrg{
1464a49301eSmrg   struct gl_texture_object *texObj = (struct gl_texture_object *) data;
1473464ebd5Sriastradh   struct gl_context *ctx = (struct gl_context *) userData;
1484a49301eSmrg   ctx->Driver.DeleteTexture(ctx, texObj);
1494a49301eSmrg}
1504a49301eSmrg
1514a49301eSmrg
1524a49301eSmrg/**
1534a49301eSmrg * Callback for deleting a program object.  Called by _mesa_HashDeleteAll().
1544a49301eSmrg */
1554a49301eSmrgstatic void
1564a49301eSmrgdelete_program_cb(GLuint id, void *data, void *userData)
1574a49301eSmrg{
1584a49301eSmrg   struct gl_program *prog = (struct gl_program *) data;
1593464ebd5Sriastradh   struct gl_context *ctx = (struct gl_context *) userData;
1604a49301eSmrg   if(prog != &_mesa_DummyProgram) {
1614a49301eSmrg      ASSERT(prog->RefCount == 1); /* should only be referenced by hash table */
1624a49301eSmrg      prog->RefCount = 0;  /* now going away */
1634a49301eSmrg      ctx->Driver.DeleteProgram(ctx, prog);
1644a49301eSmrg   }
1654a49301eSmrg}
1664a49301eSmrg
1674a49301eSmrg
1684a49301eSmrg/**
1694a49301eSmrg * Callback for deleting an ATI fragment shader object.
1704a49301eSmrg * Called by _mesa_HashDeleteAll().
1714a49301eSmrg */
1724a49301eSmrgstatic void
1734a49301eSmrgdelete_fragshader_cb(GLuint id, void *data, void *userData)
1744a49301eSmrg{
1754a49301eSmrg   struct ati_fragment_shader *shader = (struct ati_fragment_shader *) data;
1763464ebd5Sriastradh   struct gl_context *ctx = (struct gl_context *) userData;
1774a49301eSmrg   _mesa_delete_ati_fragment_shader(ctx, shader);
1784a49301eSmrg}
1794a49301eSmrg
1804a49301eSmrg
1814a49301eSmrg/**
1824a49301eSmrg * Callback for deleting a buffer object.  Called by _mesa_HashDeleteAll().
1834a49301eSmrg */
1844a49301eSmrgstatic void
1854a49301eSmrgdelete_bufferobj_cb(GLuint id, void *data, void *userData)
1864a49301eSmrg{
1874a49301eSmrg   struct gl_buffer_object *bufObj = (struct gl_buffer_object *) data;
1883464ebd5Sriastradh   struct gl_context *ctx = (struct gl_context *) userData;
189af69d88dSmrg
190af69d88dSmrg   _mesa_buffer_unmap_all_mappings(ctx, bufObj);
1914a49301eSmrg   _mesa_reference_buffer_object(ctx, &bufObj, NULL);
1924a49301eSmrg}
1934a49301eSmrg
1944a49301eSmrg
1954a49301eSmrg/**
1964a49301eSmrg * Callback for freeing shader program data. Call it before delete_shader_cb
1974a49301eSmrg * to avoid memory access error.
1984a49301eSmrg */
1994a49301eSmrgstatic void
2004a49301eSmrgfree_shader_program_data_cb(GLuint id, void *data, void *userData)
2014a49301eSmrg{
2023464ebd5Sriastradh   struct gl_context *ctx = (struct gl_context *) userData;
2034a49301eSmrg   struct gl_shader_program *shProg = (struct gl_shader_program *) data;
2044a49301eSmrg
2054a49301eSmrg   if (shProg->Type == GL_SHADER_PROGRAM_MESA) {
2064a49301eSmrg       _mesa_free_shader_program_data(ctx, shProg);
2074a49301eSmrg   }
2084a49301eSmrg}
2094a49301eSmrg
2104a49301eSmrg
2114a49301eSmrg/**
2124a49301eSmrg * Callback for deleting shader and shader programs objects.
2134a49301eSmrg * Called by _mesa_HashDeleteAll().
2144a49301eSmrg */
2154a49301eSmrgstatic void
2164a49301eSmrgdelete_shader_cb(GLuint id, void *data, void *userData)
2174a49301eSmrg{
2183464ebd5Sriastradh   struct gl_context *ctx = (struct gl_context *) userData;
2194a49301eSmrg   struct gl_shader *sh = (struct gl_shader *) data;
220af69d88dSmrg   if (_mesa_validate_shader_target(ctx, sh->Type)) {
2213464ebd5Sriastradh      ctx->Driver.DeleteShader(ctx, sh);
2224a49301eSmrg   }
2234a49301eSmrg   else {
2244a49301eSmrg      struct gl_shader_program *shProg = (struct gl_shader_program *) data;
2254a49301eSmrg      ASSERT(shProg->Type == GL_SHADER_PROGRAM_MESA);
2263464ebd5Sriastradh      ctx->Driver.DeleteShaderProgram(ctx, shProg);
2274a49301eSmrg   }
2284a49301eSmrg}
2294a49301eSmrg
2304a49301eSmrg
2314a49301eSmrg/**
2324a49301eSmrg * Callback for deleting a framebuffer object.  Called by _mesa_HashDeleteAll()
2334a49301eSmrg */
2344a49301eSmrgstatic void
2354a49301eSmrgdelete_framebuffer_cb(GLuint id, void *data, void *userData)
2364a49301eSmrg{
2374a49301eSmrg   struct gl_framebuffer *fb = (struct gl_framebuffer *) data;
2384a49301eSmrg   /* The fact that the framebuffer is in the hashtable means its refcount
2394a49301eSmrg    * is one, but we're removing from the hashtable now.  So clear refcount.
2404a49301eSmrg    */
2414a49301eSmrg   /*assert(fb->RefCount == 1);*/
2424a49301eSmrg   fb->RefCount = 0;
2434a49301eSmrg
2444a49301eSmrg   /* NOTE: Delete should always be defined but there are two reports
2454a49301eSmrg    * of it being NULL (bugs 13507, 14293).  Work-around for now.
2464a49301eSmrg    */
2474a49301eSmrg   if (fb->Delete)
2484a49301eSmrg      fb->Delete(fb);
2494a49301eSmrg}
2504a49301eSmrg
2514a49301eSmrg
2524a49301eSmrg/**
2534a49301eSmrg * Callback for deleting a renderbuffer object. Called by _mesa_HashDeleteAll()
2544a49301eSmrg */
2554a49301eSmrgstatic void
2564a49301eSmrgdelete_renderbuffer_cb(GLuint id, void *data, void *userData)
2574a49301eSmrg{
258af69d88dSmrg   struct gl_context *ctx = (struct gl_context *) userData;
2594a49301eSmrg   struct gl_renderbuffer *rb = (struct gl_renderbuffer *) data;
2604a49301eSmrg   rb->RefCount = 0;  /* see comment for FBOs above */
2614a49301eSmrg   if (rb->Delete)
262af69d88dSmrg      rb->Delete(ctx, rb);
2634a49301eSmrg}
2644a49301eSmrg
2654a49301eSmrg
2663464ebd5Sriastradh/**
2673464ebd5Sriastradh * Callback for deleting a sampler object. Called by _mesa_HashDeleteAll()
2683464ebd5Sriastradh */
2693464ebd5Sriastradhstatic void
2703464ebd5Sriastradhdelete_sampler_object_cb(GLuint id, void *data, void *userData)
2713464ebd5Sriastradh{
2723464ebd5Sriastradh   struct gl_context *ctx = (struct gl_context *) userData;
2733464ebd5Sriastradh   struct gl_sampler_object *sampObj = (struct gl_sampler_object *) data;
2743464ebd5Sriastradh   _mesa_reference_sampler_object(ctx, &sampObj, NULL);
2753464ebd5Sriastradh}
2763464ebd5Sriastradh
2773464ebd5Sriastradh
2784a49301eSmrg/**
2794a49301eSmrg * Deallocate a shared state object and all children structures.
2804a49301eSmrg *
2814a49301eSmrg * \param ctx GL context.
2824a49301eSmrg * \param shared shared state pointer.
2834a49301eSmrg *
2844a49301eSmrg * Frees the display lists, the texture objects (calling the driver texture
2854a49301eSmrg * deletion callback to free its private data) and the vertex programs, as well
2864a49301eSmrg * as their hash tables.
2874a49301eSmrg *
2884a49301eSmrg * \sa alloc_shared_state().
2894a49301eSmrg */
2904a49301eSmrgstatic void
2913464ebd5Sriastradhfree_shared_state(struct gl_context *ctx, struct gl_shared_state *shared)
2924a49301eSmrg{
2934a49301eSmrg   GLuint i;
2944a49301eSmrg
295af69d88dSmrg   /* Free the dummy/fallback texture objects */
296af69d88dSmrg   for (i = 0; i < NUM_TEXTURE_TARGETS; i++) {
297af69d88dSmrg      if (shared->FallbackTex[i])
298af69d88dSmrg         ctx->Driver.DeleteTexture(ctx, shared->FallbackTex[i]);
299af69d88dSmrg   }
3003464ebd5Sriastradh
3014a49301eSmrg   /*
3024a49301eSmrg    * Free display lists
3034a49301eSmrg    */
3044a49301eSmrg   _mesa_HashDeleteAll(shared->DisplayList, delete_displaylist_cb, ctx);
3054a49301eSmrg   _mesa_DeleteHashTable(shared->DisplayList);
3064a49301eSmrg
3074a49301eSmrg   _mesa_HashWalk(shared->ShaderObjects, free_shader_program_data_cb, ctx);
3084a49301eSmrg   _mesa_HashDeleteAll(shared->ShaderObjects, delete_shader_cb, ctx);
3094a49301eSmrg   _mesa_DeleteHashTable(shared->ShaderObjects);
3104a49301eSmrg
3114a49301eSmrg   _mesa_HashDeleteAll(shared->Programs, delete_program_cb, ctx);
3124a49301eSmrg   _mesa_DeleteHashTable(shared->Programs);
3134a49301eSmrg
3144a49301eSmrg   _mesa_reference_vertprog(ctx, &shared->DefaultVertexProgram, NULL);
315af69d88dSmrg   _mesa_reference_geomprog(ctx, &shared->DefaultGeometryProgram, NULL);
3164a49301eSmrg   _mesa_reference_fragprog(ctx, &shared->DefaultFragmentProgram, NULL);
3174a49301eSmrg
3184a49301eSmrg   _mesa_HashDeleteAll(shared->ATIShaders, delete_fragshader_cb, ctx);
3194a49301eSmrg   _mesa_DeleteHashTable(shared->ATIShaders);
3204a49301eSmrg   _mesa_delete_ati_fragment_shader(ctx, shared->DefaultFragmentShader);
3214a49301eSmrg
3224a49301eSmrg   _mesa_HashDeleteAll(shared->BufferObjects, delete_bufferobj_cb, ctx);
3234a49301eSmrg   _mesa_DeleteHashTable(shared->BufferObjects);
3244a49301eSmrg
3254a49301eSmrg   _mesa_HashDeleteAll(shared->FrameBuffers, delete_framebuffer_cb, ctx);
3264a49301eSmrg   _mesa_DeleteHashTable(shared->FrameBuffers);
3274a49301eSmrg   _mesa_HashDeleteAll(shared->RenderBuffers, delete_renderbuffer_cb, ctx);
3284a49301eSmrg   _mesa_DeleteHashTable(shared->RenderBuffers);
3294a49301eSmrg
3304a49301eSmrg   _mesa_reference_buffer_object(ctx, &shared->NullBufferObj, NULL);
3314a49301eSmrg
3324a49301eSmrg   {
333af69d88dSmrg      struct set_entry *entry;
3344a49301eSmrg
335af69d88dSmrg      set_foreach(shared->SyncObjects, entry) {
336af69d88dSmrg         _mesa_unref_sync_object(ctx, (struct gl_sync_object *) entry->key);
3374a49301eSmrg      }
3384a49301eSmrg   }
339af69d88dSmrg   _mesa_set_destroy(shared->SyncObjects, NULL);
3403464ebd5Sriastradh
3413464ebd5Sriastradh   _mesa_HashDeleteAll(shared->SamplerObjects, delete_sampler_object_cb, ctx);
3423464ebd5Sriastradh   _mesa_DeleteHashTable(shared->SamplerObjects);
3434a49301eSmrg
3444a49301eSmrg   /*
3454a49301eSmrg    * Free texture objects (after FBOs since some textures might have
3464a49301eSmrg    * been bound to FBOs).
3474a49301eSmrg    */
3484a49301eSmrg   ASSERT(ctx->Driver.DeleteTexture);
3494a49301eSmrg   /* the default textures */
3504a49301eSmrg   for (i = 0; i < NUM_TEXTURE_TARGETS; i++) {
3514a49301eSmrg      ctx->Driver.DeleteTexture(ctx, shared->DefaultTex[i]);
3524a49301eSmrg   }
3534a49301eSmrg
3544a49301eSmrg   /* all other textures */
3554a49301eSmrg   _mesa_HashDeleteAll(shared->TexObjects, delete_texture_cb, ctx);
3564a49301eSmrg   _mesa_DeleteHashTable(shared->TexObjects);
3574a49301eSmrg
358af69d88dSmrg   mtx_destroy(&shared->Mutex);
359af69d88dSmrg   mtx_destroy(&shared->TexMutex);
3604a49301eSmrg
361cdc920a0Smrg   free(shared);
3624a49301eSmrg}
3634a49301eSmrg
3644a49301eSmrg
3654a49301eSmrg/**
366af69d88dSmrg * gl_shared_state objects are ref counted.
367af69d88dSmrg * If ptr's refcount goes to zero, free the shared state.
3684a49301eSmrg */
3694a49301eSmrgvoid
370af69d88dSmrg_mesa_reference_shared_state(struct gl_context *ctx,
371af69d88dSmrg                             struct gl_shared_state **ptr,
372af69d88dSmrg                             struct gl_shared_state *state)
3734a49301eSmrg{
374af69d88dSmrg   if (*ptr == state)
375af69d88dSmrg      return;
376af69d88dSmrg
377af69d88dSmrg   if (*ptr) {
378af69d88dSmrg      /* unref old state */
379af69d88dSmrg      struct gl_shared_state *old = *ptr;
380af69d88dSmrg      GLboolean delete;
381af69d88dSmrg
382af69d88dSmrg      mtx_lock(&old->Mutex);
383af69d88dSmrg      assert(old->RefCount >= 1);
384af69d88dSmrg      old->RefCount--;
385af69d88dSmrg      delete = (old->RefCount == 0);
386af69d88dSmrg      mtx_unlock(&old->Mutex);
387af69d88dSmrg
388af69d88dSmrg      if (delete) {
389af69d88dSmrg         free_shared_state(ctx, old);
390af69d88dSmrg      }
3914a49301eSmrg
392af69d88dSmrg      *ptr = NULL;
393af69d88dSmrg   }
3944a49301eSmrg
395af69d88dSmrg   if (state) {
396af69d88dSmrg      /* reference new state */
397af69d88dSmrg      mtx_lock(&state->Mutex);
398af69d88dSmrg      state->RefCount++;
399af69d88dSmrg      *ptr = state;
400af69d88dSmrg      mtx_unlock(&state->Mutex);
4014a49301eSmrg   }
4024a49301eSmrg}
403