blob: 1e282e7373a4a2fd34d27e606b699f44610f9cde [file] [log] [blame]
Brian34ae99d2006-12-18 08:28:54 -07001/*
2 * Mesa 3-D graphics library
Brian5b01c5e2006-12-19 18:02:03 -07003 * Version: 6.5.3
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"
Brian34ae99d2006-12-18 08:28:54 -070041#include "program.h"
42#include "prog_parameter.h"
Brian34ae99d2006-12-18 08:28:54 -070043#include "shader_api.h"
44
45#include "slang_compile.h"
46#include "slang_link.h"
47
48
49
Brianf2923612006-12-20 09:56:44 -070050/**
51 * Allocate a new gl_shader_program object, initialize it.
52 */
53struct gl_shader_program *
54_mesa_new_shader_program(GLcontext *ctx, GLuint name)
55{
56 struct gl_shader_program *shProg;
57 shProg = CALLOC_STRUCT(gl_shader_program);
58 if (shProg) {
59 shProg->Type = GL_SHADER_PROGRAM;
60 shProg->Name = name;
61 shProg->RefCount = 1;
62 }
63 return shProg;
64}
65
66
67void
68_mesa_free_shader_program_data(GLcontext *ctx,
69 struct gl_shader_program *shProg)
70{
71 assert(shProg->Type == GL_SHADER_PROGRAM);
72
73 if (shProg->VertexProgram) {
74 if (shProg->VertexProgram->Base.Parameters == shProg->Uniforms) {
75 /* to prevent a double-free in the next call */
76 shProg->VertexProgram->Base.Parameters = NULL;
77 }
78 _mesa_delete_program(ctx, &shProg->VertexProgram->Base);
79 shProg->VertexProgram = NULL;
80 }
81
82 if (shProg->FragmentProgram) {
83 if (shProg->FragmentProgram->Base.Parameters == shProg->Uniforms) {
84 /* to prevent a double-free in the next call */
85 shProg->FragmentProgram->Base.Parameters = NULL;
86 }
87 _mesa_delete_program(ctx, &shProg->FragmentProgram->Base);
88 shProg->FragmentProgram = NULL;
89 }
90
91
92 if (shProg->Uniforms) {
93 _mesa_free_parameter_list(shProg->Uniforms);
94 shProg->Uniforms = NULL;
95 }
96
97 if (shProg->Varying) {
98 _mesa_free_parameter_list(shProg->Varying);
99 shProg->Varying = NULL;
100 }
101}
102
103
104
105void
106_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg)
107{
108 _mesa_free_shader_program_data(ctx, shProg);
109 _mesa_free(shProg);
110}
111
112
113/**
114 * Lookup a GLSL program object.
115 */
116struct gl_shader_program *
117_mesa_lookup_shader_program(GLcontext *ctx, GLuint name)
118{
119 struct gl_shader_program *shProg;
120 if (name) {
121 shProg = (struct gl_shader_program *)
122 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
123 /* Note that both gl_shader and gl_shader_program objects are kept
124 * in the same hash table. Check the object's type to be sure it's
125 * what we're expecting.
126 */
127 if (shProg && shProg->Type != GL_SHADER_PROGRAM) {
128 return NULL;
129 }
130 return shProg;
131 }
132 return NULL;
133}
134
135
136/**
137 * Allocate a new gl_shader object, initialize it.
138 */
139struct gl_shader *
140_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
141{
142 struct gl_shader *shader;
143 assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
144 shader = CALLOC_STRUCT(gl_shader);
145 if (shader) {
146 shader->Type = type;
147 shader->Name = name;
148 shader->RefCount = 1;
149 }
150 return shader;
151}
152
153
154void
155_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh)
156{
157 GLuint i;
158 if (sh->Source)
159 _mesa_free((void *) sh->Source);
160 if (sh->InfoLog)
161 _mesa_free(sh->InfoLog);
162 for (i = 0; i < sh->NumPrograms; i++) {
163 assert(sh->Programs[i]);
164 _mesa_delete_program(ctx, sh->Programs[i]);
165 }
166 if (sh->Programs)
167 _mesa_free(sh->Programs);
168 _mesa_free(sh);
169}
170
171
172/**
173 * Lookup a GLSL shader object.
174 */
175struct gl_shader *
176_mesa_lookup_shader(GLcontext *ctx, GLuint name)
177{
178 if (name) {
179 struct gl_shader *sh = (struct gl_shader *)
180 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
181 /* Note that both gl_shader and gl_shader_program objects are kept
182 * in the same hash table. Check the object's type to be sure it's
183 * what we're expecting.
184 */
185 if (sh && sh->Type == GL_SHADER_PROGRAM) {
186 assert(sh->Type == GL_VERTEX_SHADER ||
187 sh->Type == GL_FRAGMENT_SHADER);
188 return NULL;
189 }
190 return sh;
191 }
192 return NULL;
193}
194
195
196void
197_mesa_init_shader_state(GLcontext * ctx)
198{
199 ctx->Shader._FragmentShaderPresent = GL_FALSE;
200 ctx->Shader._VertexShaderPresent = GL_FALSE;
201}
202
203
204
Brian34ae99d2006-12-18 08:28:54 -0700205
Brian5b01c5e2006-12-19 18:02:03 -0700206
207/**
208 * Copy string from <src> to <dst>, up to maxLength characters, returning
209 * length of <dst> in <length>.
210 * \param src the strings source
211 * \param maxLength max chars to copy
212 * \param length returns number of chars copied
213 * \param dst the string destination
214 */
215static void
216copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
217{
218 GLsizei len;
219 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
220 dst[len] = src[len];
221 if (maxLength > 0)
222 dst[len] = 0;
223 if (length)
224 *length = len;
225}
226
227
228
229
230/**
231 * Called via ctx->Driver.AttachShader()
232 */
233void
234_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
235{
Brian65a18442006-12-19 18:46:56 -0700236 struct gl_shader_program *shProg
237 = _mesa_lookup_shader_program(ctx, program);
238 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
239 const GLuint n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700240 GLuint i;
241
Brian65a18442006-12-19 18:46:56 -0700242 if (!shProg || !sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700243 _mesa_error(ctx, GL_INVALID_OPERATION,
244 "glAttachShader(bad program or shader name)");
245 return;
246 }
247
248 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700249 if (shProg->Shaders[i] == sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700250 /* already attached */
251 return;
Brian34ae99d2006-12-18 08:28:54 -0700252 }
253 }
Brian5b01c5e2006-12-19 18:02:03 -0700254
255 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700256 shProg->Shaders = (struct gl_shader **)
257 _mesa_realloc(shProg->Shaders,
258 n * sizeof(struct gl_shader *),
259 (n + 1) * sizeof(struct gl_shader *));
260 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700261 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
262 return;
263 }
264
265 /* append */
Brian65a18442006-12-19 18:46:56 -0700266 shProg->Shaders[n] = sh;
267 sh->RefCount++;
268 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700269}
270
271
272void
273_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
274 const GLchar *name)
275{
Brian65a18442006-12-19 18:46:56 -0700276 struct gl_shader_program *shProg
277 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700278
Brian65a18442006-12-19 18:46:56 -0700279 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700280 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindAttribLocation(program)");
281 return;
282 }
283
Brian9e4bae92006-12-20 09:27:42 -0700284 if (!name)
285 return;
286
287 if (strncmp(name, "gl_", 3) == 0) {
288 _mesa_error(ctx, GL_INVALID_OPERATION,
289 "glBindAttribLocation(illegal name)");
290 return;
291 }
292
Brian5b01c5e2006-12-19 18:02:03 -0700293#if 0 /* XXXX */
294 if (name == NULL || index >= MAX_VERTEX_ATTRIBS)
295 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocationARB");
296 else if (IS_NAME_WITH_GL_PREFIX(name))
297 _mesa_error(ctx, GL_INVALID_OPERATION, "glBindAttribLocationARB");
298 else
299 (**pro).OverrideAttribBinding(pro, index, name);
300 RELEASE_PROGRAM(pro);
Brian34ae99d2006-12-18 08:28:54 -0700301#endif
302}
303
304
Brian5b01c5e2006-12-19 18:02:03 -0700305GLuint
306_mesa_create_shader(GLcontext *ctx, GLenum type)
307{
Brian65a18442006-12-19 18:46:56 -0700308 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700309 GLuint name;
310
311 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
312
313 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700314 case GL_FRAGMENT_SHADER:
315 case GL_VERTEX_SHADER:
316 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700317 break;
318 default:
319 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
320 return 0;
321 }
322
Brian65a18442006-12-19 18:46:56 -0700323 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700324
325 return name;
326}
327
328
329GLuint
330_mesa_create_program(GLcontext *ctx)
331{
332 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700333 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700334
Brian65a18442006-12-19 18:46:56 -0700335 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
336 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700337
Brian65a18442006-12-19 18:46:56 -0700338 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700339
340 return name;
341}
342
343
344void
345_mesa_delete_program2(GLcontext *ctx, GLuint name)
346{
Brian65a18442006-12-19 18:46:56 -0700347 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700348
Brian65a18442006-12-19 18:46:56 -0700349 shProg = _mesa_lookup_shader_program(ctx, name);
350 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700351 _mesa_error(ctx, GL_INVALID_OPERATION, "glDeleteProgram(name)");
352 return;
353 }
354
Brian9e4bae92006-12-20 09:27:42 -0700355 /* always remove from hash table */
Brian65a18442006-12-19 18:46:56 -0700356 _mesa_HashRemove(ctx->Shared->ShaderObjects, name);
Brian9e4bae92006-12-20 09:27:42 -0700357
358 shProg->DeletePending = GL_TRUE;
359
360 /* decrement refcount, delete if zero */
361 shProg->RefCount--;
362 if (shProg->RefCount <= 0) {
363 _mesa_free_shader_program(ctx, shProg);
364 }
Brian5b01c5e2006-12-19 18:02:03 -0700365}
366
367
368void
369_mesa_delete_shader(GLcontext *ctx, GLuint shader)
370{
Brian9e4bae92006-12-20 09:27:42 -0700371 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
372 if (!sh) {
373 return;
374 }
Brian5b01c5e2006-12-19 18:02:03 -0700375
Brian9e4bae92006-12-20 09:27:42 -0700376 sh->DeletePending = GL_TRUE;
377 sh->RefCount--;
378 if (sh->RefCount <= 0) {
379 _mesa_free_shader(ctx, sh);
380 }
Brian5b01c5e2006-12-19 18:02:03 -0700381}
382
383
384void
385_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
386{
Brian65a18442006-12-19 18:46:56 -0700387 struct gl_shader_program *shProg
388 = _mesa_lookup_shader_program(ctx, program);
389 const GLuint n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700390 GLuint i, j;
391
Brian65a18442006-12-19 18:46:56 -0700392 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700393 _mesa_error(ctx, GL_INVALID_OPERATION,
394 "glDetachShader(bad program or shader name)");
395 return;
396 }
397
398 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700399 if (shProg->Shaders[i]->Name == shader) {
400 struct gl_shader **newList;
Brian5b01c5e2006-12-19 18:02:03 -0700401 /* found it */
Brian9e4bae92006-12-20 09:27:42 -0700402
403 shProg->Shaders[i]->RefCount--;
404
Brian5b01c5e2006-12-19 18:02:03 -0700405 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700406 newList = (struct gl_shader **)
407 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700408 if (!newList) {
409 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
410 return;
411 }
412 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700413 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700414 }
415 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700416 newList[j++] = shProg->Shaders[i];
417 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700418
419 /* XXX refcounting! */
420
Brian65a18442006-12-19 18:46:56 -0700421 shProg->Shaders = newList;
Brian5b01c5e2006-12-19 18:02:03 -0700422 return;
423 }
424 }
425
426 /* not found */
427 _mesa_error(ctx, GL_INVALID_OPERATION,
428 "glDetachShader(shader not found)");
429}
430
431
432void
433_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
434 GLsizei maxLength, GLsizei *length, GLint *size,
435 GLenum *type, GLchar *nameOut)
436{
437 static const GLenum vec_types[] = {
438 GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4
439 };
Brian65a18442006-12-19 18:46:56 -0700440 struct gl_shader_program *shProg
441 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700442 GLint sz;
443
Brian65a18442006-12-19 18:46:56 -0700444 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700445 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetActiveUniform");
446 return;
447 }
448
Brian65a18442006-12-19 18:46:56 -0700449 if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) {
Brian5b01c5e2006-12-19 18:02:03 -0700450 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
451 return;
452 }
453
454 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700455 shProg->Attributes->Parameters[index].Name);
456 sz = shProg->Attributes->Parameters[index].Size;
Brian5b01c5e2006-12-19 18:02:03 -0700457 if (size)
458 *size = sz;
459 if (type)
460 *type = vec_types[sz]; /* XXX this is a temporary hack */
461}
462
463
464/**
465 * Called via ctx->Driver.GetActiveUniform().
466 */
467void
468_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
469 GLsizei maxLength, GLsizei *length, GLint *size,
470 GLenum *type, GLchar *nameOut)
471{
472 static const GLenum vec_types[] = {
473 GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4
474 };
Brian65a18442006-12-19 18:46:56 -0700475 struct gl_shader_program *shProg
476 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700477 GLint sz;
478
Brian65a18442006-12-19 18:46:56 -0700479 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700480 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetActiveUniform");
481 return;
482 }
483
Brian65a18442006-12-19 18:46:56 -0700484 if (!shProg->Uniforms || index >= shProg->Uniforms->NumParameters) {
Brian5b01c5e2006-12-19 18:02:03 -0700485 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
486 return;
487 }
488
489 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700490 shProg->Uniforms->Parameters[index].Name);
491 sz = shProg->Uniforms->Parameters[index].Size;
Brian5b01c5e2006-12-19 18:02:03 -0700492 if (size)
493 *size = sz;
494 if (type)
495 *type = vec_types[sz]; /* XXX this is a temporary hack */
496}
497
498
499/**
500 * Called via ctx->Driver.GetAttachedShaders().
501 */
502void
503_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
504 GLsizei *count, GLuint *obj)
505{
Brian65a18442006-12-19 18:46:56 -0700506 struct gl_shader_program *shProg
507 = _mesa_lookup_shader_program(ctx, program);
508 if (shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700509 GLuint i;
Brian65a18442006-12-19 18:46:56 -0700510 for (i = 0; i < maxCount && i < shProg->NumShaders; i++) {
511 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700512 }
513 if (count)
514 *count = i;
515 }
516 else {
517 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetAttachedShaders");
518 }
519}
520
521
522GLint
523_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
524 const GLchar *name)
525{
Brian65a18442006-12-19 18:46:56 -0700526 struct gl_shader_program *shProg
527 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700528
Brian65a18442006-12-19 18:46:56 -0700529 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700530 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetAttribLocation");
531 return -1;
532 }
533
Brian65a18442006-12-19 18:46:56 -0700534 if (!shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -0700535 _mesa_error(ctx, GL_INVALID_OPERATION,
536 "glGetAttribLocation(program not linked)");
537 return -1;
538 }
539
540 if (!name)
541 return -1;
542
Brian65a18442006-12-19 18:46:56 -0700543 if (shProg->Attributes) {
Brian5b01c5e2006-12-19 18:02:03 -0700544 GLuint i;
Brian65a18442006-12-19 18:46:56 -0700545 for (i = 0; i < shProg->Attributes->NumParameters; i++) {
546 if (!strcmp(shProg->Attributes->Parameters[i].Name, name)) {
Brian5b01c5e2006-12-19 18:02:03 -0700547 return i;
548 }
549 }
550 }
551 return -1;
552}
553
554
555GLuint
556_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700557{
558#if 0
559 GET_CURRENT_CONTEXT(ctx);
560
561 switch (pname) {
562 case GL_PROGRAM_OBJECT_ARB:
563 {
Brian5b01c5e2006-12-19 18:02:03 -0700564 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700565
566 if (pro != NULL)
567 return (**pro)._container._generic.
568 GetName((struct gl2_generic_intf **) (pro));
569 }
570 break;
571 default:
572 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
573 }
574#endif
575 return 0;
576}
577
578
Brian5b01c5e2006-12-19 18:02:03 -0700579void
580_mesa_get_programiv(GLcontext *ctx, GLuint program,
581 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700582{
Brian65a18442006-12-19 18:46:56 -0700583 struct gl_shader_program *shProg
584 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700585
Brian65a18442006-12-19 18:46:56 -0700586 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700587 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700588 return;
589 }
590
Brian5b01c5e2006-12-19 18:02:03 -0700591 switch (pname) {
592 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700593 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700594 break;
595 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700596 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700597 break;
Brian5b01c5e2006-12-19 18:02:03 -0700598 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700599 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700600 break;
601 case GL_INFO_LOG_LENGTH:
Brian65a18442006-12-19 18:46:56 -0700602 *params = shProg->InfoLog ? strlen(shProg->InfoLog) : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700603 break;
604 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700605 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700606 break;
607 case GL_ACTIVE_ATTRIBUTES:
Brian65a18442006-12-19 18:46:56 -0700608 *params = shProg->Uniforms ? shProg->Uniforms->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700609 break;
610 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian65a18442006-12-19 18:46:56 -0700611 *params = _mesa_parameter_longest_name(shProg->Attributes);
Brian5b01c5e2006-12-19 18:02:03 -0700612 break;
613 case GL_ACTIVE_UNIFORMS:
Brian65a18442006-12-19 18:46:56 -0700614 *params = shProg->Uniforms ? shProg->Uniforms->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700615 break;
616 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian65a18442006-12-19 18:46:56 -0700617 *params = _mesa_parameter_longest_name(shProg->Uniforms);
Brian34ae99d2006-12-18 08:28:54 -0700618 break;
619 default:
Brian5b01c5e2006-12-19 18:02:03 -0700620 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
621 return;
Brian34ae99d2006-12-18 08:28:54 -0700622 }
Brian5b01c5e2006-12-19 18:02:03 -0700623}
Brian34ae99d2006-12-18 08:28:54 -0700624
Brian34ae99d2006-12-18 08:28:54 -0700625
Brian5b01c5e2006-12-19 18:02:03 -0700626void
627_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
628{
Brian65a18442006-12-19 18:46:56 -0700629 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700630
631 if (!shader) {
632 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderiv(shader)");
633 return;
634 }
Brian65a18442006-12-19 18:46:56 -0700635
Brian5b01c5e2006-12-19 18:02:03 -0700636 switch (pname) {
637 case GL_SHADER_TYPE:
638 *params = shader->Type;
639 break;
640 case GL_DELETE_STATUS:
641 *params = shader->DeletePending;
642 break;
643 case GL_COMPILE_STATUS:
644 *params = shader->CompileStatus;
645 break;
646 case GL_INFO_LOG_LENGTH:
647 *params = shader->InfoLog ? strlen(shader->InfoLog) : 0;
648 break;
649 case GL_SHADER_SOURCE_LENGTH:
650 *params = shader->Source ? strlen((char *) shader->Source) : 0;
651 break;
652 default:
653 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
654 return;
655 }
656}
657
658
659void
660_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
661 GLsizei *length, GLchar *infoLog)
662{
Brian65a18442006-12-19 18:46:56 -0700663 struct gl_shader_program *shProg
664 = _mesa_lookup_shader_program(ctx, program);
665 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700666 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
667 return;
668 }
Brian65a18442006-12-19 18:46:56 -0700669 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700670}
671
672
673void
674_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
675 GLsizei *length, GLchar *infoLog)
676{
Brian65a18442006-12-19 18:46:56 -0700677 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
678 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700679 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
680 return;
681 }
Brian65a18442006-12-19 18:46:56 -0700682 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700683}
684
685
686/**
687 * Called via ctx->Driver.GetShaderSource().
688 */
689void
690_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
691 GLsizei *length, GLchar *sourceOut)
692{
Brian65a18442006-12-19 18:46:56 -0700693 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
694 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700695 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderSource(shader)");
696 return;
697 }
Brian65a18442006-12-19 18:46:56 -0700698 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -0700699}
700
701
702/**
703 * Called via ctx->Driver.GetUniformfv().
704 */
705void
706_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
707 GLfloat *params)
708{
Brian65a18442006-12-19 18:46:56 -0700709 struct gl_shader_program *shProg
710 = _mesa_lookup_shader_program(ctx, program);
711 if (shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700712 GLuint i;
Brian65a18442006-12-19 18:46:56 -0700713 if (location >= 0 && location < shProg->Uniforms->NumParameters) {
714 for (i = 0; i < shProg->Uniforms->Parameters[location].Size; i++) {
715 params[i] = shProg->Uniforms->ParameterValues[location][i];
Brian5b01c5e2006-12-19 18:02:03 -0700716 }
717 }
718 else {
719 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(location)");
720 }
721 }
722 else {
723 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
724 }
725}
726
727
728/**
729 * Called via ctx->Driver.GetUniformLocation().
730 */
731GLint
732_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
733{
734 if (ctx->Shader.CurrentProgram) {
Brian65a18442006-12-19 18:46:56 -0700735 const struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian5b01c5e2006-12-19 18:02:03 -0700736 GLuint loc;
Brian65a18442006-12-19 18:46:56 -0700737 for (loc = 0; loc < shProg->Uniforms->NumParameters; loc++) {
Brian5b01c5e2006-12-19 18:02:03 -0700738 const struct gl_program_parameter *u
Brian65a18442006-12-19 18:46:56 -0700739 = shProg->Uniforms->Parameters + loc;
Brian29053852006-12-21 11:21:26 -0700740 /* XXX this is a temporary simplification / short-cut.
741 * We need to handle things like "e.c[0].b" as seen in the
742 * GLSL orange book, page 189.
743 */
Brian5b01c5e2006-12-19 18:02:03 -0700744 if (u->Type == PROGRAM_UNIFORM && !strcmp(u->Name, name)) {
745 return loc;
746 }
747 }
748 }
749 return -1;
750
751}
752
753
754GLboolean
755_mesa_is_program(GLcontext *ctx, GLuint name)
756{
Brian65a18442006-12-19 18:46:56 -0700757 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
758 return shProg ? GL_TRUE : GL_FALSE;
Brian5b01c5e2006-12-19 18:02:03 -0700759}
760
761
762GLboolean
763_mesa_is_shader(GLcontext *ctx, GLuint name)
764{
Brian65a18442006-12-19 18:46:56 -0700765 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700766 return shader ? GL_TRUE : GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700767}
768
769
770
Brian5b01c5e2006-12-19 18:02:03 -0700771/**
772 * Called via ctx->Driver.ShaderSource()
773 */
774void
775_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -0700776{
Brian65a18442006-12-19 18:46:56 -0700777 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
778 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700779 _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSource(shaderObj)");
Brian34ae99d2006-12-18 08:28:54 -0700780 return;
781 }
782
Brian34ae99d2006-12-18 08:28:54 -0700783 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -0700784 if (sh->Source) {
785 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -0700786 }
Brian65a18442006-12-19 18:46:56 -0700787 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -0700788 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700789}
790
791
Brian5b01c5e2006-12-19 18:02:03 -0700792/**
793 * Called via ctx->Driver.CompileShader()
794 */
795void
796_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -0700797{
Brian65a18442006-12-19 18:46:56 -0700798 struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj);
Brian34ae99d2006-12-18 08:28:54 -0700799 slang_info_log info_log;
800 slang_code_object obj;
801 slang_unit_type type;
802
Brian65a18442006-12-19 18:46:56 -0700803 if (!sh) {
Brian34ae99d2006-12-18 08:28:54 -0700804 _mesa_error(ctx, GL_INVALID_VALUE, "glCompileShader(shaderObj)");
805 return;
806 }
807
808 slang_info_log_construct(&info_log);
809 _slang_code_object_ctr(&obj);
810
Brian65a18442006-12-19 18:46:56 -0700811 if (sh->Type == GL_VERTEX_SHADER) {
Brian34ae99d2006-12-18 08:28:54 -0700812 type = slang_unit_vertex_shader;
813 }
814 else {
Brian65a18442006-12-19 18:46:56 -0700815 assert(sh->Type == GL_FRAGMENT_SHADER);
Brian34ae99d2006-12-18 08:28:54 -0700816 type = slang_unit_fragment_shader;
817 }
818
Brian65a18442006-12-19 18:46:56 -0700819 if (_slang_compile(sh->Source, &obj, type, &info_log, sh)) {
820 sh->CompileStatus = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -0700821 }
822 else {
Brian65a18442006-12-19 18:46:56 -0700823 sh->CompileStatus = GL_FALSE;
824 /* XXX temporary */
Brian34ae99d2006-12-18 08:28:54 -0700825 _mesa_problem(ctx, "Program did not compile!");
826 }
827}
828
829
Brian5b01c5e2006-12-19 18:02:03 -0700830/**
831 * Called via ctx->Driver.LinkProgram()
832 */
833void
834_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -0700835{
Brian65a18442006-12-19 18:46:56 -0700836 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -0700837
Brian65a18442006-12-19 18:46:56 -0700838 shProg = _mesa_lookup_shader_program(ctx, program);
839 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700840 _mesa_error(ctx, GL_INVALID_OPERATION, "glLinkProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -0700841 return;
842 }
843
Brian65a18442006-12-19 18:46:56 -0700844 _slang_link2(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -0700845}
846
847
848/**
Brian5b01c5e2006-12-19 18:02:03 -0700849 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -0700850 */
Brian5b01c5e2006-12-19 18:02:03 -0700851void
852_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -0700853{
Brian9e4bae92006-12-20 09:27:42 -0700854 /* unbind old */
855 if (ctx->Shader.CurrentProgram) {
856 ctx->Shader.CurrentProgram->RefCount--;
857 if (ctx->Shader.CurrentProgram->RefCount <= 0) {
858 _mesa_free_shader_program(ctx, ctx->Shader.CurrentProgram);
859 }
860 ctx->Shader.CurrentProgram = NULL;
861 }
862
Brian5b01c5e2006-12-19 18:02:03 -0700863 /* XXXX need to handle reference counting here! */
864 if (program) {
Brian65a18442006-12-19 18:46:56 -0700865 struct gl_shader_program *shProg;
866 shProg = _mesa_lookup_shader_program(ctx, program);
867 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700868 _mesa_error(ctx, GL_INVALID_OPERATION,
869 "glUseProgramObjectARB(programObj)");
870 return;
871 }
Brian65a18442006-12-19 18:46:56 -0700872 ctx->Shader.CurrentProgram = shProg;
Brian9e4bae92006-12-20 09:27:42 -0700873 shProg->RefCount++;
Brian5b01c5e2006-12-19 18:02:03 -0700874 }
875 else {
876 /* don't use a shader program */
877 ctx->Shader.CurrentProgram = NULL;
878 }
879}
Brian34ae99d2006-12-18 08:28:54 -0700880
Brian5b01c5e2006-12-19 18:02:03 -0700881
882/**
883 * Called via ctx->Driver.Uniform().
884 */
885void
886_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
887 const GLvoid *values, GLenum type)
888{
Brian3a8e2772006-12-20 17:19:16 -0700889 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
890
891 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -0700892 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -0700893 return;
894 }
895
896 if (location < 0 || location >= shProg->Uniforms->NumParameters) {
897 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
898 return;
899 }
900
901 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
902
903 {
904 GLfloat *v = shProg->Uniforms->ParameterValues[location];
905 const GLfloat *fValues = (const GLfloat *) values; /* XXX */
906 GLint i;
907 if (type == GL_FLOAT_VEC4)
908 count *= 4;
909 else if (type == GL_FLOAT_VEC3)
910 count *= 3;
911 else
912 abort();
913
914 for (i = 0; i < count; i++)
915 v[i] = fValues[i];
916 return;
Brian5b01c5e2006-12-19 18:02:03 -0700917 }
Brian34ae99d2006-12-18 08:28:54 -0700918}
919
920
921/**
Brian5b01c5e2006-12-19 18:02:03 -0700922 * Called by ctx->Driver.UniformMatrix().
Brian34ae99d2006-12-18 08:28:54 -0700923 */
Brian5b01c5e2006-12-19 18:02:03 -0700924void
925_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
926 GLenum matrixType, GLint location, GLsizei count,
927 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -0700928{
Brian3a8e2772006-12-20 17:19:16 -0700929 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
930 if (!shProg || !shProg->LinkStatus) {
931 _mesa_error(ctx, GL_INVALID_OPERATION,
932 "glUniformMatrix(program not linked)");
933 return;
934 }
935 if (location < 0 || location >= shProg->Uniforms->NumParameters) {
936 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
937 return;
938 }
Brian34ae99d2006-12-18 08:28:54 -0700939 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -0700940 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -0700941 return;
942 }
943
944 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
945
Brian3a8e2772006-12-20 17:19:16 -0700946 /*
947 * Note: the _columns_ of a matrix are stored in program registers, not
948 * the rows.
949 */
950 /* XXXX need to test 3x3 and 2x2 matrices... */
Brian34ae99d2006-12-18 08:28:54 -0700951 if (transpose) {
Brian3a8e2772006-12-20 17:19:16 -0700952 GLuint row, col;
953 for (col = 0; col < cols; col++) {
954 GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
955 for (row = 0; row < rows; row++) {
956 v[row] = values[col * rows + row];
Brian34ae99d2006-12-18 08:28:54 -0700957 }
Brian34ae99d2006-12-18 08:28:54 -0700958 }
Brian34ae99d2006-12-18 08:28:54 -0700959 }
960 else {
Brian3a8e2772006-12-20 17:19:16 -0700961 GLuint row, col;
962 for (col = 0; col < cols; col++) {
963 GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
964 for (row = 0; row < rows; row++) {
965 v[row] = values[row * cols + col];
966 }
967 }
Brian34ae99d2006-12-18 08:28:54 -0700968 }
969}
970
971
Brian5b01c5e2006-12-19 18:02:03 -0700972void
973_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -0700974{
Brian65a18442006-12-19 18:46:56 -0700975 struct gl_shader_program *shProg;
976 shProg = _mesa_lookup_shader_program(ctx, program);
977 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700978 _mesa_error(ctx, GL_INVALID_OPERATION, "glValidateProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -0700979 return;
980 }
Brian5b01c5e2006-12-19 18:02:03 -0700981 /* XXX temporary */
Brian65a18442006-12-19 18:46:56 -0700982 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -0700983
Brian5b01c5e2006-12-19 18:02:03 -0700984 /* From the GL spec:
985 any two active samplers in the current program object are of
986 different types, but refer to the same texture image unit,
987
988 any active sampler in the current program object refers to a texture
989 image unit where fixed-function fragment processing accesses a
990 texture target that does not match the sampler type, or
991
992 the sum of the number of active samplers in the program and the
993 number of texture image units enabled for fixed-function fragment
994 processing exceeds the combined limit on the total number of texture
995 image units allowed.
996 */
Brian34ae99d2006-12-18 08:28:54 -0700997}