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