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