blob: bd258f8737bc78ffd24c8eb4f23059a33fe7b891 [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) {
Brian43975832007-01-04 08:21:09 -0700243 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700244 "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) {
Brian43975832007-01-04 08:21:09 -0700280 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700281 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) {
Brian43975832007-01-04 08:21:09 -0700351 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteProgram(name)");
Brian5b01c5e2006-12-19 18:02:03 -0700352 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) {
Brian43975832007-01-04 08:21:09 -0700393 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700394 "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 */
Brian43975832007-01-04 08:21:09 -0700427 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700428 "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) {
Brian43975832007-01-04 08:21:09 -0700445 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform");
Brian5b01c5e2006-12-19 18:02:03 -0700446 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) {
Brian43975832007-01-04 08:21:09 -0700480 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform");
Brian5b01c5e2006-12-19 18:02:03 -0700481 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 {
Brian43975832007-01-04 08:21:09 -0700517 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttachedShaders");
Brian5b01c5e2006-12-19 18:02:03 -0700518 }
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) {
Brian43975832007-01-04 08:21:09 -0700530 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttribLocation");
Brian5b01c5e2006-12-19 18:02:03 -0700531 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 {
Brian43975832007-01-04 08:21:09 -0700723 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700724 }
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 */
Brian5cf73262007-01-05 16:02:45 -0700744 if ((u->Type == PROGRAM_UNIFORM ||
745 u->Type == PROGRAM_SAMPLER) && !strcmp(u->Name, name)) {
Brian5b01c5e2006-12-19 18:02:03 -0700746 return loc;
747 }
748 }
749 }
750 return -1;
751
752}
753
754
755GLboolean
756_mesa_is_program(GLcontext *ctx, GLuint name)
757{
Brian65a18442006-12-19 18:46:56 -0700758 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
759 return shProg ? GL_TRUE : GL_FALSE;
Brian5b01c5e2006-12-19 18:02:03 -0700760}
761
762
763GLboolean
764_mesa_is_shader(GLcontext *ctx, GLuint name)
765{
Brian65a18442006-12-19 18:46:56 -0700766 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700767 return shader ? GL_TRUE : GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700768}
769
770
771
Brian5b01c5e2006-12-19 18:02:03 -0700772/**
773 * Called via ctx->Driver.ShaderSource()
774 */
775void
776_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -0700777{
Brian65a18442006-12-19 18:46:56 -0700778 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
779 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700780 _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSource(shaderObj)");
Brian34ae99d2006-12-18 08:28:54 -0700781 return;
782 }
783
Brian34ae99d2006-12-18 08:28:54 -0700784 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -0700785 if (sh->Source) {
786 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -0700787 }
Brian65a18442006-12-19 18:46:56 -0700788 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -0700789 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700790}
791
792
Brian5b01c5e2006-12-19 18:02:03 -0700793/**
794 * Called via ctx->Driver.CompileShader()
795 */
796void
797_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -0700798{
Brian65a18442006-12-19 18:46:56 -0700799 struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj);
Brian34ae99d2006-12-18 08:28:54 -0700800
Brian65a18442006-12-19 18:46:56 -0700801 if (!sh) {
Brian34ae99d2006-12-18 08:28:54 -0700802 _mesa_error(ctx, GL_INVALID_VALUE, "glCompileShader(shaderObj)");
803 return;
804 }
805
Brian43975832007-01-04 08:21:09 -0700806 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -0700807}
808
809
Brian5b01c5e2006-12-19 18:02:03 -0700810/**
811 * Called via ctx->Driver.LinkProgram()
812 */
813void
814_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -0700815{
Brian65a18442006-12-19 18:46:56 -0700816 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -0700817
Brian65a18442006-12-19 18:46:56 -0700818 shProg = _mesa_lookup_shader_program(ctx, program);
819 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700820 _mesa_error(ctx, GL_INVALID_VALUE, "glLinkProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -0700821 return;
822 }
823
Brian65a18442006-12-19 18:46:56 -0700824 _slang_link2(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -0700825}
826
827
828/**
Brian5b01c5e2006-12-19 18:02:03 -0700829 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -0700830 */
Brian5b01c5e2006-12-19 18:02:03 -0700831void
832_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -0700833{
Brian9e4bae92006-12-20 09:27:42 -0700834 /* unbind old */
835 if (ctx->Shader.CurrentProgram) {
836 ctx->Shader.CurrentProgram->RefCount--;
837 if (ctx->Shader.CurrentProgram->RefCount <= 0) {
838 _mesa_free_shader_program(ctx, ctx->Shader.CurrentProgram);
839 }
840 ctx->Shader.CurrentProgram = NULL;
841 }
842
Brian5b01c5e2006-12-19 18:02:03 -0700843 /* XXXX need to handle reference counting here! */
844 if (program) {
Brian65a18442006-12-19 18:46:56 -0700845 struct gl_shader_program *shProg;
846 shProg = _mesa_lookup_shader_program(ctx, program);
847 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700848 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700849 "glUseProgramObjectARB(programObj)");
850 return;
851 }
Brian65a18442006-12-19 18:46:56 -0700852 ctx->Shader.CurrentProgram = shProg;
Brian9e4bae92006-12-20 09:27:42 -0700853 shProg->RefCount++;
Brian5b01c5e2006-12-19 18:02:03 -0700854 }
855 else {
856 /* don't use a shader program */
857 ctx->Shader.CurrentProgram = NULL;
858 }
859}
Brian34ae99d2006-12-18 08:28:54 -0700860
Brian5b01c5e2006-12-19 18:02:03 -0700861
862/**
863 * Called via ctx->Driver.Uniform().
864 */
865void
866_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
867 const GLvoid *values, GLenum type)
868{
Brian3a8e2772006-12-20 17:19:16 -0700869 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian89dc4852007-01-04 14:35:44 -0700870 GLfloat *uniformVal;
Brian3a8e2772006-12-20 17:19:16 -0700871
872 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -0700873 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -0700874 return;
875 }
876
877 if (location < 0 || location >= shProg->Uniforms->NumParameters) {
878 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
879 return;
880 }
881
882 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
883
Brian89dc4852007-01-04 14:35:44 -0700884 uniformVal = shProg->Uniforms->ParameterValues[location];
Brian3a8e2772006-12-20 17:19:16 -0700885
Brian89dc4852007-01-04 14:35:44 -0700886 if (type == GL_INT ||
887 type == GL_INT_VEC2 ||
888 type == GL_INT_VEC3 ||
889 type == GL_INT_VEC4) {
890 const GLint *iValues = (const GLint *) values;
891 switch (type) {
892 case GL_INT_VEC4:
893 uniformVal[3] = (GLfloat) iValues[3];
894 /* fall-through */
895 case GL_INT_VEC3:
896 uniformVal[2] = (GLfloat) iValues[2];
897 /* fall-through */
898 case GL_INT_VEC2:
899 uniformVal[1] = (GLfloat) iValues[1];
900 /* fall-through */
901 case GL_INT:
902 uniformVal[0] = (GLfloat) iValues[0];
903 break;
904 default:
905 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
906 return;
907 }
908 }
909 else {
910 const GLfloat *fValues = (const GLfloat *) values; /* XXX */
911 switch (type) {
912 case GL_FLOAT_VEC4:
913 uniformVal[3] = fValues[3];
914 /* fall-through */
915 case GL_FLOAT_VEC3:
916 uniformVal[2] = fValues[2];
917 /* fall-through */
918 case GL_FLOAT_VEC2:
919 uniformVal[1] = fValues[1];
920 /* fall-through */
921 case GL_FLOAT:
922 uniformVal[0] = fValues[0];
923 break;
924 default:
925 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
926 return;
927 }
Brian5b01c5e2006-12-19 18:02:03 -0700928 }
Brian5cf73262007-01-05 16:02:45 -0700929
930 if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
931 _slang_resolve_samplers(shProg, &shProg->VertexProgram->Base);
932 _slang_resolve_samplers(shProg, &shProg->FragmentProgram->Base);
933 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
934 }
Brian34ae99d2006-12-18 08:28:54 -0700935}
936
937
938/**
Brian5b01c5e2006-12-19 18:02:03 -0700939 * Called by ctx->Driver.UniformMatrix().
Brian34ae99d2006-12-18 08:28:54 -0700940 */
Brian5b01c5e2006-12-19 18:02:03 -0700941void
942_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
943 GLenum matrixType, GLint location, GLsizei count,
944 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -0700945{
Brian3a8e2772006-12-20 17:19:16 -0700946 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
947 if (!shProg || !shProg->LinkStatus) {
948 _mesa_error(ctx, GL_INVALID_OPERATION,
949 "glUniformMatrix(program not linked)");
950 return;
951 }
952 if (location < 0 || location >= shProg->Uniforms->NumParameters) {
953 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
954 return;
955 }
Brian34ae99d2006-12-18 08:28:54 -0700956 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -0700957 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -0700958 return;
959 }
960
961 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
962
Brian3a8e2772006-12-20 17:19:16 -0700963 /*
964 * Note: the _columns_ of a matrix are stored in program registers, not
965 * the rows.
966 */
967 /* XXXX need to test 3x3 and 2x2 matrices... */
Brian34ae99d2006-12-18 08:28:54 -0700968 if (transpose) {
Brian3a8e2772006-12-20 17:19:16 -0700969 GLuint row, col;
970 for (col = 0; col < cols; col++) {
971 GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
972 for (row = 0; row < rows; row++) {
973 v[row] = values[col * rows + row];
Brian34ae99d2006-12-18 08:28:54 -0700974 }
Brian34ae99d2006-12-18 08:28:54 -0700975 }
Brian34ae99d2006-12-18 08:28:54 -0700976 }
977 else {
Brian3a8e2772006-12-20 17:19:16 -0700978 GLuint row, col;
979 for (col = 0; col < cols; col++) {
980 GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
981 for (row = 0; row < rows; row++) {
982 v[row] = values[row * cols + col];
983 }
984 }
Brian34ae99d2006-12-18 08:28:54 -0700985 }
986}
987
988
Brian5b01c5e2006-12-19 18:02:03 -0700989void
990_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -0700991{
Brian65a18442006-12-19 18:46:56 -0700992 struct gl_shader_program *shProg;
993 shProg = _mesa_lookup_shader_program(ctx, program);
994 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700995 _mesa_error(ctx, GL_INVALID_VALUE, "glValidateProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -0700996 return;
997 }
Brian5b01c5e2006-12-19 18:02:03 -0700998 /* XXX temporary */
Brian65a18442006-12-19 18:46:56 -0700999 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001000
Brian5b01c5e2006-12-19 18:02:03 -07001001 /* From the GL spec:
1002 any two active samplers in the current program object are of
1003 different types, but refer to the same texture image unit,
1004
1005 any active sampler in the current program object refers to a texture
1006 image unit where fixed-function fragment processing accesses a
1007 texture target that does not match the sampler type, or
1008
1009 the sum of the number of active samplers in the program and the
1010 number of texture image units enabled for fixed-function fragment
1011 processing exceeds the combined limit on the total number of texture
1012 image units allowed.
1013 */
Brian34ae99d2006-12-18 08:28:54 -07001014}