mesa: add support for memory object creation/import/delete
[mesa.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 * 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
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
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 *
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
122 _mesa_delete_shader(struct gl_context *ctx, struct gl_shader *sh)
123 {
124 free((void *)sh->Source);
125 free((void *)sh->FallbackSource);
126 free(sh->Label);
127 ralloc_free(sh);
128 }
129
130
131 /**
132 * Delete a shader object.
133 */
134 void
135 _mesa_delete_linked_shader(struct gl_context *ctx,
136 struct gl_linked_shader *sh)
137 {
138 _mesa_reference_program(ctx, &sh->Program, NULL);
139 ralloc_free(sh);
140 }
141
142
143 /**
144 * Lookup a GLSL shader object.
145 */
146 struct gl_shader *
147 _mesa_lookup_shader(struct gl_context *ctx, GLuint name)
148 {
149 if (name) {
150 struct gl_shader *sh = (struct gl_shader *)
151 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
152 /* Note that both gl_shader and gl_shader_program objects are kept
153 * in the same hash table. Check the object's type to be sure it's
154 * what we're expecting.
155 */
156 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
157 return NULL;
158 }
159 return sh;
160 }
161 return NULL;
162 }
163
164
165 /**
166 * As above, but record an error if shader is not found.
167 */
168 struct gl_shader *
169 _mesa_lookup_shader_err(struct gl_context *ctx, GLuint name, const char *caller)
170 {
171 if (!name) {
172 _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
173 return NULL;
174 }
175 else {
176 struct gl_shader *sh = (struct gl_shader *)
177 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
178 if (!sh) {
179 _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
180 return NULL;
181 }
182 if (sh->Type == GL_SHADER_PROGRAM_MESA) {
183 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
184 return NULL;
185 }
186 return sh;
187 }
188 }
189
190
191
192 /**********************************************************************/
193 /*** Shader Program object functions ***/
194 /**********************************************************************/
195
196
197 void
198 _mesa_reference_shader_program_data(struct gl_context *ctx,
199 struct gl_shader_program_data **ptr,
200 struct gl_shader_program_data *data)
201 {
202 if (*ptr == data)
203 return;
204
205 if (*ptr) {
206 struct gl_shader_program_data *oldData = *ptr;
207
208 assert(oldData->RefCount > 0);
209
210 if (p_atomic_dec_zero(&oldData->RefCount)) {
211 assert(ctx);
212 ralloc_free(oldData);
213 }
214
215 *ptr = NULL;
216 }
217
218 if (data)
219 p_atomic_inc(&data->RefCount);
220
221 *ptr = data;
222 }
223
224 /**
225 * Set ptr to point to shProg.
226 * If ptr is pointing to another object, decrement its refcount (and delete
227 * if refcount hits zero).
228 * Then set ptr to point to shProg, incrementing its refcount.
229 */
230 void
231 _mesa_reference_shader_program_(struct gl_context *ctx,
232 struct gl_shader_program **ptr,
233 struct gl_shader_program *shProg)
234 {
235 assert(ptr);
236 if (*ptr == shProg) {
237 /* no-op */
238 return;
239 }
240 if (*ptr) {
241 /* Unreference the old shader program */
242 struct gl_shader_program *old = *ptr;
243
244 assert(old->RefCount > 0);
245
246 if (p_atomic_dec_zero(&old->RefCount)) {
247 if (old->Name != 0)
248 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
249 _mesa_delete_shader_program(ctx, old);
250 }
251
252 *ptr = NULL;
253 }
254 assert(!*ptr);
255
256 if (shProg) {
257 p_atomic_inc(&shProg->RefCount);
258 *ptr = shProg;
259 }
260 }
261
262 static struct gl_shader_program_data *
263 create_shader_program_data()
264 {
265 struct gl_shader_program_data *data;
266 data = rzalloc(NULL, struct gl_shader_program_data);
267 if (data)
268 data->RefCount = 1;
269
270 return data;
271 }
272
273 static void
274 init_shader_program(struct gl_shader_program *prog)
275 {
276 prog->Type = GL_SHADER_PROGRAM_MESA;
277 prog->RefCount = 1;
278
279 prog->AttributeBindings = string_to_uint_map_ctor();
280 prog->FragDataBindings = string_to_uint_map_ctor();
281 prog->FragDataIndexBindings = string_to_uint_map_ctor();
282
283 prog->Geom.UsesEndPrimitive = false;
284 prog->Geom.UsesStreams = false;
285
286 prog->TransformFeedback.BufferMode = GL_INTERLEAVED_ATTRIBS;
287
288 exec_list_make_empty(&prog->EmptyUniformLocations);
289
290 prog->data->InfoLog = ralloc_strdup(prog->data, "");
291 }
292
293 /**
294 * Allocate a new gl_shader_program object, initialize it.
295 */
296 struct gl_shader_program *
297 _mesa_new_shader_program(GLuint name)
298 {
299 struct gl_shader_program *shProg;
300 shProg = rzalloc(NULL, struct gl_shader_program);
301 if (shProg) {
302 shProg->Name = name;
303 shProg->data = create_shader_program_data();
304 if (!shProg->data) {
305 ralloc_free(shProg);
306 return NULL;
307 }
308 init_shader_program(shProg);
309 }
310 return shProg;
311 }
312
313
314 /**
315 * Clear (free) the shader program state that gets produced by linking.
316 */
317 void
318 _mesa_clear_shader_program_data(struct gl_context *ctx,
319 struct gl_shader_program *shProg)
320 {
321 for (gl_shader_stage sh = 0; sh < MESA_SHADER_STAGES; sh++) {
322 if (shProg->_LinkedShaders[sh] != NULL) {
323 _mesa_delete_linked_shader(ctx, shProg->_LinkedShaders[sh]);
324 shProg->_LinkedShaders[sh] = NULL;
325 }
326 }
327
328 shProg->data->linked_stages = 0;
329
330 if (shProg->data->UniformStorage && !shProg->data->cache_fallback) {
331 for (unsigned i = 0; i < shProg->data->NumUniformStorage; ++i)
332 _mesa_uniform_detach_all_driver_storage(&shProg->data->
333 UniformStorage[i]);
334 ralloc_free(shProg->data->UniformStorage);
335 shProg->data->NumUniformStorage = 0;
336 shProg->data->UniformStorage = NULL;
337 }
338
339 if (shProg->UniformRemapTable && !shProg->data->cache_fallback) {
340 ralloc_free(shProg->UniformRemapTable);
341 shProg->NumUniformRemapTable = 0;
342 shProg->UniformRemapTable = NULL;
343 }
344
345 if (shProg->UniformHash) {
346 string_to_uint_map_dtor(shProg->UniformHash);
347 shProg->UniformHash = NULL;
348 }
349
350 assert(shProg->data->InfoLog != NULL);
351 ralloc_free(shProg->data->InfoLog);
352 shProg->data->InfoLog = ralloc_strdup(shProg->data, "");
353
354 if (!shProg->data->cache_fallback) {
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
364 if (shProg->data->AtomicBuffers && !shProg->data->cache_fallback) {
365 ralloc_free(shProg->data->AtomicBuffers);
366 shProg->data->AtomicBuffers = NULL;
367 shProg->data->NumAtomicBuffers = 0;
368 }
369
370 if (shProg->data->ProgramResourceList) {
371 ralloc_free(shProg->data->ProgramResourceList);
372 shProg->data->ProgramResourceList = NULL;
373 shProg->data->NumProgramResourceList = 0;
374 }
375 }
376
377
378 /**
379 * Free all the data that hangs off a shader program object, but not the
380 * object itself.
381 */
382 void
383 _mesa_free_shader_program_data(struct gl_context *ctx,
384 struct gl_shader_program *shProg)
385 {
386 GLuint i;
387
388 assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
389
390 _mesa_clear_shader_program_data(ctx, shProg);
391
392 if (shProg->AttributeBindings) {
393 string_to_uint_map_dtor(shProg->AttributeBindings);
394 shProg->AttributeBindings = NULL;
395 }
396
397 if (shProg->FragDataBindings) {
398 string_to_uint_map_dtor(shProg->FragDataBindings);
399 shProg->FragDataBindings = NULL;
400 }
401
402 if (shProg->FragDataIndexBindings) {
403 string_to_uint_map_dtor(shProg->FragDataIndexBindings);
404 shProg->FragDataIndexBindings = NULL;
405 }
406
407 /* detach shaders */
408 for (i = 0; i < shProg->NumShaders; i++) {
409 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
410 }
411 shProg->NumShaders = 0;
412
413 free(shProg->Shaders);
414 shProg->Shaders = NULL;
415
416 /* Transform feedback varying vars */
417 for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) {
418 free(shProg->TransformFeedback.VaryingNames[i]);
419 }
420 free(shProg->TransformFeedback.VaryingNames);
421 shProg->TransformFeedback.VaryingNames = NULL;
422 shProg->TransformFeedback.NumVarying = 0;
423
424 free(shProg->Label);
425 shProg->Label = NULL;
426 }
427
428
429 /**
430 * Free/delete a shader program object.
431 */
432 void
433 _mesa_delete_shader_program(struct gl_context *ctx,
434 struct gl_shader_program *shProg)
435 {
436 _mesa_free_shader_program_data(ctx, shProg);
437 if (!shProg->data->cache_fallback)
438 _mesa_reference_shader_program_data(ctx, &shProg->data, NULL);
439 ralloc_free(shProg);
440 }
441
442
443 /**
444 * Lookup a GLSL program object.
445 */
446 struct gl_shader_program *
447 _mesa_lookup_shader_program(struct gl_context *ctx, GLuint name)
448 {
449 struct gl_shader_program *shProg;
450 if (name) {
451 shProg = (struct gl_shader_program *)
452 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
453 /* Note that both gl_shader and gl_shader_program objects are kept
454 * in the same hash table. Check the object's type to be sure it's
455 * what we're expecting.
456 */
457 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
458 return NULL;
459 }
460 return shProg;
461 }
462 return NULL;
463 }
464
465
466 /**
467 * As above, but record an error if program is not found.
468 */
469 struct gl_shader_program *
470 _mesa_lookup_shader_program_err(struct gl_context *ctx, GLuint name,
471 const char *caller)
472 {
473 if (!name) {
474 _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
475 return NULL;
476 }
477 else {
478 struct gl_shader_program *shProg = (struct gl_shader_program *)
479 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
480 if (!shProg) {
481 _mesa_error(ctx, GL_INVALID_VALUE, "%s", caller);
482 return NULL;
483 }
484 if (shProg->Type != GL_SHADER_PROGRAM_MESA) {
485 _mesa_error(ctx, GL_INVALID_OPERATION, "%s", caller);
486 return NULL;
487 }
488 return shProg;
489 }
490 }
491
492
493 void
494 _mesa_init_shader_object_functions(struct dd_function_table *driver)
495 {
496 driver->LinkShader = _mesa_ir_link_shader;
497 }