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 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25/** 26 * \file shaderobj.c 27 * \author Brian Paul 28 * 29 */ 30 31 32#include "main/glheader.h" 33#include "main/context.h" 34#include "main/hash.h" 35#include "main/mfeatures.h" 36#include "main/mtypes.h" 37#include "main/shaderobj.h" 38#include "main/uniforms.h" 39#include "program/program.h" 40#include "program/prog_parameter.h" 41#include "program/hash_table.h" 42#include "ralloc.h" 43 44/**********************************************************************/ 45/*** Shader object functions ***/ 46/**********************************************************************/ 47 48 49/** 50 * Set ptr to point to sh. 51 * If ptr is pointing to another shader, decrement its refcount (and delete 52 * if refcount hits zero). 53 * Then set ptr to point to sh, incrementing its refcount. 54 */ 55void 56_mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr, 57 struct gl_shader *sh) 58{ 59 assert(ptr); 60 if (*ptr == sh) { 61 /* no-op */ 62 return; 63 } 64 if (*ptr) { 65 /* Unreference the old shader */ 66 GLboolean deleteFlag = GL_FALSE; 67 struct gl_shader *old = *ptr; 68 69 ASSERT(old->RefCount > 0); 70 old->RefCount--; 71 /*printf("SHADER DECR %p (%d) to %d\n", 72 (void*) old, old->Name, old->RefCount);*/ 73 deleteFlag = (old->RefCount == 0); 74 75 if (deleteFlag) { 76 if (old->Name != 0) 77 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name); 78 ctx->Driver.DeleteShader(ctx, old); 79 } 80 81 *ptr = NULL; 82 } 83 assert(!*ptr); 84 85 if (sh) { 86 /* reference new */ 87 sh->RefCount++; 88 /*printf("SHADER INCR %p (%d) to %d\n", 89 (void*) sh, sh->Name, sh->RefCount);*/ 90 *ptr = sh; 91 } 92} 93 94void 95_mesa_init_shader(struct gl_context *ctx, struct gl_shader *shader) 96{ 97 shader->RefCount = 1; 98} 99 100/** 101 * Allocate a new gl_shader object, initialize it. 102 * Called via ctx->Driver.NewShader() 103 */ 104struct gl_shader * 105_mesa_new_shader(struct gl_context *ctx, GLuint name, GLenum type) 106{ 107 struct gl_shader *shader; 108 assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER || 109 type == GL_GEOMETRY_SHADER_ARB); 110 shader = rzalloc(NULL, struct gl_shader); 111 if (shader) { 112 shader->Type = type; 113 shader->Name = name; 114 _mesa_init_shader(ctx, shader); 115 } 116 return shader; 117} 118 119 120/** 121 * Delete a shader object. 122 * Called via ctx->Driver.DeleteShader(). 123 */ 124static void 125_mesa_delete_shader(struct gl_context *ctx, struct gl_shader *sh) 126{ 127 if (sh->Source) 128 free((void *) sh->Source); 129 _mesa_reference_program(ctx, &sh->Program, NULL); 130 ralloc_free(sh); 131} 132 133 134/** 135 * Lookup a GLSL shader object. 136 */ 137struct gl_shader * 138_mesa_lookup_shader(struct gl_context *ctx, GLuint name) 139{ 140 if (name) { 141 struct gl_shader *sh = (struct gl_shader *) 142 _mesa_HashLookup(ctx->Shared->ShaderObjects, name); 143 /* Note that both gl_shader and gl_shader_program objects are kept 144 * in the same hash table. Check the object's type to be sure it's 145 * what we're expecting. 146 */ 147 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) { 148 return NULL; 149 } 150 return sh; 151 } 152 return NULL; 153} 154 155 156/** 157 * As above, but record an error if shader is not found. 158 */ 159struct gl_shader * 160_mesa_lookup_shader_err(struct gl_context *ctx, GLuint name, const char *caller) 161{ 162 if (!name) { 163 _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller); 164 return NULL; 165 } 166 else { 167 struct gl_shader *sh = (struct gl_shader *) 168 _mesa_HashLookup(ctx->Shared->ShaderObjects, name); 169 if (!sh) { 170 _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller); 171 return NULL; 172 } 173 if (sh->Type == GL_SHADER_PROGRAM_MESA) { 174 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); 175 return NULL; 176 } 177 return sh; 178 } 179} 180 181 182 183/**********************************************************************/ 184/*** Shader Program object functions ***/ 185/**********************************************************************/ 186 187 188/** 189 * Set ptr to point to shProg. 190 * If ptr is pointing to another object, decrement its refcount (and delete 191 * if refcount hits zero). 192 * Then set ptr to point to shProg, incrementing its refcount. 193 */ 194void 195_mesa_reference_shader_program(struct gl_context *ctx, 196 struct gl_shader_program **ptr, 197 struct gl_shader_program *shProg) 198{ 199 assert(ptr); 200 if (*ptr == shProg) { 201 /* no-op */ 202 return; 203 } 204 if (*ptr) { 205 /* Unreference the old shader program */ 206 GLboolean deleteFlag = GL_FALSE; 207 struct gl_shader_program *old = *ptr; 208 209 ASSERT(old->RefCount > 0); 210 old->RefCount--; 211#if 0 212 printf("ShaderProgram %p ID=%u RefCount-- to %d\n", 213 (void *) old, old->Name, old->RefCount); 214#endif 215 deleteFlag = (old->RefCount == 0); 216 217 if (deleteFlag) { 218 if (old->Name != 0) 219 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name); 220 ctx->Driver.DeleteShaderProgram(ctx, old); 221 } 222 223 *ptr = NULL; 224 } 225 assert(!*ptr); 226 227 if (shProg) { 228 shProg->RefCount++; 229#if 0 230 printf("ShaderProgram %p ID=%u RefCount++ to %d\n", 231 (void *) shProg, shProg->Name, shProg->RefCount); 232#endif 233 *ptr = shProg; 234 } 235} 236 237void 238_mesa_init_shader_program(struct gl_context *ctx, struct gl_shader_program *prog) 239{ 240 prog->Type = GL_SHADER_PROGRAM_MESA; 241 prog->RefCount = 1; 242 243 prog->AttributeBindings = string_to_uint_map_ctor(); 244 prog->FragDataBindings = string_to_uint_map_ctor(); 245 prog->FragDataIndexBindings = string_to_uint_map_ctor(); 246 247#if FEATURE_ARB_geometry_shader4 248 prog->Geom.VerticesOut = 0; 249 prog->Geom.InputType = GL_TRIANGLES; 250 prog->Geom.OutputType = GL_TRIANGLE_STRIP; 251#endif 252 253 prog->TransformFeedback.BufferMode = GL_INTERLEAVED_ATTRIBS; 254 255 prog->InfoLog = ralloc_strdup(prog, ""); 256} 257 258/** 259 * Allocate a new gl_shader_program object, initialize it. 260 * Called via ctx->Driver.NewShaderProgram() 261 */ 262static struct gl_shader_program * 263_mesa_new_shader_program(struct gl_context *ctx, GLuint name) 264{ 265 struct gl_shader_program *shProg; 266 shProg = rzalloc(NULL, struct gl_shader_program); 267 if (shProg) { 268 shProg->Name = name; 269 _mesa_init_shader_program(ctx, shProg); 270 } 271 return shProg; 272} 273 274 275/** 276 * Clear (free) the shader program state that gets produced by linking. 277 */ 278void 279_mesa_clear_shader_program_data(struct gl_context *ctx, 280 struct gl_shader_program *shProg) 281{ 282 if (shProg->UniformStorage) { 283 unsigned i; 284 for (i = 0; i < shProg->NumUserUniformStorage; ++i) 285 _mesa_uniform_detach_all_driver_storage(&shProg->UniformStorage[i]); 286 ralloc_free(shProg->UniformStorage); 287 shProg->NumUserUniformStorage = 0; 288 shProg->UniformStorage = NULL; 289 } 290 291 if (shProg->UniformHash) { 292 string_to_uint_map_dtor(shProg->UniformHash); 293 shProg->UniformHash = NULL; 294 } 295 296 assert(shProg->InfoLog != NULL); 297 ralloc_free(shProg->InfoLog); 298 shProg->InfoLog = ralloc_strdup(shProg, ""); 299} 300 301 302/** 303 * Free all the data that hangs off a shader program object, but not the 304 * object itself. 305 */ 306void 307_mesa_free_shader_program_data(struct gl_context *ctx, 308 struct gl_shader_program *shProg) 309{ 310 GLuint i; 311 gl_shader_type sh; 312 313 assert(shProg->Type == GL_SHADER_PROGRAM_MESA); 314 315 _mesa_clear_shader_program_data(ctx, shProg); 316 317 if (shProg->AttributeBindings) { 318 string_to_uint_map_dtor(shProg->AttributeBindings); 319 shProg->AttributeBindings = NULL; 320 } 321 322 if (shProg->FragDataBindings) { 323 string_to_uint_map_dtor(shProg->FragDataBindings); 324 shProg->FragDataBindings = NULL; 325 } 326 327 if (shProg->FragDataIndexBindings) { 328 string_to_uint_map_dtor(shProg->FragDataIndexBindings); 329 shProg->FragDataIndexBindings = NULL; 330 } 331 332 /* detach shaders */ 333 for (i = 0; i < shProg->NumShaders; i++) { 334 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL); 335 } 336 shProg->NumShaders = 0; 337 338 if (shProg->Shaders) { 339 free(shProg->Shaders); 340 shProg->Shaders = NULL; 341 } 342 343 /* Transform feedback varying vars */ 344 for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) { 345 free(shProg->TransformFeedback.VaryingNames[i]); 346 } 347 free(shProg->TransformFeedback.VaryingNames); 348 shProg->TransformFeedback.VaryingNames = NULL; 349 shProg->TransformFeedback.NumVarying = 0; 350 351 352 for (sh = 0; sh < MESA_SHADER_TYPES; sh++) { 353 if (shProg->_LinkedShaders[sh] != NULL) { 354 ctx->Driver.DeleteShader(ctx, shProg->_LinkedShaders[sh]); 355 shProg->_LinkedShaders[sh] = NULL; 356 } 357 } 358} 359 360 361/** 362 * Free/delete a shader program object. 363 * Called via ctx->Driver.DeleteShaderProgram(). 364 */ 365static void 366_mesa_delete_shader_program(struct gl_context *ctx, struct gl_shader_program *shProg) 367{ 368 _mesa_free_shader_program_data(ctx, shProg); 369 370 ralloc_free(shProg); 371} 372 373 374/** 375 * Lookup a GLSL program object. 376 */ 377struct gl_shader_program * 378_mesa_lookup_shader_program(struct gl_context *ctx, GLuint name) 379{ 380 struct gl_shader_program *shProg; 381 if (name) { 382 shProg = (struct gl_shader_program *) 383 _mesa_HashLookup(ctx->Shared->ShaderObjects, name); 384 /* Note that both gl_shader and gl_shader_program objects are kept 385 * in the same hash table. Check the object's type to be sure it's 386 * what we're expecting. 387 */ 388 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) { 389 return NULL; 390 } 391 return shProg; 392 } 393 return NULL; 394} 395 396 397/** 398 * As above, but record an error if program is not found. 399 */ 400struct gl_shader_program * 401_mesa_lookup_shader_program_err(struct gl_context *ctx, GLuint name, 402 const char *caller) 403{ 404 if (!name) { 405 _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller); 406 return NULL; 407 } 408 else { 409 struct gl_shader_program *shProg = (struct gl_shader_program *) 410 _mesa_HashLookup(ctx->Shared->ShaderObjects, name); 411 if (!shProg) { 412 _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller); 413 return NULL; 414 } 415 if (shProg->Type != GL_SHADER_PROGRAM_MESA) { 416 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller); 417 return NULL; 418 } 419 return shProg; 420 } 421} 422 423 424void 425_mesa_init_shader_object_functions(struct dd_function_table *driver) 426{ 427 driver->NewShader = _mesa_new_shader; 428 driver->DeleteShader = _mesa_delete_shader; 429 driver->NewShaderProgram = _mesa_new_shader_program; 430 driver->DeleteShaderProgram = _mesa_delete_shader_program; 431 driver->LinkShader = _mesa_ir_link_shader; 432} 433