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
_mesa_reference_shader(struct gl_context * ctx,struct gl_shader ** ptr,struct gl_shader * sh)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
_mesa_init_shader(struct gl_shader * shader)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 *
_mesa_new_shader(GLuint name,gl_shader_stage stage)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
_mesa_delete_shader(struct gl_context * ctx,struct gl_shader * sh)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
_mesa_delete_linked_shader(struct gl_context * ctx,struct gl_linked_shader * sh)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 *
_mesa_lookup_shader(struct gl_context * ctx,GLuint name)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 *
_mesa_lookup_shader_err(struct gl_context * ctx,GLuint name,const char * caller)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
_mesa_reference_shader_program_data(struct gl_context * ctx,struct gl_shader_program_data ** ptr,struct gl_shader_program_data * data)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
_mesa_reference_shader_program_(struct gl_context * ctx,struct gl_shader_program ** ptr,struct gl_shader_program * shProg)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 *
create_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
init_shader_program(struct gl_shader_program * prog)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 *
_mesa_new_shader_program(GLuint name)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
_mesa_clear_shader_program_data(struct gl_context * ctx,struct gl_shader_program * shProg)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
_mesa_free_shader_program_data(struct gl_context * ctx,struct gl_shader_program * shProg)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
_mesa_delete_shader_program(struct gl_context * ctx,struct gl_shader_program * shProg)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 *
_mesa_lookup_shader_program(struct gl_context * ctx,GLuint name)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 *
_mesa_lookup_shader_program_err(struct gl_context * ctx,GLuint name,const char * caller)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
_mesa_init_shader_object_functions(struct dd_function_table * driver)490 _mesa_init_shader_object_functions(struct dd_function_table *driver)
491 {
492 driver->LinkShader = _mesa_ir_link_shader;
493 }
494