blob: a1e73ef125c71343a9f9b62c3c560b00f5fc80c3 [file] [log] [blame]
Brian34ae99d2006-12-18 08:28:54 -07001/*
2 * Mesa 3-D graphics library
Brian3e4302f2007-05-09 08:04:32 -06003 * Version: 7.0
Brian34ae99d2006-12-18 08:28:54 -07004 *
Brian5b01c5e2006-12-19 18:02:03 -07005 * Copyright (C) 2004-2007 Brian Paul All Rights Reserved.
Brian34ae99d2006-12-18 08:28:54 -07006 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25/**
26 * \file shader_api.c
Brian5b01c5e2006-12-19 18:02:03 -070027 * Implementation of GLSL-related API functions
Brian34ae99d2006-12-18 08:28:54 -070028 * \author Brian Paul
29 */
30
31/**
32 * XXX things to do:
33 * 1. Check that the right error code is generated for all _mesa_error() calls.
Brian5b01c5e2006-12-19 18:02:03 -070034 * 2. Insert FLUSH_VERTICES calls in various places
Brian34ae99d2006-12-18 08:28:54 -070035 */
36
37
38#include "glheader.h"
39#include "context.h"
40#include "hash.h"
Brian274ac7a2007-04-18 16:05:53 -060041#include "macros.h"
Brian34ae99d2006-12-18 08:28:54 -070042#include "program.h"
43#include "prog_parameter.h"
Brian3209c3e2007-01-09 17:49:24 -070044#include "prog_print.h"
45#include "prog_statevars.h"
Brianc223c6b2007-07-04 13:15:20 -060046#include "shader/shader_api.h"
47#include "shader/slang/slang_compile.h"
48#include "shader/slang/slang_link.h"
Brian34ae99d2006-12-18 08:28:54 -070049
50
51
Brianf2923612006-12-20 09:56:44 -070052/**
53 * Allocate a new gl_shader_program object, initialize it.
54 */
55struct gl_shader_program *
56_mesa_new_shader_program(GLcontext *ctx, GLuint name)
57{
58 struct gl_shader_program *shProg;
59 shProg = CALLOC_STRUCT(gl_shader_program);
60 if (shProg) {
Brianf3e8c322007-04-18 14:53:23 -060061 shProg->Type = GL_SHADER_PROGRAM_MESA;
Brianf2923612006-12-20 09:56:44 -070062 shProg->Name = name;
63 shProg->RefCount = 1;
Brian3209c3e2007-01-09 17:49:24 -070064 shProg->Attributes = _mesa_new_parameter_list();
Brianf2923612006-12-20 09:56:44 -070065 }
66 return shProg;
67}
68
69
Brianb9fbedd2007-03-26 09:23:44 -060070/**
Brian3c008a02007-04-12 15:22:32 -060071 * Clear (free) the shader program state that gets produced by linking.
Brianb9fbedd2007-03-26 09:23:44 -060072 */
Brianf2923612006-12-20 09:56:44 -070073void
Brian3c008a02007-04-12 15:22:32 -060074_mesa_clear_shader_program_data(GLcontext *ctx,
75 struct gl_shader_program *shProg)
Brianf2923612006-12-20 09:56:44 -070076{
Brianf2923612006-12-20 09:56:44 -070077 if (shProg->VertexProgram) {
78 if (shProg->VertexProgram->Base.Parameters == shProg->Uniforms) {
79 /* to prevent a double-free in the next call */
80 shProg->VertexProgram->Base.Parameters = NULL;
81 }
82 _mesa_delete_program(ctx, &shProg->VertexProgram->Base);
83 shProg->VertexProgram = NULL;
84 }
85
86 if (shProg->FragmentProgram) {
87 if (shProg->FragmentProgram->Base.Parameters == shProg->Uniforms) {
88 /* to prevent a double-free in the next call */
89 shProg->FragmentProgram->Base.Parameters = NULL;
90 }
91 _mesa_delete_program(ctx, &shProg->FragmentProgram->Base);
92 shProg->FragmentProgram = NULL;
93 }
94
Brianf2923612006-12-20 09:56:44 -070095 if (shProg->Uniforms) {
96 _mesa_free_parameter_list(shProg->Uniforms);
97 shProg->Uniforms = NULL;
98 }
99
100 if (shProg->Varying) {
101 _mesa_free_parameter_list(shProg->Varying);
102 shProg->Varying = NULL;
103 }
104}
105
106
Brianb9fbedd2007-03-26 09:23:44 -0600107/**
Brian3c008a02007-04-12 15:22:32 -0600108 * Free all the data that hangs off a shader program object, but not the
109 * object itself.
110 */
111void
112_mesa_free_shader_program_data(GLcontext *ctx,
113 struct gl_shader_program *shProg)
114{
115 GLuint i;
116
Brianf3e8c322007-04-18 14:53:23 -0600117 assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
Brian3c008a02007-04-12 15:22:32 -0600118
119 _mesa_clear_shader_program_data(ctx, shProg);
120
Brian4b7c6fc2007-04-19 15:23:34 -0600121 if (shProg->Attributes) {
122 _mesa_free_parameter_list(shProg->Attributes);
123 shProg->Attributes = NULL;
124 }
125
Brian3c008a02007-04-12 15:22:32 -0600126 /* detach shaders */
127 for (i = 0; i < shProg->NumShaders; i++) {
128 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
129 }
130 if (shProg->Shaders) {
131 _mesa_free(shProg->Shaders);
132 shProg->Shaders = NULL;
133 }
134}
135
136
137/**
Brianb9fbedd2007-03-26 09:23:44 -0600138 * Free/delete a shader program object.
139 */
Brianf2923612006-12-20 09:56:44 -0700140void
141_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg)
142{
143 _mesa_free_shader_program_data(ctx, shProg);
Brianb9fbedd2007-03-26 09:23:44 -0600144 if (shProg->Shaders) {
145 _mesa_free(shProg->Shaders);
146 shProg->Shaders = NULL;
147 }
Brianf2923612006-12-20 09:56:44 -0700148 _mesa_free(shProg);
149}
150
151
152/**
Brian3c008a02007-04-12 15:22:32 -0600153 * Set ptr to point to shProg.
154 * If ptr is pointing to another object, decrement its refcount (and delete
155 * if refcount hits zero).
156 * Then set ptr to point to shProg, incrementing its refcount.
157 */
158/* XXX this could be static */
159void
160_mesa_reference_shader_program(GLcontext *ctx,
161 struct gl_shader_program **ptr,
162 struct gl_shader_program *shProg)
163{
164 assert(ptr);
165 if (*ptr == shProg) {
166 /* no-op */
167 return;
168 }
169 if (*ptr) {
170 /* Unreference the old shader program */
171 GLboolean deleteFlag = GL_FALSE;
172 struct gl_shader_program *old = *ptr;
173
174 ASSERT(old->RefCount > 0);
175 old->RefCount--;
176 /*printf("SHPROG DECR %p (%d) to %d\n",
177 (void*) old, old->Name, old->RefCount);*/
178 deleteFlag = (old->RefCount == 0);
179
180 if (deleteFlag) {
181 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
182 _mesa_free_shader_program(ctx, old);
183 }
184
185 *ptr = NULL;
186 }
187 assert(!*ptr);
188
189 if (shProg) {
190 shProg->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600191 /*printf("SHPROG INCR %p (%d) to %d\n",
192 (void*) shProg, shProg->Name, shProg->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600193 *ptr = shProg;
194 }
195}
196
197
198/**
Brianf2923612006-12-20 09:56:44 -0700199 * Lookup a GLSL program object.
200 */
201struct gl_shader_program *
202_mesa_lookup_shader_program(GLcontext *ctx, GLuint name)
203{
204 struct gl_shader_program *shProg;
205 if (name) {
206 shProg = (struct gl_shader_program *)
207 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
208 /* Note that both gl_shader and gl_shader_program objects are kept
209 * in the same hash table. Check the object's type to be sure it's
210 * what we're expecting.
211 */
Brianf3e8c322007-04-18 14:53:23 -0600212 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700213 return NULL;
214 }
215 return shProg;
216 }
217 return NULL;
218}
219
220
221/**
222 * Allocate a new gl_shader object, initialize it.
223 */
224struct gl_shader *
225_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
226{
227 struct gl_shader *shader;
228 assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
229 shader = CALLOC_STRUCT(gl_shader);
230 if (shader) {
231 shader->Type = type;
232 shader->Name = name;
233 shader->RefCount = 1;
234 }
235 return shader;
236}
237
238
239void
240_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh)
241{
242 GLuint i;
243 if (sh->Source)
244 _mesa_free((void *) sh->Source);
245 if (sh->InfoLog)
246 _mesa_free(sh->InfoLog);
247 for (i = 0; i < sh->NumPrograms; i++) {
248 assert(sh->Programs[i]);
249 _mesa_delete_program(ctx, sh->Programs[i]);
250 }
251 if (sh->Programs)
252 _mesa_free(sh->Programs);
253 _mesa_free(sh);
254}
255
256
257/**
Brian3c008a02007-04-12 15:22:32 -0600258 * Set ptr to point to sh.
259 * If ptr is pointing to another shader, decrement its refcount (and delete
260 * if refcount hits zero).
261 * Then set ptr to point to sh, incrementing its refcount.
262 */
263/* XXX this could be static */
264void
265_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr,
266 struct gl_shader *sh)
267{
268 assert(ptr);
269 if (*ptr == sh) {
270 /* no-op */
271 return;
272 }
273 if (*ptr) {
274 /* Unreference the old shader */
275 GLboolean deleteFlag = GL_FALSE;
276 struct gl_shader *old = *ptr;
277
278 ASSERT(old->RefCount > 0);
279 old->RefCount--;
Brian99193e42007-04-12 15:45:02 -0600280 /*printf("SHADER DECR %p (%d) to %d\n",
281 (void*) old, old->Name, old->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600282 deleteFlag = (old->RefCount == 0);
283
284 if (deleteFlag) {
285 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
286 _mesa_free_shader(ctx, old);
287 }
288
289 *ptr = NULL;
290 }
291 assert(!*ptr);
292
293 if (sh) {
294 /* reference new */
295 sh->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600296 /*printf("SHADER INCR %p (%d) to %d\n",
297 (void*) sh, sh->Name, sh->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600298 *ptr = sh;
299 }
300}
301
302
303/**
Brianf2923612006-12-20 09:56:44 -0700304 * Lookup a GLSL shader object.
305 */
306struct gl_shader *
307_mesa_lookup_shader(GLcontext *ctx, GLuint name)
308{
309 if (name) {
310 struct gl_shader *sh = (struct gl_shader *)
311 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
312 /* Note that both gl_shader and gl_shader_program objects are kept
313 * in the same hash table. Check the object's type to be sure it's
314 * what we're expecting.
315 */
Brianf3e8c322007-04-18 14:53:23 -0600316 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700317 return NULL;
318 }
319 return sh;
320 }
321 return NULL;
322}
323
324
Brianfa4d0362007-02-26 18:33:50 -0700325/**
326 * Initialize context's shader state.
327 */
Brianf2923612006-12-20 09:56:44 -0700328void
329_mesa_init_shader_state(GLcontext * ctx)
330{
Brianfa4d0362007-02-26 18:33:50 -0700331 /* Device drivers may override these to control what kind of instructions
332 * are generated by the GLSL compiler.
333 */
334 ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
Brian63556fa2007-03-23 14:47:46 -0600335 ctx->Shader.EmitCondCodes = GL_TRUE; /* XXX probably want GL_FALSE... */
Brianfa4d0362007-02-26 18:33:50 -0700336 ctx->Shader.EmitComments = GL_FALSE;
Brianf2923612006-12-20 09:56:44 -0700337}
338
339
Brian5b01c5e2006-12-19 18:02:03 -0700340/**
Brian935f93f2007-03-24 16:20:02 -0600341 * Free the per-context shader-related state.
342 */
343void
344_mesa_free_shader_state(GLcontext *ctx)
345{
Brian3c008a02007-04-12 15:22:32 -0600346 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
Brian935f93f2007-03-24 16:20:02 -0600347}
348
349
350/**
Brian5b01c5e2006-12-19 18:02:03 -0700351 * Copy string from <src> to <dst>, up to maxLength characters, returning
352 * length of <dst> in <length>.
353 * \param src the strings source
354 * \param maxLength max chars to copy
355 * \param length returns number of chars copied
356 * \param dst the string destination
357 */
358static void
359copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
360{
361 GLsizei len;
362 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
363 dst[len] = src[len];
364 if (maxLength > 0)
365 dst[len] = 0;
366 if (length)
367 *length = len;
368}
369
370
Brian5b01c5e2006-12-19 18:02:03 -0700371/**
372 * Called via ctx->Driver.AttachShader()
373 */
374void
375_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
376{
Brian65a18442006-12-19 18:46:56 -0700377 struct gl_shader_program *shProg
378 = _mesa_lookup_shader_program(ctx, program);
379 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
Brian237b9852007-08-07 21:48:31 +0100380 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700381 GLuint i;
382
Brian65a18442006-12-19 18:46:56 -0700383 if (!shProg || !sh) {
Brian43975832007-01-04 08:21:09 -0700384 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700385 "glAttachShader(bad program or shader name)");
386 return;
387 }
388
Brian237b9852007-08-07 21:48:31 +0100389 n = shProg->NumShaders;
390
Brian5b01c5e2006-12-19 18:02:03 -0700391 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700392 if (shProg->Shaders[i] == sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700393 /* already attached */
394 return;
Brian34ae99d2006-12-18 08:28:54 -0700395 }
396 }
Brian5b01c5e2006-12-19 18:02:03 -0700397
398 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700399 shProg->Shaders = (struct gl_shader **)
400 _mesa_realloc(shProg->Shaders,
401 n * sizeof(struct gl_shader *),
402 (n + 1) * sizeof(struct gl_shader *));
403 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700404 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
405 return;
406 }
407
408 /* append */
Brian3c008a02007-04-12 15:22:32 -0600409 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
410 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700411 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700412}
413
414
415void
416_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
417 const GLchar *name)
418{
Brian65a18442006-12-19 18:46:56 -0700419 struct gl_shader_program *shProg
420 = _mesa_lookup_shader_program(ctx, program);
Brianb7978af2007-01-09 19:17:17 -0700421 const GLint size = -1; /* unknown size */
422 GLint i, oldIndex;
Brian5b01c5e2006-12-19 18:02:03 -0700423
Brian65a18442006-12-19 18:46:56 -0700424 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700425 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700426 return;
427 }
428
Brian9e4bae92006-12-20 09:27:42 -0700429 if (!name)
430 return;
431
432 if (strncmp(name, "gl_", 3) == 0) {
433 _mesa_error(ctx, GL_INVALID_OPERATION,
434 "glBindAttribLocation(illegal name)");
435 return;
436 }
437
Brian9f660252007-04-11 09:00:56 -0600438 if (shProg->LinkStatus) {
439 /* get current index/location for the attribute */
440 oldIndex = _mesa_get_attrib_location(ctx, program, name);
441 }
442 else {
443 oldIndex = -1;
444 }
Brian3209c3e2007-01-09 17:49:24 -0700445
446 /* this will replace the current value if it's already in the list */
Brianb7978af2007-01-09 19:17:17 -0700447 i = _mesa_add_attribute(shProg->Attributes, name, size, index);
Brian3209c3e2007-01-09 17:49:24 -0700448 if (i < 0) {
449 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
450 }
451
Brian9f660252007-04-11 09:00:56 -0600452 if (shProg->VertexProgram && oldIndex >= 0 && oldIndex != index) {
453 /* If the index changed, need to search/replace references to that attribute
454 * in the vertex program.
455 */
Brian3209c3e2007-01-09 17:49:24 -0700456 _slang_remap_attribute(&shProg->VertexProgram->Base, oldIndex, index);
457 }
Brian34ae99d2006-12-18 08:28:54 -0700458}
459
460
Brian5b01c5e2006-12-19 18:02:03 -0700461GLuint
462_mesa_create_shader(GLcontext *ctx, GLenum type)
463{
Brian65a18442006-12-19 18:46:56 -0700464 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700465 GLuint name;
466
467 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
468
469 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700470 case GL_FRAGMENT_SHADER:
471 case GL_VERTEX_SHADER:
472 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700473 break;
474 default:
475 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
476 return 0;
477 }
478
Brian65a18442006-12-19 18:46:56 -0700479 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700480
481 return name;
482}
483
484
485GLuint
486_mesa_create_program(GLcontext *ctx)
487{
488 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700489 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700490
Brian65a18442006-12-19 18:46:56 -0700491 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
492 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700493
Brian65a18442006-12-19 18:46:56 -0700494 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700495
Brian3c008a02007-04-12 15:22:32 -0600496 assert(shProg->RefCount == 1);
497
Brian5b01c5e2006-12-19 18:02:03 -0700498 return name;
499}
500
501
Brian3c008a02007-04-12 15:22:32 -0600502/**
503 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
504 * DeleteProgramARB.
505 */
Brian5b01c5e2006-12-19 18:02:03 -0700506void
507_mesa_delete_program2(GLcontext *ctx, GLuint name)
508{
Brian3c008a02007-04-12 15:22:32 -0600509 /*
510 * NOTE: deleting shaders/programs works a bit differently than
511 * texture objects (and buffer objects, etc). Shader/program
512 * handles/IDs exist in the hash table until the object is really
513 * deleted (refcount==0). With texture objects, the handle/ID is
514 * removed from the hash table in glDeleteTextures() while the tex
515 * object itself might linger until its refcount goes to zero.
516 */
Brian65a18442006-12-19 18:46:56 -0700517 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700518
Brian65a18442006-12-19 18:46:56 -0700519 shProg = _mesa_lookup_shader_program(ctx, name);
520 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700521 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteProgram(name)");
Brian5b01c5e2006-12-19 18:02:03 -0700522 return;
523 }
524
Brian9e4bae92006-12-20 09:27:42 -0700525 shProg->DeletePending = GL_TRUE;
526
Brian3c008a02007-04-12 15:22:32 -0600527 /* effectively, decr shProg's refcount */
528 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700529}
530
531
532void
533_mesa_delete_shader(GLcontext *ctx, GLuint shader)
534{
Brian9e4bae92006-12-20 09:27:42 -0700535 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
536 if (!sh) {
537 return;
538 }
Brian5b01c5e2006-12-19 18:02:03 -0700539
Brian9e4bae92006-12-20 09:27:42 -0700540 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600541
542 /* effectively, decr sh's refcount */
543 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700544}
545
546
547void
548_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
549{
Brian65a18442006-12-19 18:46:56 -0700550 struct gl_shader_program *shProg
551 = _mesa_lookup_shader_program(ctx, program);
Brian237b9852007-08-07 21:48:31 +0100552 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700553 GLuint i, j;
554
Brian65a18442006-12-19 18:46:56 -0700555 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700556 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700557 "glDetachShader(bad program or shader name)");
558 return;
559 }
560
Brian237b9852007-08-07 21:48:31 +0100561 n = shProg->NumShaders;
562
Brian5b01c5e2006-12-19 18:02:03 -0700563 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700564 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700565 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600566 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700567
Brian3c008a02007-04-12 15:22:32 -0600568 /* derefernce */
569 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700570
Brian5b01c5e2006-12-19 18:02:03 -0700571 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700572 newList = (struct gl_shader **)
573 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700574 if (!newList) {
575 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
576 return;
577 }
578 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700579 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700580 }
581 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700582 newList[j++] = shProg->Shaders[i];
583 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700584
Brian65a18442006-12-19 18:46:56 -0700585 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600586 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600587
588#ifdef DEBUG
589 /* sanity check */
590 {
591 for (j = 0; j < shProg->NumShaders; j++) {
592 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
593 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
594 assert(shProg->Shaders[j]->RefCount > 0);
595 }
596 }
597#endif
598
Brian5b01c5e2006-12-19 18:02:03 -0700599 return;
600 }
601 }
602
603 /* not found */
Brian43975832007-01-04 08:21:09 -0700604 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700605 "glDetachShader(shader not found)");
606}
607
608
609void
610_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
611 GLsizei maxLength, GLsizei *length, GLint *size,
612 GLenum *type, GLchar *nameOut)
613{
614 static const GLenum vec_types[] = {
615 GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4
616 };
Brian65a18442006-12-19 18:46:56 -0700617 struct gl_shader_program *shProg
618 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700619 GLint sz;
620
Brian65a18442006-12-19 18:46:56 -0700621 if (!shProg) {
Brianaaa57412007-04-18 15:22:43 -0600622 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib");
Brian5b01c5e2006-12-19 18:02:03 -0700623 return;
624 }
625
Brian65a18442006-12-19 18:46:56 -0700626 if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600627 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700628 return;
629 }
630
631 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700632 shProg->Attributes->Parameters[index].Name);
633 sz = shProg->Attributes->Parameters[index].Size;
Brian5b01c5e2006-12-19 18:02:03 -0700634 if (size)
635 *size = sz;
636 if (type)
637 *type = vec_types[sz]; /* XXX this is a temporary hack */
638}
639
640
641/**
642 * Called via ctx->Driver.GetActiveUniform().
643 */
644void
645_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
646 GLsizei maxLength, GLsizei *length, GLint *size,
647 GLenum *type, GLchar *nameOut)
648{
Brian65a18442006-12-19 18:46:56 -0700649 struct gl_shader_program *shProg
650 = _mesa_lookup_shader_program(ctx, program);
Brian274ac7a2007-04-18 16:05:53 -0600651 GLuint ind, j;
Brian5b01c5e2006-12-19 18:02:03 -0700652
Brian65a18442006-12-19 18:46:56 -0700653 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700654 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform");
Brian5b01c5e2006-12-19 18:02:03 -0700655 return;
656 }
657
Brian65a18442006-12-19 18:46:56 -0700658 if (!shProg->Uniforms || index >= shProg->Uniforms->NumParameters) {
Brian5b01c5e2006-12-19 18:02:03 -0700659 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
660 return;
661 }
662
Brian274ac7a2007-04-18 16:05:53 -0600663 ind = 0;
664 for (j = 0; j < shProg->Uniforms->NumParameters; j++) {
665 if (shProg->Uniforms->Parameters[j].Type == PROGRAM_UNIFORM ||
666 shProg->Uniforms->Parameters[j].Type == PROGRAM_SAMPLER) {
667 if (ind == index) {
668 /* found it */
669 copy_string(nameOut, maxLength, length,
670 shProg->Uniforms->Parameters[j].Name);
Brian274ac7a2007-04-18 16:05:53 -0600671 if (size)
Brianc93e8832007-04-18 16:27:35 -0600672 *size = shProg->Uniforms->Parameters[j].Size;
Brian274ac7a2007-04-18 16:05:53 -0600673 if (type)
Brianc93e8832007-04-18 16:27:35 -0600674 *type = shProg->Uniforms->Parameters[j].DataType;
Brian274ac7a2007-04-18 16:05:53 -0600675 return;
676 }
677 ind++;
678 }
679 }
680
681 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700682}
683
684
685/**
686 * Called via ctx->Driver.GetAttachedShaders().
687 */
688void
689_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
690 GLsizei *count, GLuint *obj)
691{
Brian65a18442006-12-19 18:46:56 -0700692 struct gl_shader_program *shProg
693 = _mesa_lookup_shader_program(ctx, program);
694 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700695 GLint i;
Brian65a18442006-12-19 18:46:56 -0700696 for (i = 0; i < maxCount && i < shProg->NumShaders; i++) {
697 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700698 }
699 if (count)
700 *count = i;
701 }
702 else {
Brian43975832007-01-04 08:21:09 -0700703 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttachedShaders");
Brian5b01c5e2006-12-19 18:02:03 -0700704 }
705}
706
707
708GLint
709_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
710 const GLchar *name)
711{
Brian65a18442006-12-19 18:46:56 -0700712 struct gl_shader_program *shProg
713 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700714
Brian65a18442006-12-19 18:46:56 -0700715 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700716 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttribLocation");
Brian5b01c5e2006-12-19 18:02:03 -0700717 return -1;
718 }
719
Brian65a18442006-12-19 18:46:56 -0700720 if (!shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -0700721 _mesa_error(ctx, GL_INVALID_OPERATION,
722 "glGetAttribLocation(program not linked)");
723 return -1;
724 }
725
726 if (!name)
727 return -1;
728
Brian65a18442006-12-19 18:46:56 -0700729 if (shProg->Attributes) {
Brian3209c3e2007-01-09 17:49:24 -0700730 GLint i = _mesa_lookup_parameter_index(shProg->Attributes, -1, name);
731 if (i >= 0) {
Brian01a91eb2007-01-09 19:26:22 -0700732 return shProg->Attributes->Parameters[i].StateIndexes[0];
Brian5b01c5e2006-12-19 18:02:03 -0700733 }
734 }
735 return -1;
736}
737
738
739GLuint
740_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700741{
742#if 0
743 GET_CURRENT_CONTEXT(ctx);
744
745 switch (pname) {
746 case GL_PROGRAM_OBJECT_ARB:
747 {
Brian5b01c5e2006-12-19 18:02:03 -0700748 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700749
750 if (pro != NULL)
751 return (**pro)._container._generic.
752 GetName((struct gl2_generic_intf **) (pro));
753 }
754 break;
755 default:
756 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
757 }
758#endif
759 return 0;
760}
761
762
Brian5b01c5e2006-12-19 18:02:03 -0700763void
764_mesa_get_programiv(GLcontext *ctx, GLuint program,
765 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700766{
Brian65a18442006-12-19 18:46:56 -0700767 struct gl_shader_program *shProg
768 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700769
Brian65a18442006-12-19 18:46:56 -0700770 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700771 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700772 return;
773 }
774
Brian5b01c5e2006-12-19 18:02:03 -0700775 switch (pname) {
776 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700777 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700778 break;
779 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700780 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700781 break;
Brian5b01c5e2006-12-19 18:02:03 -0700782 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700783 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700784 break;
785 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600786 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700787 break;
788 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700789 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700790 break;
791 case GL_ACTIVE_ATTRIBUTES:
Brian3209c3e2007-01-09 17:49:24 -0700792 *params = shProg->Attributes ? shProg->Attributes->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700793 break;
794 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600795 *params = _mesa_longest_parameter_name(shProg->Attributes,
796 PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700797 break;
798 case GL_ACTIVE_UNIFORMS:
Brian274ac7a2007-04-18 16:05:53 -0600799 *params
800 = _mesa_num_parameters_of_type(shProg->Uniforms, PROGRAM_UNIFORM)
801 + _mesa_num_parameters_of_type(shProg->Uniforms, PROGRAM_SAMPLER);
Brian5b01c5e2006-12-19 18:02:03 -0700802 break;
803 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600804 *params = MAX2(
805 _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_UNIFORM),
806 _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_SAMPLER));
807 if (*params > 0)
808 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700809 break;
810 default:
Brian5b01c5e2006-12-19 18:02:03 -0700811 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
812 return;
Brian34ae99d2006-12-18 08:28:54 -0700813 }
Brian5b01c5e2006-12-19 18:02:03 -0700814}
Brian34ae99d2006-12-18 08:28:54 -0700815
Brian34ae99d2006-12-18 08:28:54 -0700816
Brian5b01c5e2006-12-19 18:02:03 -0700817void
818_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
819{
Brian65a18442006-12-19 18:46:56 -0700820 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700821
822 if (!shader) {
823 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderiv(shader)");
824 return;
825 }
Brian65a18442006-12-19 18:46:56 -0700826
Brian5b01c5e2006-12-19 18:02:03 -0700827 switch (pname) {
828 case GL_SHADER_TYPE:
829 *params = shader->Type;
830 break;
831 case GL_DELETE_STATUS:
832 *params = shader->DeletePending;
833 break;
834 case GL_COMPILE_STATUS:
835 *params = shader->CompileStatus;
836 break;
837 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600838 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700839 break;
840 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600841 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700842 break;
843 default:
844 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
845 return;
846 }
847}
848
849
850void
851_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
852 GLsizei *length, GLchar *infoLog)
853{
Brian65a18442006-12-19 18:46:56 -0700854 struct gl_shader_program *shProg
855 = _mesa_lookup_shader_program(ctx, program);
856 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700857 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
858 return;
859 }
Brian65a18442006-12-19 18:46:56 -0700860 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700861}
862
863
864void
865_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
866 GLsizei *length, GLchar *infoLog)
867{
Brian65a18442006-12-19 18:46:56 -0700868 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
869 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700870 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
871 return;
872 }
Brian65a18442006-12-19 18:46:56 -0700873 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700874}
875
876
877/**
878 * Called via ctx->Driver.GetShaderSource().
879 */
880void
881_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
882 GLsizei *length, GLchar *sourceOut)
883{
Brian65a18442006-12-19 18:46:56 -0700884 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
885 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700886 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderSource(shader)");
887 return;
888 }
Brian65a18442006-12-19 18:46:56 -0700889 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -0700890}
891
892
893/**
894 * Called via ctx->Driver.GetUniformfv().
895 */
896void
897_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
898 GLfloat *params)
899{
Brian65a18442006-12-19 18:46:56 -0700900 struct gl_shader_program *shProg
901 = _mesa_lookup_shader_program(ctx, program);
902 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700903 GLint i;
Brian65a18442006-12-19 18:46:56 -0700904 if (location >= 0 && location < shProg->Uniforms->NumParameters) {
905 for (i = 0; i < shProg->Uniforms->Parameters[location].Size; i++) {
906 params[i] = shProg->Uniforms->ParameterValues[location][i];
Brian5b01c5e2006-12-19 18:02:03 -0700907 }
908 }
909 else {
910 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(location)");
911 }
912 }
913 else {
Brian43975832007-01-04 08:21:09 -0700914 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700915 }
916}
917
918
919/**
920 * Called via ctx->Driver.GetUniformLocation().
921 */
922GLint
923_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
924{
Brian71623982007-01-30 16:55:03 -0700925 struct gl_shader_program *shProg
926 = _mesa_lookup_shader_program(ctx, program);
927 if (shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700928 GLuint loc;
Brian65a18442006-12-19 18:46:56 -0700929 for (loc = 0; loc < shProg->Uniforms->NumParameters; loc++) {
Brian5b01c5e2006-12-19 18:02:03 -0700930 const struct gl_program_parameter *u
Brian65a18442006-12-19 18:46:56 -0700931 = shProg->Uniforms->Parameters + loc;
Brian29053852006-12-21 11:21:26 -0700932 /* XXX this is a temporary simplification / short-cut.
933 * We need to handle things like "e.c[0].b" as seen in the
934 * GLSL orange book, page 189.
935 */
Brian5cf73262007-01-05 16:02:45 -0700936 if ((u->Type == PROGRAM_UNIFORM ||
937 u->Type == PROGRAM_SAMPLER) && !strcmp(u->Name, name)) {
Brian5b01c5e2006-12-19 18:02:03 -0700938 return loc;
939 }
940 }
941 }
942 return -1;
943
944}
945
946
947GLboolean
948_mesa_is_program(GLcontext *ctx, GLuint name)
949{
Brian65a18442006-12-19 18:46:56 -0700950 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
951 return shProg ? GL_TRUE : GL_FALSE;
Brian5b01c5e2006-12-19 18:02:03 -0700952}
953
954
955GLboolean
956_mesa_is_shader(GLcontext *ctx, GLuint name)
957{
Brian65a18442006-12-19 18:46:56 -0700958 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700959 return shader ? GL_TRUE : GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700960}
961
962
963
Brian5b01c5e2006-12-19 18:02:03 -0700964/**
965 * Called via ctx->Driver.ShaderSource()
966 */
967void
968_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -0700969{
Brian65a18442006-12-19 18:46:56 -0700970 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
971 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700972 _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSource(shaderObj)");
Brian34ae99d2006-12-18 08:28:54 -0700973 return;
974 }
975
Brian34ae99d2006-12-18 08:28:54 -0700976 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -0700977 if (sh->Source) {
978 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -0700979 }
Brian65a18442006-12-19 18:46:56 -0700980 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -0700981 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700982}
983
984
Brian5b01c5e2006-12-19 18:02:03 -0700985/**
986 * Called via ctx->Driver.CompileShader()
987 */
988void
989_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -0700990{
Brian65a18442006-12-19 18:46:56 -0700991 struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj);
Brian34ae99d2006-12-18 08:28:54 -0700992
Brian65a18442006-12-19 18:46:56 -0700993 if (!sh) {
Brian34ae99d2006-12-18 08:28:54 -0700994 _mesa_error(ctx, GL_INVALID_VALUE, "glCompileShader(shaderObj)");
995 return;
996 }
997
Brian43975832007-01-04 08:21:09 -0700998 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -0700999}
1000
1001
Brian5b01c5e2006-12-19 18:02:03 -07001002/**
1003 * Called via ctx->Driver.LinkProgram()
1004 */
1005void
1006_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001007{
Brian65a18442006-12-19 18:46:56 -07001008 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001009
Brian65a18442006-12-19 18:46:56 -07001010 shProg = _mesa_lookup_shader_program(ctx, program);
1011 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001012 _mesa_error(ctx, GL_INVALID_VALUE, "glLinkProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001013 return;
1014 }
1015
Brianc1771912007-02-16 09:56:19 -07001016 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001017}
1018
1019
1020/**
Brian5b01c5e2006-12-19 18:02:03 -07001021 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001022 */
Brian5b01c5e2006-12-19 18:02:03 -07001023void
1024_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001025{
Brian3c008a02007-04-12 15:22:32 -06001026 struct gl_shader_program *shProg;
1027
Brian00d63aa2007-02-03 11:35:02 -07001028 if (ctx->Shader.CurrentProgram &&
1029 ctx->Shader.CurrentProgram->Name == program) {
1030 /* no-op */
1031 return;
1032 }
1033
1034 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1035
Brian5b01c5e2006-12-19 18:02:03 -07001036 if (program) {
Brian65a18442006-12-19 18:46:56 -07001037 shProg = _mesa_lookup_shader_program(ctx, program);
1038 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001039 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -07001040 "glUseProgramObjectARB(programObj)");
1041 return;
1042 }
Brian5b01c5e2006-12-19 18:02:03 -07001043 }
1044 else {
Brian3c008a02007-04-12 15:22:32 -06001045 shProg = NULL;
1046 }
1047
1048 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001049}
Brian34ae99d2006-12-18 08:28:54 -07001050
Brian5b01c5e2006-12-19 18:02:03 -07001051
1052/**
1053 * Called via ctx->Driver.Uniform().
1054 */
1055void
1056_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1057 const GLvoid *values, GLenum type)
1058{
Brian3a8e2772006-12-20 17:19:16 -07001059 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian98650bd2007-03-13 16:32:48 -06001060 GLint elems, i, k;
Brian3a8e2772006-12-20 17:19:16 -07001061
1062 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001063 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001064 return;
1065 }
1066
Brian223d7cb2007-01-23 16:37:51 -07001067 if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) {
Brian3a8e2772006-12-20 17:19:16 -07001068 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
1069 return;
1070 }
1071
1072 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1073
Brianfee9bbe2007-02-02 18:05:43 -07001074 /*
1075 * If we're setting a sampler, we must use glUniformi1()!
1076 */
1077 if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
Brian3e4302f2007-05-09 08:04:32 -06001078 GLint unit;
Brianfee9bbe2007-02-02 18:05:43 -07001079 if (type != GL_INT || count != 1) {
1080 _mesa_error(ctx, GL_INVALID_OPERATION,
1081 "glUniform(only glUniform1i can be used "
1082 "to set sampler uniforms)");
1083 return;
1084 }
Brian3e4302f2007-05-09 08:04:32 -06001085 /* check that the sampler (tex unit index) is legal */
1086 unit = ((GLint *) values)[0];
1087 if (unit >= ctx->Const.MaxTextureImageUnits) {
1088 _mesa_error(ctx, GL_INVALID_VALUE,
1089 "glUniform1(invalid sampler/tex unit index)");
1090 return;
1091 }
Brianfee9bbe2007-02-02 18:05:43 -07001092 }
1093
Brian52363952007-03-13 16:50:24 -06001094 if (count < 0) {
1095 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1096 return;
1097 }
1098
Brian98650bd2007-03-13 16:32:48 -06001099 switch (type) {
1100 case GL_FLOAT:
1101 case GL_INT:
1102 elems = 1;
1103 break;
1104 case GL_FLOAT_VEC2:
1105 case GL_INT_VEC2:
1106 elems = 2;
1107 break;
1108 case GL_FLOAT_VEC3:
1109 case GL_INT_VEC3:
1110 elems = 3;
1111 break;
1112 case GL_FLOAT_VEC4:
1113 case GL_INT_VEC4:
1114 elems = 4;
1115 break;
1116 default:
1117 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1118 return;
Brian89dc4852007-01-04 14:35:44 -07001119 }
Brian98650bd2007-03-13 16:32:48 -06001120
1121 if (count * elems > shProg->Uniforms->Parameters[location].Size) {
1122 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1123 return;
1124 }
1125
1126 for (k = 0; k < count; k++) {
1127 GLfloat *uniformVal = shProg->Uniforms->ParameterValues[location + k];
1128 if (type == GL_INT ||
1129 type == GL_INT_VEC2 ||
1130 type == GL_INT_VEC3 ||
1131 type == GL_INT_VEC4) {
Brian52363952007-03-13 16:50:24 -06001132 const GLint *iValues = ((const GLint *) values) + k * elems;
Brian98650bd2007-03-13 16:32:48 -06001133 for (i = 0; i < elems; i++) {
1134 uniformVal[i] = (GLfloat) iValues[i];
1135 }
1136 }
1137 else {
Brian52363952007-03-13 16:50:24 -06001138 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
Brian98650bd2007-03-13 16:32:48 -06001139 for (i = 0; i < elems; i++) {
1140 uniformVal[i] = fValues[i];
1141 }
Brian89dc4852007-01-04 14:35:44 -07001142 }
Brian5b01c5e2006-12-19 18:02:03 -07001143 }
Brian5cf73262007-01-05 16:02:45 -07001144
1145 if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
Briancec81ee2007-03-07 08:04:06 -07001146 if (shProg->VertexProgram)
1147 _slang_resolve_samplers(shProg, &shProg->VertexProgram->Base);
1148 if (shProg->FragmentProgram)
1149 _slang_resolve_samplers(shProg, &shProg->FragmentProgram->Base);
Brian5cf73262007-01-05 16:02:45 -07001150 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1151 }
Brian34ae99d2006-12-18 08:28:54 -07001152}
1153
1154
1155/**
Brian5b01c5e2006-12-19 18:02:03 -07001156 * Called by ctx->Driver.UniformMatrix().
Brian34ae99d2006-12-18 08:28:54 -07001157 */
Brian5b01c5e2006-12-19 18:02:03 -07001158void
1159_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1160 GLenum matrixType, GLint location, GLsizei count,
1161 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001162{
Brian3a8e2772006-12-20 17:19:16 -07001163 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
1164 if (!shProg || !shProg->LinkStatus) {
1165 _mesa_error(ctx, GL_INVALID_OPERATION,
1166 "glUniformMatrix(program not linked)");
1167 return;
1168 }
1169 if (location < 0 || location >= shProg->Uniforms->NumParameters) {
1170 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
1171 return;
1172 }
Brian34ae99d2006-12-18 08:28:54 -07001173 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001174 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001175 return;
1176 }
1177
1178 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1179
Brian3a8e2772006-12-20 17:19:16 -07001180 /*
1181 * Note: the _columns_ of a matrix are stored in program registers, not
1182 * the rows.
1183 */
1184 /* XXXX need to test 3x3 and 2x2 matrices... */
Brian34ae99d2006-12-18 08:28:54 -07001185 if (transpose) {
Brian3a8e2772006-12-20 17:19:16 -07001186 GLuint row, col;
1187 for (col = 0; col < cols; col++) {
1188 GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
1189 for (row = 0; row < rows; row++) {
Brian9f442472007-03-09 11:34:18 -07001190 v[row] = values[row * cols + col];
Brian34ae99d2006-12-18 08:28:54 -07001191 }
Brian34ae99d2006-12-18 08:28:54 -07001192 }
Brian34ae99d2006-12-18 08:28:54 -07001193 }
1194 else {
Brian3a8e2772006-12-20 17:19:16 -07001195 GLuint row, col;
1196 for (col = 0; col < cols; col++) {
1197 GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
1198 for (row = 0; row < rows; row++) {
Brian9f442472007-03-09 11:34:18 -07001199 v[row] = values[col * rows + row];
Brian3a8e2772006-12-20 17:19:16 -07001200 }
1201 }
Brian34ae99d2006-12-18 08:28:54 -07001202 }
1203}
1204
1205
Brian5b01c5e2006-12-19 18:02:03 -07001206void
1207_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001208{
Brian65a18442006-12-19 18:46:56 -07001209 struct gl_shader_program *shProg;
1210 shProg = _mesa_lookup_shader_program(ctx, program);
1211 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001212 _mesa_error(ctx, GL_INVALID_VALUE, "glValidateProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001213 return;
1214 }
Brian5b01c5e2006-12-19 18:02:03 -07001215 /* XXX temporary */
Brian65a18442006-12-19 18:46:56 -07001216 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001217
Brian5b01c5e2006-12-19 18:02:03 -07001218 /* From the GL spec:
1219 any two active samplers in the current program object are of
1220 different types, but refer to the same texture image unit,
1221
1222 any active sampler in the current program object refers to a texture
1223 image unit where fixed-function fragment processing accesses a
1224 texture target that does not match the sampler type, or
1225
1226 the sum of the number of active samplers in the program and the
1227 number of texture image units enabled for fixed-function fragment
1228 processing exceeds the combined limit on the total number of texture
1229 image units allowed.
1230 */
Brian34ae99d2006-12-18 08:28:54 -07001231}