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