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 */ 58static void 59_reference_shader(struct gl_context *ctx, struct gl_shader **ptr, 60 struct gl_shader *sh, bool skip_locking) 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 if (skip_locking) 76 _mesa_HashRemoveLocked(ctx->Shared->ShaderObjects, old->Name); 77 else 78 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name); 79 } 80 _mesa_delete_shader(ctx, old); 81 } 82 83 *ptr = NULL; 84 } 85 assert(!*ptr); 86 87 if (sh) { 88 /* reference new */ 89 p_atomic_inc(&sh->RefCount); 90 *ptr = sh; 91 } 92} 93 94void 95_mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr, 96 struct gl_shader *sh) 97{ 98 _reference_shader(ctx, ptr, sh, false); 99} 100 101static void 102_mesa_init_shader(struct gl_shader *shader) 103{ 104 shader->RefCount = 1; 105 shader->info.Geom.VerticesOut = -1; 106 shader->info.Geom.InputType = SHADER_PRIM_TRIANGLES; 107 shader->info.Geom.OutputType = SHADER_PRIM_TRIANGLE_STRIP; 108} 109 110/** 111 * Allocate a new gl_shader object, initialize it. 112 */ 113struct gl_shader * 114_mesa_new_shader(GLuint name, gl_shader_stage stage) 115{ 116 struct gl_shader *shader; 117 shader = rzalloc(NULL, struct gl_shader); 118 if (shader) { 119 shader->Stage = stage; 120 shader->Name = name; 121 _mesa_init_shader(shader); 122 } 123 return shader; 124} 125 126 127/** 128 * Delete a shader object. 129 */ 130void 131_mesa_delete_shader(struct gl_context *ctx, struct gl_shader *sh) 132{ 133 _mesa_shader_spirv_data_reference(&sh->spirv_data, NULL); 134 free((void *)sh->Source); 135 free((void *)sh->FallbackSource); 136 free(sh->Label); 137 ralloc_free(sh); 138} 139 140 141/** 142 * Delete a shader object. 143 */ 144void 145_mesa_delete_linked_shader(struct gl_context *ctx, 146 struct gl_linked_shader *sh) 147{ 148 _mesa_shader_spirv_data_reference(&sh->spirv_data, NULL); 149 _mesa_reference_program(ctx, &sh->Program, NULL); 150 ralloc_free(sh); 151} 152 153 154/** 155 * Lookup a GLSL shader object. 156 */ 157struct gl_shader * 158_mesa_lookup_shader(struct gl_context *ctx, GLuint name) 159{ 160 if (name) { 161 struct gl_shader *sh = (struct gl_shader *) 162 _mesa_HashLookup(ctx->Shared->ShaderObjects, name); 163 /* Note that both gl_shader and gl_shader_program objects are kept 164 * in the same hash table. Check the object's type to be sure it's 165 * what we're expecting. 166 */ 167 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) { 168 return NULL; 169 } 170 return sh; 171 } 172 return NULL; 173} 174 175 176/** 177 * As above, but record an error if shader is not found. 178 */ 179struct gl_shader * 180_mesa_lookup_shader_err(struct gl_context *ctx, GLuint name, const char *caller) 181{ 182 if (!name) { 183 _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller); 184 return NULL; 185 } 186 else { 187 struct gl_shader *sh = (struct gl_shader *) 188 _mesa_HashLookup(ctx->Shared->ShaderObjects, name); 189 if (!sh) { 190 _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller); 191 return NULL; 192 } 193 if (sh->Type == GL_SHADER_PROGRAM_MESA) { 194 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); 195 return NULL; 196 } 197 return sh; 198 } 199} 200 201 202 203/**********************************************************************/ 204/*** Shader Program object functions ***/ 205/**********************************************************************/ 206 207void 208_mesa_reference_shader_program_data(struct gl_shader_program_data **ptr, 209 struct gl_shader_program_data *data) 210{ 211 if (*ptr == data) 212 return; 213 214 if (*ptr) { 215 struct gl_shader_program_data *oldData = *ptr; 216 217 assert(oldData->RefCount > 0); 218 219 if (p_atomic_dec_zero(&oldData->RefCount)) { 220 assert(oldData->NumUniformStorage == 0 || 221 oldData->UniformStorage); 222 223 for (unsigned i = 0; i < oldData->NumUniformStorage; ++i) 224 _mesa_uniform_detach_all_driver_storage(&oldData->UniformStorage[i]); 225 226 ralloc_free(oldData); 227 } 228 229 *ptr = NULL; 230 } 231 232 if (data) 233 p_atomic_inc(&data->RefCount); 234 235 *ptr = data; 236} 237 238/** 239 * Set ptr to point to shProg. 240 * If ptr is pointing to another object, decrement its refcount (and delete 241 * if refcount hits zero). 242 * Then set ptr to point to shProg, incrementing its refcount. 243 */ 244void 245_mesa_reference_shader_program_(struct gl_context *ctx, 246 struct gl_shader_program **ptr, 247 struct gl_shader_program *shProg) 248{ 249 assert(ptr); 250 if (*ptr == shProg) { 251 /* no-op */ 252 return; 253 } 254 if (*ptr) { 255 /* Unreference the old shader program */ 256 struct gl_shader_program *old = *ptr; 257 258 assert(old->RefCount > 0); 259 260 if (p_atomic_dec_zero(&old->RefCount)) { 261 _mesa_HashLockMutex(ctx->Shared->ShaderObjects); 262 if (old->Name != 0) 263 _mesa_HashRemoveLocked(ctx->Shared->ShaderObjects, old->Name); 264 _mesa_delete_shader_program(ctx, old); 265 _mesa_HashUnlockMutex(ctx->Shared->ShaderObjects); 266 } 267 268 *ptr = NULL; 269 } 270 assert(!*ptr); 271 272 if (shProg) { 273 p_atomic_inc(&shProg->RefCount); 274 *ptr = shProg; 275 } 276} 277 278struct gl_shader_program_data * 279_mesa_create_shader_program_data() 280{ 281 struct gl_shader_program_data *data; 282 data = rzalloc(NULL, struct gl_shader_program_data); 283 if (data) { 284 data->RefCount = 1; 285 data->InfoLog = ralloc_strdup(data, ""); 286 } 287 288 return data; 289} 290 291static void 292init_shader_program(struct gl_shader_program *prog) 293{ 294 prog->Type = GL_SHADER_PROGRAM_MESA; 295 prog->RefCount = 1; 296 297 prog->AttributeBindings = string_to_uint_map_ctor(); 298 prog->FragDataBindings = string_to_uint_map_ctor(); 299 prog->FragDataIndexBindings = string_to_uint_map_ctor(); 300 301 prog->Geom.UsesEndPrimitive = false; 302 prog->Geom.ActiveStreamMask = 0; 303 304 prog->TransformFeedback.BufferMode = GL_INTERLEAVED_ATTRIBS; 305 306 exec_list_make_empty(&prog->EmptyUniformLocations); 307} 308 309/** 310 * Allocate a new gl_shader_program object, initialize it. 311 */ 312struct gl_shader_program * 313_mesa_new_shader_program(GLuint name) 314{ 315 struct gl_shader_program *shProg; 316 shProg = rzalloc(NULL, struct gl_shader_program); 317 if (shProg) { 318 shProg->Name = name; 319 shProg->data = _mesa_create_shader_program_data(); 320 if (!shProg->data) { 321 ralloc_free(shProg); 322 return NULL; 323 } 324 init_shader_program(shProg); 325 } 326 return shProg; 327} 328 329 330/** 331 * Clear (free) the shader program state that gets produced by linking. 332 */ 333void 334_mesa_clear_shader_program_data(struct gl_context *ctx, 335 struct gl_shader_program *shProg) 336{ 337 for (gl_shader_stage sh = 0; sh < MESA_SHADER_STAGES; sh++) { 338 if (shProg->_LinkedShaders[sh] != NULL) { 339 _mesa_delete_linked_shader(ctx, shProg->_LinkedShaders[sh]); 340 shProg->_LinkedShaders[sh] = NULL; 341 } 342 } 343 344 if (shProg->UniformRemapTable) { 345 ralloc_free(shProg->UniformRemapTable); 346 shProg->NumUniformRemapTable = 0; 347 shProg->UniformRemapTable = NULL; 348 } 349 350 if (shProg->UniformHash) { 351 string_to_uint_map_dtor(shProg->UniformHash); 352 shProg->UniformHash = NULL; 353 } 354 355 if (shProg->data) 356 _mesa_program_resource_hash_destroy(shProg); 357 358 _mesa_reference_shader_program_data(&shProg->data, NULL); 359} 360 361 362/** 363 * Free all the data that hangs off a shader program object, but not the 364 * object itself. 365 * Must be called with shared->ShaderObjects locked. 366 */ 367void 368_mesa_free_shader_program_data(struct gl_context *ctx, 369 struct gl_shader_program *shProg) 370{ 371 GLuint i; 372 373 assert(shProg->Type == GL_SHADER_PROGRAM_MESA); 374 375 _mesa_clear_shader_program_data(ctx, shProg); 376 377 if (shProg->AttributeBindings) { 378 string_to_uint_map_dtor(shProg->AttributeBindings); 379 shProg->AttributeBindings = NULL; 380 } 381 382 if (shProg->FragDataBindings) { 383 string_to_uint_map_dtor(shProg->FragDataBindings); 384 shProg->FragDataBindings = NULL; 385 } 386 387 if (shProg->FragDataIndexBindings) { 388 string_to_uint_map_dtor(shProg->FragDataIndexBindings); 389 shProg->FragDataIndexBindings = NULL; 390 } 391 392 /* detach shaders */ 393 for (i = 0; i < shProg->NumShaders; i++) { 394 _reference_shader(ctx, &shProg->Shaders[i], NULL, true); 395 } 396 shProg->NumShaders = 0; 397 398 free(shProg->Shaders); 399 shProg->Shaders = NULL; 400 401 /* Transform feedback varying vars */ 402 for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) { 403 free(shProg->TransformFeedback.VaryingNames[i]); 404 } 405 free(shProg->TransformFeedback.VaryingNames); 406 shProg->TransformFeedback.VaryingNames = NULL; 407 shProg->TransformFeedback.NumVarying = 0; 408 409 free(shProg->Label); 410 shProg->Label = NULL; 411} 412 413 414/** 415 * Free/delete a shader program object. 416 */ 417void 418_mesa_delete_shader_program(struct gl_context *ctx, 419 struct gl_shader_program *shProg) 420{ 421 _mesa_free_shader_program_data(ctx, shProg); 422 ralloc_free(shProg); 423} 424 425 426/** 427 * Lookup a GLSL program object. 428 */ 429struct gl_shader_program * 430_mesa_lookup_shader_program(struct gl_context *ctx, GLuint name) 431{ 432 struct gl_shader_program *shProg; 433 if (name) { 434 shProg = (struct gl_shader_program *) 435 _mesa_HashLookup(ctx->Shared->ShaderObjects, name); 436 /* Note that both gl_shader and gl_shader_program objects are kept 437 * in the same hash table. Check the object's type to be sure it's 438 * what we're expecting. 439 */ 440 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) { 441 return NULL; 442 } 443 return shProg; 444 } 445 return NULL; 446} 447 448 449/** 450 * As above, but record an error if program is not found. 451 */ 452struct gl_shader_program * 453_mesa_lookup_shader_program_err_glthread(struct gl_context *ctx, GLuint name, 454 bool glthread, const char *caller) 455{ 456 if (!name) { 457 _mesa_error_glthread_safe(ctx, GL_INVALID_VALUE, glthread, "%s", caller); 458 return NULL; 459 } 460 else { 461 struct gl_shader_program *shProg = (struct gl_shader_program *) 462 _mesa_HashLookup(ctx->Shared->ShaderObjects, name); 463 if (!shProg) { 464 _mesa_error_glthread_safe(ctx, GL_INVALID_VALUE, glthread, 465 "%s", caller); 466 return NULL; 467 } 468 if (shProg->Type != GL_SHADER_PROGRAM_MESA) { 469 _mesa_error_glthread_safe(ctx, GL_INVALID_OPERATION, glthread, 470 "%s", caller); 471 return NULL; 472 } 473 return shProg; 474 } 475} 476 477 478struct gl_shader_program * 479_mesa_lookup_shader_program_err(struct gl_context *ctx, GLuint name, 480 const char *caller) 481{ 482 return _mesa_lookup_shader_program_err_glthread(ctx, name, false, caller); 483} 484