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