shaderobj.c revision 01e04c3f
1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 2004-2008 Brian Paul All Rights Reserved. 5 * Copyright (C) 2009-2010 VMware, Inc. All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 * OTHER DEALINGS IN THE SOFTWARE. 24 */ 25 26/** 27 * \file shaderobj.c 28 * \author Brian Paul 29 * 30 */ 31 32 33#include "compiler/glsl/string_to_uint_map.h" 34#include "main/glheader.h" 35#include "main/context.h" 36#include "main/glspirv.h" 37#include "main/hash.h" 38#include "main/mtypes.h" 39#include "main/shaderapi.h" 40#include "main/shaderobj.h" 41#include "main/uniforms.h" 42#include "program/program.h" 43#include "program/prog_parameter.h" 44#include "util/ralloc.h" 45#include "util/u_atomic.h" 46 47/**********************************************************************/ 48/*** Shader object functions ***/ 49/**********************************************************************/ 50 51 52/** 53 * Set ptr to point to sh. 54 * If ptr is pointing to another shader, decrement its refcount (and delete 55 * if refcount hits zero). 56 * Then set ptr to point to sh, incrementing its refcount. 57 */ 58void 59_mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr, 60 struct gl_shader *sh) 61{ 62 assert(ptr); 63 if (*ptr == sh) { 64 /* no-op */ 65 return; 66 } 67 if (*ptr) { 68 /* Unreference the old shader */ 69 struct gl_shader *old = *ptr; 70 71 assert(old->RefCount > 0); 72 73 if (p_atomic_dec_zero(&old->RefCount)) { 74 if (old->Name != 0) 75 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name); 76 _mesa_delete_shader(ctx, old); 77 } 78 79 *ptr = NULL; 80 } 81 assert(!*ptr); 82 83 if (sh) { 84 /* reference new */ 85 p_atomic_inc(&sh->RefCount); 86 *ptr = sh; 87 } 88} 89 90static void 91_mesa_init_shader(struct gl_shader *shader) 92{ 93 shader->RefCount = 1; 94 shader->info.Geom.VerticesOut = -1; 95 shader->info.Geom.InputType = GL_TRIANGLES; 96 shader->info.Geom.OutputType = GL_TRIANGLE_STRIP; 97} 98 99/** 100 * Allocate a new gl_shader object, initialize it. 101 */ 102struct gl_shader * 103_mesa_new_shader(GLuint name, gl_shader_stage stage) 104{ 105 struct gl_shader *shader; 106 shader = rzalloc(NULL, struct gl_shader); 107 if (shader) { 108 shader->Stage = stage; 109 shader->Name = name; 110#ifdef DEBUG 111 shader->SourceChecksum = 0xa110c; /* alloc */ 112#endif 113 _mesa_init_shader(shader); 114 } 115 return shader; 116} 117 118 119/** 120 * Delete a shader object. 121 */ 122void 123_mesa_delete_shader(struct gl_context *ctx, struct gl_shader *sh) 124{ 125 _mesa_shader_spirv_data_reference(&sh->spirv_data, NULL); 126 free((void *)sh->Source); 127 free((void *)sh->FallbackSource); 128 free(sh->Label); 129 ralloc_free(sh); 130} 131 132 133/** 134 * Delete a shader object. 135 */ 136void 137_mesa_delete_linked_shader(struct gl_context *ctx, 138 struct gl_linked_shader *sh) 139{ 140 _mesa_shader_spirv_data_reference(&sh->spirv_data, NULL); 141 _mesa_reference_program(ctx, &sh->Program, NULL); 142 ralloc_free(sh); 143} 144 145 146/** 147 * Lookup a GLSL shader object. 148 */ 149struct gl_shader * 150_mesa_lookup_shader(struct gl_context *ctx, GLuint name) 151{ 152 if (name) { 153 struct gl_shader *sh = (struct gl_shader *) 154 _mesa_HashLookup(ctx->Shared->ShaderObjects, name); 155 /* Note that both gl_shader and gl_shader_program objects are kept 156 * in the same hash table. Check the object's type to be sure it's 157 * what we're expecting. 158 */ 159 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) { 160 return NULL; 161 } 162 return sh; 163 } 164 return NULL; 165} 166 167 168/** 169 * As above, but record an error if shader is not found. 170 */ 171struct gl_shader * 172_mesa_lookup_shader_err(struct gl_context *ctx, GLuint name, const char *caller) 173{ 174 if (!name) { 175 _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller); 176 return NULL; 177 } 178 else { 179 struct gl_shader *sh = (struct gl_shader *) 180 _mesa_HashLookup(ctx->Shared->ShaderObjects, name); 181 if (!sh) { 182 _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller); 183 return NULL; 184 } 185 if (sh->Type == GL_SHADER_PROGRAM_MESA) { 186 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); 187 return NULL; 188 } 189 return sh; 190 } 191} 192 193 194 195/**********************************************************************/ 196/*** Shader Program object functions ***/ 197/**********************************************************************/ 198 199void 200_mesa_reference_shader_program_data(struct gl_context *ctx, 201 struct gl_shader_program_data **ptr, 202 struct gl_shader_program_data *data) 203{ 204 if (*ptr == data) 205 return; 206 207 if (*ptr) { 208 struct gl_shader_program_data *oldData = *ptr; 209 210 assert(oldData->RefCount > 0); 211 212 if (p_atomic_dec_zero(&oldData->RefCount)) { 213 assert(ctx); 214 assert(oldData->NumUniformStorage == 0 || 215 oldData->UniformStorage); 216 217 for (unsigned i = 0; i < oldData->NumUniformStorage; ++i) 218 _mesa_uniform_detach_all_driver_storage(&oldData->UniformStorage[i]); 219 220 ralloc_free(oldData); 221 } 222 223 *ptr = NULL; 224 } 225 226 if (data) 227 p_atomic_inc(&data->RefCount); 228 229 *ptr = data; 230} 231 232/** 233 * Set ptr to point to shProg. 234 * If ptr is pointing to another object, decrement its refcount (and delete 235 * if refcount hits zero). 236 * Then set ptr to point to shProg, incrementing its refcount. 237 */ 238void 239_mesa_reference_shader_program_(struct gl_context *ctx, 240 struct gl_shader_program **ptr, 241 struct gl_shader_program *shProg) 242{ 243 assert(ptr); 244 if (*ptr == shProg) { 245 /* no-op */ 246 return; 247 } 248 if (*ptr) { 249 /* Unreference the old shader program */ 250 struct gl_shader_program *old = *ptr; 251 252 assert(old->RefCount > 0); 253 254 if (p_atomic_dec_zero(&old->RefCount)) { 255 if (old->Name != 0) 256 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name); 257 _mesa_delete_shader_program(ctx, old); 258 } 259 260 *ptr = NULL; 261 } 262 assert(!*ptr); 263 264 if (shProg) { 265 p_atomic_inc(&shProg->RefCount); 266 *ptr = shProg; 267 } 268} 269 270struct gl_shader_program_data * 271_mesa_create_shader_program_data() 272{ 273 struct gl_shader_program_data *data; 274 data = rzalloc(NULL, struct gl_shader_program_data); 275 if (data) { 276 data->RefCount = 1; 277 data->InfoLog = ralloc_strdup(data, ""); 278 } 279 280 return data; 281} 282 283static void 284init_shader_program(struct gl_shader_program *prog) 285{ 286 prog->Type = GL_SHADER_PROGRAM_MESA; 287 prog->RefCount = 1; 288 289 prog->AttributeBindings = string_to_uint_map_ctor(); 290 prog->FragDataBindings = string_to_uint_map_ctor(); 291 prog->FragDataIndexBindings = string_to_uint_map_ctor(); 292 293 prog->Geom.UsesEndPrimitive = false; 294 prog->Geom.UsesStreams = false; 295 296 prog->TransformFeedback.BufferMode = GL_INTERLEAVED_ATTRIBS; 297 298 exec_list_make_empty(&prog->EmptyUniformLocations); 299} 300 301/** 302 * Allocate a new gl_shader_program object, initialize it. 303 */ 304struct gl_shader_program * 305_mesa_new_shader_program(GLuint name) 306{ 307 struct gl_shader_program *shProg; 308 shProg = rzalloc(NULL, struct gl_shader_program); 309 if (shProg) { 310 shProg->Name = name; 311 shProg->data = _mesa_create_shader_program_data(); 312 if (!shProg->data) { 313 ralloc_free(shProg); 314 return NULL; 315 } 316 init_shader_program(shProg); 317 } 318 return shProg; 319} 320 321 322/** 323 * Clear (free) the shader program state that gets produced by linking. 324 */ 325void 326_mesa_clear_shader_program_data(struct gl_context *ctx, 327 struct gl_shader_program *shProg) 328{ 329 for (gl_shader_stage sh = 0; sh < MESA_SHADER_STAGES; sh++) { 330 if (shProg->_LinkedShaders[sh] != NULL) { 331 _mesa_delete_linked_shader(ctx, shProg->_LinkedShaders[sh]); 332 shProg->_LinkedShaders[sh] = NULL; 333 } 334 } 335 336 if (shProg->UniformRemapTable) { 337 ralloc_free(shProg->UniformRemapTable); 338 shProg->NumUniformRemapTable = 0; 339 shProg->UniformRemapTable = NULL; 340 } 341 342 if (shProg->UniformHash) { 343 string_to_uint_map_dtor(shProg->UniformHash); 344 shProg->UniformHash = NULL; 345 } 346 347 _mesa_reference_shader_program_data(ctx, &shProg->data, NULL); 348} 349 350 351/** 352 * Free all the data that hangs off a shader program object, but not the 353 * object itself. 354 */ 355void 356_mesa_free_shader_program_data(struct gl_context *ctx, 357 struct gl_shader_program *shProg) 358{ 359 GLuint i; 360 361 assert(shProg->Type == GL_SHADER_PROGRAM_MESA); 362 363 _mesa_clear_shader_program_data(ctx, shProg); 364 365 if (shProg->AttributeBindings) { 366 string_to_uint_map_dtor(shProg->AttributeBindings); 367 shProg->AttributeBindings = NULL; 368 } 369 370 if (shProg->FragDataBindings) { 371 string_to_uint_map_dtor(shProg->FragDataBindings); 372 shProg->FragDataBindings = NULL; 373 } 374 375 if (shProg->FragDataIndexBindings) { 376 string_to_uint_map_dtor(shProg->FragDataIndexBindings); 377 shProg->FragDataIndexBindings = NULL; 378 } 379 380 /* detach shaders */ 381 for (i = 0; i < shProg->NumShaders; i++) { 382 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL); 383 } 384 shProg->NumShaders = 0; 385 386 free(shProg->Shaders); 387 shProg->Shaders = NULL; 388 389 /* Transform feedback varying vars */ 390 for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) { 391 free(shProg->TransformFeedback.VaryingNames[i]); 392 } 393 free(shProg->TransformFeedback.VaryingNames); 394 shProg->TransformFeedback.VaryingNames = NULL; 395 shProg->TransformFeedback.NumVarying = 0; 396 397 free(shProg->Label); 398 shProg->Label = NULL; 399} 400 401 402/** 403 * Free/delete a shader program object. 404 */ 405void 406_mesa_delete_shader_program(struct gl_context *ctx, 407 struct gl_shader_program *shProg) 408{ 409 _mesa_free_shader_program_data(ctx, shProg); 410 ralloc_free(shProg); 411} 412 413 414/** 415 * Lookup a GLSL program object. 416 */ 417struct gl_shader_program * 418_mesa_lookup_shader_program(struct gl_context *ctx, GLuint name) 419{ 420 struct gl_shader_program *shProg; 421 if (name) { 422 shProg = (struct gl_shader_program *) 423 _mesa_HashLookup(ctx->Shared->ShaderObjects, name); 424 /* Note that both gl_shader and gl_shader_program objects are kept 425 * in the same hash table. Check the object's type to be sure it's 426 * what we're expecting. 427 */ 428 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) { 429 return NULL; 430 } 431 return shProg; 432 } 433 return NULL; 434} 435 436 437/** 438 * As above, but record an error if program is not found. 439 */ 440struct gl_shader_program * 441_mesa_lookup_shader_program_err(struct gl_context *ctx, GLuint name, 442 const char *caller) 443{ 444 if (!name) { 445 _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller); 446 return NULL; 447 } 448 else { 449 struct gl_shader_program *shProg = (struct gl_shader_program *) 450 _mesa_HashLookup(ctx->Shared->ShaderObjects, name); 451 if (!shProg) { 452 _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller); 453 return NULL; 454 } 455 if (shProg->Type != GL_SHADER_PROGRAM_MESA) { 456 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); 457 return NULL; 458 } 459 return shProg; 460 } 461} 462 463 464void 465_mesa_init_shader_object_functions(struct dd_function_table *driver) 466{ 467 driver->LinkShader = _mesa_ir_link_shader; 468} 469