• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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