1848b8605Smrg/*
2848b8605Smrg * Mesa 3-D graphics library
3848b8605Smrg *
4848b8605Smrg * Copyright (C) 2004-2008  Brian Paul   All Rights Reserved.
5848b8605Smrg * Copyright (C) 2009-2010  VMware, Inc.  All Rights Reserved.
6848b8605Smrg *
7848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
8848b8605Smrg * copy of this software and associated documentation files (the "Software"),
9848b8605Smrg * to deal in the Software without restriction, including without limitation
10848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
12848b8605Smrg * Software is furnished to do so, subject to the following conditions:
13848b8605Smrg *
14848b8605Smrg * The above copyright notice and this permission notice shall be included
15848b8605Smrg * in all copies or substantial portions of the Software.
16848b8605Smrg *
17848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20848b8605Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21848b8605Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22848b8605Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23848b8605Smrg * OTHER DEALINGS IN THE SOFTWARE.
24848b8605Smrg */
25848b8605Smrg
26848b8605Smrg/**
27848b8605Smrg * \file shaderobj.c
28848b8605Smrg * \author Brian Paul
29848b8605Smrg *
30848b8605Smrg */
31848b8605Smrg
32848b8605Smrg
33b8e80941Smrg#include "compiler/glsl/string_to_uint_map.h"
34848b8605Smrg#include "main/glheader.h"
35848b8605Smrg#include "main/context.h"
36b8e80941Smrg#include "main/glspirv.h"
37848b8605Smrg#include "main/hash.h"
38848b8605Smrg#include "main/mtypes.h"
39848b8605Smrg#include "main/shaderapi.h"
40848b8605Smrg#include "main/shaderobj.h"
41848b8605Smrg#include "main/uniforms.h"
42848b8605Smrg#include "program/program.h"
43848b8605Smrg#include "program/prog_parameter.h"
44848b8605Smrg#include "util/ralloc.h"
45b8e80941Smrg#include "util/u_atomic.h"
46848b8605Smrg
47848b8605Smrg/**********************************************************************/
48848b8605Smrg/*** Shader object functions                                        ***/
49848b8605Smrg/**********************************************************************/
50848b8605Smrg
51848b8605Smrg
52848b8605Smrg/**
53848b8605Smrg * Set ptr to point to sh.
54848b8605Smrg * If ptr is pointing to another shader, decrement its refcount (and delete
55848b8605Smrg * if refcount hits zero).
56848b8605Smrg * Then set ptr to point to sh, incrementing its refcount.
57848b8605Smrg */
58848b8605Smrgvoid
59848b8605Smrg_mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr,
60848b8605Smrg                       struct gl_shader *sh)
61848b8605Smrg{
62848b8605Smrg   assert(ptr);
63848b8605Smrg   if (*ptr == sh) {
64848b8605Smrg      /* no-op */
65848b8605Smrg      return;
66848b8605Smrg   }
67848b8605Smrg   if (*ptr) {
68848b8605Smrg      /* Unreference the old shader */
69848b8605Smrg      struct gl_shader *old = *ptr;
70848b8605Smrg
71b8e80941Smrg      assert(old->RefCount > 0);
72848b8605Smrg
73b8e80941Smrg      if (p_atomic_dec_zero(&old->RefCount)) {
74848b8605Smrg	 if (old->Name != 0)
75848b8605Smrg	    _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
76b8e80941Smrg         _mesa_delete_shader(ctx, old);
77848b8605Smrg      }
78848b8605Smrg
79848b8605Smrg      *ptr = NULL;
80848b8605Smrg   }
81848b8605Smrg   assert(!*ptr);
82848b8605Smrg
83848b8605Smrg   if (sh) {
84848b8605Smrg      /* reference new */
85b8e80941Smrg      p_atomic_inc(&sh->RefCount);
86848b8605Smrg      *ptr = sh;
87848b8605Smrg   }
88848b8605Smrg}
89848b8605Smrg
90b8e80941Smrgstatic void
91b8e80941Smrg_mesa_init_shader(struct gl_shader *shader)
92848b8605Smrg{
93848b8605Smrg   shader->RefCount = 1;
94b8e80941Smrg   shader->info.Geom.VerticesOut = -1;
95b8e80941Smrg   shader->info.Geom.InputType = GL_TRIANGLES;
96b8e80941Smrg   shader->info.Geom.OutputType = GL_TRIANGLE_STRIP;
97848b8605Smrg}
98848b8605Smrg
99848b8605Smrg/**
100848b8605Smrg * Allocate a new gl_shader object, initialize it.
101848b8605Smrg */
102848b8605Smrgstruct gl_shader *
103b8e80941Smrg_mesa_new_shader(GLuint name, gl_shader_stage stage)
104848b8605Smrg{
105848b8605Smrg   struct gl_shader *shader;
106848b8605Smrg   shader = rzalloc(NULL, struct gl_shader);
107848b8605Smrg   if (shader) {
108b8e80941Smrg      shader->Stage = stage;
109848b8605Smrg      shader->Name = name;
110b8e80941Smrg#ifdef DEBUG
111b8e80941Smrg      shader->SourceChecksum = 0xa110c; /* alloc */
112b8e80941Smrg#endif
113b8e80941Smrg      _mesa_init_shader(shader);
114848b8605Smrg   }
115848b8605Smrg   return shader;
116848b8605Smrg}
117848b8605Smrg
118848b8605Smrg
119848b8605Smrg/**
120848b8605Smrg * Delete a shader object.
121848b8605Smrg */
122b8e80941Smrgvoid
123848b8605Smrg_mesa_delete_shader(struct gl_context *ctx, struct gl_shader *sh)
124848b8605Smrg{
125b8e80941Smrg   _mesa_shader_spirv_data_reference(&sh->spirv_data, NULL);
126848b8605Smrg   free((void *)sh->Source);
127b8e80941Smrg   free((void *)sh->FallbackSource);
128848b8605Smrg   free(sh->Label);
129b8e80941Smrg   ralloc_free(sh);
130b8e80941Smrg}
131b8e80941Smrg
132b8e80941Smrg
133b8e80941Smrg/**
134b8e80941Smrg * Delete a shader object.
135b8e80941Smrg */
136b8e80941Smrgvoid
137b8e80941Smrg_mesa_delete_linked_shader(struct gl_context *ctx,
138b8e80941Smrg                           struct gl_linked_shader *sh)
139b8e80941Smrg{
140b8e80941Smrg   _mesa_shader_spirv_data_reference(&sh->spirv_data, NULL);
141848b8605Smrg   _mesa_reference_program(ctx, &sh->Program, NULL);
142848b8605Smrg   ralloc_free(sh);
143848b8605Smrg}
144848b8605Smrg
145848b8605Smrg
146848b8605Smrg/**
147848b8605Smrg * Lookup a GLSL shader object.
148848b8605Smrg */
149848b8605Smrgstruct gl_shader *
150848b8605Smrg_mesa_lookup_shader(struct gl_context *ctx, GLuint name)
151848b8605Smrg{
152848b8605Smrg   if (name) {
153848b8605Smrg      struct gl_shader *sh = (struct gl_shader *)
154848b8605Smrg         _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
155848b8605Smrg      /* Note that both gl_shader and gl_shader_program objects are kept
156848b8605Smrg       * in the same hash table.  Check the object's type to be sure it's
157848b8605Smrg       * what we're expecting.
158848b8605Smrg       */
159848b8605Smrg      if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
160848b8605Smrg         return NULL;
161848b8605Smrg      }
162848b8605Smrg      return sh;
163848b8605Smrg   }
164848b8605Smrg   return NULL;
165848b8605Smrg}
166848b8605Smrg
167848b8605Smrg
168848b8605Smrg/**
169848b8605Smrg * As above, but record an error if shader is not found.
170848b8605Smrg */
171848b8605Smrgstruct gl_shader *
172848b8605Smrg_mesa_lookup_shader_err(struct gl_context *ctx, GLuint name, const char *caller)
173848b8605Smrg{
174848b8605Smrg   if (!name) {
175848b8605Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
176848b8605Smrg      return NULL;
177848b8605Smrg   }
178848b8605Smrg   else {
179848b8605Smrg      struct gl_shader *sh = (struct gl_shader *)
180848b8605Smrg         _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
181848b8605Smrg      if (!sh) {
182848b8605Smrg         _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
183848b8605Smrg         return NULL;
184848b8605Smrg      }
185848b8605Smrg      if (sh->Type == GL_SHADER_PROGRAM_MESA) {
186848b8605Smrg         _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
187848b8605Smrg         return NULL;
188848b8605Smrg      }
189848b8605Smrg      return sh;
190848b8605Smrg   }
191848b8605Smrg}
192848b8605Smrg
193848b8605Smrg
194848b8605Smrg
195848b8605Smrg/**********************************************************************/
196848b8605Smrg/*** Shader Program object functions                                ***/
197848b8605Smrg/**********************************************************************/
198848b8605Smrg
199b8e80941Smrgvoid
200b8e80941Smrg_mesa_reference_shader_program_data(struct gl_context *ctx,
201b8e80941Smrg                                    struct gl_shader_program_data **ptr,
202b8e80941Smrg                                    struct gl_shader_program_data *data)
203b8e80941Smrg{
204b8e80941Smrg   if (*ptr == data)
205b8e80941Smrg      return;
206b8e80941Smrg
207b8e80941Smrg   if (*ptr) {
208b8e80941Smrg      struct gl_shader_program_data *oldData = *ptr;
209b8e80941Smrg
210b8e80941Smrg      assert(oldData->RefCount > 0);
211b8e80941Smrg
212b8e80941Smrg      if (p_atomic_dec_zero(&oldData->RefCount)) {
213b8e80941Smrg         assert(ctx);
214b8e80941Smrg         assert(oldData->NumUniformStorage == 0 ||
215b8e80941Smrg                oldData->UniformStorage);
216b8e80941Smrg
217b8e80941Smrg         for (unsigned i = 0; i < oldData->NumUniformStorage; ++i)
218b8e80941Smrg            _mesa_uniform_detach_all_driver_storage(&oldData->UniformStorage[i]);
219b8e80941Smrg
220b8e80941Smrg         ralloc_free(oldData);
221b8e80941Smrg      }
222b8e80941Smrg
223b8e80941Smrg      *ptr = NULL;
224b8e80941Smrg   }
225b8e80941Smrg
226b8e80941Smrg   if (data)
227b8e80941Smrg      p_atomic_inc(&data->RefCount);
228b8e80941Smrg
229b8e80941Smrg   *ptr = data;
230b8e80941Smrg}
231848b8605Smrg
232848b8605Smrg/**
233848b8605Smrg * Set ptr to point to shProg.
234848b8605Smrg * If ptr is pointing to another object, decrement its refcount (and delete
235848b8605Smrg * if refcount hits zero).
236848b8605Smrg * Then set ptr to point to shProg, incrementing its refcount.
237848b8605Smrg */
238848b8605Smrgvoid
239b8e80941Smrg_mesa_reference_shader_program_(struct gl_context *ctx,
240b8e80941Smrg                                struct gl_shader_program **ptr,
241b8e80941Smrg                                struct gl_shader_program *shProg)
242848b8605Smrg{
243848b8605Smrg   assert(ptr);
244848b8605Smrg   if (*ptr == shProg) {
245848b8605Smrg      /* no-op */
246848b8605Smrg      return;
247848b8605Smrg   }
248848b8605Smrg   if (*ptr) {
249848b8605Smrg      /* Unreference the old shader program */
250848b8605Smrg      struct gl_shader_program *old = *ptr;
251848b8605Smrg
252b8e80941Smrg      assert(old->RefCount > 0);
253848b8605Smrg
254b8e80941Smrg      if (p_atomic_dec_zero(&old->RefCount)) {
255848b8605Smrg	 if (old->Name != 0)
256848b8605Smrg	    _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
257b8e80941Smrg         _mesa_delete_shader_program(ctx, old);
258848b8605Smrg      }
259848b8605Smrg
260848b8605Smrg      *ptr = NULL;
261848b8605Smrg   }
262848b8605Smrg   assert(!*ptr);
263848b8605Smrg
264848b8605Smrg   if (shProg) {
265b8e80941Smrg      p_atomic_inc(&shProg->RefCount);
266848b8605Smrg      *ptr = shProg;
267848b8605Smrg   }
268848b8605Smrg}
269848b8605Smrg
270b8e80941Smrgstruct gl_shader_program_data *
271b8e80941Smrg_mesa_create_shader_program_data()
272b8e80941Smrg{
273b8e80941Smrg   struct gl_shader_program_data *data;
274b8e80941Smrg   data = rzalloc(NULL, struct gl_shader_program_data);
275b8e80941Smrg   if (data) {
276b8e80941Smrg      data->RefCount = 1;
277b8e80941Smrg      data->InfoLog = ralloc_strdup(data, "");
278b8e80941Smrg   }
279b8e80941Smrg
280b8e80941Smrg   return data;
281b8e80941Smrg}
282b8e80941Smrg
283b8e80941Smrgstatic void
284b8e80941Smrginit_shader_program(struct gl_shader_program *prog)
285848b8605Smrg{
286848b8605Smrg   prog->Type = GL_SHADER_PROGRAM_MESA;
287848b8605Smrg   prog->RefCount = 1;
288848b8605Smrg
289848b8605Smrg   prog->AttributeBindings = string_to_uint_map_ctor();
290848b8605Smrg   prog->FragDataBindings = string_to_uint_map_ctor();
291848b8605Smrg   prog->FragDataIndexBindings = string_to_uint_map_ctor();
292848b8605Smrg
293848b8605Smrg   prog->Geom.UsesEndPrimitive = false;
294848b8605Smrg   prog->Geom.UsesStreams = false;
295848b8605Smrg
296848b8605Smrg   prog->TransformFeedback.BufferMode = GL_INTERLEAVED_ATTRIBS;
297848b8605Smrg
298b8e80941Smrg   exec_list_make_empty(&prog->EmptyUniformLocations);
299848b8605Smrg}
300848b8605Smrg
301848b8605Smrg/**
302848b8605Smrg * Allocate a new gl_shader_program object, initialize it.
303848b8605Smrg */
304b8e80941Smrgstruct gl_shader_program *
305b8e80941Smrg_mesa_new_shader_program(GLuint name)
306848b8605Smrg{
307848b8605Smrg   struct gl_shader_program *shProg;
308848b8605Smrg   shProg = rzalloc(NULL, struct gl_shader_program);
309848b8605Smrg   if (shProg) {
310848b8605Smrg      shProg->Name = name;
311b8e80941Smrg      shProg->data = _mesa_create_shader_program_data();
312b8e80941Smrg      if (!shProg->data) {
313b8e80941Smrg         ralloc_free(shProg);
314b8e80941Smrg         return NULL;
315b8e80941Smrg      }
316b8e80941Smrg      init_shader_program(shProg);
317848b8605Smrg   }
318848b8605Smrg   return shProg;
319848b8605Smrg}
320848b8605Smrg
321848b8605Smrg
322848b8605Smrg/**
323848b8605Smrg * Clear (free) the shader program state that gets produced by linking.
324848b8605Smrg */
325848b8605Smrgvoid
326848b8605Smrg_mesa_clear_shader_program_data(struct gl_context *ctx,
327848b8605Smrg                                struct gl_shader_program *shProg)
328848b8605Smrg{
329b8e80941Smrg   for (gl_shader_stage sh = 0; sh < MESA_SHADER_STAGES; sh++) {
330b8e80941Smrg      if (shProg->_LinkedShaders[sh] != NULL) {
331b8e80941Smrg         _mesa_delete_linked_shader(ctx, shProg->_LinkedShaders[sh]);
332b8e80941Smrg         shProg->_LinkedShaders[sh] = NULL;
333b8e80941Smrg      }
334848b8605Smrg   }
335848b8605Smrg
336848b8605Smrg   if (shProg->UniformRemapTable) {
337848b8605Smrg      ralloc_free(shProg->UniformRemapTable);
338848b8605Smrg      shProg->NumUniformRemapTable = 0;
339848b8605Smrg      shProg->UniformRemapTable = NULL;
340848b8605Smrg   }
341848b8605Smrg
342848b8605Smrg   if (shProg->UniformHash) {
343848b8605Smrg      string_to_uint_map_dtor(shProg->UniformHash);
344848b8605Smrg      shProg->UniformHash = NULL;
345848b8605Smrg   }
346848b8605Smrg
347b8e80941Smrg   _mesa_reference_shader_program_data(ctx, &shProg->data, NULL);
348848b8605Smrg}
349848b8605Smrg
350848b8605Smrg
351848b8605Smrg/**
352848b8605Smrg * Free all the data that hangs off a shader program object, but not the
353848b8605Smrg * object itself.
354848b8605Smrg */
355848b8605Smrgvoid
356848b8605Smrg_mesa_free_shader_program_data(struct gl_context *ctx,
357848b8605Smrg                               struct gl_shader_program *shProg)
358848b8605Smrg{
359848b8605Smrg   GLuint i;
360848b8605Smrg
361848b8605Smrg   assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
362848b8605Smrg
363848b8605Smrg   _mesa_clear_shader_program_data(ctx, shProg);
364848b8605Smrg
365848b8605Smrg   if (shProg->AttributeBindings) {
366848b8605Smrg      string_to_uint_map_dtor(shProg->AttributeBindings);
367848b8605Smrg      shProg->AttributeBindings = NULL;
368848b8605Smrg   }
369848b8605Smrg
370848b8605Smrg   if (shProg->FragDataBindings) {
371848b8605Smrg      string_to_uint_map_dtor(shProg->FragDataBindings);
372848b8605Smrg      shProg->FragDataBindings = NULL;
373848b8605Smrg   }
374848b8605Smrg
375848b8605Smrg   if (shProg->FragDataIndexBindings) {
376848b8605Smrg      string_to_uint_map_dtor(shProg->FragDataIndexBindings);
377848b8605Smrg      shProg->FragDataIndexBindings = NULL;
378848b8605Smrg   }
379848b8605Smrg
380848b8605Smrg   /* detach shaders */
381848b8605Smrg   for (i = 0; i < shProg->NumShaders; i++) {
382848b8605Smrg      _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
383848b8605Smrg   }
384848b8605Smrg   shProg->NumShaders = 0;
385848b8605Smrg
386848b8605Smrg   free(shProg->Shaders);
387848b8605Smrg   shProg->Shaders = NULL;
388848b8605Smrg
389848b8605Smrg   /* Transform feedback varying vars */
390848b8605Smrg   for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) {
391848b8605Smrg      free(shProg->TransformFeedback.VaryingNames[i]);
392848b8605Smrg   }
393848b8605Smrg   free(shProg->TransformFeedback.VaryingNames);
394848b8605Smrg   shProg->TransformFeedback.VaryingNames = NULL;
395848b8605Smrg   shProg->TransformFeedback.NumVarying = 0;
396848b8605Smrg
397848b8605Smrg   free(shProg->Label);
398848b8605Smrg   shProg->Label = NULL;
399848b8605Smrg}
400848b8605Smrg
401848b8605Smrg
402848b8605Smrg/**
403848b8605Smrg * Free/delete a shader program object.
404848b8605Smrg */
405b8e80941Smrgvoid
406b8e80941Smrg_mesa_delete_shader_program(struct gl_context *ctx,
407b8e80941Smrg                            struct gl_shader_program *shProg)
408848b8605Smrg{
409848b8605Smrg   _mesa_free_shader_program_data(ctx, shProg);
410848b8605Smrg   ralloc_free(shProg);
411848b8605Smrg}
412848b8605Smrg
413848b8605Smrg
414848b8605Smrg/**
415848b8605Smrg * Lookup a GLSL program object.
416848b8605Smrg */
417848b8605Smrgstruct gl_shader_program *
418848b8605Smrg_mesa_lookup_shader_program(struct gl_context *ctx, GLuint name)
419848b8605Smrg{
420848b8605Smrg   struct gl_shader_program *shProg;
421848b8605Smrg   if (name) {
422848b8605Smrg      shProg = (struct gl_shader_program *)
423848b8605Smrg         _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
424848b8605Smrg      /* Note that both gl_shader and gl_shader_program objects are kept
425848b8605Smrg       * in the same hash table.  Check the object's type to be sure it's
426848b8605Smrg       * what we're expecting.
427848b8605Smrg       */
428848b8605Smrg      if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
429848b8605Smrg         return NULL;
430848b8605Smrg      }
431848b8605Smrg      return shProg;
432848b8605Smrg   }
433848b8605Smrg   return NULL;
434848b8605Smrg}
435848b8605Smrg
436848b8605Smrg
437848b8605Smrg/**
438848b8605Smrg * As above, but record an error if program is not found.
439848b8605Smrg */
440848b8605Smrgstruct gl_shader_program *
441848b8605Smrg_mesa_lookup_shader_program_err(struct gl_context *ctx, GLuint name,
442848b8605Smrg                                const char *caller)
443848b8605Smrg{
444848b8605Smrg   if (!name) {
445848b8605Smrg      _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
446848b8605Smrg      return NULL;
447848b8605Smrg   }
448848b8605Smrg   else {
449848b8605Smrg      struct gl_shader_program *shProg = (struct gl_shader_program *)
450848b8605Smrg         _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
451848b8605Smrg      if (!shProg) {
452848b8605Smrg         _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
453848b8605Smrg         return NULL;
454848b8605Smrg      }
455848b8605Smrg      if (shProg->Type != GL_SHADER_PROGRAM_MESA) {
456848b8605Smrg         _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
457848b8605Smrg         return NULL;
458848b8605Smrg      }
459848b8605Smrg      return shProg;
460848b8605Smrg   }
461848b8605Smrg}
462848b8605Smrg
463848b8605Smrg
464848b8605Smrgvoid
465848b8605Smrg_mesa_init_shader_object_functions(struct dd_function_table *driver)
466848b8605Smrg{
467848b8605Smrg   driver->LinkShader = _mesa_ir_link_shader;
468848b8605Smrg}
469