blob: c1fbcde61e45b593d83ca5fda5b65ebea1f5ea82 [file] [log] [blame]
Brian34ae99d2006-12-18 08:28:54 -07001/*
2 * Mesa 3-D graphics library
Brian3e4302f2007-05-09 08:04:32 -06003 * Version: 7.0
Brian34ae99d2006-12-18 08:28:54 -07004 *
Brian5b01c5e2006-12-19 18:02:03 -07005 * Copyright (C) 2004-2007 Brian Paul All Rights Reserved.
Brian34ae99d2006-12-18 08:28:54 -07006 *
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 shader_api.c
Brian5b01c5e2006-12-19 18:02:03 -070027 * Implementation of GLSL-related API functions
Brian34ae99d2006-12-18 08:28:54 -070028 * \author Brian Paul
29 */
30
31/**
32 * XXX things to do:
33 * 1. Check that the right error code is generated for all _mesa_error() calls.
Brian5b01c5e2006-12-19 18:02:03 -070034 * 2. Insert FLUSH_VERTICES calls in various places
Brian34ae99d2006-12-18 08:28:54 -070035 */
36
37
38#include "glheader.h"
39#include "context.h"
40#include "hash.h"
Brian274ac7a2007-04-18 16:05:53 -060041#include "macros.h"
Brian34ae99d2006-12-18 08:28:54 -070042#include "program.h"
43#include "prog_parameter.h"
Brian3209c3e2007-01-09 17:49:24 -070044#include "prog_print.h"
45#include "prog_statevars.h"
Brianbc029242008-04-04 18:59:21 -060046#include "prog_uniform.h"
Brianc223c6b2007-07-04 13:15:20 -060047#include "shader/shader_api.h"
48#include "shader/slang/slang_compile.h"
49#include "shader/slang/slang_link.h"
Brian34ae99d2006-12-18 08:28:54 -070050
51
52
Brianf2923612006-12-20 09:56:44 -070053/**
54 * Allocate a new gl_shader_program object, initialize it.
55 */
Brian2d2bb352007-12-07 17:11:30 -070056static struct gl_shader_program *
Brianf2923612006-12-20 09:56:44 -070057_mesa_new_shader_program(GLcontext *ctx, GLuint name)
58{
59 struct gl_shader_program *shProg;
60 shProg = CALLOC_STRUCT(gl_shader_program);
61 if (shProg) {
Brianf3e8c322007-04-18 14:53:23 -060062 shProg->Type = GL_SHADER_PROGRAM_MESA;
Brianf2923612006-12-20 09:56:44 -070063 shProg->Name = name;
64 shProg->RefCount = 1;
Brian3209c3e2007-01-09 17:49:24 -070065 shProg->Attributes = _mesa_new_parameter_list();
Brianf2923612006-12-20 09:56:44 -070066 }
67 return shProg;
68}
69
70
Brianb9fbedd2007-03-26 09:23:44 -060071/**
Brian3c008a02007-04-12 15:22:32 -060072 * Clear (free) the shader program state that gets produced by linking.
Brianb9fbedd2007-03-26 09:23:44 -060073 */
Brianf2923612006-12-20 09:56:44 -070074void
Brian3c008a02007-04-12 15:22:32 -060075_mesa_clear_shader_program_data(GLcontext *ctx,
76 struct gl_shader_program *shProg)
Brianf2923612006-12-20 09:56:44 -070077{
Brian Paul470f6992008-05-16 09:56:59 -060078 _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL);
79 _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL);
Brianf2923612006-12-20 09:56:44 -070080
Brianf2923612006-12-20 09:56:44 -070081 if (shProg->Uniforms) {
Brianbc029242008-04-04 18:59:21 -060082 _mesa_free_uniform_list(shProg->Uniforms);
Brianf2923612006-12-20 09:56:44 -070083 shProg->Uniforms = NULL;
84 }
85
86 if (shProg->Varying) {
87 _mesa_free_parameter_list(shProg->Varying);
88 shProg->Varying = NULL;
89 }
90}
91
92
Brianb9fbedd2007-03-26 09:23:44 -060093/**
Brian3c008a02007-04-12 15:22:32 -060094 * Free all the data that hangs off a shader program object, but not the
95 * object itself.
96 */
97void
98_mesa_free_shader_program_data(GLcontext *ctx,
99 struct gl_shader_program *shProg)
100{
101 GLuint i;
102
Brianf3e8c322007-04-18 14:53:23 -0600103 assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
Brian3c008a02007-04-12 15:22:32 -0600104
105 _mesa_clear_shader_program_data(ctx, shProg);
106
Brian4b7c6fc2007-04-19 15:23:34 -0600107 if (shProg->Attributes) {
108 _mesa_free_parameter_list(shProg->Attributes);
109 shProg->Attributes = NULL;
110 }
111
Brian3c008a02007-04-12 15:22:32 -0600112 /* detach shaders */
113 for (i = 0; i < shProg->NumShaders; i++) {
114 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
115 }
Brian Paul887bfee2008-05-14 16:44:08 -0600116 shProg->NumShaders = 0;
117
Brian3c008a02007-04-12 15:22:32 -0600118 if (shProg->Shaders) {
119 _mesa_free(shProg->Shaders);
120 shProg->Shaders = NULL;
121 }
Brian Paul887bfee2008-05-14 16:44:08 -0600122
123 if (shProg->InfoLog) {
124 _mesa_free(shProg->InfoLog);
125 shProg->InfoLog = NULL;
126 }
Brian3c008a02007-04-12 15:22:32 -0600127}
128
129
130/**
Brianb9fbedd2007-03-26 09:23:44 -0600131 * Free/delete a shader program object.
132 */
Brianf2923612006-12-20 09:56:44 -0700133void
134_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg)
135{
136 _mesa_free_shader_program_data(ctx, shProg);
Brian Paul887bfee2008-05-14 16:44:08 -0600137
Brianf2923612006-12-20 09:56:44 -0700138 _mesa_free(shProg);
139}
140
141
142/**
Brian3c008a02007-04-12 15:22:32 -0600143 * Set ptr to point to shProg.
144 * If ptr is pointing to another object, decrement its refcount (and delete
145 * if refcount hits zero).
146 * Then set ptr to point to shProg, incrementing its refcount.
147 */
148/* XXX this could be static */
149void
150_mesa_reference_shader_program(GLcontext *ctx,
151 struct gl_shader_program **ptr,
152 struct gl_shader_program *shProg)
153{
154 assert(ptr);
155 if (*ptr == shProg) {
156 /* no-op */
157 return;
158 }
159 if (*ptr) {
160 /* Unreference the old shader program */
161 GLboolean deleteFlag = GL_FALSE;
162 struct gl_shader_program *old = *ptr;
163
164 ASSERT(old->RefCount > 0);
165 old->RefCount--;
Brian Paul470f6992008-05-16 09:56:59 -0600166#if 0
167 printf("ShaderProgram %p ID=%u RefCount-- to %d\n",
168 (void *) old, old->Name, old->RefCount);
169#endif
Brian3c008a02007-04-12 15:22:32 -0600170 deleteFlag = (old->RefCount == 0);
171
172 if (deleteFlag) {
173 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
174 _mesa_free_shader_program(ctx, old);
175 }
176
177 *ptr = NULL;
178 }
179 assert(!*ptr);
180
181 if (shProg) {
182 shProg->RefCount++;
Brian Paul470f6992008-05-16 09:56:59 -0600183#if 0
184 printf("ShaderProgram %p ID=%u RefCount++ to %d\n",
185 (void *) shProg, shProg->Name, shProg->RefCount);
186#endif
Brian3c008a02007-04-12 15:22:32 -0600187 *ptr = shProg;
188 }
189}
190
191
192/**
Brianf2923612006-12-20 09:56:44 -0700193 * Lookup a GLSL program object.
194 */
195struct gl_shader_program *
196_mesa_lookup_shader_program(GLcontext *ctx, GLuint name)
197{
198 struct gl_shader_program *shProg;
199 if (name) {
200 shProg = (struct gl_shader_program *)
201 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
202 /* Note that both gl_shader and gl_shader_program objects are kept
203 * in the same hash table. Check the object's type to be sure it's
204 * what we're expecting.
205 */
Brianf3e8c322007-04-18 14:53:23 -0600206 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700207 return NULL;
208 }
209 return shProg;
210 }
211 return NULL;
212}
213
214
215/**
Brian Pauld4172262008-07-03 16:21:15 -0600216 * As above, but record an error if program is not found.
217 */
218static struct gl_shader_program *
219_mesa_lookup_shader_program_err(GLcontext *ctx, GLuint name,
220 const char *caller)
221{
222 if (!name) {
223 _mesa_error(ctx, GL_INVALID_VALUE, caller);
224 return NULL;
225 }
226 else {
227 struct gl_shader_program *shProg = (struct gl_shader_program *)
228 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
229 if (!shProg) {
230 _mesa_error(ctx, GL_INVALID_VALUE, caller);
231 return NULL;
232 }
233 if (shProg->Type != GL_SHADER_PROGRAM_MESA) {
234 _mesa_error(ctx, GL_INVALID_OPERATION, caller);
235 return NULL;
236 }
237 return shProg;
238 }
239}
240
241
242
243
244/**
Brianf2923612006-12-20 09:56:44 -0700245 * Allocate a new gl_shader object, initialize it.
246 */
247struct gl_shader *
248_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
249{
250 struct gl_shader *shader;
251 assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
252 shader = CALLOC_STRUCT(gl_shader);
253 if (shader) {
254 shader->Type = type;
255 shader->Name = name;
256 shader->RefCount = 1;
257 }
258 return shader;
259}
260
261
262void
263_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh)
264{
265 GLuint i;
266 if (sh->Source)
267 _mesa_free((void *) sh->Source);
268 if (sh->InfoLog)
269 _mesa_free(sh->InfoLog);
Brian Pauld7913862008-05-14 12:19:22 -0600270 for (i = 0; i < sh->NumPrograms; i++)
271 _mesa_reference_program(ctx, &sh->Programs[i], NULL);
Brianf2923612006-12-20 09:56:44 -0700272 if (sh->Programs)
273 _mesa_free(sh->Programs);
274 _mesa_free(sh);
275}
276
277
278/**
Brian3c008a02007-04-12 15:22:32 -0600279 * Set ptr to point to sh.
280 * If ptr is pointing to another shader, decrement its refcount (and delete
281 * if refcount hits zero).
282 * Then set ptr to point to sh, incrementing its refcount.
283 */
284/* XXX this could be static */
285void
286_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr,
287 struct gl_shader *sh)
288{
289 assert(ptr);
290 if (*ptr == sh) {
291 /* no-op */
292 return;
293 }
294 if (*ptr) {
295 /* Unreference the old shader */
296 GLboolean deleteFlag = GL_FALSE;
297 struct gl_shader *old = *ptr;
298
299 ASSERT(old->RefCount > 0);
300 old->RefCount--;
Brian99193e42007-04-12 15:45:02 -0600301 /*printf("SHADER DECR %p (%d) to %d\n",
302 (void*) old, old->Name, old->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600303 deleteFlag = (old->RefCount == 0);
304
305 if (deleteFlag) {
306 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
307 _mesa_free_shader(ctx, old);
308 }
309
310 *ptr = NULL;
311 }
312 assert(!*ptr);
313
314 if (sh) {
315 /* reference new */
316 sh->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600317 /*printf("SHADER INCR %p (%d) to %d\n",
318 (void*) sh, sh->Name, sh->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600319 *ptr = sh;
320 }
321}
322
323
324/**
Brianf2923612006-12-20 09:56:44 -0700325 * Lookup a GLSL shader object.
326 */
327struct gl_shader *
328_mesa_lookup_shader(GLcontext *ctx, GLuint name)
329{
330 if (name) {
331 struct gl_shader *sh = (struct gl_shader *)
332 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
333 /* Note that both gl_shader and gl_shader_program objects are kept
334 * in the same hash table. Check the object's type to be sure it's
335 * what we're expecting.
336 */
Brianf3e8c322007-04-18 14:53:23 -0600337 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700338 return NULL;
339 }
340 return sh;
341 }
342 return NULL;
343}
344
345
Brianfa4d0362007-02-26 18:33:50 -0700346/**
Brian Pauld4172262008-07-03 16:21:15 -0600347 * As above, but record an error if shader is not found.
348 */
349static struct gl_shader *
350_mesa_lookup_shader_err(GLcontext *ctx, GLuint name, const char *caller)
351{
352 if (!name) {
353 _mesa_error(ctx, GL_INVALID_VALUE, caller);
354 return NULL;
355 }
356 else {
357 struct gl_shader *sh = (struct gl_shader *)
358 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
359 if (!sh) {
360 _mesa_error(ctx, GL_INVALID_VALUE, caller);
361 return NULL;
362 }
363 if (sh->Type == GL_SHADER_PROGRAM_MESA) {
364 _mesa_error(ctx, GL_INVALID_OPERATION, caller);
365 return NULL;
366 }
367 return sh;
368 }
369}
370
371
372
373/**
Brianfa4d0362007-02-26 18:33:50 -0700374 * Initialize context's shader state.
375 */
Brianf2923612006-12-20 09:56:44 -0700376void
377_mesa_init_shader_state(GLcontext * ctx)
378{
Brianfa4d0362007-02-26 18:33:50 -0700379 /* Device drivers may override these to control what kind of instructions
380 * are generated by the GLSL compiler.
381 */
382 ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
michal4a470f62007-08-07 15:34:11 +0100383 ctx->Shader.EmitCondCodes = GL_FALSE;/*GL_TRUE;*/ /* XXX probably want GL_FALSE... */
Brianfa4d0362007-02-26 18:33:50 -0700384 ctx->Shader.EmitComments = GL_FALSE;
Brianf2923612006-12-20 09:56:44 -0700385}
386
387
Brian5b01c5e2006-12-19 18:02:03 -0700388/**
Brian935f93f2007-03-24 16:20:02 -0600389 * Free the per-context shader-related state.
390 */
391void
392_mesa_free_shader_state(GLcontext *ctx)
393{
Brian3c008a02007-04-12 15:22:32 -0600394 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
Brian935f93f2007-03-24 16:20:02 -0600395}
396
397
398/**
Brian5b01c5e2006-12-19 18:02:03 -0700399 * Copy string from <src> to <dst>, up to maxLength characters, returning
400 * length of <dst> in <length>.
401 * \param src the strings source
402 * \param maxLength max chars to copy
403 * \param length returns number of chars copied
404 * \param dst the string destination
405 */
406static void
407copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
408{
409 GLsizei len;
410 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
411 dst[len] = src[len];
412 if (maxLength > 0)
413 dst[len] = 0;
414 if (length)
415 *length = len;
416}
417
418
Brian Pauld4172262008-07-03 16:21:15 -0600419static GLboolean
420_mesa_is_program(GLcontext *ctx, GLuint name)
421{
422 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
423 return shProg ? GL_TRUE : GL_FALSE;
424}
425
426
427static GLboolean
428_mesa_is_shader(GLcontext *ctx, GLuint name)
429{
430 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
431 return shader ? GL_TRUE : GL_FALSE;
432}
433
434
Brian5b01c5e2006-12-19 18:02:03 -0700435/**
436 * Called via ctx->Driver.AttachShader()
437 */
Brian2d2bb352007-12-07 17:11:30 -0700438static void
Brian5b01c5e2006-12-19 18:02:03 -0700439_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
440{
Brian Pauld4172262008-07-03 16:21:15 -0600441 struct gl_shader_program *shProg;
442 struct gl_shader *sh;
443 GLuint i, n;
Brian5b01c5e2006-12-19 18:02:03 -0700444
Brian Pauld4172262008-07-03 16:21:15 -0600445 shProg = _mesa_lookup_shader_program_err(ctx, program, "glAttachShader");
446 if (!shProg)
447 return;
448
449 sh = _mesa_lookup_shader_err(ctx, shader, "glAttachShader");
450 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700451 return;
452 }
453
Brian Paulfc0a48d2008-05-16 15:48:11 -0600454 n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700455 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700456 if (shProg->Shaders[i] == sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700457 /* already attached */
458 return;
Brian34ae99d2006-12-18 08:28:54 -0700459 }
460 }
Brian5b01c5e2006-12-19 18:02:03 -0700461
462 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700463 shProg->Shaders = (struct gl_shader **)
464 _mesa_realloc(shProg->Shaders,
465 n * sizeof(struct gl_shader *),
466 (n + 1) * sizeof(struct gl_shader *));
467 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700468 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
469 return;
470 }
471
472 /* append */
Brian3c008a02007-04-12 15:22:32 -0600473 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
474 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700475 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700476}
477
478
Brian2d2bb352007-12-07 17:11:30 -0700479static GLint
480_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
481 const GLchar *name)
482{
483 struct gl_shader_program *shProg
Brian Pauld4172262008-07-03 16:21:15 -0600484 = _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
Brian2d2bb352007-12-07 17:11:30 -0700485
486 if (!shProg) {
Brian2d2bb352007-12-07 17:11:30 -0700487 return -1;
488 }
489
490 if (!shProg->LinkStatus) {
491 _mesa_error(ctx, GL_INVALID_OPERATION,
492 "glGetAttribLocation(program not linked)");
493 return -1;
494 }
495
496 if (!name)
497 return -1;
498
499 if (shProg->Attributes) {
500 GLint i = _mesa_lookup_parameter_index(shProg->Attributes, -1, name);
501 if (i >= 0) {
502 return shProg->Attributes->Parameters[i].StateIndexes[0];
503 }
504 }
505 return -1;
506}
507
508
509static void
Brian5b01c5e2006-12-19 18:02:03 -0700510_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
511 const GLchar *name)
512{
Brian Pauld4172262008-07-03 16:21:15 -0600513 struct gl_shader_program *shProg;
Brianb7978af2007-01-09 19:17:17 -0700514 const GLint size = -1; /* unknown size */
515 GLint i, oldIndex;
Brian5b01c5e2006-12-19 18:02:03 -0700516
Brian Pauld4172262008-07-03 16:21:15 -0600517 shProg = _mesa_lookup_shader_program_err(ctx, program,
518 "glBindAttribLocation");
Brian65a18442006-12-19 18:46:56 -0700519 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700520 return;
521 }
522
Brian9e4bae92006-12-20 09:27:42 -0700523 if (!name)
524 return;
525
526 if (strncmp(name, "gl_", 3) == 0) {
527 _mesa_error(ctx, GL_INVALID_OPERATION,
528 "glBindAttribLocation(illegal name)");
529 return;
530 }
531
Brian Pauld4172262008-07-03 16:21:15 -0600532 if (index >= ctx->Const.VertexProgram.MaxAttribs) {
533 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
534 return;
535 }
536
Brian9f660252007-04-11 09:00:56 -0600537 if (shProg->LinkStatus) {
538 /* get current index/location for the attribute */
539 oldIndex = _mesa_get_attrib_location(ctx, program, name);
540 }
541 else {
542 oldIndex = -1;
543 }
Brian3209c3e2007-01-09 17:49:24 -0700544
545 /* this will replace the current value if it's already in the list */
Brianb7978af2007-01-09 19:17:17 -0700546 i = _mesa_add_attribute(shProg->Attributes, name, size, index);
Brian3209c3e2007-01-09 17:49:24 -0700547 if (i < 0) {
548 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
549 }
550
Brian9f660252007-04-11 09:00:56 -0600551 if (shProg->VertexProgram && oldIndex >= 0 && oldIndex != index) {
552 /* If the index changed, need to search/replace references to that attribute
553 * in the vertex program.
554 */
Brian3209c3e2007-01-09 17:49:24 -0700555 _slang_remap_attribute(&shProg->VertexProgram->Base, oldIndex, index);
556 }
Brian34ae99d2006-12-18 08:28:54 -0700557}
558
559
Brian2d2bb352007-12-07 17:11:30 -0700560static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700561_mesa_create_shader(GLcontext *ctx, GLenum type)
562{
Brian65a18442006-12-19 18:46:56 -0700563 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700564 GLuint name;
565
566 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
567
568 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700569 case GL_FRAGMENT_SHADER:
570 case GL_VERTEX_SHADER:
571 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700572 break;
573 default:
574 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
575 return 0;
576 }
577
Brian65a18442006-12-19 18:46:56 -0700578 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700579
580 return name;
581}
582
583
Brian2d2bb352007-12-07 17:11:30 -0700584static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700585_mesa_create_program(GLcontext *ctx)
586{
587 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700588 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700589
Brian65a18442006-12-19 18:46:56 -0700590 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
591 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700592
Brian65a18442006-12-19 18:46:56 -0700593 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700594
Brian3c008a02007-04-12 15:22:32 -0600595 assert(shProg->RefCount == 1);
596
Brian5b01c5e2006-12-19 18:02:03 -0700597 return name;
598}
599
600
Brian3c008a02007-04-12 15:22:32 -0600601/**
602 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
603 * DeleteProgramARB.
604 */
Brian2d2bb352007-12-07 17:11:30 -0700605static void
Brian5b01c5e2006-12-19 18:02:03 -0700606_mesa_delete_program2(GLcontext *ctx, GLuint name)
607{
Brian3c008a02007-04-12 15:22:32 -0600608 /*
609 * NOTE: deleting shaders/programs works a bit differently than
610 * texture objects (and buffer objects, etc). Shader/program
611 * handles/IDs exist in the hash table until the object is really
612 * deleted (refcount==0). With texture objects, the handle/ID is
613 * removed from the hash table in glDeleteTextures() while the tex
614 * object itself might linger until its refcount goes to zero.
615 */
Brian65a18442006-12-19 18:46:56 -0700616 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700617
Brian Pauld4172262008-07-03 16:21:15 -0600618 shProg = _mesa_lookup_shader_program_err(ctx, name, "glDeleteProgram");
619 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700620 return;
Brian5b01c5e2006-12-19 18:02:03 -0700621
Brian9e4bae92006-12-20 09:27:42 -0700622 shProg->DeletePending = GL_TRUE;
623
Brian3c008a02007-04-12 15:22:32 -0600624 /* effectively, decr shProg's refcount */
625 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700626}
627
628
Brian2d2bb352007-12-07 17:11:30 -0700629static void
Brian5b01c5e2006-12-19 18:02:03 -0700630_mesa_delete_shader(GLcontext *ctx, GLuint shader)
631{
Brian Pauld4172262008-07-03 16:21:15 -0600632 struct gl_shader *sh;
633
634 sh = _mesa_lookup_shader_err(ctx, shader, "glDeleteShader");
635 if (!sh)
Brian9e4bae92006-12-20 09:27:42 -0700636 return;
Brian5b01c5e2006-12-19 18:02:03 -0700637
Brian9e4bae92006-12-20 09:27:42 -0700638 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600639
640 /* effectively, decr sh's refcount */
641 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700642}
643
644
Brian2d2bb352007-12-07 17:11:30 -0700645static void
Brian5b01c5e2006-12-19 18:02:03 -0700646_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
647{
Brian Pauld4172262008-07-03 16:21:15 -0600648 struct gl_shader_program *shProg;
Brian Paulfc0a48d2008-05-16 15:48:11 -0600649 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700650 GLuint i, j;
651
Brian Pauld4172262008-07-03 16:21:15 -0600652 shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader");
653 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700654 return;
Brian5b01c5e2006-12-19 18:02:03 -0700655
Brian Paulfc0a48d2008-05-16 15:48:11 -0600656 n = shProg->NumShaders;
657
Brian5b01c5e2006-12-19 18:02:03 -0700658 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700659 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700660 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600661 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700662
Brian Pauld4172262008-07-03 16:21:15 -0600663 /* release */
Brian3c008a02007-04-12 15:22:32 -0600664 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700665
Brian5b01c5e2006-12-19 18:02:03 -0700666 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700667 newList = (struct gl_shader **)
668 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700669 if (!newList) {
670 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
671 return;
672 }
673 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700674 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700675 }
676 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700677 newList[j++] = shProg->Shaders[i];
678 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700679
Brian65a18442006-12-19 18:46:56 -0700680 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600681 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600682
683#ifdef DEBUG
684 /* sanity check */
685 {
686 for (j = 0; j < shProg->NumShaders; j++) {
687 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
688 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
689 assert(shProg->Shaders[j]->RefCount > 0);
690 }
691 }
692#endif
693
Brian5b01c5e2006-12-19 18:02:03 -0700694 return;
695 }
696 }
697
698 /* not found */
Brian Pauld4172262008-07-03 16:21:15 -0600699 {
700 GLenum err;
701 if (_mesa_is_shader(ctx, shader))
702 err = GL_INVALID_OPERATION;
703 else if (_mesa_is_program(ctx, shader))
704 err = GL_INVALID_OPERATION;
705 else
706 err = GL_INVALID_VALUE;
707 _mesa_error(ctx, err, "glDetachProgram(shader)");
708 return;
709 }
Brian5b01c5e2006-12-19 18:02:03 -0700710}
711
712
Brian2d2bb352007-12-07 17:11:30 -0700713static void
Brian5b01c5e2006-12-19 18:02:03 -0700714_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
715 GLsizei maxLength, GLsizei *length, GLint *size,
716 GLenum *type, GLchar *nameOut)
717{
718 static const GLenum vec_types[] = {
719 GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4
720 };
Brian Pauld4172262008-07-03 16:21:15 -0600721 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700722 GLint sz;
723
Brian Pauld4172262008-07-03 16:21:15 -0600724 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
725 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700726 return;
Brian5b01c5e2006-12-19 18:02:03 -0700727
Brian65a18442006-12-19 18:46:56 -0700728 if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600729 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700730 return;
731 }
732
733 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700734 shProg->Attributes->Parameters[index].Name);
735 sz = shProg->Attributes->Parameters[index].Size;
Brian5b01c5e2006-12-19 18:02:03 -0700736 if (size)
737 *size = sz;
738 if (type)
739 *type = vec_types[sz]; /* XXX this is a temporary hack */
740}
741
742
743/**
744 * Called via ctx->Driver.GetActiveUniform().
745 */
Brian2d2bb352007-12-07 17:11:30 -0700746static void
Brian5b01c5e2006-12-19 18:02:03 -0700747_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
748 GLsizei maxLength, GLsizei *length, GLint *size,
749 GLenum *type, GLchar *nameOut)
750{
Brian Pauld4172262008-07-03 16:21:15 -0600751 const struct gl_shader_program *shProg;
Brianbc029242008-04-04 18:59:21 -0600752 const struct gl_program *prog;
753 GLint progPos;
Brian5b01c5e2006-12-19 18:02:03 -0700754
Brian Pauld4172262008-07-03 16:21:15 -0600755 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
756 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700757 return;
Brian5b01c5e2006-12-19 18:02:03 -0700758
Brianbc029242008-04-04 18:59:21 -0600759 if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
Brian5b01c5e2006-12-19 18:02:03 -0700760 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
761 return;
762 }
763
Brianbc029242008-04-04 18:59:21 -0600764 progPos = shProg->Uniforms->Uniforms[index].VertPos;
765 if (progPos >= 0) {
766 prog = &shProg->VertexProgram->Base;
767 }
768 else {
769 progPos = shProg->Uniforms->Uniforms[index].FragPos;
770 if (progPos >= 0) {
771 prog = &shProg->FragmentProgram->Base;
Brian274ac7a2007-04-18 16:05:53 -0600772 }
773 }
774
Brianbc029242008-04-04 18:59:21 -0600775 if (!prog || progPos < 0)
776 return; /* should never happen */
777
778 if (nameOut)
779 copy_string(nameOut, maxLength, length,
780 prog->Parameters->Parameters[progPos].Name);
781 if (size)
782 *size = prog->Parameters->Parameters[progPos].Size;
783
784 if (type)
785 *type = prog->Parameters->Parameters[progPos].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700786}
787
788
789/**
790 * Called via ctx->Driver.GetAttachedShaders().
791 */
Brian2d2bb352007-12-07 17:11:30 -0700792static void
Brian5b01c5e2006-12-19 18:02:03 -0700793_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
794 GLsizei *count, GLuint *obj)
795{
Brian Pauld4172262008-07-03 16:21:15 -0600796 struct gl_shader_program *shProg =
797 _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders");
Brian65a18442006-12-19 18:46:56 -0700798 if (shProg) {
José Fonseca53174af2008-05-31 18:14:09 +0900799 GLuint i;
Brian Pauld4172262008-07-03 16:21:15 -0600800 for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) {
Brian65a18442006-12-19 18:46:56 -0700801 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700802 }
803 if (count)
804 *count = i;
805 }
Brian5b01c5e2006-12-19 18:02:03 -0700806}
807
808
Brian2d2bb352007-12-07 17:11:30 -0700809static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700810_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700811{
812#if 0
813 GET_CURRENT_CONTEXT(ctx);
814
815 switch (pname) {
816 case GL_PROGRAM_OBJECT_ARB:
817 {
Brian5b01c5e2006-12-19 18:02:03 -0700818 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700819
820 if (pro != NULL)
821 return (**pro)._container._generic.
822 GetName((struct gl2_generic_intf **) (pro));
823 }
824 break;
825 default:
826 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
827 }
828#endif
829 return 0;
830}
831
832
Brian2d2bb352007-12-07 17:11:30 -0700833static void
Brian5b01c5e2006-12-19 18:02:03 -0700834_mesa_get_programiv(GLcontext *ctx, GLuint program,
835 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700836{
Brian65a18442006-12-19 18:46:56 -0700837 struct gl_shader_program *shProg
838 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700839
Brian65a18442006-12-19 18:46:56 -0700840 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700841 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700842 return;
843 }
844
Brian5b01c5e2006-12-19 18:02:03 -0700845 switch (pname) {
846 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700847 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700848 break;
849 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700850 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700851 break;
Brian5b01c5e2006-12-19 18:02:03 -0700852 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700853 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700854 break;
855 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600856 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700857 break;
858 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700859 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700860 break;
861 case GL_ACTIVE_ATTRIBUTES:
Brian3209c3e2007-01-09 17:49:24 -0700862 *params = shProg->Attributes ? shProg->Attributes->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700863 break;
864 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600865 *params = _mesa_longest_parameter_name(shProg->Attributes,
866 PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700867 break;
868 case GL_ACTIVE_UNIFORMS:
Brianbc029242008-04-04 18:59:21 -0600869 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700870 break;
871 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brianbc029242008-04-04 18:59:21 -0600872 *params = _mesa_longest_uniform_name(shProg->Uniforms);
Brian274ac7a2007-04-18 16:05:53 -0600873 if (*params > 0)
874 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700875 break;
876 default:
Brian5b01c5e2006-12-19 18:02:03 -0700877 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
878 return;
Brian34ae99d2006-12-18 08:28:54 -0700879 }
Brian5b01c5e2006-12-19 18:02:03 -0700880}
Brian34ae99d2006-12-18 08:28:54 -0700881
Brian34ae99d2006-12-18 08:28:54 -0700882
Brian2d2bb352007-12-07 17:11:30 -0700883static void
Brian5b01c5e2006-12-19 18:02:03 -0700884_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
885{
Brian Pauld4172262008-07-03 16:21:15 -0600886 struct gl_shader *shader = _mesa_lookup_shader_err(ctx, name, "glGetShaderiv");
Brian5b01c5e2006-12-19 18:02:03 -0700887
888 if (!shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700889 return;
890 }
Brian65a18442006-12-19 18:46:56 -0700891
Brian5b01c5e2006-12-19 18:02:03 -0700892 switch (pname) {
893 case GL_SHADER_TYPE:
894 *params = shader->Type;
895 break;
896 case GL_DELETE_STATUS:
897 *params = shader->DeletePending;
898 break;
899 case GL_COMPILE_STATUS:
900 *params = shader->CompileStatus;
901 break;
902 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600903 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700904 break;
905 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600906 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700907 break;
908 default:
909 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
910 return;
911 }
912}
913
914
Brian2d2bb352007-12-07 17:11:30 -0700915static void
Brian5b01c5e2006-12-19 18:02:03 -0700916_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
917 GLsizei *length, GLchar *infoLog)
918{
Brian65a18442006-12-19 18:46:56 -0700919 struct gl_shader_program *shProg
920 = _mesa_lookup_shader_program(ctx, program);
921 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700922 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
923 return;
924 }
Brian65a18442006-12-19 18:46:56 -0700925 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700926}
927
928
Brian2d2bb352007-12-07 17:11:30 -0700929static void
Brian5b01c5e2006-12-19 18:02:03 -0700930_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
931 GLsizei *length, GLchar *infoLog)
932{
Brian65a18442006-12-19 18:46:56 -0700933 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
934 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700935 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
936 return;
937 }
Brian65a18442006-12-19 18:46:56 -0700938 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700939}
940
941
942/**
943 * Called via ctx->Driver.GetShaderSource().
944 */
Brian2d2bb352007-12-07 17:11:30 -0700945static void
Brian5b01c5e2006-12-19 18:02:03 -0700946_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
947 GLsizei *length, GLchar *sourceOut)
948{
Brian Pauld4172262008-07-03 16:21:15 -0600949 struct gl_shader *sh;
950 sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource");
Brian65a18442006-12-19 18:46:56 -0700951 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700952 return;
953 }
Brian65a18442006-12-19 18:46:56 -0700954 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -0700955}
956
957
Brian Paul072c4742008-07-08 16:12:01 -0600958#define MAX_UNIFORM_ELEMENTS 16
959
Brian5b01c5e2006-12-19 18:02:03 -0700960/**
Brian Paul072c4742008-07-08 16:12:01 -0600961 * Helper for GetUniformfv(), GetUniformiv()
962 * Returns number of elements written to 'params' output.
Brian5b01c5e2006-12-19 18:02:03 -0700963 */
Brian Paul072c4742008-07-08 16:12:01 -0600964static GLuint
965get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
966 GLfloat *params)
Brian5b01c5e2006-12-19 18:02:03 -0700967{
Brian65a18442006-12-19 18:46:56 -0700968 struct gl_shader_program *shProg
969 = _mesa_lookup_shader_program(ctx, program);
970 if (shProg) {
Brian Paul22427692008-06-28 16:47:22 -0600971 if (shProg->Uniforms &&
972 location >= 0 && location < shProg->Uniforms->NumUniforms) {
973 GLint progPos;
974 GLuint i;
Brian Paulfc0a48d2008-05-16 15:48:11 -0600975 const struct gl_program *prog = NULL;
Brianbc029242008-04-04 18:59:21 -0600976
977 progPos = shProg->Uniforms->Uniforms[location].VertPos;
978 if (progPos >= 0) {
979 prog = &shProg->VertexProgram->Base;
980 }
981 else {
982 progPos = shProg->Uniforms->Uniforms[location].FragPos;
983 if (progPos >= 0) {
984 prog = &shProg->FragmentProgram->Base;
985 }
986 }
987
Brian Paulfc0a48d2008-05-16 15:48:11 -0600988 ASSERT(prog);
989 if (prog) {
Brian Paul072c4742008-07-08 16:12:01 -0600990 /* See uniformiv() below */
991 assert(prog->Parameters->Parameters[progPos].Size <= MAX_UNIFORM_ELEMENTS);
992
Brian Paulfc0a48d2008-05-16 15:48:11 -0600993 for (i = 0; i < prog->Parameters->Parameters[progPos].Size; i++) {
994 params[i] = prog->Parameters->ParameterValues[progPos][i];
995 }
Brian Paul072c4742008-07-08 16:12:01 -0600996 return prog->Parameters->Parameters[progPos].Size;
Brian5b01c5e2006-12-19 18:02:03 -0700997 }
998 }
999 else {
Brian Paul22427692008-06-28 16:47:22 -06001000 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
Brian5b01c5e2006-12-19 18:02:03 -07001001 }
1002 }
1003 else {
Brian Paul22427692008-06-28 16:47:22 -06001004 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
Brian5b01c5e2006-12-19 18:02:03 -07001005 }
Brian Paul072c4742008-07-08 16:12:01 -06001006 return 0;
1007}
1008
1009
1010/**
1011 * Called via ctx->Driver.GetUniformfv().
1012 */
1013static void
1014_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1015 GLfloat *params)
1016{
1017 (void) get_uniformfv(ctx, program, location, params);
1018}
1019
1020
1021/**
1022 * Called via ctx->Driver.GetUniformiv().
1023 */
1024static void
1025_mesa_get_uniformiv(GLcontext *ctx, GLuint program, GLint location,
1026 GLint *params)
1027{
1028 GLfloat fparams[MAX_UNIFORM_ELEMENTS];
1029 GLuint n = get_uniformfv(ctx, program, location, fparams);
1030 GLuint i;
1031 assert(n <= MAX_UNIFORM_ELEMENTS);
1032 for (i = 0; i < n; i++) {
1033 params[i] = (GLint) fparams[i];
1034 }
Brian5b01c5e2006-12-19 18:02:03 -07001035}
1036
1037
1038/**
1039 * Called via ctx->Driver.GetUniformLocation().
1040 */
Brian2d2bb352007-12-07 17:11:30 -07001041static GLint
Brian5b01c5e2006-12-19 18:02:03 -07001042_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
1043{
Brian Pauld4172262008-07-03 16:21:15 -06001044 struct gl_shader_program *shProg =
1045 _mesa_lookup_shader_program_err(ctx, program, "glGetUniformLocation");
1046
Brianbc029242008-04-04 18:59:21 -06001047 if (!shProg)
1048 return -1;
Brian5b01c5e2006-12-19 18:02:03 -07001049
Brian Paul294b0612008-07-04 09:58:14 -06001050 if (shProg->LinkStatus == GL_FALSE) {
1051 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
1052 return -1;
1053 }
1054
Brian Pauld4172262008-07-03 16:21:15 -06001055 /* XXX we should return -1 if the uniform was declared, but not
1056 * actually used.
1057 */
1058
Brianbc029242008-04-04 18:59:21 -06001059 return _mesa_lookup_uniform(shProg->Uniforms, name);
Brian5b01c5e2006-12-19 18:02:03 -07001060}
1061
1062
Brian34ae99d2006-12-18 08:28:54 -07001063
Brian5b01c5e2006-12-19 18:02:03 -07001064/**
1065 * Called via ctx->Driver.ShaderSource()
1066 */
Brian2d2bb352007-12-07 17:11:30 -07001067static void
Brian5b01c5e2006-12-19 18:02:03 -07001068_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -07001069{
Brian Pauld4172262008-07-03 16:21:15 -06001070 struct gl_shader *sh;
1071
1072 sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource");
1073 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001074 return;
Brian34ae99d2006-12-18 08:28:54 -07001075
Brian34ae99d2006-12-18 08:28:54 -07001076 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -07001077 if (sh->Source) {
1078 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -07001079 }
Brian65a18442006-12-19 18:46:56 -07001080 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -07001081 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -07001082}
1083
1084
Brian5b01c5e2006-12-19 18:02:03 -07001085/**
1086 * Called via ctx->Driver.CompileShader()
1087 */
Brian2d2bb352007-12-07 17:11:30 -07001088static void
Brian5b01c5e2006-12-19 18:02:03 -07001089_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -07001090{
Brian Pauld4172262008-07-03 16:21:15 -06001091 struct gl_shader *sh;
Brian34ae99d2006-12-18 08:28:54 -07001092
Brian Pauld4172262008-07-03 16:21:15 -06001093 sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader");
1094 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001095 return;
Brian34ae99d2006-12-18 08:28:54 -07001096
Brian43975832007-01-04 08:21:09 -07001097 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -07001098}
1099
1100
Brian5b01c5e2006-12-19 18:02:03 -07001101/**
1102 * Called via ctx->Driver.LinkProgram()
1103 */
Brian2d2bb352007-12-07 17:11:30 -07001104static void
Brian5b01c5e2006-12-19 18:02:03 -07001105_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001106{
Brian65a18442006-12-19 18:46:56 -07001107 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001108
Brian Pauld4172262008-07-03 16:21:15 -06001109 shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
1110 if (!shProg)
Brian34ae99d2006-12-18 08:28:54 -07001111 return;
Brian34ae99d2006-12-18 08:28:54 -07001112
Brian Paulfc0a48d2008-05-16 15:48:11 -06001113 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1114
Brianc1771912007-02-16 09:56:19 -07001115 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001116}
1117
1118
1119/**
Brian5b01c5e2006-12-19 18:02:03 -07001120 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001121 */
Brian5b01c5e2006-12-19 18:02:03 -07001122void
1123_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001124{
Brian3c008a02007-04-12 15:22:32 -06001125 struct gl_shader_program *shProg;
1126
Brian00d63aa2007-02-03 11:35:02 -07001127 if (ctx->Shader.CurrentProgram &&
1128 ctx->Shader.CurrentProgram->Name == program) {
1129 /* no-op */
1130 return;
1131 }
1132
1133 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1134
Brian5b01c5e2006-12-19 18:02:03 -07001135 if (program) {
Brian Pauld4172262008-07-03 16:21:15 -06001136 shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
Brian65a18442006-12-19 18:46:56 -07001137 if (!shProg) {
Brian Pauld4172262008-07-03 16:21:15 -06001138 return;
1139 }
1140 if (!shProg->LinkStatus) {
1141 _mesa_error(ctx, GL_INVALID_OPERATION, "glUseProgram");
Brian5b01c5e2006-12-19 18:02:03 -07001142 return;
1143 }
Brian5b01c5e2006-12-19 18:02:03 -07001144 }
1145 else {
Brian3c008a02007-04-12 15:22:32 -06001146 shProg = NULL;
1147 }
1148
1149 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001150}
Brian34ae99d2006-12-18 08:28:54 -07001151
Brian5b01c5e2006-12-19 18:02:03 -07001152
Brian8fed2462007-10-26 19:19:09 -06001153
1154/**
1155 * Update the vertex and fragment program's TexturesUsed arrays.
1156 */
1157static void
1158update_textures_used(struct gl_program *prog)
1159{
1160 GLuint s;
1161
1162 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1163
1164 for (s = 0; s < MAX_SAMPLERS; s++) {
1165 if (prog->SamplersUsed & (1 << s)) {
1166 GLuint u = prog->SamplerUnits[s];
1167 GLuint t = prog->SamplerTargets[s];
1168 assert(u < MAX_TEXTURE_IMAGE_UNITS);
1169 prog->TexturesUsed[u] |= (1 << t);
1170 }
1171 }
1172}
1173
1174
Brian5b01c5e2006-12-19 18:02:03 -07001175/**
Brianbc029242008-04-04 18:59:21 -06001176 * Set the value of a program's uniform variable.
1177 * \param program the program whose uniform to update
1178 * \param location the location/index of the uniform
1179 * \param type the datatype of the uniform
1180 * \param count the number of uniforms to set
1181 * \param elems number of elements per uniform
1182 * \param values the new values
1183 */
1184static void
1185set_program_uniform(GLcontext *ctx, struct gl_program *program, GLint location,
José Fonseca18ec1402008-06-24 11:34:46 +09001186 GLenum type, GLsizei count, GLint elems, const void *values)
Brianbc029242008-04-04 18:59:21 -06001187{
1188 if (program->Parameters->Parameters[location].Type == PROGRAM_SAMPLER) {
1189 /* This controls which texture unit which is used by a sampler */
1190 GLuint texUnit, sampler;
1191
1192 /* data type for setting samplers must be int */
1193 if (type != GL_INT || count != 1) {
1194 _mesa_error(ctx, GL_INVALID_OPERATION,
1195 "glUniform(only glUniform1i can be used "
1196 "to set sampler uniforms)");
1197 return;
1198 }
1199
1200 sampler = (GLuint) program->Parameters->ParameterValues[location][0];
1201 texUnit = ((GLuint *) values)[0];
1202
1203 /* check that the sampler (tex unit index) is legal */
1204 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1205 _mesa_error(ctx, GL_INVALID_VALUE,
1206 "glUniform1(invalid sampler/tex unit index)");
1207 return;
1208 }
1209
1210 /* This maps a sampler to a texture unit: */
1211 program->SamplerUnits[sampler] = texUnit;
1212 update_textures_used(program);
1213
1214 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1215 }
1216 else {
1217 /* ordinary uniform variable */
José Fonseca18ec1402008-06-24 11:34:46 +09001218 GLsizei k, i;
Brianbc029242008-04-04 18:59:21 -06001219
1220 if (count * elems > program->Parameters->Parameters[location].Size) {
1221 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1222 return;
1223 }
1224
1225 for (k = 0; k < count; k++) {
1226 GLfloat *uniformVal = program->Parameters->ParameterValues[location + k];
1227 if (type == GL_INT ||
1228 type == GL_INT_VEC2 ||
1229 type == GL_INT_VEC3 ||
1230 type == GL_INT_VEC4) {
1231 const GLint *iValues = ((const GLint *) values) + k * elems;
1232 for (i = 0; i < elems; i++) {
1233 uniformVal[i] = (GLfloat) iValues[i];
1234 }
1235 }
1236 else {
1237 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1238 for (i = 0; i < elems; i++) {
1239 uniformVal[i] = fValues[i];
1240 }
1241 }
1242 }
1243 }
1244}
1245
1246
1247/**
Brian5b01c5e2006-12-19 18:02:03 -07001248 * Called via ctx->Driver.Uniform().
1249 */
Brian2d2bb352007-12-07 17:11:30 -07001250static void
Brian5b01c5e2006-12-19 18:02:03 -07001251_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1252 const GLvoid *values, GLenum type)
1253{
Brian3a8e2772006-12-20 17:19:16 -07001254 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brianbc029242008-04-04 18:59:21 -06001255 GLint elems;
Brian3a8e2772006-12-20 17:19:16 -07001256
1257 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001258 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001259 return;
1260 }
1261
Brian Paulf84005c2008-05-14 16:01:31 -06001262 if (location == -1)
1263 return; /* The standard specifies this as a no-op */
1264
Brianbc029242008-04-04 18:59:21 -06001265 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian3a8e2772006-12-20 17:19:16 -07001266 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
1267 return;
1268 }
1269
Brian52363952007-03-13 16:50:24 -06001270 if (count < 0) {
1271 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1272 return;
1273 }
1274
Brian98650bd2007-03-13 16:32:48 -06001275 switch (type) {
1276 case GL_FLOAT:
1277 case GL_INT:
1278 elems = 1;
1279 break;
1280 case GL_FLOAT_VEC2:
1281 case GL_INT_VEC2:
1282 elems = 2;
1283 break;
1284 case GL_FLOAT_VEC3:
1285 case GL_INT_VEC3:
1286 elems = 3;
1287 break;
1288 case GL_FLOAT_VEC4:
1289 case GL_INT_VEC4:
1290 elems = 4;
1291 break;
1292 default:
1293 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1294 return;
Brian89dc4852007-01-04 14:35:44 -07001295 }
Brian98650bd2007-03-13 16:32:48 -06001296
Brianbc029242008-04-04 18:59:21 -06001297 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1298
1299 /* A uniform var may be used by both a vertex shader and a fragment
1300 * shader. We may need to update one or both shader's uniform here:
1301 */
1302 if (shProg->VertexProgram) {
1303 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1304 if (loc >= 0) {
1305 set_program_uniform(ctx, &shProg->VertexProgram->Base,
1306 loc, type, count, elems, values);
1307 }
Brian98650bd2007-03-13 16:32:48 -06001308 }
1309
Brianbc029242008-04-04 18:59:21 -06001310 if (shProg->FragmentProgram) {
1311 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1312 if (loc >= 0) {
1313 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
1314 loc, type, count, elems, values);
Brian8fed2462007-10-26 19:19:09 -06001315 }
Brianbc029242008-04-04 18:59:21 -06001316 }
1317}
Brian8fed2462007-10-26 19:19:09 -06001318
Brian8fed2462007-10-26 19:19:09 -06001319
Brianbc029242008-04-04 18:59:21 -06001320static void
1321set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
1322 GLuint location, GLuint rows, GLuint cols,
1323 GLboolean transpose, const GLfloat *values)
1324{
1325 /*
1326 * Note: the _columns_ of a matrix are stored in program registers, not
1327 * the rows.
1328 */
1329 /* XXXX need to test 3x3 and 2x2 matrices... */
1330 if (transpose) {
1331 GLuint row, col;
1332 for (col = 0; col < cols; col++) {
1333 GLfloat *v = program->Parameters->ParameterValues[location + col];
1334 for (row = 0; row < rows; row++) {
1335 v[row] = values[row * cols + col];
1336 }
Brian8fed2462007-10-26 19:19:09 -06001337 }
Brian5cf73262007-01-05 16:02:45 -07001338 }
Brian8fed2462007-10-26 19:19:09 -06001339 else {
Brianbc029242008-04-04 18:59:21 -06001340 GLuint row, col;
1341 for (col = 0; col < cols; col++) {
1342 GLfloat *v = program->Parameters->ParameterValues[location + col];
1343 for (row = 0; row < rows; row++) {
1344 v[row] = values[col * rows + row];
Brian8fed2462007-10-26 19:19:09 -06001345 }
1346 }
1347 }
Brian34ae99d2006-12-18 08:28:54 -07001348}
1349
1350
1351/**
Brian5b01c5e2006-12-19 18:02:03 -07001352 * Called by ctx->Driver.UniformMatrix().
Brian34ae99d2006-12-18 08:28:54 -07001353 */
Brian2d2bb352007-12-07 17:11:30 -07001354static void
Brian5b01c5e2006-12-19 18:02:03 -07001355_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1356 GLenum matrixType, GLint location, GLsizei count,
1357 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001358{
Brian3a8e2772006-12-20 17:19:16 -07001359 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paulf84005c2008-05-14 16:01:31 -06001360
Brian3a8e2772006-12-20 17:19:16 -07001361 if (!shProg || !shProg->LinkStatus) {
1362 _mesa_error(ctx, GL_INVALID_OPERATION,
1363 "glUniformMatrix(program not linked)");
1364 return;
1365 }
Brian Paulf84005c2008-05-14 16:01:31 -06001366
1367 if (location == -1)
1368 return; /* The standard specifies this as a no-op */
1369
Brianbc029242008-04-04 18:59:21 -06001370 if (location < 0 || location >= shProg->Uniforms->NumUniforms) {
Brian3a8e2772006-12-20 17:19:16 -07001371 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
1372 return;
1373 }
Brian34ae99d2006-12-18 08:28:54 -07001374 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001375 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001376 return;
1377 }
1378
1379 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1380
Brianbc029242008-04-04 18:59:21 -06001381 if (shProg->VertexProgram) {
1382 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1383 if (loc >= 0) {
1384 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
1385 loc, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07001386 }
Brian34ae99d2006-12-18 08:28:54 -07001387 }
Brianbc029242008-04-04 18:59:21 -06001388
1389 if (shProg->FragmentProgram) {
1390 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1391 if (loc >= 0) {
1392 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
1393 loc, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07001394 }
Brian34ae99d2006-12-18 08:28:54 -07001395 }
1396}
1397
1398
Brian2d2bb352007-12-07 17:11:30 -07001399static void
Brian5b01c5e2006-12-19 18:02:03 -07001400_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001401{
Brian65a18442006-12-19 18:46:56 -07001402 struct gl_shader_program *shProg;
1403 shProg = _mesa_lookup_shader_program(ctx, program);
1404 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001405 _mesa_error(ctx, GL_INVALID_VALUE, "glValidateProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001406 return;
1407 }
Brian5b01c5e2006-12-19 18:02:03 -07001408 /* XXX temporary */
Brian65a18442006-12-19 18:46:56 -07001409 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001410
Brian5b01c5e2006-12-19 18:02:03 -07001411 /* From the GL spec:
1412 any two active samplers in the current program object are of
1413 different types, but refer to the same texture image unit,
1414
1415 any active sampler in the current program object refers to a texture
1416 image unit where fixed-function fragment processing accesses a
1417 texture target that does not match the sampler type, or
1418
1419 the sum of the number of active samplers in the program and the
1420 number of texture image units enabled for fixed-function fragment
1421 processing exceeds the combined limit on the total number of texture
1422 image units allowed.
1423 */
Brian34ae99d2006-12-18 08:28:54 -07001424}
Brian2d2bb352007-12-07 17:11:30 -07001425
1426
1427/**
1428 * Plug in Mesa's GLSL functions into the device driver function table.
1429 */
1430void
1431_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
1432{
1433 driver->AttachShader = _mesa_attach_shader;
1434 driver->BindAttribLocation = _mesa_bind_attrib_location;
1435 driver->CompileShader = _mesa_compile_shader;
1436 driver->CreateProgram = _mesa_create_program;
1437 driver->CreateShader = _mesa_create_shader;
1438 driver->DeleteProgram2 = _mesa_delete_program2;
1439 driver->DeleteShader = _mesa_delete_shader;
1440 driver->DetachShader = _mesa_detach_shader;
1441 driver->GetActiveAttrib = _mesa_get_active_attrib;
1442 driver->GetActiveUniform = _mesa_get_active_uniform;
1443 driver->GetAttachedShaders = _mesa_get_attached_shaders;
1444 driver->GetAttribLocation = _mesa_get_attrib_location;
1445 driver->GetHandle = _mesa_get_handle;
1446 driver->GetProgramiv = _mesa_get_programiv;
1447 driver->GetProgramInfoLog = _mesa_get_program_info_log;
1448 driver->GetShaderiv = _mesa_get_shaderiv;
1449 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
1450 driver->GetShaderSource = _mesa_get_shader_source;
1451 driver->GetUniformfv = _mesa_get_uniformfv;
Brian Paul072c4742008-07-08 16:12:01 -06001452 driver->GetUniformiv = _mesa_get_uniformiv;
Brian2d2bb352007-12-07 17:11:30 -07001453 driver->GetUniformLocation = _mesa_get_uniform_location;
1454 driver->IsProgram = _mesa_is_program;
1455 driver->IsShader = _mesa_is_shader;
1456 driver->LinkProgram = _mesa_link_program;
1457 driver->ShaderSource = _mesa_shader_source;
1458 driver->Uniform = _mesa_uniform;
1459 driver->UniformMatrix = _mesa_uniform_matrix;
1460 driver->UseProgram = _mesa_use_program;
1461 driver->ValidateProgram = _mesa_validate_program;
1462}