blob: 64f2a9fa12682be847da004a57147aec6a122cec [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"
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"
Brian34ae99d2006-12-18 08:28:54 -070046#include "shader_api.h"
47
48#include "slang_compile.h"
49#include "slang_link.h"
50
51
52
Brianf2923612006-12-20 09:56:44 -070053/**
54 * Allocate a new gl_shader_program object, initialize it.
55 */
56struct gl_shader_program *
57_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{
Brianf2923612006-12-20 09:56:44 -070078 if (shProg->VertexProgram) {
79 if (shProg->VertexProgram->Base.Parameters == shProg->Uniforms) {
80 /* to prevent a double-free in the next call */
81 shProg->VertexProgram->Base.Parameters = NULL;
82 }
83 _mesa_delete_program(ctx, &shProg->VertexProgram->Base);
84 shProg->VertexProgram = NULL;
85 }
86
87 if (shProg->FragmentProgram) {
88 if (shProg->FragmentProgram->Base.Parameters == shProg->Uniforms) {
89 /* to prevent a double-free in the next call */
90 shProg->FragmentProgram->Base.Parameters = NULL;
91 }
92 _mesa_delete_program(ctx, &shProg->FragmentProgram->Base);
93 shProg->FragmentProgram = NULL;
94 }
95
Brianf2923612006-12-20 09:56:44 -070096 if (shProg->Uniforms) {
97 _mesa_free_parameter_list(shProg->Uniforms);
98 shProg->Uniforms = NULL;
99 }
100
101 if (shProg->Varying) {
102 _mesa_free_parameter_list(shProg->Varying);
103 shProg->Varying = NULL;
104 }
105}
106
107
Brianb9fbedd2007-03-26 09:23:44 -0600108/**
Brian3c008a02007-04-12 15:22:32 -0600109 * Free all the data that hangs off a shader program object, but not the
110 * object itself.
111 */
112void
113_mesa_free_shader_program_data(GLcontext *ctx,
114 struct gl_shader_program *shProg)
115{
116 GLuint i;
117
Brianf3e8c322007-04-18 14:53:23 -0600118 assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
Brian3c008a02007-04-12 15:22:32 -0600119
120 _mesa_clear_shader_program_data(ctx, shProg);
121
Brian4b7c6fc2007-04-19 15:23:34 -0600122 if (shProg->Attributes) {
123 _mesa_free_parameter_list(shProg->Attributes);
124 shProg->Attributes = NULL;
125 }
126
Brian3c008a02007-04-12 15:22:32 -0600127 /* detach shaders */
128 for (i = 0; i < shProg->NumShaders; i++) {
129 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
130 }
131 if (shProg->Shaders) {
132 _mesa_free(shProg->Shaders);
133 shProg->Shaders = NULL;
134 }
135}
136
137
138/**
Brianb9fbedd2007-03-26 09:23:44 -0600139 * Free/delete a shader program object.
140 */
Brianf2923612006-12-20 09:56:44 -0700141void
142_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg)
143{
144 _mesa_free_shader_program_data(ctx, shProg);
Brianb9fbedd2007-03-26 09:23:44 -0600145 if (shProg->Shaders) {
146 _mesa_free(shProg->Shaders);
147 shProg->Shaders = NULL;
148 }
Brianf2923612006-12-20 09:56:44 -0700149 _mesa_free(shProg);
150}
151
152
153/**
Brian3c008a02007-04-12 15:22:32 -0600154 * Set ptr to point to shProg.
155 * If ptr is pointing to another object, decrement its refcount (and delete
156 * if refcount hits zero).
157 * Then set ptr to point to shProg, incrementing its refcount.
158 */
159/* XXX this could be static */
160void
161_mesa_reference_shader_program(GLcontext *ctx,
162 struct gl_shader_program **ptr,
163 struct gl_shader_program *shProg)
164{
165 assert(ptr);
166 if (*ptr == shProg) {
167 /* no-op */
168 return;
169 }
170 if (*ptr) {
171 /* Unreference the old shader program */
172 GLboolean deleteFlag = GL_FALSE;
173 struct gl_shader_program *old = *ptr;
174
175 ASSERT(old->RefCount > 0);
176 old->RefCount--;
177 /*printf("SHPROG DECR %p (%d) to %d\n",
178 (void*) old, old->Name, old->RefCount);*/
179 deleteFlag = (old->RefCount == 0);
180
181 if (deleteFlag) {
182 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
183 _mesa_free_shader_program(ctx, old);
184 }
185
186 *ptr = NULL;
187 }
188 assert(!*ptr);
189
190 if (shProg) {
191 shProg->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600192 /*printf("SHPROG INCR %p (%d) to %d\n",
193 (void*) shProg, shProg->Name, shProg->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600194 *ptr = shProg;
195 }
196}
197
198
199/**
Brianf2923612006-12-20 09:56:44 -0700200 * Lookup a GLSL program object.
201 */
202struct gl_shader_program *
203_mesa_lookup_shader_program(GLcontext *ctx, GLuint name)
204{
205 struct gl_shader_program *shProg;
206 if (name) {
207 shProg = (struct gl_shader_program *)
208 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
209 /* Note that both gl_shader and gl_shader_program objects are kept
210 * in the same hash table. Check the object's type to be sure it's
211 * what we're expecting.
212 */
Brianf3e8c322007-04-18 14:53:23 -0600213 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700214 return NULL;
215 }
216 return shProg;
217 }
218 return NULL;
219}
220
221
222/**
223 * Allocate a new gl_shader object, initialize it.
224 */
225struct gl_shader *
226_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
227{
228 struct gl_shader *shader;
229 assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
230 shader = CALLOC_STRUCT(gl_shader);
231 if (shader) {
232 shader->Type = type;
233 shader->Name = name;
234 shader->RefCount = 1;
235 }
236 return shader;
237}
238
239
240void
241_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh)
242{
243 GLuint i;
244 if (sh->Source)
245 _mesa_free((void *) sh->Source);
246 if (sh->InfoLog)
247 _mesa_free(sh->InfoLog);
248 for (i = 0; i < sh->NumPrograms; i++) {
249 assert(sh->Programs[i]);
250 _mesa_delete_program(ctx, sh->Programs[i]);
251 }
252 if (sh->Programs)
253 _mesa_free(sh->Programs);
254 _mesa_free(sh);
255}
256
257
258/**
Brian3c008a02007-04-12 15:22:32 -0600259 * Set ptr to point to sh.
260 * If ptr is pointing to another shader, decrement its refcount (and delete
261 * if refcount hits zero).
262 * Then set ptr to point to sh, incrementing its refcount.
263 */
264/* XXX this could be static */
265void
266_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr,
267 struct gl_shader *sh)
268{
269 assert(ptr);
270 if (*ptr == sh) {
271 /* no-op */
272 return;
273 }
274 if (*ptr) {
275 /* Unreference the old shader */
276 GLboolean deleteFlag = GL_FALSE;
277 struct gl_shader *old = *ptr;
278
279 ASSERT(old->RefCount > 0);
280 old->RefCount--;
Brian99193e42007-04-12 15:45:02 -0600281 /*printf("SHADER DECR %p (%d) to %d\n",
282 (void*) old, old->Name, old->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600283 deleteFlag = (old->RefCount == 0);
284
285 if (deleteFlag) {
286 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
287 _mesa_free_shader(ctx, old);
288 }
289
290 *ptr = NULL;
291 }
292 assert(!*ptr);
293
294 if (sh) {
295 /* reference new */
296 sh->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600297 /*printf("SHADER INCR %p (%d) to %d\n",
298 (void*) sh, sh->Name, sh->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600299 *ptr = sh;
300 }
301}
302
303
304/**
Brianf2923612006-12-20 09:56:44 -0700305 * Lookup a GLSL shader object.
306 */
307struct gl_shader *
308_mesa_lookup_shader(GLcontext *ctx, GLuint name)
309{
310 if (name) {
311 struct gl_shader *sh = (struct gl_shader *)
312 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
313 /* Note that both gl_shader and gl_shader_program objects are kept
314 * in the same hash table. Check the object's type to be sure it's
315 * what we're expecting.
316 */
Brianf3e8c322007-04-18 14:53:23 -0600317 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700318 return NULL;
319 }
320 return sh;
321 }
322 return NULL;
323}
324
325
Brianfa4d0362007-02-26 18:33:50 -0700326/**
327 * Initialize context's shader state.
328 */
Brianf2923612006-12-20 09:56:44 -0700329void
330_mesa_init_shader_state(GLcontext * ctx)
331{
Brianfa4d0362007-02-26 18:33:50 -0700332 /* Device drivers may override these to control what kind of instructions
333 * are generated by the GLSL compiler.
334 */
335 ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
Brian63556fa2007-03-23 14:47:46 -0600336 ctx->Shader.EmitCondCodes = GL_TRUE; /* XXX probably want GL_FALSE... */
Brianfa4d0362007-02-26 18:33:50 -0700337 ctx->Shader.EmitComments = GL_FALSE;
Brianf2923612006-12-20 09:56:44 -0700338}
339
340
Brian5b01c5e2006-12-19 18:02:03 -0700341/**
Brian935f93f2007-03-24 16:20:02 -0600342 * Free the per-context shader-related state.
343 */
344void
345_mesa_free_shader_state(GLcontext *ctx)
346{
Brian3c008a02007-04-12 15:22:32 -0600347 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
Brian935f93f2007-03-24 16:20:02 -0600348}
349
350
351/**
Brian5b01c5e2006-12-19 18:02:03 -0700352 * Copy string from <src> to <dst>, up to maxLength characters, returning
353 * length of <dst> in <length>.
354 * \param src the strings source
355 * \param maxLength max chars to copy
356 * \param length returns number of chars copied
357 * \param dst the string destination
358 */
359static void
360copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
361{
362 GLsizei len;
363 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
364 dst[len] = src[len];
365 if (maxLength > 0)
366 dst[len] = 0;
367 if (length)
368 *length = len;
369}
370
371
Brian5b01c5e2006-12-19 18:02:03 -0700372/**
373 * Called via ctx->Driver.AttachShader()
374 */
375void
376_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
377{
Brian65a18442006-12-19 18:46:56 -0700378 struct gl_shader_program *shProg
379 = _mesa_lookup_shader_program(ctx, program);
380 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
381 const GLuint n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700382 GLuint i;
383
Brian65a18442006-12-19 18:46:56 -0700384 if (!shProg || !sh) {
Brian43975832007-01-04 08:21:09 -0700385 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700386 "glAttachShader(bad program or shader name)");
387 return;
388 }
389
390 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700391 if (shProg->Shaders[i] == sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700392 /* already attached */
393 return;
Brian34ae99d2006-12-18 08:28:54 -0700394 }
395 }
Brian5b01c5e2006-12-19 18:02:03 -0700396
397 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700398 shProg->Shaders = (struct gl_shader **)
399 _mesa_realloc(shProg->Shaders,
400 n * sizeof(struct gl_shader *),
401 (n + 1) * sizeof(struct gl_shader *));
402 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700403 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
404 return;
405 }
406
407 /* append */
Brian3c008a02007-04-12 15:22:32 -0600408 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
409 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700410 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700411}
412
413
414void
415_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
416 const GLchar *name)
417{
Brian65a18442006-12-19 18:46:56 -0700418 struct gl_shader_program *shProg
419 = _mesa_lookup_shader_program(ctx, program);
Brianb7978af2007-01-09 19:17:17 -0700420 const GLint size = -1; /* unknown size */
421 GLint i, oldIndex;
Brian5b01c5e2006-12-19 18:02:03 -0700422
Brian65a18442006-12-19 18:46:56 -0700423 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700424 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700425 return;
426 }
427
Brian9e4bae92006-12-20 09:27:42 -0700428 if (!name)
429 return;
430
431 if (strncmp(name, "gl_", 3) == 0) {
432 _mesa_error(ctx, GL_INVALID_OPERATION,
433 "glBindAttribLocation(illegal name)");
434 return;
435 }
436
Brian9f660252007-04-11 09:00:56 -0600437 if (shProg->LinkStatus) {
438 /* get current index/location for the attribute */
439 oldIndex = _mesa_get_attrib_location(ctx, program, name);
440 }
441 else {
442 oldIndex = -1;
443 }
Brian3209c3e2007-01-09 17:49:24 -0700444
445 /* this will replace the current value if it's already in the list */
Brianb7978af2007-01-09 19:17:17 -0700446 i = _mesa_add_attribute(shProg->Attributes, name, size, index);
Brian3209c3e2007-01-09 17:49:24 -0700447 if (i < 0) {
448 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
449 }
450
Brian9f660252007-04-11 09:00:56 -0600451 if (shProg->VertexProgram && oldIndex >= 0 && oldIndex != index) {
452 /* If the index changed, need to search/replace references to that attribute
453 * in the vertex program.
454 */
Brian3209c3e2007-01-09 17:49:24 -0700455 _slang_remap_attribute(&shProg->VertexProgram->Base, oldIndex, index);
456 }
Brian34ae99d2006-12-18 08:28:54 -0700457}
458
459
Brian5b01c5e2006-12-19 18:02:03 -0700460GLuint
461_mesa_create_shader(GLcontext *ctx, GLenum type)
462{
Brian65a18442006-12-19 18:46:56 -0700463 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700464 GLuint name;
465
466 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
467
468 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700469 case GL_FRAGMENT_SHADER:
470 case GL_VERTEX_SHADER:
471 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700472 break;
473 default:
474 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
475 return 0;
476 }
477
Brian65a18442006-12-19 18:46:56 -0700478 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700479
480 return name;
481}
482
483
484GLuint
485_mesa_create_program(GLcontext *ctx)
486{
487 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700488 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700489
Brian65a18442006-12-19 18:46:56 -0700490 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
491 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700492
Brian65a18442006-12-19 18:46:56 -0700493 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700494
Brian3c008a02007-04-12 15:22:32 -0600495 assert(shProg->RefCount == 1);
496
Brian5b01c5e2006-12-19 18:02:03 -0700497 return name;
498}
499
500
Brian3c008a02007-04-12 15:22:32 -0600501/**
502 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
503 * DeleteProgramARB.
504 */
Brian5b01c5e2006-12-19 18:02:03 -0700505void
506_mesa_delete_program2(GLcontext *ctx, GLuint name)
507{
Brian3c008a02007-04-12 15:22:32 -0600508 /*
509 * NOTE: deleting shaders/programs works a bit differently than
510 * texture objects (and buffer objects, etc). Shader/program
511 * handles/IDs exist in the hash table until the object is really
512 * deleted (refcount==0). With texture objects, the handle/ID is
513 * removed from the hash table in glDeleteTextures() while the tex
514 * object itself might linger until its refcount goes to zero.
515 */
Brian65a18442006-12-19 18:46:56 -0700516 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700517
Brian65a18442006-12-19 18:46:56 -0700518 shProg = _mesa_lookup_shader_program(ctx, name);
519 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700520 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteProgram(name)");
Brian5b01c5e2006-12-19 18:02:03 -0700521 return;
522 }
523
Brian9e4bae92006-12-20 09:27:42 -0700524 shProg->DeletePending = GL_TRUE;
525
Brian3c008a02007-04-12 15:22:32 -0600526 /* effectively, decr shProg's refcount */
527 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700528}
529
530
531void
532_mesa_delete_shader(GLcontext *ctx, GLuint shader)
533{
Brian9e4bae92006-12-20 09:27:42 -0700534 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
535 if (!sh) {
536 return;
537 }
Brian5b01c5e2006-12-19 18:02:03 -0700538
Brian9e4bae92006-12-20 09:27:42 -0700539 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600540
541 /* effectively, decr sh's refcount */
542 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700543}
544
545
546void
547_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
548{
Brian65a18442006-12-19 18:46:56 -0700549 struct gl_shader_program *shProg
550 = _mesa_lookup_shader_program(ctx, program);
551 const GLuint n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700552 GLuint i, j;
553
Brian65a18442006-12-19 18:46:56 -0700554 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700555 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700556 "glDetachShader(bad program or shader name)");
557 return;
558 }
559
560 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700561 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700562 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600563 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700564
Brian3c008a02007-04-12 15:22:32 -0600565 /* derefernce */
566 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700567
Brian5b01c5e2006-12-19 18:02:03 -0700568 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700569 newList = (struct gl_shader **)
570 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700571 if (!newList) {
572 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
573 return;
574 }
575 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700576 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700577 }
578 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700579 newList[j++] = shProg->Shaders[i];
580 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700581
Brian65a18442006-12-19 18:46:56 -0700582 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600583 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600584
585#ifdef DEBUG
586 /* sanity check */
587 {
588 for (j = 0; j < shProg->NumShaders; j++) {
589 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
590 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
591 assert(shProg->Shaders[j]->RefCount > 0);
592 }
593 }
594#endif
595
Brian5b01c5e2006-12-19 18:02:03 -0700596 return;
597 }
598 }
599
600 /* not found */
Brian43975832007-01-04 08:21:09 -0700601 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700602 "glDetachShader(shader not found)");
603}
604
605
606void
607_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
608 GLsizei maxLength, GLsizei *length, GLint *size,
609 GLenum *type, GLchar *nameOut)
610{
611 static const GLenum vec_types[] = {
612 GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4
613 };
Brian65a18442006-12-19 18:46:56 -0700614 struct gl_shader_program *shProg
615 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700616 GLint sz;
617
Brian65a18442006-12-19 18:46:56 -0700618 if (!shProg) {
Brianaaa57412007-04-18 15:22:43 -0600619 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib");
Brian5b01c5e2006-12-19 18:02:03 -0700620 return;
621 }
622
Brian65a18442006-12-19 18:46:56 -0700623 if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600624 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700625 return;
626 }
627
628 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700629 shProg->Attributes->Parameters[index].Name);
630 sz = shProg->Attributes->Parameters[index].Size;
Brian5b01c5e2006-12-19 18:02:03 -0700631 if (size)
632 *size = sz;
633 if (type)
634 *type = vec_types[sz]; /* XXX this is a temporary hack */
635}
636
637
638/**
639 * Called via ctx->Driver.GetActiveUniform().
640 */
641void
642_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
643 GLsizei maxLength, GLsizei *length, GLint *size,
644 GLenum *type, GLchar *nameOut)
645{
Brian65a18442006-12-19 18:46:56 -0700646 struct gl_shader_program *shProg
647 = _mesa_lookup_shader_program(ctx, program);
Brian274ac7a2007-04-18 16:05:53 -0600648 GLuint ind, j;
Brian5b01c5e2006-12-19 18:02:03 -0700649
Brian65a18442006-12-19 18:46:56 -0700650 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700651 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform");
Brian5b01c5e2006-12-19 18:02:03 -0700652 return;
653 }
654
Brian65a18442006-12-19 18:46:56 -0700655 if (!shProg->Uniforms || index >= shProg->Uniforms->NumParameters) {
Brian5b01c5e2006-12-19 18:02:03 -0700656 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
657 return;
658 }
659
Brian274ac7a2007-04-18 16:05:53 -0600660 ind = 0;
661 for (j = 0; j < shProg->Uniforms->NumParameters; j++) {
662 if (shProg->Uniforms->Parameters[j].Type == PROGRAM_UNIFORM ||
663 shProg->Uniforms->Parameters[j].Type == PROGRAM_SAMPLER) {
664 if (ind == index) {
665 /* found it */
666 copy_string(nameOut, maxLength, length,
667 shProg->Uniforms->Parameters[j].Name);
Brian274ac7a2007-04-18 16:05:53 -0600668 if (size)
Brianc93e8832007-04-18 16:27:35 -0600669 *size = shProg->Uniforms->Parameters[j].Size;
Brian274ac7a2007-04-18 16:05:53 -0600670 if (type)
Brianc93e8832007-04-18 16:27:35 -0600671 *type = shProg->Uniforms->Parameters[j].DataType;
Brian274ac7a2007-04-18 16:05:53 -0600672 return;
673 }
674 ind++;
675 }
676 }
677
678 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700679}
680
681
682/**
683 * Called via ctx->Driver.GetAttachedShaders().
684 */
685void
686_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
687 GLsizei *count, GLuint *obj)
688{
Brian65a18442006-12-19 18:46:56 -0700689 struct gl_shader_program *shProg
690 = _mesa_lookup_shader_program(ctx, program);
691 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700692 GLint i;
Brian65a18442006-12-19 18:46:56 -0700693 for (i = 0; i < maxCount && i < shProg->NumShaders; i++) {
694 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700695 }
696 if (count)
697 *count = i;
698 }
699 else {
Brian43975832007-01-04 08:21:09 -0700700 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttachedShaders");
Brian5b01c5e2006-12-19 18:02:03 -0700701 }
702}
703
704
705GLint
706_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
707 const GLchar *name)
708{
Brian65a18442006-12-19 18:46:56 -0700709 struct gl_shader_program *shProg
710 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700711
Brian65a18442006-12-19 18:46:56 -0700712 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700713 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttribLocation");
Brian5b01c5e2006-12-19 18:02:03 -0700714 return -1;
715 }
716
Brian65a18442006-12-19 18:46:56 -0700717 if (!shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -0700718 _mesa_error(ctx, GL_INVALID_OPERATION,
719 "glGetAttribLocation(program not linked)");
720 return -1;
721 }
722
723 if (!name)
724 return -1;
725
Brian65a18442006-12-19 18:46:56 -0700726 if (shProg->Attributes) {
Brian3209c3e2007-01-09 17:49:24 -0700727 GLint i = _mesa_lookup_parameter_index(shProg->Attributes, -1, name);
728 if (i >= 0) {
Brian01a91eb2007-01-09 19:26:22 -0700729 return shProg->Attributes->Parameters[i].StateIndexes[0];
Brian5b01c5e2006-12-19 18:02:03 -0700730 }
731 }
732 return -1;
733}
734
735
736GLuint
737_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700738{
739#if 0
740 GET_CURRENT_CONTEXT(ctx);
741
742 switch (pname) {
743 case GL_PROGRAM_OBJECT_ARB:
744 {
Brian5b01c5e2006-12-19 18:02:03 -0700745 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700746
747 if (pro != NULL)
748 return (**pro)._container._generic.
749 GetName((struct gl2_generic_intf **) (pro));
750 }
751 break;
752 default:
753 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
754 }
755#endif
756 return 0;
757}
758
759
Brian5b01c5e2006-12-19 18:02:03 -0700760void
761_mesa_get_programiv(GLcontext *ctx, GLuint program,
762 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700763{
Brian65a18442006-12-19 18:46:56 -0700764 struct gl_shader_program *shProg
765 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700766
Brian65a18442006-12-19 18:46:56 -0700767 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700768 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700769 return;
770 }
771
Brian5b01c5e2006-12-19 18:02:03 -0700772 switch (pname) {
773 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700774 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700775 break;
776 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700777 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700778 break;
Brian5b01c5e2006-12-19 18:02:03 -0700779 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700780 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700781 break;
782 case GL_INFO_LOG_LENGTH:
Brian65a18442006-12-19 18:46:56 -0700783 *params = shProg->InfoLog ? strlen(shProg->InfoLog) : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700784 break;
785 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700786 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700787 break;
788 case GL_ACTIVE_ATTRIBUTES:
Brian3209c3e2007-01-09 17:49:24 -0700789 *params = shProg->Attributes ? shProg->Attributes->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700790 break;
791 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600792 *params = _mesa_longest_parameter_name(shProg->Attributes,
793 PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700794 break;
795 case GL_ACTIVE_UNIFORMS:
Brian274ac7a2007-04-18 16:05:53 -0600796 *params
797 = _mesa_num_parameters_of_type(shProg->Uniforms, PROGRAM_UNIFORM)
798 + _mesa_num_parameters_of_type(shProg->Uniforms, PROGRAM_SAMPLER);
Brian5b01c5e2006-12-19 18:02:03 -0700799 break;
800 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600801 *params = MAX2(
802 _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_UNIFORM),
803 _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_SAMPLER));
804 if (*params > 0)
805 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700806 break;
807 default:
Brian5b01c5e2006-12-19 18:02:03 -0700808 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
809 return;
Brian34ae99d2006-12-18 08:28:54 -0700810 }
Brian5b01c5e2006-12-19 18:02:03 -0700811}
Brian34ae99d2006-12-18 08:28:54 -0700812
Brian34ae99d2006-12-18 08:28:54 -0700813
Brian5b01c5e2006-12-19 18:02:03 -0700814void
815_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
816{
Brian65a18442006-12-19 18:46:56 -0700817 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700818
819 if (!shader) {
820 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderiv(shader)");
821 return;
822 }
Brian65a18442006-12-19 18:46:56 -0700823
Brian5b01c5e2006-12-19 18:02:03 -0700824 switch (pname) {
825 case GL_SHADER_TYPE:
826 *params = shader->Type;
827 break;
828 case GL_DELETE_STATUS:
829 *params = shader->DeletePending;
830 break;
831 case GL_COMPILE_STATUS:
832 *params = shader->CompileStatus;
833 break;
834 case GL_INFO_LOG_LENGTH:
835 *params = shader->InfoLog ? strlen(shader->InfoLog) : 0;
836 break;
837 case GL_SHADER_SOURCE_LENGTH:
838 *params = shader->Source ? strlen((char *) shader->Source) : 0;
839 break;
840 default:
841 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
842 return;
843 }
844}
845
846
847void
848_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
849 GLsizei *length, GLchar *infoLog)
850{
Brian65a18442006-12-19 18:46:56 -0700851 struct gl_shader_program *shProg
852 = _mesa_lookup_shader_program(ctx, program);
853 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700854 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
855 return;
856 }
Brian65a18442006-12-19 18:46:56 -0700857 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700858}
859
860
861void
862_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
863 GLsizei *length, GLchar *infoLog)
864{
Brian65a18442006-12-19 18:46:56 -0700865 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
866 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700867 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
868 return;
869 }
Brian65a18442006-12-19 18:46:56 -0700870 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700871}
872
873
874/**
875 * Called via ctx->Driver.GetShaderSource().
876 */
877void
878_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
879 GLsizei *length, GLchar *sourceOut)
880{
Brian65a18442006-12-19 18:46:56 -0700881 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
882 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700883 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderSource(shader)");
884 return;
885 }
Brian65a18442006-12-19 18:46:56 -0700886 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -0700887}
888
889
890/**
891 * Called via ctx->Driver.GetUniformfv().
892 */
893void
894_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
895 GLfloat *params)
896{
Brian65a18442006-12-19 18:46:56 -0700897 struct gl_shader_program *shProg
898 = _mesa_lookup_shader_program(ctx, program);
899 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700900 GLint i;
Brian65a18442006-12-19 18:46:56 -0700901 if (location >= 0 && location < shProg->Uniforms->NumParameters) {
902 for (i = 0; i < shProg->Uniforms->Parameters[location].Size; i++) {
903 params[i] = shProg->Uniforms->ParameterValues[location][i];
Brian5b01c5e2006-12-19 18:02:03 -0700904 }
905 }
906 else {
907 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(location)");
908 }
909 }
910 else {
Brian43975832007-01-04 08:21:09 -0700911 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700912 }
913}
914
915
916/**
917 * Called via ctx->Driver.GetUniformLocation().
918 */
919GLint
920_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
921{
Brian71623982007-01-30 16:55:03 -0700922 struct gl_shader_program *shProg
923 = _mesa_lookup_shader_program(ctx, program);
924 if (shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700925 GLuint loc;
Brian65a18442006-12-19 18:46:56 -0700926 for (loc = 0; loc < shProg->Uniforms->NumParameters; loc++) {
Brian5b01c5e2006-12-19 18:02:03 -0700927 const struct gl_program_parameter *u
Brian65a18442006-12-19 18:46:56 -0700928 = shProg->Uniforms->Parameters + loc;
Brian29053852006-12-21 11:21:26 -0700929 /* XXX this is a temporary simplification / short-cut.
930 * We need to handle things like "e.c[0].b" as seen in the
931 * GLSL orange book, page 189.
932 */
Brian5cf73262007-01-05 16:02:45 -0700933 if ((u->Type == PROGRAM_UNIFORM ||
934 u->Type == PROGRAM_SAMPLER) && !strcmp(u->Name, name)) {
Brian5b01c5e2006-12-19 18:02:03 -0700935 return loc;
936 }
937 }
938 }
939 return -1;
940
941}
942
943
944GLboolean
945_mesa_is_program(GLcontext *ctx, GLuint name)
946{
Brian65a18442006-12-19 18:46:56 -0700947 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
948 return shProg ? GL_TRUE : GL_FALSE;
Brian5b01c5e2006-12-19 18:02:03 -0700949}
950
951
952GLboolean
953_mesa_is_shader(GLcontext *ctx, GLuint name)
954{
Brian65a18442006-12-19 18:46:56 -0700955 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700956 return shader ? GL_TRUE : GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700957}
958
959
960
Brian5b01c5e2006-12-19 18:02:03 -0700961/**
962 * Called via ctx->Driver.ShaderSource()
963 */
964void
965_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -0700966{
Brian65a18442006-12-19 18:46:56 -0700967 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
968 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700969 _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSource(shaderObj)");
Brian34ae99d2006-12-18 08:28:54 -0700970 return;
971 }
972
Brian34ae99d2006-12-18 08:28:54 -0700973 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -0700974 if (sh->Source) {
975 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -0700976 }
Brian65a18442006-12-19 18:46:56 -0700977 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -0700978 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700979}
980
981
Brian5b01c5e2006-12-19 18:02:03 -0700982/**
983 * Called via ctx->Driver.CompileShader()
984 */
985void
986_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -0700987{
Brian65a18442006-12-19 18:46:56 -0700988 struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj);
Brian34ae99d2006-12-18 08:28:54 -0700989
Brian65a18442006-12-19 18:46:56 -0700990 if (!sh) {
Brian34ae99d2006-12-18 08:28:54 -0700991 _mesa_error(ctx, GL_INVALID_VALUE, "glCompileShader(shaderObj)");
992 return;
993 }
994
Brian43975832007-01-04 08:21:09 -0700995 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -0700996}
997
998
Brian5b01c5e2006-12-19 18:02:03 -0700999/**
1000 * Called via ctx->Driver.LinkProgram()
1001 */
1002void
1003_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001004{
Brian65a18442006-12-19 18:46:56 -07001005 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001006
Brian65a18442006-12-19 18:46:56 -07001007 shProg = _mesa_lookup_shader_program(ctx, program);
1008 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001009 _mesa_error(ctx, GL_INVALID_VALUE, "glLinkProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001010 return;
1011 }
1012
Brianc1771912007-02-16 09:56:19 -07001013 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001014}
1015
1016
1017/**
Brian5b01c5e2006-12-19 18:02:03 -07001018 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001019 */
Brian5b01c5e2006-12-19 18:02:03 -07001020void
1021_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001022{
Brian3c008a02007-04-12 15:22:32 -06001023 struct gl_shader_program *shProg;
1024
Brian00d63aa2007-02-03 11:35:02 -07001025 if (ctx->Shader.CurrentProgram &&
1026 ctx->Shader.CurrentProgram->Name == program) {
1027 /* no-op */
1028 return;
1029 }
1030
1031 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1032
Brian5b01c5e2006-12-19 18:02:03 -07001033 if (program) {
Brian65a18442006-12-19 18:46:56 -07001034 shProg = _mesa_lookup_shader_program(ctx, program);
1035 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001036 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -07001037 "glUseProgramObjectARB(programObj)");
1038 return;
1039 }
Brian5b01c5e2006-12-19 18:02:03 -07001040 }
1041 else {
Brian3c008a02007-04-12 15:22:32 -06001042 shProg = NULL;
1043 }
1044
1045 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001046}
Brian34ae99d2006-12-18 08:28:54 -07001047
Brian5b01c5e2006-12-19 18:02:03 -07001048
1049/**
1050 * Called via ctx->Driver.Uniform().
1051 */
1052void
1053_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1054 const GLvoid *values, GLenum type)
1055{
Brian3a8e2772006-12-20 17:19:16 -07001056 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian98650bd2007-03-13 16:32:48 -06001057 GLint elems, i, k;
Brian3a8e2772006-12-20 17:19:16 -07001058
1059 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001060 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001061 return;
1062 }
1063
Brian223d7cb2007-01-23 16:37:51 -07001064 if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) {
Brian3a8e2772006-12-20 17:19:16 -07001065 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
1066 return;
1067 }
1068
1069 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1070
Brianfee9bbe2007-02-02 18:05:43 -07001071 /*
1072 * If we're setting a sampler, we must use glUniformi1()!
1073 */
1074 if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
1075 if (type != GL_INT || count != 1) {
1076 _mesa_error(ctx, GL_INVALID_OPERATION,
1077 "glUniform(only glUniform1i can be used "
1078 "to set sampler uniforms)");
1079 return;
1080 }
1081 }
1082
Brian52363952007-03-13 16:50:24 -06001083 if (count < 0) {
1084 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1085 return;
1086 }
1087
Brian98650bd2007-03-13 16:32:48 -06001088 switch (type) {
1089 case GL_FLOAT:
1090 case GL_INT:
1091 elems = 1;
1092 break;
1093 case GL_FLOAT_VEC2:
1094 case GL_INT_VEC2:
1095 elems = 2;
1096 break;
1097 case GL_FLOAT_VEC3:
1098 case GL_INT_VEC3:
1099 elems = 3;
1100 break;
1101 case GL_FLOAT_VEC4:
1102 case GL_INT_VEC4:
1103 elems = 4;
1104 break;
1105 default:
1106 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1107 return;
Brian89dc4852007-01-04 14:35:44 -07001108 }
Brian98650bd2007-03-13 16:32:48 -06001109
1110 if (count * elems > shProg->Uniforms->Parameters[location].Size) {
1111 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1112 return;
1113 }
1114
1115 for (k = 0; k < count; k++) {
1116 GLfloat *uniformVal = shProg->Uniforms->ParameterValues[location + k];
1117 if (type == GL_INT ||
1118 type == GL_INT_VEC2 ||
1119 type == GL_INT_VEC3 ||
1120 type == GL_INT_VEC4) {
Brian52363952007-03-13 16:50:24 -06001121 const GLint *iValues = ((const GLint *) values) + k * elems;
Brian98650bd2007-03-13 16:32:48 -06001122 for (i = 0; i < elems; i++) {
1123 uniformVal[i] = (GLfloat) iValues[i];
1124 }
1125 }
1126 else {
Brian52363952007-03-13 16:50:24 -06001127 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
Brian98650bd2007-03-13 16:32:48 -06001128 for (i = 0; i < elems; i++) {
1129 uniformVal[i] = fValues[i];
1130 }
Brian89dc4852007-01-04 14:35:44 -07001131 }
Brian5b01c5e2006-12-19 18:02:03 -07001132 }
Brian5cf73262007-01-05 16:02:45 -07001133
1134 if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
Briancec81ee2007-03-07 08:04:06 -07001135 if (shProg->VertexProgram)
1136 _slang_resolve_samplers(shProg, &shProg->VertexProgram->Base);
1137 if (shProg->FragmentProgram)
1138 _slang_resolve_samplers(shProg, &shProg->FragmentProgram->Base);
Brian5cf73262007-01-05 16:02:45 -07001139 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1140 }
Brian34ae99d2006-12-18 08:28:54 -07001141}
1142
1143
1144/**
Brian5b01c5e2006-12-19 18:02:03 -07001145 * Called by ctx->Driver.UniformMatrix().
Brian34ae99d2006-12-18 08:28:54 -07001146 */
Brian5b01c5e2006-12-19 18:02:03 -07001147void
1148_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1149 GLenum matrixType, GLint location, GLsizei count,
1150 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001151{
Brian3a8e2772006-12-20 17:19:16 -07001152 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
1153 if (!shProg || !shProg->LinkStatus) {
1154 _mesa_error(ctx, GL_INVALID_OPERATION,
1155 "glUniformMatrix(program not linked)");
1156 return;
1157 }
1158 if (location < 0 || location >= shProg->Uniforms->NumParameters) {
1159 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
1160 return;
1161 }
Brian34ae99d2006-12-18 08:28:54 -07001162 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001163 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001164 return;
1165 }
1166
1167 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1168
Brian3a8e2772006-12-20 17:19:16 -07001169 /*
1170 * Note: the _columns_ of a matrix are stored in program registers, not
1171 * the rows.
1172 */
1173 /* XXXX need to test 3x3 and 2x2 matrices... */
Brian34ae99d2006-12-18 08:28:54 -07001174 if (transpose) {
Brian3a8e2772006-12-20 17:19:16 -07001175 GLuint row, col;
1176 for (col = 0; col < cols; col++) {
1177 GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
1178 for (row = 0; row < rows; row++) {
Brian9f442472007-03-09 11:34:18 -07001179 v[row] = values[row * cols + col];
Brian34ae99d2006-12-18 08:28:54 -07001180 }
Brian34ae99d2006-12-18 08:28:54 -07001181 }
Brian34ae99d2006-12-18 08:28:54 -07001182 }
1183 else {
Brian3a8e2772006-12-20 17:19:16 -07001184 GLuint row, col;
1185 for (col = 0; col < cols; col++) {
1186 GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
1187 for (row = 0; row < rows; row++) {
Brian9f442472007-03-09 11:34:18 -07001188 v[row] = values[col * rows + row];
Brian3a8e2772006-12-20 17:19:16 -07001189 }
1190 }
Brian34ae99d2006-12-18 08:28:54 -07001191 }
1192}
1193
1194
Brian5b01c5e2006-12-19 18:02:03 -07001195void
1196_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001197{
Brian65a18442006-12-19 18:46:56 -07001198 struct gl_shader_program *shProg;
1199 shProg = _mesa_lookup_shader_program(ctx, program);
1200 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001201 _mesa_error(ctx, GL_INVALID_VALUE, "glValidateProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001202 return;
1203 }
Brian5b01c5e2006-12-19 18:02:03 -07001204 /* XXX temporary */
Brian65a18442006-12-19 18:46:56 -07001205 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001206
Brian5b01c5e2006-12-19 18:02:03 -07001207 /* From the GL spec:
1208 any two active samplers in the current program object are of
1209 different types, but refer to the same texture image unit,
1210
1211 any active sampler in the current program object refers to a texture
1212 image unit where fixed-function fragment processing accesses a
1213 texture target that does not match the sampler type, or
1214
1215 the sum of the number of active samplers in the program and the
1216 number of texture image units enabled for fixed-function fragment
1217 processing exceeds the combined limit on the total number of texture
1218 image units allowed.
1219 */
Brian34ae99d2006-12-18 08:28:54 -07001220}