blob: 4470a87af0a3439d34f011dc5609c5c7e2ca1dab [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 */
Brian2d2bb352007-12-07 17:11:30 -070055static struct gl_shader_program *
Brianf2923612006-12-20 09:56:44 -070056_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;
michal4a470f62007-08-07 15:34:11 +0100335 ctx->Shader.EmitCondCodes = GL_FALSE;/*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 */
Brian2d2bb352007-12-07 17:11:30 -0700374static void
Brian5b01c5e2006-12-19 18:02:03 -0700375_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);
380 const GLuint n = shProg->NumShaders;
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
389 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700390 if (shProg->Shaders[i] == sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700391 /* already attached */
392 return;
Brian34ae99d2006-12-18 08:28:54 -0700393 }
394 }
Brian5b01c5e2006-12-19 18:02:03 -0700395
396 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700397 shProg->Shaders = (struct gl_shader **)
398 _mesa_realloc(shProg->Shaders,
399 n * sizeof(struct gl_shader *),
400 (n + 1) * sizeof(struct gl_shader *));
401 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700402 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
403 return;
404 }
405
406 /* append */
Brian3c008a02007-04-12 15:22:32 -0600407 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
408 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700409 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700410}
411
412
Brian2d2bb352007-12-07 17:11:30 -0700413static GLint
414_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
415 const GLchar *name)
416{
417 struct gl_shader_program *shProg
418 = _mesa_lookup_shader_program(ctx, program);
419
420 if (!shProg) {
421 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttribLocation");
422 return -1;
423 }
424
425 if (!shProg->LinkStatus) {
426 _mesa_error(ctx, GL_INVALID_OPERATION,
427 "glGetAttribLocation(program not linked)");
428 return -1;
429 }
430
431 if (!name)
432 return -1;
433
434 if (shProg->Attributes) {
435 GLint i = _mesa_lookup_parameter_index(shProg->Attributes, -1, name);
436 if (i >= 0) {
437 return shProg->Attributes->Parameters[i].StateIndexes[0];
438 }
439 }
440 return -1;
441}
442
443
444static void
Brian5b01c5e2006-12-19 18:02:03 -0700445_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
446 const GLchar *name)
447{
Brian65a18442006-12-19 18:46:56 -0700448 struct gl_shader_program *shProg
449 = _mesa_lookup_shader_program(ctx, program);
Brianb7978af2007-01-09 19:17:17 -0700450 const GLint size = -1; /* unknown size */
451 GLint i, oldIndex;
Brian5b01c5e2006-12-19 18:02:03 -0700452
Brian65a18442006-12-19 18:46:56 -0700453 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700454 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700455 return;
456 }
457
Brian9e4bae92006-12-20 09:27:42 -0700458 if (!name)
459 return;
460
461 if (strncmp(name, "gl_", 3) == 0) {
462 _mesa_error(ctx, GL_INVALID_OPERATION,
463 "glBindAttribLocation(illegal name)");
464 return;
465 }
466
Brian9f660252007-04-11 09:00:56 -0600467 if (shProg->LinkStatus) {
468 /* get current index/location for the attribute */
469 oldIndex = _mesa_get_attrib_location(ctx, program, name);
470 }
471 else {
472 oldIndex = -1;
473 }
Brian3209c3e2007-01-09 17:49:24 -0700474
475 /* this will replace the current value if it's already in the list */
Brianb7978af2007-01-09 19:17:17 -0700476 i = _mesa_add_attribute(shProg->Attributes, name, size, index);
Brian3209c3e2007-01-09 17:49:24 -0700477 if (i < 0) {
478 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
479 }
480
Brian9f660252007-04-11 09:00:56 -0600481 if (shProg->VertexProgram && oldIndex >= 0 && oldIndex != index) {
482 /* If the index changed, need to search/replace references to that attribute
483 * in the vertex program.
484 */
Brian3209c3e2007-01-09 17:49:24 -0700485 _slang_remap_attribute(&shProg->VertexProgram->Base, oldIndex, index);
486 }
Brian34ae99d2006-12-18 08:28:54 -0700487}
488
489
Brian2d2bb352007-12-07 17:11:30 -0700490static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700491_mesa_create_shader(GLcontext *ctx, GLenum type)
492{
Brian65a18442006-12-19 18:46:56 -0700493 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700494 GLuint name;
495
496 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
497
498 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700499 case GL_FRAGMENT_SHADER:
500 case GL_VERTEX_SHADER:
501 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700502 break;
503 default:
504 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
505 return 0;
506 }
507
Brian65a18442006-12-19 18:46:56 -0700508 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700509
510 return name;
511}
512
513
Brian2d2bb352007-12-07 17:11:30 -0700514static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700515_mesa_create_program(GLcontext *ctx)
516{
517 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700518 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700519
Brian65a18442006-12-19 18:46:56 -0700520 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
521 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700522
Brian65a18442006-12-19 18:46:56 -0700523 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700524
Brian3c008a02007-04-12 15:22:32 -0600525 assert(shProg->RefCount == 1);
526
Brian5b01c5e2006-12-19 18:02:03 -0700527 return name;
528}
529
530
Brian3c008a02007-04-12 15:22:32 -0600531/**
532 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
533 * DeleteProgramARB.
534 */
Brian2d2bb352007-12-07 17:11:30 -0700535static void
Brian5b01c5e2006-12-19 18:02:03 -0700536_mesa_delete_program2(GLcontext *ctx, GLuint name)
537{
Brian3c008a02007-04-12 15:22:32 -0600538 /*
539 * NOTE: deleting shaders/programs works a bit differently than
540 * texture objects (and buffer objects, etc). Shader/program
541 * handles/IDs exist in the hash table until the object is really
542 * deleted (refcount==0). With texture objects, the handle/ID is
543 * removed from the hash table in glDeleteTextures() while the tex
544 * object itself might linger until its refcount goes to zero.
545 */
Brian65a18442006-12-19 18:46:56 -0700546 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700547
Brian65a18442006-12-19 18:46:56 -0700548 shProg = _mesa_lookup_shader_program(ctx, name);
549 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700550 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteProgram(name)");
Brian5b01c5e2006-12-19 18:02:03 -0700551 return;
552 }
553
Brian9e4bae92006-12-20 09:27:42 -0700554 shProg->DeletePending = GL_TRUE;
555
Brian3c008a02007-04-12 15:22:32 -0600556 /* effectively, decr shProg's refcount */
557 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700558}
559
560
Brian2d2bb352007-12-07 17:11:30 -0700561static void
Brian5b01c5e2006-12-19 18:02:03 -0700562_mesa_delete_shader(GLcontext *ctx, GLuint shader)
563{
Brian9e4bae92006-12-20 09:27:42 -0700564 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
565 if (!sh) {
566 return;
567 }
Brian5b01c5e2006-12-19 18:02:03 -0700568
Brian9e4bae92006-12-20 09:27:42 -0700569 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600570
571 /* effectively, decr sh's refcount */
572 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700573}
574
575
Brian2d2bb352007-12-07 17:11:30 -0700576static void
Brian5b01c5e2006-12-19 18:02:03 -0700577_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
578{
Brian65a18442006-12-19 18:46:56 -0700579 struct gl_shader_program *shProg
580 = _mesa_lookup_shader_program(ctx, program);
581 const GLuint n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700582 GLuint i, j;
583
Brian65a18442006-12-19 18:46:56 -0700584 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700585 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700586 "glDetachShader(bad program or shader name)");
587 return;
588 }
589
590 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700591 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700592 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600593 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700594
Brian3c008a02007-04-12 15:22:32 -0600595 /* derefernce */
596 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700597
Brian5b01c5e2006-12-19 18:02:03 -0700598 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700599 newList = (struct gl_shader **)
600 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700601 if (!newList) {
602 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
603 return;
604 }
605 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700606 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700607 }
608 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700609 newList[j++] = shProg->Shaders[i];
610 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700611
Brian65a18442006-12-19 18:46:56 -0700612 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600613 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600614
615#ifdef DEBUG
616 /* sanity check */
617 {
618 for (j = 0; j < shProg->NumShaders; j++) {
619 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
620 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
621 assert(shProg->Shaders[j]->RefCount > 0);
622 }
623 }
624#endif
625
Brian5b01c5e2006-12-19 18:02:03 -0700626 return;
627 }
628 }
629
630 /* not found */
Brian43975832007-01-04 08:21:09 -0700631 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700632 "glDetachShader(shader not found)");
633}
634
635
Brian2d2bb352007-12-07 17:11:30 -0700636static void
Brian5b01c5e2006-12-19 18:02:03 -0700637_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
638 GLsizei maxLength, GLsizei *length, GLint *size,
639 GLenum *type, GLchar *nameOut)
640{
641 static const GLenum vec_types[] = {
642 GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4
643 };
Brian65a18442006-12-19 18:46:56 -0700644 struct gl_shader_program *shProg
645 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700646 GLint sz;
647
Brian65a18442006-12-19 18:46:56 -0700648 if (!shProg) {
Brianaaa57412007-04-18 15:22:43 -0600649 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib");
Brian5b01c5e2006-12-19 18:02:03 -0700650 return;
651 }
652
Brian65a18442006-12-19 18:46:56 -0700653 if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600654 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700655 return;
656 }
657
658 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700659 shProg->Attributes->Parameters[index].Name);
660 sz = shProg->Attributes->Parameters[index].Size;
Brian5b01c5e2006-12-19 18:02:03 -0700661 if (size)
662 *size = sz;
663 if (type)
664 *type = vec_types[sz]; /* XXX this is a temporary hack */
665}
666
667
668/**
669 * Called via ctx->Driver.GetActiveUniform().
670 */
Brian2d2bb352007-12-07 17:11:30 -0700671static void
Brian5b01c5e2006-12-19 18:02:03 -0700672_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
673 GLsizei maxLength, GLsizei *length, GLint *size,
674 GLenum *type, GLchar *nameOut)
675{
Brian65a18442006-12-19 18:46:56 -0700676 struct gl_shader_program *shProg
677 = _mesa_lookup_shader_program(ctx, program);
Brian274ac7a2007-04-18 16:05:53 -0600678 GLuint ind, j;
Brian5b01c5e2006-12-19 18:02:03 -0700679
Brian65a18442006-12-19 18:46:56 -0700680 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700681 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform");
Brian5b01c5e2006-12-19 18:02:03 -0700682 return;
683 }
684
Brian65a18442006-12-19 18:46:56 -0700685 if (!shProg->Uniforms || index >= shProg->Uniforms->NumParameters) {
Brian5b01c5e2006-12-19 18:02:03 -0700686 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
687 return;
688 }
689
Brian274ac7a2007-04-18 16:05:53 -0600690 ind = 0;
691 for (j = 0; j < shProg->Uniforms->NumParameters; j++) {
692 if (shProg->Uniforms->Parameters[j].Type == PROGRAM_UNIFORM ||
693 shProg->Uniforms->Parameters[j].Type == PROGRAM_SAMPLER) {
694 if (ind == index) {
695 /* found it */
696 copy_string(nameOut, maxLength, length,
697 shProg->Uniforms->Parameters[j].Name);
Brian274ac7a2007-04-18 16:05:53 -0600698 if (size)
Brianc93e8832007-04-18 16:27:35 -0600699 *size = shProg->Uniforms->Parameters[j].Size;
Brian274ac7a2007-04-18 16:05:53 -0600700 if (type)
Brianc93e8832007-04-18 16:27:35 -0600701 *type = shProg->Uniforms->Parameters[j].DataType;
Brian274ac7a2007-04-18 16:05:53 -0600702 return;
703 }
704 ind++;
705 }
706 }
707
708 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700709}
710
711
712/**
713 * Called via ctx->Driver.GetAttachedShaders().
714 */
Brian2d2bb352007-12-07 17:11:30 -0700715static void
Brian5b01c5e2006-12-19 18:02:03 -0700716_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
717 GLsizei *count, GLuint *obj)
718{
Brian65a18442006-12-19 18:46:56 -0700719 struct gl_shader_program *shProg
720 = _mesa_lookup_shader_program(ctx, program);
721 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700722 GLint i;
Brian65a18442006-12-19 18:46:56 -0700723 for (i = 0; i < maxCount && i < shProg->NumShaders; i++) {
724 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700725 }
726 if (count)
727 *count = i;
728 }
729 else {
Brian43975832007-01-04 08:21:09 -0700730 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttachedShaders");
Brian5b01c5e2006-12-19 18:02:03 -0700731 }
732}
733
734
Brian2d2bb352007-12-07 17:11:30 -0700735static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700736_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700737{
738#if 0
739 GET_CURRENT_CONTEXT(ctx);
740
741 switch (pname) {
742 case GL_PROGRAM_OBJECT_ARB:
743 {
Brian5b01c5e2006-12-19 18:02:03 -0700744 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700745
746 if (pro != NULL)
747 return (**pro)._container._generic.
748 GetName((struct gl2_generic_intf **) (pro));
749 }
750 break;
751 default:
752 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
753 }
754#endif
755 return 0;
756}
757
758
Brian2d2bb352007-12-07 17:11:30 -0700759static void
Brian5b01c5e2006-12-19 18:02:03 -0700760_mesa_get_programiv(GLcontext *ctx, GLuint program,
761 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700762{
Brian65a18442006-12-19 18:46:56 -0700763 struct gl_shader_program *shProg
764 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700765
Brian65a18442006-12-19 18:46:56 -0700766 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700767 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700768 return;
769 }
770
Brian5b01c5e2006-12-19 18:02:03 -0700771 switch (pname) {
772 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700773 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700774 break;
775 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700776 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700777 break;
Brian5b01c5e2006-12-19 18:02:03 -0700778 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700779 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700780 break;
781 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600782 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700783 break;
784 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700785 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700786 break;
787 case GL_ACTIVE_ATTRIBUTES:
Brian3209c3e2007-01-09 17:49:24 -0700788 *params = shProg->Attributes ? shProg->Attributes->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700789 break;
790 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600791 *params = _mesa_longest_parameter_name(shProg->Attributes,
792 PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700793 break;
794 case GL_ACTIVE_UNIFORMS:
Brian274ac7a2007-04-18 16:05:53 -0600795 *params
796 = _mesa_num_parameters_of_type(shProg->Uniforms, PROGRAM_UNIFORM)
797 + _mesa_num_parameters_of_type(shProg->Uniforms, PROGRAM_SAMPLER);
Brian5b01c5e2006-12-19 18:02:03 -0700798 break;
799 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600800 *params = MAX2(
801 _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_UNIFORM),
802 _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_SAMPLER));
803 if (*params > 0)
804 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700805 break;
806 default:
Brian5b01c5e2006-12-19 18:02:03 -0700807 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
808 return;
Brian34ae99d2006-12-18 08:28:54 -0700809 }
Brian5b01c5e2006-12-19 18:02:03 -0700810}
Brian34ae99d2006-12-18 08:28:54 -0700811
Brian34ae99d2006-12-18 08:28:54 -0700812
Brian2d2bb352007-12-07 17:11:30 -0700813static void
Brian5b01c5e2006-12-19 18:02:03 -0700814_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
815{
Brian65a18442006-12-19 18:46:56 -0700816 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700817
818 if (!shader) {
819 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderiv(shader)");
820 return;
821 }
Brian65a18442006-12-19 18:46:56 -0700822
Brian5b01c5e2006-12-19 18:02:03 -0700823 switch (pname) {
824 case GL_SHADER_TYPE:
825 *params = shader->Type;
826 break;
827 case GL_DELETE_STATUS:
828 *params = shader->DeletePending;
829 break;
830 case GL_COMPILE_STATUS:
831 *params = shader->CompileStatus;
832 break;
833 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600834 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700835 break;
836 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600837 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700838 break;
839 default:
840 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
841 return;
842 }
843}
844
845
Brian2d2bb352007-12-07 17:11:30 -0700846static void
Brian5b01c5e2006-12-19 18:02:03 -0700847_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
848 GLsizei *length, GLchar *infoLog)
849{
Brian65a18442006-12-19 18:46:56 -0700850 struct gl_shader_program *shProg
851 = _mesa_lookup_shader_program(ctx, program);
852 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700853 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
854 return;
855 }
Brian65a18442006-12-19 18:46:56 -0700856 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700857}
858
859
Brian2d2bb352007-12-07 17:11:30 -0700860static void
Brian5b01c5e2006-12-19 18:02:03 -0700861_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
862 GLsizei *length, GLchar *infoLog)
863{
Brian65a18442006-12-19 18:46:56 -0700864 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
865 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700866 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
867 return;
868 }
Brian65a18442006-12-19 18:46:56 -0700869 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700870}
871
872
873/**
874 * Called via ctx->Driver.GetShaderSource().
875 */
Brian2d2bb352007-12-07 17:11:30 -0700876static void
Brian5b01c5e2006-12-19 18:02:03 -0700877_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
878 GLsizei *length, GLchar *sourceOut)
879{
Brian65a18442006-12-19 18:46:56 -0700880 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
881 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700882 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderSource(shader)");
883 return;
884 }
Brian65a18442006-12-19 18:46:56 -0700885 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -0700886}
887
888
889/**
890 * Called via ctx->Driver.GetUniformfv().
891 */
Brian2d2bb352007-12-07 17:11:30 -0700892static void
Brian5b01c5e2006-12-19 18:02:03 -0700893_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
894 GLfloat *params)
895{
Brian65a18442006-12-19 18:46:56 -0700896 struct gl_shader_program *shProg
897 = _mesa_lookup_shader_program(ctx, program);
898 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700899 GLint i;
Brian65a18442006-12-19 18:46:56 -0700900 if (location >= 0 && location < shProg->Uniforms->NumParameters) {
901 for (i = 0; i < shProg->Uniforms->Parameters[location].Size; i++) {
902 params[i] = shProg->Uniforms->ParameterValues[location][i];
Brian5b01c5e2006-12-19 18:02:03 -0700903 }
904 }
905 else {
906 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(location)");
907 }
908 }
909 else {
Brian43975832007-01-04 08:21:09 -0700910 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700911 }
912}
913
914
915/**
916 * Called via ctx->Driver.GetUniformLocation().
917 */
Brian2d2bb352007-12-07 17:11:30 -0700918static GLint
Brian5b01c5e2006-12-19 18:02:03 -0700919_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
920{
Brian71623982007-01-30 16:55:03 -0700921 struct gl_shader_program *shProg
922 = _mesa_lookup_shader_program(ctx, program);
923 if (shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700924 GLuint loc;
Brian65a18442006-12-19 18:46:56 -0700925 for (loc = 0; loc < shProg->Uniforms->NumParameters; loc++) {
Brian5b01c5e2006-12-19 18:02:03 -0700926 const struct gl_program_parameter *u
Brian65a18442006-12-19 18:46:56 -0700927 = shProg->Uniforms->Parameters + loc;
Brian29053852006-12-21 11:21:26 -0700928 /* XXX this is a temporary simplification / short-cut.
929 * We need to handle things like "e.c[0].b" as seen in the
930 * GLSL orange book, page 189.
931 */
Brian5cf73262007-01-05 16:02:45 -0700932 if ((u->Type == PROGRAM_UNIFORM ||
933 u->Type == PROGRAM_SAMPLER) && !strcmp(u->Name, name)) {
Brian5b01c5e2006-12-19 18:02:03 -0700934 return loc;
935 }
936 }
937 }
938 return -1;
939
940}
941
942
Brian2d2bb352007-12-07 17:11:30 -0700943static GLboolean
Brian5b01c5e2006-12-19 18:02:03 -0700944_mesa_is_program(GLcontext *ctx, GLuint name)
945{
Brian65a18442006-12-19 18:46:56 -0700946 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
947 return shProg ? GL_TRUE : GL_FALSE;
Brian5b01c5e2006-12-19 18:02:03 -0700948}
949
950
Brian2d2bb352007-12-07 17:11:30 -0700951static GLboolean
Brian5b01c5e2006-12-19 18:02:03 -0700952_mesa_is_shader(GLcontext *ctx, GLuint name)
953{
Brian65a18442006-12-19 18:46:56 -0700954 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700955 return shader ? GL_TRUE : GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700956}
957
958
959
Brian5b01c5e2006-12-19 18:02:03 -0700960/**
961 * Called via ctx->Driver.ShaderSource()
962 */
Brian2d2bb352007-12-07 17:11:30 -0700963static void
Brian5b01c5e2006-12-19 18:02:03 -0700964_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -0700965{
Brian65a18442006-12-19 18:46:56 -0700966 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
967 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700968 _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSource(shaderObj)");
Brian34ae99d2006-12-18 08:28:54 -0700969 return;
970 }
971
Brian34ae99d2006-12-18 08:28:54 -0700972 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -0700973 if (sh->Source) {
974 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -0700975 }
Brian65a18442006-12-19 18:46:56 -0700976 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -0700977 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700978}
979
980
Brian5b01c5e2006-12-19 18:02:03 -0700981/**
982 * Called via ctx->Driver.CompileShader()
983 */
Brian2d2bb352007-12-07 17:11:30 -0700984static void
Brian5b01c5e2006-12-19 18:02:03 -0700985_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -0700986{
Brian65a18442006-12-19 18:46:56 -0700987 struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj);
Brian34ae99d2006-12-18 08:28:54 -0700988
Brian65a18442006-12-19 18:46:56 -0700989 if (!sh) {
Brian34ae99d2006-12-18 08:28:54 -0700990 _mesa_error(ctx, GL_INVALID_VALUE, "glCompileShader(shaderObj)");
991 return;
992 }
993
Brian43975832007-01-04 08:21:09 -0700994 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -0700995}
996
997
Brian5b01c5e2006-12-19 18:02:03 -0700998/**
999 * Called via ctx->Driver.LinkProgram()
1000 */
Brian2d2bb352007-12-07 17:11:30 -07001001static void
Brian5b01c5e2006-12-19 18:02:03 -07001002_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001003{
Brian65a18442006-12-19 18:46:56 -07001004 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001005
Brian65a18442006-12-19 18:46:56 -07001006 shProg = _mesa_lookup_shader_program(ctx, program);
1007 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001008 _mesa_error(ctx, GL_INVALID_VALUE, "glLinkProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001009 return;
1010 }
1011
Brianc1771912007-02-16 09:56:19 -07001012 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001013}
1014
1015
1016/**
Brian5b01c5e2006-12-19 18:02:03 -07001017 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001018 */
Brian5b01c5e2006-12-19 18:02:03 -07001019void
1020_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001021{
Brian3c008a02007-04-12 15:22:32 -06001022 struct gl_shader_program *shProg;
1023
Brian00d63aa2007-02-03 11:35:02 -07001024 if (ctx->Shader.CurrentProgram &&
1025 ctx->Shader.CurrentProgram->Name == program) {
1026 /* no-op */
1027 return;
1028 }
1029
1030 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1031
Brian5b01c5e2006-12-19 18:02:03 -07001032 if (program) {
Brian65a18442006-12-19 18:46:56 -07001033 shProg = _mesa_lookup_shader_program(ctx, program);
1034 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001035 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -07001036 "glUseProgramObjectARB(programObj)");
1037 return;
1038 }
Brian5b01c5e2006-12-19 18:02:03 -07001039 }
1040 else {
Brian3c008a02007-04-12 15:22:32 -06001041 shProg = NULL;
1042 }
1043
1044 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001045}
Brian34ae99d2006-12-18 08:28:54 -07001046
Brian5b01c5e2006-12-19 18:02:03 -07001047
Brian8fed2462007-10-26 19:19:09 -06001048
1049/**
1050 * Update the vertex and fragment program's TexturesUsed arrays.
1051 */
1052static void
1053update_textures_used(struct gl_program *prog)
1054{
1055 GLuint s;
1056
1057 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1058
1059 for (s = 0; s < MAX_SAMPLERS; s++) {
1060 if (prog->SamplersUsed & (1 << s)) {
1061 GLuint u = prog->SamplerUnits[s];
1062 GLuint t = prog->SamplerTargets[s];
1063 assert(u < MAX_TEXTURE_IMAGE_UNITS);
1064 prog->TexturesUsed[u] |= (1 << t);
1065 }
1066 }
1067}
1068
1069
Brian5b01c5e2006-12-19 18:02:03 -07001070/**
1071 * Called via ctx->Driver.Uniform().
1072 */
Brian2d2bb352007-12-07 17:11:30 -07001073static void
Brian5b01c5e2006-12-19 18:02:03 -07001074_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1075 const GLvoid *values, GLenum type)
1076{
Brian3a8e2772006-12-20 17:19:16 -07001077 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian98650bd2007-03-13 16:32:48 -06001078 GLint elems, i, k;
Brian3a8e2772006-12-20 17:19:16 -07001079
1080 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001081 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001082 return;
1083 }
1084
Brian223d7cb2007-01-23 16:37:51 -07001085 if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) {
Brian3a8e2772006-12-20 17:19:16 -07001086 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
1087 return;
1088 }
1089
1090 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1091
Brian52363952007-03-13 16:50:24 -06001092 if (count < 0) {
1093 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1094 return;
1095 }
1096
Brian98650bd2007-03-13 16:32:48 -06001097 switch (type) {
1098 case GL_FLOAT:
1099 case GL_INT:
1100 elems = 1;
1101 break;
1102 case GL_FLOAT_VEC2:
1103 case GL_INT_VEC2:
1104 elems = 2;
1105 break;
1106 case GL_FLOAT_VEC3:
1107 case GL_INT_VEC3:
1108 elems = 3;
1109 break;
1110 case GL_FLOAT_VEC4:
1111 case GL_INT_VEC4:
1112 elems = 4;
1113 break;
1114 default:
1115 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1116 return;
Brian89dc4852007-01-04 14:35:44 -07001117 }
Brian98650bd2007-03-13 16:32:48 -06001118
1119 if (count * elems > shProg->Uniforms->Parameters[location].Size) {
1120 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1121 return;
1122 }
1123
Brian5cf73262007-01-05 16:02:45 -07001124 if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
Brian8fed2462007-10-26 19:19:09 -06001125 /* This controls which texture unit which is used by a sampler */
1126 GLuint texUnit, sampler;
1127
1128 /* data type for setting samplers must be int */
1129 if (type != GL_INT || count != 1) {
1130 _mesa_error(ctx, GL_INVALID_OPERATION,
1131 "glUniform(only glUniform1i can be used "
1132 "to set sampler uniforms)");
1133 return;
1134 }
1135
1136 sampler = (GLuint) shProg->Uniforms->ParameterValues[location][0];
1137 texUnit = ((GLuint *) values)[0];
1138
1139 /* check that the sampler (tex unit index) is legal */
1140 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1141 _mesa_error(ctx, GL_INVALID_VALUE,
1142 "glUniform1(invalid sampler/tex unit index)");
1143 return;
1144 }
1145
1146 if (shProg->VertexProgram) {
1147 shProg->VertexProgram->Base.SamplerUnits[sampler] = texUnit;
1148 update_textures_used(&shProg->VertexProgram->Base);
1149 }
1150 if (shProg->FragmentProgram) {
1151 shProg->FragmentProgram->Base.SamplerUnits[sampler] = texUnit;
1152 update_textures_used(&shProg->FragmentProgram->Base);
1153 }
1154
1155
Brian5cf73262007-01-05 16:02:45 -07001156 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1157 }
Brian8fed2462007-10-26 19:19:09 -06001158 else {
1159 /* ordinary uniform variable */
1160 for (k = 0; k < count; k++) {
1161 GLfloat *uniformVal = shProg->Uniforms->ParameterValues[location + k];
1162 if (type == GL_INT ||
1163 type == GL_INT_VEC2 ||
1164 type == GL_INT_VEC3 ||
1165 type == GL_INT_VEC4) {
1166 const GLint *iValues = ((const GLint *) values) + k * elems;
1167 for (i = 0; i < elems; i++) {
1168 uniformVal[i] = (GLfloat) iValues[i];
1169 }
1170 }
1171 else {
1172 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1173 for (i = 0; i < elems; i++) {
1174 uniformVal[i] = fValues[i];
1175 }
1176 }
1177 }
1178 }
Brian34ae99d2006-12-18 08:28:54 -07001179}
1180
1181
1182/**
Brian5b01c5e2006-12-19 18:02:03 -07001183 * Called by ctx->Driver.UniformMatrix().
Brian34ae99d2006-12-18 08:28:54 -07001184 */
Brian2d2bb352007-12-07 17:11:30 -07001185static void
Brian5b01c5e2006-12-19 18:02:03 -07001186_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1187 GLenum matrixType, GLint location, GLsizei count,
1188 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001189{
Brian3a8e2772006-12-20 17:19:16 -07001190 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
1191 if (!shProg || !shProg->LinkStatus) {
1192 _mesa_error(ctx, GL_INVALID_OPERATION,
1193 "glUniformMatrix(program not linked)");
1194 return;
1195 }
1196 if (location < 0 || location >= shProg->Uniforms->NumParameters) {
1197 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
1198 return;
1199 }
Brian34ae99d2006-12-18 08:28:54 -07001200 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001201 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001202 return;
1203 }
1204
1205 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1206
Brian3a8e2772006-12-20 17:19:16 -07001207 /*
1208 * Note: the _columns_ of a matrix are stored in program registers, not
1209 * the rows.
1210 */
1211 /* XXXX need to test 3x3 and 2x2 matrices... */
Brian34ae99d2006-12-18 08:28:54 -07001212 if (transpose) {
Brian3a8e2772006-12-20 17:19:16 -07001213 GLuint row, col;
1214 for (col = 0; col < cols; col++) {
1215 GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
1216 for (row = 0; row < rows; row++) {
Brian9f442472007-03-09 11:34:18 -07001217 v[row] = values[row * cols + col];
Brian34ae99d2006-12-18 08:28:54 -07001218 }
Brian34ae99d2006-12-18 08:28:54 -07001219 }
Brian34ae99d2006-12-18 08:28:54 -07001220 }
1221 else {
Brian3a8e2772006-12-20 17:19:16 -07001222 GLuint row, col;
1223 for (col = 0; col < cols; col++) {
1224 GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
1225 for (row = 0; row < rows; row++) {
Brian9f442472007-03-09 11:34:18 -07001226 v[row] = values[col * rows + row];
Brian3a8e2772006-12-20 17:19:16 -07001227 }
1228 }
Brian34ae99d2006-12-18 08:28:54 -07001229 }
1230}
1231
1232
Brian2d2bb352007-12-07 17:11:30 -07001233static void
Brian5b01c5e2006-12-19 18:02:03 -07001234_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001235{
Brian65a18442006-12-19 18:46:56 -07001236 struct gl_shader_program *shProg;
1237 shProg = _mesa_lookup_shader_program(ctx, program);
1238 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001239 _mesa_error(ctx, GL_INVALID_VALUE, "glValidateProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001240 return;
1241 }
Brian5b01c5e2006-12-19 18:02:03 -07001242 /* XXX temporary */
Brian65a18442006-12-19 18:46:56 -07001243 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001244
Brian5b01c5e2006-12-19 18:02:03 -07001245 /* From the GL spec:
1246 any two active samplers in the current program object are of
1247 different types, but refer to the same texture image unit,
1248
1249 any active sampler in the current program object refers to a texture
1250 image unit where fixed-function fragment processing accesses a
1251 texture target that does not match the sampler type, or
1252
1253 the sum of the number of active samplers in the program and the
1254 number of texture image units enabled for fixed-function fragment
1255 processing exceeds the combined limit on the total number of texture
1256 image units allowed.
1257 */
Brian34ae99d2006-12-18 08:28:54 -07001258}
Brian2d2bb352007-12-07 17:11:30 -07001259
1260
1261/**
1262 * Plug in Mesa's GLSL functions into the device driver function table.
1263 */
1264void
1265_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
1266{
1267 driver->AttachShader = _mesa_attach_shader;
1268 driver->BindAttribLocation = _mesa_bind_attrib_location;
1269 driver->CompileShader = _mesa_compile_shader;
1270 driver->CreateProgram = _mesa_create_program;
1271 driver->CreateShader = _mesa_create_shader;
1272 driver->DeleteProgram2 = _mesa_delete_program2;
1273 driver->DeleteShader = _mesa_delete_shader;
1274 driver->DetachShader = _mesa_detach_shader;
1275 driver->GetActiveAttrib = _mesa_get_active_attrib;
1276 driver->GetActiveUniform = _mesa_get_active_uniform;
1277 driver->GetAttachedShaders = _mesa_get_attached_shaders;
1278 driver->GetAttribLocation = _mesa_get_attrib_location;
1279 driver->GetHandle = _mesa_get_handle;
1280 driver->GetProgramiv = _mesa_get_programiv;
1281 driver->GetProgramInfoLog = _mesa_get_program_info_log;
1282 driver->GetShaderiv = _mesa_get_shaderiv;
1283 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
1284 driver->GetShaderSource = _mesa_get_shader_source;
1285 driver->GetUniformfv = _mesa_get_uniformfv;
1286 driver->GetUniformLocation = _mesa_get_uniform_location;
1287 driver->IsProgram = _mesa_is_program;
1288 driver->IsShader = _mesa_is_shader;
1289 driver->LinkProgram = _mesa_link_program;
1290 driver->ShaderSource = _mesa_shader_source;
1291 driver->Uniform = _mesa_uniform;
1292 driver->UniformMatrix = _mesa_uniform_matrix;
1293 driver->UseProgram = _mesa_use_program;
1294 driver->ValidateProgram = _mesa_validate_program;
1295}