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 "compiler/glsl/string_to_uint_map.h"
34 #include "main/glheader.h"
35 #include "main/context.h"
36 #include "main/glspirv.h"
37 #include "main/hash.h"
38 #include "main/mtypes.h"
39 #include "main/shaderapi.h"
40 #include "main/shaderobj.h"
41 #include "main/uniforms.h"
42 #include "program/program.h"
43 #include "program/prog_parameter.h"
44 #include "util/ralloc.h"
45 #include "util/u_atomic.h"
46 
47 /**********************************************************************/
48 /*** Shader object functions                                        ***/
49 /**********************************************************************/
50 
51 
52 /**
53  * Set ptr to point to sh.
54  * If ptr is pointing to another shader, decrement its refcount (and delete
55  * if refcount hits zero).
56  * Then set ptr to point to sh, incrementing its refcount.
57  */
58 static void
_reference_shader(struct gl_context * ctx,struct gl_shader ** ptr,struct gl_shader * sh,bool skip_locking)59 _reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
60                        struct gl_shader *sh, bool skip_locking)
61 {
62    assert(ptr);
63    if (*ptr == sh) {
64       /* no-op */
65       return;
66    }
67    if (*ptr) {
68       /* Unreference the old shader */
69       struct gl_shader *old = *ptr;
70 
71       assert(old->RefCount > 0);
72 
73       if (p_atomic_dec_zero(&old->RefCount)) {
74          if (old->Name != 0) {
75             if (skip_locking)
76                _mesa_HashRemoveLocked(ctx->Shared->ShaderObjects, old->Name);
77             else
78                _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
79          }
80          _mesa_delete_shader(ctx, old);
81       }
82 
83       *ptr = NULL;
84    }
85    assert(!*ptr);
86 
87    if (sh) {
88       /* reference new */
89       p_atomic_inc(&sh->RefCount);
90       *ptr = sh;
91    }
92 }
93 
94 void
_mesa_reference_shader(struct gl_context * ctx,struct gl_shader ** ptr,struct gl_shader * sh)95 _mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
96                        struct gl_shader *sh)
97 {
98    _reference_shader(ctx, ptr, sh, false);
99 }
100 
101 static void
_mesa_init_shader(struct gl_shader * shader)102 _mesa_init_shader(struct gl_shader *shader)
103 {
104    shader->RefCount = 1;
105    shader->info.Geom.VerticesOut = -1;
106    shader->info.Geom.InputType = GL_TRIANGLES;
107    shader->info.Geom.OutputType = GL_TRIANGLE_STRIP;
108 }
109 
110 /**
111  * Allocate a new gl_shader object, initialize it.
112  */
113 struct gl_shader *
_mesa_new_shader(GLuint name,gl_shader_stage stage)114 _mesa_new_shader(GLuint name, gl_shader_stage stage)
115 {
116    struct gl_shader *shader;
117    shader = rzalloc(NULL, struct gl_shader);
118    if (shader) {
119       shader->Stage = stage;
120       shader->Name = name;
121 #ifdef DEBUG
122       shader->SourceChecksum = 0xa110c; /* alloc */
123 #endif
124       _mesa_init_shader(shader);
125    }
126    return shader;
127 }
128 
129 
130 /**
131  * Delete a shader object.
132  */
133 void
_mesa_delete_shader(struct gl_context * ctx,struct gl_shader * sh)134 _mesa_delete_shader(struct gl_context *ctx, struct gl_shader *sh)
135 {
136    _mesa_shader_spirv_data_reference(&sh->spirv_data, NULL);
137    free((void *)sh->Source);
138    free((void *)sh->FallbackSource);
139    free(sh->Label);
140    ralloc_free(sh);
141 }
142 
143 
144 /**
145  * Delete a shader object.
146  */
147 void
_mesa_delete_linked_shader(struct gl_context * ctx,struct gl_linked_shader * sh)148 _mesa_delete_linked_shader(struct gl_context *ctx,
149                            struct gl_linked_shader *sh)
150 {
151    _mesa_shader_spirv_data_reference(&sh->spirv_data, NULL);
152    _mesa_reference_program(ctx, &sh->Program, NULL);
153    ralloc_free(sh);
154 }
155 
156 
157 /**
158  * Lookup a GLSL shader object.
159  */
160 struct gl_shader *
_mesa_lookup_shader(struct gl_context * ctx,GLuint name)161 _mesa_lookup_shader(struct gl_context *ctx, GLuint name)
162 {
163    if (name) {
164       struct gl_shader *sh = (struct gl_shader *)
165          _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
166       /* Note that both gl_shader and gl_shader_program objects are kept
167        * in the same hash table.  Check the object's type to be sure it's
168        * what we're expecting.
169        */
170       if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
171          return NULL;
172       }
173       return sh;
174    }
175    return NULL;
176 }
177 
178 
179 /**
180  * As above, but record an error if shader is not found.
181  */
182 struct gl_shader *
_mesa_lookup_shader_err(struct gl_context * ctx,GLuint name,const char * caller)183 _mesa_lookup_shader_err(struct gl_context *ctx, GLuint name, const char *caller)
184 {
185    if (!name) {
186       _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
187       return NULL;
188    }
189    else {
190       struct gl_shader *sh = (struct gl_shader *)
191          _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
192       if (!sh) {
193          _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
194          return NULL;
195       }
196       if (sh->Type == GL_SHADER_PROGRAM_MESA) {
197          _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
198          return NULL;
199       }
200       return sh;
201    }
202 }
203 
204 
205 
206 /**********************************************************************/
207 /*** Shader Program object functions                                ***/
208 /**********************************************************************/
209 
210 void
_mesa_reference_shader_program_data(struct gl_context * ctx,struct gl_shader_program_data ** ptr,struct gl_shader_program_data * data)211 _mesa_reference_shader_program_data(struct gl_context *ctx,
212                                     struct gl_shader_program_data **ptr,
213                                     struct gl_shader_program_data *data)
214 {
215    if (*ptr == data)
216       return;
217 
218    if (*ptr) {
219       struct gl_shader_program_data *oldData = *ptr;
220 
221       assert(oldData->RefCount > 0);
222 
223       if (p_atomic_dec_zero(&oldData->RefCount)) {
224          assert(ctx);
225          assert(oldData->NumUniformStorage == 0 ||
226                 oldData->UniformStorage);
227 
228          for (unsigned i = 0; i < oldData->NumUniformStorage; ++i)
229             _mesa_uniform_detach_all_driver_storage(&oldData->UniformStorage[i]);
230 
231          ralloc_free(oldData);
232       }
233 
234       *ptr = NULL;
235    }
236 
237    if (data)
238       p_atomic_inc(&data->RefCount);
239 
240    *ptr = data;
241 }
242 
243 /**
244  * Set ptr to point to shProg.
245  * If ptr is pointing to another object, decrement its refcount (and delete
246  * if refcount hits zero).
247  * Then set ptr to point to shProg, incrementing its refcount.
248  */
249 void
_mesa_reference_shader_program_(struct gl_context * ctx,struct gl_shader_program ** ptr,struct gl_shader_program * shProg)250 _mesa_reference_shader_program_(struct gl_context *ctx,
251                                 struct gl_shader_program **ptr,
252                                 struct gl_shader_program *shProg)
253 {
254    assert(ptr);
255    if (*ptr == shProg) {
256       /* no-op */
257       return;
258    }
259    if (*ptr) {
260       /* Unreference the old shader program */
261       struct gl_shader_program *old = *ptr;
262 
263       assert(old->RefCount > 0);
264 
265       if (p_atomic_dec_zero(&old->RefCount)) {
266          _mesa_HashLockMutex(ctx->Shared->ShaderObjects);
267          if (old->Name != 0)
268 	         _mesa_HashRemoveLocked(ctx->Shared->ShaderObjects, old->Name);
269          _mesa_delete_shader_program(ctx, old);
270          _mesa_HashUnlockMutex(ctx->Shared->ShaderObjects);
271       }
272 
273       *ptr = NULL;
274    }
275    assert(!*ptr);
276 
277    if (shProg) {
278       p_atomic_inc(&shProg->RefCount);
279       *ptr = shProg;
280    }
281 }
282 
283 struct gl_shader_program_data *
_mesa_create_shader_program_data()284 _mesa_create_shader_program_data()
285 {
286    struct gl_shader_program_data *data;
287    data = rzalloc(NULL, struct gl_shader_program_data);
288    if (data) {
289       data->RefCount = 1;
290       data->InfoLog = ralloc_strdup(data, "");
291    }
292 
293    return data;
294 }
295 
296 static void
init_shader_program(struct gl_shader_program * prog)297 init_shader_program(struct gl_shader_program *prog)
298 {
299    prog->Type = GL_SHADER_PROGRAM_MESA;
300    prog->RefCount = 1;
301 
302    prog->AttributeBindings = string_to_uint_map_ctor();
303    prog->FragDataBindings = string_to_uint_map_ctor();
304    prog->FragDataIndexBindings = string_to_uint_map_ctor();
305 
306    prog->Geom.UsesEndPrimitive = false;
307    prog->Geom.ActiveStreamMask = 0;
308 
309    prog->TransformFeedback.BufferMode = GL_INTERLEAVED_ATTRIBS;
310 
311    exec_list_make_empty(&prog->EmptyUniformLocations);
312 }
313 
314 /**
315  * Allocate a new gl_shader_program object, initialize it.
316  */
317 struct gl_shader_program *
_mesa_new_shader_program(GLuint name)318 _mesa_new_shader_program(GLuint name)
319 {
320    struct gl_shader_program *shProg;
321    shProg = rzalloc(NULL, struct gl_shader_program);
322    if (shProg) {
323       shProg->Name = name;
324       shProg->data = _mesa_create_shader_program_data();
325       if (!shProg->data) {
326          ralloc_free(shProg);
327          return NULL;
328       }
329       init_shader_program(shProg);
330    }
331    return shProg;
332 }
333 
334 
335 /**
336  * Clear (free) the shader program state that gets produced by linking.
337  */
338 void
_mesa_clear_shader_program_data(struct gl_context * ctx,struct gl_shader_program * shProg)339 _mesa_clear_shader_program_data(struct gl_context *ctx,
340                                 struct gl_shader_program *shProg)
341 {
342    for (gl_shader_stage sh = 0; sh < MESA_SHADER_STAGES; sh++) {
343       if (shProg->_LinkedShaders[sh] != NULL) {
344          _mesa_delete_linked_shader(ctx, shProg->_LinkedShaders[sh]);
345          shProg->_LinkedShaders[sh] = NULL;
346       }
347    }
348 
349    if (shProg->UniformRemapTable) {
350       ralloc_free(shProg->UniformRemapTable);
351       shProg->NumUniformRemapTable = 0;
352       shProg->UniformRemapTable = NULL;
353    }
354 
355    if (shProg->UniformHash) {
356       string_to_uint_map_dtor(shProg->UniformHash);
357       shProg->UniformHash = NULL;
358    }
359 
360    if (shProg->data && shProg->data->ProgramResourceHash) {
361       _mesa_hash_table_u64_destroy(shProg->data->ProgramResourceHash);
362       shProg->data->ProgramResourceHash = NULL;
363    }
364 
365    _mesa_reference_shader_program_data(ctx, &shProg->data, NULL);
366 }
367 
368 
369 /**
370  * Free all the data that hangs off a shader program object, but not the
371  * object itself.
372  * Must be called with shared->ShaderObjects locked.
373  */
374 void
_mesa_free_shader_program_data(struct gl_context * ctx,struct gl_shader_program * shProg)375 _mesa_free_shader_program_data(struct gl_context *ctx,
376                                struct gl_shader_program *shProg)
377 {
378    GLuint i;
379 
380    assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
381 
382    _mesa_clear_shader_program_data(ctx, shProg);
383 
384    if (shProg->AttributeBindings) {
385       string_to_uint_map_dtor(shProg->AttributeBindings);
386       shProg->AttributeBindings = NULL;
387    }
388 
389    if (shProg->FragDataBindings) {
390       string_to_uint_map_dtor(shProg->FragDataBindings);
391       shProg->FragDataBindings = NULL;
392    }
393 
394    if (shProg->FragDataIndexBindings) {
395       string_to_uint_map_dtor(shProg->FragDataIndexBindings);
396       shProg->FragDataIndexBindings = NULL;
397    }
398 
399    /* detach shaders */
400    for (i = 0; i < shProg->NumShaders; i++) {
401       _reference_shader(ctx, &shProg->Shaders[i], NULL, true);
402    }
403    shProg->NumShaders = 0;
404 
405    free(shProg->Shaders);
406    shProg->Shaders = NULL;
407 
408    /* Transform feedback varying vars */
409    for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) {
410       free(shProg->TransformFeedback.VaryingNames[i]);
411    }
412    free(shProg->TransformFeedback.VaryingNames);
413    shProg->TransformFeedback.VaryingNames = NULL;
414    shProg->TransformFeedback.NumVarying = 0;
415 
416    free(shProg->Label);
417    shProg->Label = NULL;
418 }
419 
420 
421 /**
422  * Free/delete a shader program object.
423  */
424 void
_mesa_delete_shader_program(struct gl_context * ctx,struct gl_shader_program * shProg)425 _mesa_delete_shader_program(struct gl_context *ctx,
426                             struct gl_shader_program *shProg)
427 {
428    _mesa_free_shader_program_data(ctx, shProg);
429    ralloc_free(shProg);
430 }
431 
432 
433 /**
434  * Lookup a GLSL program object.
435  */
436 struct gl_shader_program *
_mesa_lookup_shader_program(struct gl_context * ctx,GLuint name)437 _mesa_lookup_shader_program(struct gl_context *ctx, GLuint name)
438 {
439    struct gl_shader_program *shProg;
440    if (name) {
441       shProg = (struct gl_shader_program *)
442          _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
443       /* Note that both gl_shader and gl_shader_program objects are kept
444        * in the same hash table.  Check the object's type to be sure it's
445        * what we're expecting.
446        */
447       if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
448          return NULL;
449       }
450       return shProg;
451    }
452    return NULL;
453 }
454 
455 
456 /**
457  * As above, but record an error if program is not found.
458  */
459 struct gl_shader_program *
_mesa_lookup_shader_program_err_glthread(struct gl_context * ctx,GLuint name,bool glthread,const char * caller)460 _mesa_lookup_shader_program_err_glthread(struct gl_context *ctx, GLuint name,
461                                          bool glthread, const char *caller)
462 {
463    if (!name) {
464       _mesa_error_glthread_safe(ctx, GL_INVALID_VALUE, glthread, "%s", caller);
465       return NULL;
466    }
467    else {
468       struct gl_shader_program *shProg = (struct gl_shader_program *)
469          _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
470       if (!shProg) {
471          _mesa_error_glthread_safe(ctx, GL_INVALID_VALUE, glthread,
472                                    "%s", caller);
473          return NULL;
474       }
475       if (shProg->Type != GL_SHADER_PROGRAM_MESA) {
476          _mesa_error_glthread_safe(ctx, GL_INVALID_OPERATION, glthread,
477                                    "%s", caller);
478          return NULL;
479       }
480       return shProg;
481    }
482 }
483 
484 
485 struct gl_shader_program *
_mesa_lookup_shader_program_err(struct gl_context * ctx,GLuint name,const char * caller)486 _mesa_lookup_shader_program_err(struct gl_context *ctx, GLuint name,
487                                 const char *caller)
488 {
489    return _mesa_lookup_shader_program_err_glthread(ctx, name, false, caller);
490 }
491 
492 
493 void
_mesa_init_shader_object_functions(struct dd_function_table * driver)494 _mesa_init_shader_object_functions(struct dd_function_table *driver)
495 {
496    driver->LinkShader = _mesa_ir_link_shader;
497 }
498