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