blob: a8ca7d62212ae26d04bbe7f6eaac874b78a1eb47 [file] [log] [blame]
Brian34ae99d2006-12-18 08:28:54 -07001/*
2 * Mesa 3-D graphics library
Brian5b01c5e2006-12-19 18:02:03 -07003 * Version: 6.5.3
Brian34ae99d2006-12-18 08:28:54 -07004 *
Brian5b01c5e2006-12-19 18:02:03 -07005 * Copyright (C) 2004-2007 Brian Paul All Rights Reserved.
Brian34ae99d2006-12-18 08:28:54 -07006 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25/**
26 * \file shader_api.c
Brian5b01c5e2006-12-19 18:02:03 -070027 * Implementation of GLSL-related API functions
Brian34ae99d2006-12-18 08:28:54 -070028 * \author Brian Paul
29 */
30
31/**
32 * XXX things to do:
33 * 1. Check that the right error code is generated for all _mesa_error() calls.
Brian5b01c5e2006-12-19 18:02:03 -070034 * 2. Insert FLUSH_VERTICES calls in various places
Brian34ae99d2006-12-18 08:28:54 -070035 */
36
37
38#include "glheader.h"
39#include "context.h"
40#include "hash.h"
Brian34ae99d2006-12-18 08:28:54 -070041#include "program.h"
42#include "prog_parameter.h"
Brian3209c3e2007-01-09 17:49:24 -070043#include "prog_print.h"
44#include "prog_statevars.h"
Brian34ae99d2006-12-18 08:28:54 -070045#include "shader_api.h"
46
47#include "slang_compile.h"
48#include "slang_link.h"
49
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
121 /* detach shaders */
122 for (i = 0; i < shProg->NumShaders; i++) {
123 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
124 }
125 if (shProg->Shaders) {
126 _mesa_free(shProg->Shaders);
127 shProg->Shaders = NULL;
128 }
129}
130
131
132/**
Brianb9fbedd2007-03-26 09:23:44 -0600133 * Free/delete a shader program object.
134 */
Brianf2923612006-12-20 09:56:44 -0700135void
136_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg)
137{
138 _mesa_free_shader_program_data(ctx, shProg);
Brianb9fbedd2007-03-26 09:23:44 -0600139 if (shProg->Shaders) {
140 _mesa_free(shProg->Shaders);
141 shProg->Shaders = NULL;
142 }
Brianf2923612006-12-20 09:56:44 -0700143 _mesa_free(shProg);
144}
145
146
147/**
Brian3c008a02007-04-12 15:22:32 -0600148 * Set ptr to point to shProg.
149 * If ptr is pointing to another object, decrement its refcount (and delete
150 * if refcount hits zero).
151 * Then set ptr to point to shProg, incrementing its refcount.
152 */
153/* XXX this could be static */
154void
155_mesa_reference_shader_program(GLcontext *ctx,
156 struct gl_shader_program **ptr,
157 struct gl_shader_program *shProg)
158{
159 assert(ptr);
160 if (*ptr == shProg) {
161 /* no-op */
162 return;
163 }
164 if (*ptr) {
165 /* Unreference the old shader program */
166 GLboolean deleteFlag = GL_FALSE;
167 struct gl_shader_program *old = *ptr;
168
169 ASSERT(old->RefCount > 0);
170 old->RefCount--;
171 /*printf("SHPROG DECR %p (%d) to %d\n",
172 (void*) old, old->Name, old->RefCount);*/
173 deleteFlag = (old->RefCount == 0);
174
175 if (deleteFlag) {
176 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
177 _mesa_free_shader_program(ctx, old);
178 }
179
180 *ptr = NULL;
181 }
182 assert(!*ptr);
183
184 if (shProg) {
185 shProg->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600186 /*printf("SHPROG INCR %p (%d) to %d\n",
187 (void*) shProg, shProg->Name, shProg->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600188 *ptr = shProg;
189 }
190}
191
192
193/**
Brianf2923612006-12-20 09:56:44 -0700194 * Lookup a GLSL program object.
195 */
196struct gl_shader_program *
197_mesa_lookup_shader_program(GLcontext *ctx, GLuint name)
198{
199 struct gl_shader_program *shProg;
200 if (name) {
201 shProg = (struct gl_shader_program *)
202 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
203 /* Note that both gl_shader and gl_shader_program objects are kept
204 * in the same hash table. Check the object's type to be sure it's
205 * what we're expecting.
206 */
Brianf3e8c322007-04-18 14:53:23 -0600207 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700208 return NULL;
209 }
210 return shProg;
211 }
212 return NULL;
213}
214
215
216/**
217 * Allocate a new gl_shader object, initialize it.
218 */
219struct gl_shader *
220_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
221{
222 struct gl_shader *shader;
223 assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
224 shader = CALLOC_STRUCT(gl_shader);
225 if (shader) {
226 shader->Type = type;
227 shader->Name = name;
228 shader->RefCount = 1;
229 }
230 return shader;
231}
232
233
234void
235_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh)
236{
237 GLuint i;
238 if (sh->Source)
239 _mesa_free((void *) sh->Source);
240 if (sh->InfoLog)
241 _mesa_free(sh->InfoLog);
242 for (i = 0; i < sh->NumPrograms; i++) {
243 assert(sh->Programs[i]);
244 _mesa_delete_program(ctx, sh->Programs[i]);
245 }
246 if (sh->Programs)
247 _mesa_free(sh->Programs);
248 _mesa_free(sh);
249}
250
251
252/**
Brian3c008a02007-04-12 15:22:32 -0600253 * Set ptr to point to sh.
254 * If ptr is pointing to another shader, decrement its refcount (and delete
255 * if refcount hits zero).
256 * Then set ptr to point to sh, incrementing its refcount.
257 */
258/* XXX this could be static */
259void
260_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr,
261 struct gl_shader *sh)
262{
263 assert(ptr);
264 if (*ptr == sh) {
265 /* no-op */
266 return;
267 }
268 if (*ptr) {
269 /* Unreference the old shader */
270 GLboolean deleteFlag = GL_FALSE;
271 struct gl_shader *old = *ptr;
272
273 ASSERT(old->RefCount > 0);
274 old->RefCount--;
Brian99193e42007-04-12 15:45:02 -0600275 /*printf("SHADER DECR %p (%d) to %d\n",
276 (void*) old, old->Name, old->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600277 deleteFlag = (old->RefCount == 0);
278
279 if (deleteFlag) {
280 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
281 _mesa_free_shader(ctx, old);
282 }
283
284 *ptr = NULL;
285 }
286 assert(!*ptr);
287
288 if (sh) {
289 /* reference new */
290 sh->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600291 /*printf("SHADER INCR %p (%d) to %d\n",
292 (void*) sh, sh->Name, sh->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600293 *ptr = sh;
294 }
295}
296
297
298/**
Brianf2923612006-12-20 09:56:44 -0700299 * Lookup a GLSL shader object.
300 */
301struct gl_shader *
302_mesa_lookup_shader(GLcontext *ctx, GLuint name)
303{
304 if (name) {
305 struct gl_shader *sh = (struct gl_shader *)
306 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
307 /* Note that both gl_shader and gl_shader_program objects are kept
308 * in the same hash table. Check the object's type to be sure it's
309 * what we're expecting.
310 */
Brianf3e8c322007-04-18 14:53:23 -0600311 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700312 return NULL;
313 }
314 return sh;
315 }
316 return NULL;
317}
318
319
Brianfa4d0362007-02-26 18:33:50 -0700320/**
321 * Initialize context's shader state.
322 */
Brianf2923612006-12-20 09:56:44 -0700323void
324_mesa_init_shader_state(GLcontext * ctx)
325{
Brianfa4d0362007-02-26 18:33:50 -0700326 /* Device drivers may override these to control what kind of instructions
327 * are generated by the GLSL compiler.
328 */
329 ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
Brian63556fa2007-03-23 14:47:46 -0600330 ctx->Shader.EmitCondCodes = GL_TRUE; /* XXX probably want GL_FALSE... */
Brianfa4d0362007-02-26 18:33:50 -0700331 ctx->Shader.EmitComments = GL_FALSE;
Brianf2923612006-12-20 09:56:44 -0700332}
333
334
Brian5b01c5e2006-12-19 18:02:03 -0700335/**
Brian935f93f2007-03-24 16:20:02 -0600336 * Free the per-context shader-related state.
337 */
338void
339_mesa_free_shader_state(GLcontext *ctx)
340{
Brian3c008a02007-04-12 15:22:32 -0600341 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
Brian935f93f2007-03-24 16:20:02 -0600342}
343
344
345/**
Brian5b01c5e2006-12-19 18:02:03 -0700346 * Copy string from <src> to <dst>, up to maxLength characters, returning
347 * length of <dst> in <length>.
348 * \param src the strings source
349 * \param maxLength max chars to copy
350 * \param length returns number of chars copied
351 * \param dst the string destination
352 */
353static void
354copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
355{
356 GLsizei len;
357 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
358 dst[len] = src[len];
359 if (maxLength > 0)
360 dst[len] = 0;
361 if (length)
362 *length = len;
363}
364
365
Brian5b01c5e2006-12-19 18:02:03 -0700366/**
367 * Called via ctx->Driver.AttachShader()
368 */
369void
370_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
371{
Brian65a18442006-12-19 18:46:56 -0700372 struct gl_shader_program *shProg
373 = _mesa_lookup_shader_program(ctx, program);
374 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
375 const GLuint n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700376 GLuint i;
377
Brian65a18442006-12-19 18:46:56 -0700378 if (!shProg || !sh) {
Brian43975832007-01-04 08:21:09 -0700379 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700380 "glAttachShader(bad program or shader name)");
381 return;
382 }
383
384 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700385 if (shProg->Shaders[i] == sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700386 /* already attached */
387 return;
Brian34ae99d2006-12-18 08:28:54 -0700388 }
389 }
Brian5b01c5e2006-12-19 18:02:03 -0700390
391 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700392 shProg->Shaders = (struct gl_shader **)
393 _mesa_realloc(shProg->Shaders,
394 n * sizeof(struct gl_shader *),
395 (n + 1) * sizeof(struct gl_shader *));
396 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700397 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
398 return;
399 }
400
401 /* append */
Brian3c008a02007-04-12 15:22:32 -0600402 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
403 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700404 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700405}
406
407
408void
409_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
410 const GLchar *name)
411{
Brian65a18442006-12-19 18:46:56 -0700412 struct gl_shader_program *shProg
413 = _mesa_lookup_shader_program(ctx, program);
Brianb7978af2007-01-09 19:17:17 -0700414 const GLint size = -1; /* unknown size */
415 GLint i, oldIndex;
Brian5b01c5e2006-12-19 18:02:03 -0700416
Brian65a18442006-12-19 18:46:56 -0700417 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700418 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700419 return;
420 }
421
Brian9e4bae92006-12-20 09:27:42 -0700422 if (!name)
423 return;
424
425 if (strncmp(name, "gl_", 3) == 0) {
426 _mesa_error(ctx, GL_INVALID_OPERATION,
427 "glBindAttribLocation(illegal name)");
428 return;
429 }
430
Brian9f660252007-04-11 09:00:56 -0600431 if (shProg->LinkStatus) {
432 /* get current index/location for the attribute */
433 oldIndex = _mesa_get_attrib_location(ctx, program, name);
434 }
435 else {
436 oldIndex = -1;
437 }
Brian3209c3e2007-01-09 17:49:24 -0700438
439 /* this will replace the current value if it's already in the list */
Brianb7978af2007-01-09 19:17:17 -0700440 i = _mesa_add_attribute(shProg->Attributes, name, size, index);
Brian3209c3e2007-01-09 17:49:24 -0700441 if (i < 0) {
442 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
443 }
444
Brian9f660252007-04-11 09:00:56 -0600445 if (shProg->VertexProgram && oldIndex >= 0 && oldIndex != index) {
446 /* If the index changed, need to search/replace references to that attribute
447 * in the vertex program.
448 */
Brian3209c3e2007-01-09 17:49:24 -0700449 _slang_remap_attribute(&shProg->VertexProgram->Base, oldIndex, index);
450 }
Brian34ae99d2006-12-18 08:28:54 -0700451}
452
453
Brian5b01c5e2006-12-19 18:02:03 -0700454GLuint
455_mesa_create_shader(GLcontext *ctx, GLenum type)
456{
Brian65a18442006-12-19 18:46:56 -0700457 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700458 GLuint name;
459
460 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
461
462 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700463 case GL_FRAGMENT_SHADER:
464 case GL_VERTEX_SHADER:
465 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700466 break;
467 default:
468 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
469 return 0;
470 }
471
Brian65a18442006-12-19 18:46:56 -0700472 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700473
474 return name;
475}
476
477
478GLuint
479_mesa_create_program(GLcontext *ctx)
480{
481 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700482 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700483
Brian65a18442006-12-19 18:46:56 -0700484 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
485 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700486
Brian65a18442006-12-19 18:46:56 -0700487 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700488
Brian3c008a02007-04-12 15:22:32 -0600489 assert(shProg->RefCount == 1);
490
Brian5b01c5e2006-12-19 18:02:03 -0700491 return name;
492}
493
494
Brian3c008a02007-04-12 15:22:32 -0600495/**
496 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
497 * DeleteProgramARB.
498 */
Brian5b01c5e2006-12-19 18:02:03 -0700499void
500_mesa_delete_program2(GLcontext *ctx, GLuint name)
501{
Brian3c008a02007-04-12 15:22:32 -0600502 /*
503 * NOTE: deleting shaders/programs works a bit differently than
504 * texture objects (and buffer objects, etc). Shader/program
505 * handles/IDs exist in the hash table until the object is really
506 * deleted (refcount==0). With texture objects, the handle/ID is
507 * removed from the hash table in glDeleteTextures() while the tex
508 * object itself might linger until its refcount goes to zero.
509 */
Brian65a18442006-12-19 18:46:56 -0700510 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700511
Brian65a18442006-12-19 18:46:56 -0700512 shProg = _mesa_lookup_shader_program(ctx, name);
513 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700514 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteProgram(name)");
Brian5b01c5e2006-12-19 18:02:03 -0700515 return;
516 }
517
Brian9e4bae92006-12-20 09:27:42 -0700518 shProg->DeletePending = GL_TRUE;
519
Brian3c008a02007-04-12 15:22:32 -0600520 /* effectively, decr shProg's refcount */
521 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700522}
523
524
525void
526_mesa_delete_shader(GLcontext *ctx, GLuint shader)
527{
Brian9e4bae92006-12-20 09:27:42 -0700528 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
529 if (!sh) {
530 return;
531 }
Brian5b01c5e2006-12-19 18:02:03 -0700532
Brian9e4bae92006-12-20 09:27:42 -0700533 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600534
535 /* effectively, decr sh's refcount */
536 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700537}
538
539
540void
541_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
542{
Brian65a18442006-12-19 18:46:56 -0700543 struct gl_shader_program *shProg
544 = _mesa_lookup_shader_program(ctx, program);
545 const GLuint n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700546 GLuint i, j;
547
Brian65a18442006-12-19 18:46:56 -0700548 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700549 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700550 "glDetachShader(bad program or shader name)");
551 return;
552 }
553
554 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700555 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700556 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600557 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700558
Brian3c008a02007-04-12 15:22:32 -0600559 /* derefernce */
560 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700561
Brian5b01c5e2006-12-19 18:02:03 -0700562 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700563 newList = (struct gl_shader **)
564 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700565 if (!newList) {
566 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
567 return;
568 }
569 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700570 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700571 }
572 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700573 newList[j++] = shProg->Shaders[i];
574 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700575
Brian65a18442006-12-19 18:46:56 -0700576 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600577 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600578
579#ifdef DEBUG
580 /* sanity check */
581 {
582 for (j = 0; j < shProg->NumShaders; j++) {
583 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
584 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
585 assert(shProg->Shaders[j]->RefCount > 0);
586 }
587 }
588#endif
589
Brian5b01c5e2006-12-19 18:02:03 -0700590 return;
591 }
592 }
593
594 /* not found */
Brian43975832007-01-04 08:21:09 -0700595 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700596 "glDetachShader(shader not found)");
597}
598
599
600void
601_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
602 GLsizei maxLength, GLsizei *length, GLint *size,
603 GLenum *type, GLchar *nameOut)
604{
605 static const GLenum vec_types[] = {
606 GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4
607 };
Brian65a18442006-12-19 18:46:56 -0700608 struct gl_shader_program *shProg
609 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700610 GLint sz;
611
Brian65a18442006-12-19 18:46:56 -0700612 if (!shProg) {
Brianaaa57412007-04-18 15:22:43 -0600613 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib");
Brian5b01c5e2006-12-19 18:02:03 -0700614 return;
615 }
616
Brian65a18442006-12-19 18:46:56 -0700617 if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600618 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700619 return;
620 }
621
622 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700623 shProg->Attributes->Parameters[index].Name);
624 sz = shProg->Attributes->Parameters[index].Size;
Brian5b01c5e2006-12-19 18:02:03 -0700625 if (size)
626 *size = sz;
627 if (type)
628 *type = vec_types[sz]; /* XXX this is a temporary hack */
629}
630
631
632/**
633 * Called via ctx->Driver.GetActiveUniform().
634 */
635void
636_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
637 GLsizei maxLength, GLsizei *length, GLint *size,
638 GLenum *type, GLchar *nameOut)
639{
640 static const GLenum vec_types[] = {
641 GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4
642 };
Brian65a18442006-12-19 18:46:56 -0700643 struct gl_shader_program *shProg
644 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700645 GLint sz;
646
Brian65a18442006-12-19 18:46:56 -0700647 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700648 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform");
Brian5b01c5e2006-12-19 18:02:03 -0700649 return;
650 }
651
Brian65a18442006-12-19 18:46:56 -0700652 if (!shProg->Uniforms || index >= shProg->Uniforms->NumParameters) {
Brian5b01c5e2006-12-19 18:02:03 -0700653 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
654 return;
655 }
656
657 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700658 shProg->Uniforms->Parameters[index].Name);
659 sz = shProg->Uniforms->Parameters[index].Size;
Brian5b01c5e2006-12-19 18:02:03 -0700660 if (size)
661 *size = sz;
662 if (type)
663 *type = vec_types[sz]; /* XXX this is a temporary hack */
664}
665
666
667/**
668 * Called via ctx->Driver.GetAttachedShaders().
669 */
670void
671_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
672 GLsizei *count, GLuint *obj)
673{
Brian65a18442006-12-19 18:46:56 -0700674 struct gl_shader_program *shProg
675 = _mesa_lookup_shader_program(ctx, program);
676 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700677 GLint i;
Brian65a18442006-12-19 18:46:56 -0700678 for (i = 0; i < maxCount && i < shProg->NumShaders; i++) {
679 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700680 }
681 if (count)
682 *count = i;
683 }
684 else {
Brian43975832007-01-04 08:21:09 -0700685 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttachedShaders");
Brian5b01c5e2006-12-19 18:02:03 -0700686 }
687}
688
689
690GLint
691_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
692 const GLchar *name)
693{
Brian65a18442006-12-19 18:46:56 -0700694 struct gl_shader_program *shProg
695 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700696
Brian65a18442006-12-19 18:46:56 -0700697 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700698 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttribLocation");
Brian5b01c5e2006-12-19 18:02:03 -0700699 return -1;
700 }
701
Brian65a18442006-12-19 18:46:56 -0700702 if (!shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -0700703 _mesa_error(ctx, GL_INVALID_OPERATION,
704 "glGetAttribLocation(program not linked)");
705 return -1;
706 }
707
708 if (!name)
709 return -1;
710
Brian65a18442006-12-19 18:46:56 -0700711 if (shProg->Attributes) {
Brian3209c3e2007-01-09 17:49:24 -0700712 GLint i = _mesa_lookup_parameter_index(shProg->Attributes, -1, name);
713 if (i >= 0) {
Brian01a91eb2007-01-09 19:26:22 -0700714 return shProg->Attributes->Parameters[i].StateIndexes[0];
Brian5b01c5e2006-12-19 18:02:03 -0700715 }
716 }
717 return -1;
718}
719
720
721GLuint
722_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700723{
724#if 0
725 GET_CURRENT_CONTEXT(ctx);
726
727 switch (pname) {
728 case GL_PROGRAM_OBJECT_ARB:
729 {
Brian5b01c5e2006-12-19 18:02:03 -0700730 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700731
732 if (pro != NULL)
733 return (**pro)._container._generic.
734 GetName((struct gl2_generic_intf **) (pro));
735 }
736 break;
737 default:
738 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
739 }
740#endif
741 return 0;
742}
743
744
Brian5b01c5e2006-12-19 18:02:03 -0700745void
746_mesa_get_programiv(GLcontext *ctx, GLuint program,
747 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700748{
Brian65a18442006-12-19 18:46:56 -0700749 struct gl_shader_program *shProg
750 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700751
Brian65a18442006-12-19 18:46:56 -0700752 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700753 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700754 return;
755 }
756
Brian5b01c5e2006-12-19 18:02:03 -0700757 switch (pname) {
758 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700759 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700760 break;
761 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700762 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700763 break;
Brian5b01c5e2006-12-19 18:02:03 -0700764 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700765 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700766 break;
767 case GL_INFO_LOG_LENGTH:
Brian65a18442006-12-19 18:46:56 -0700768 *params = shProg->InfoLog ? strlen(shProg->InfoLog) : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700769 break;
770 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700771 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700772 break;
773 case GL_ACTIVE_ATTRIBUTES:
Brian3209c3e2007-01-09 17:49:24 -0700774 *params = shProg->Attributes ? shProg->Attributes->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700775 break;
776 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian6d3d9c12007-04-18 14:19:17 -0600777 *params = _mesa_longest_parameter_name(shProg->Attributes, PROGRAM_INPUT);
Brian5b01c5e2006-12-19 18:02:03 -0700778 break;
779 case GL_ACTIVE_UNIFORMS:
Brian65a18442006-12-19 18:46:56 -0700780 *params = shProg->Uniforms ? shProg->Uniforms->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700781 break;
782 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian6d3d9c12007-04-18 14:19:17 -0600783 *params = _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_UNIFORM);
Brian34ae99d2006-12-18 08:28:54 -0700784 break;
785 default:
Brian5b01c5e2006-12-19 18:02:03 -0700786 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
787 return;
Brian34ae99d2006-12-18 08:28:54 -0700788 }
Brian5b01c5e2006-12-19 18:02:03 -0700789}
Brian34ae99d2006-12-18 08:28:54 -0700790
Brian34ae99d2006-12-18 08:28:54 -0700791
Brian5b01c5e2006-12-19 18:02:03 -0700792void
793_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
794{
Brian65a18442006-12-19 18:46:56 -0700795 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700796
797 if (!shader) {
798 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderiv(shader)");
799 return;
800 }
Brian65a18442006-12-19 18:46:56 -0700801
Brian5b01c5e2006-12-19 18:02:03 -0700802 switch (pname) {
803 case GL_SHADER_TYPE:
804 *params = shader->Type;
805 break;
806 case GL_DELETE_STATUS:
807 *params = shader->DeletePending;
808 break;
809 case GL_COMPILE_STATUS:
810 *params = shader->CompileStatus;
811 break;
812 case GL_INFO_LOG_LENGTH:
813 *params = shader->InfoLog ? strlen(shader->InfoLog) : 0;
814 break;
815 case GL_SHADER_SOURCE_LENGTH:
816 *params = shader->Source ? strlen((char *) shader->Source) : 0;
817 break;
818 default:
819 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
820 return;
821 }
822}
823
824
825void
826_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
827 GLsizei *length, GLchar *infoLog)
828{
Brian65a18442006-12-19 18:46:56 -0700829 struct gl_shader_program *shProg
830 = _mesa_lookup_shader_program(ctx, program);
831 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700832 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
833 return;
834 }
Brian65a18442006-12-19 18:46:56 -0700835 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700836}
837
838
839void
840_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
841 GLsizei *length, GLchar *infoLog)
842{
Brian65a18442006-12-19 18:46:56 -0700843 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
844 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700845 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
846 return;
847 }
Brian65a18442006-12-19 18:46:56 -0700848 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700849}
850
851
852/**
853 * Called via ctx->Driver.GetShaderSource().
854 */
855void
856_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
857 GLsizei *length, GLchar *sourceOut)
858{
Brian65a18442006-12-19 18:46:56 -0700859 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
860 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700861 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderSource(shader)");
862 return;
863 }
Brian65a18442006-12-19 18:46:56 -0700864 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -0700865}
866
867
868/**
869 * Called via ctx->Driver.GetUniformfv().
870 */
871void
872_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
873 GLfloat *params)
874{
Brian65a18442006-12-19 18:46:56 -0700875 struct gl_shader_program *shProg
876 = _mesa_lookup_shader_program(ctx, program);
877 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700878 GLint i;
Brian65a18442006-12-19 18:46:56 -0700879 if (location >= 0 && location < shProg->Uniforms->NumParameters) {
880 for (i = 0; i < shProg->Uniforms->Parameters[location].Size; i++) {
881 params[i] = shProg->Uniforms->ParameterValues[location][i];
Brian5b01c5e2006-12-19 18:02:03 -0700882 }
883 }
884 else {
885 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(location)");
886 }
887 }
888 else {
Brian43975832007-01-04 08:21:09 -0700889 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700890 }
891}
892
893
894/**
895 * Called via ctx->Driver.GetUniformLocation().
896 */
897GLint
898_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
899{
Brian71623982007-01-30 16:55:03 -0700900 struct gl_shader_program *shProg
901 = _mesa_lookup_shader_program(ctx, program);
902 if (shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700903 GLuint loc;
Brian65a18442006-12-19 18:46:56 -0700904 for (loc = 0; loc < shProg->Uniforms->NumParameters; loc++) {
Brian5b01c5e2006-12-19 18:02:03 -0700905 const struct gl_program_parameter *u
Brian65a18442006-12-19 18:46:56 -0700906 = shProg->Uniforms->Parameters + loc;
Brian29053852006-12-21 11:21:26 -0700907 /* XXX this is a temporary simplification / short-cut.
908 * We need to handle things like "e.c[0].b" as seen in the
909 * GLSL orange book, page 189.
910 */
Brian5cf73262007-01-05 16:02:45 -0700911 if ((u->Type == PROGRAM_UNIFORM ||
912 u->Type == PROGRAM_SAMPLER) && !strcmp(u->Name, name)) {
Brian5b01c5e2006-12-19 18:02:03 -0700913 return loc;
914 }
915 }
916 }
917 return -1;
918
919}
920
921
922GLboolean
923_mesa_is_program(GLcontext *ctx, GLuint name)
924{
Brian65a18442006-12-19 18:46:56 -0700925 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
926 return shProg ? GL_TRUE : GL_FALSE;
Brian5b01c5e2006-12-19 18:02:03 -0700927}
928
929
930GLboolean
931_mesa_is_shader(GLcontext *ctx, GLuint name)
932{
Brian65a18442006-12-19 18:46:56 -0700933 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700934 return shader ? GL_TRUE : GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700935}
936
937
938
Brian5b01c5e2006-12-19 18:02:03 -0700939/**
940 * Called via ctx->Driver.ShaderSource()
941 */
942void
943_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -0700944{
Brian65a18442006-12-19 18:46:56 -0700945 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
946 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700947 _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSource(shaderObj)");
Brian34ae99d2006-12-18 08:28:54 -0700948 return;
949 }
950
Brian34ae99d2006-12-18 08:28:54 -0700951 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -0700952 if (sh->Source) {
953 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -0700954 }
Brian65a18442006-12-19 18:46:56 -0700955 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -0700956 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700957}
958
959
Brian5b01c5e2006-12-19 18:02:03 -0700960/**
961 * Called via ctx->Driver.CompileShader()
962 */
963void
964_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -0700965{
Brian65a18442006-12-19 18:46:56 -0700966 struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj);
Brian34ae99d2006-12-18 08:28:54 -0700967
Brian65a18442006-12-19 18:46:56 -0700968 if (!sh) {
Brian34ae99d2006-12-18 08:28:54 -0700969 _mesa_error(ctx, GL_INVALID_VALUE, "glCompileShader(shaderObj)");
970 return;
971 }
972
Brian43975832007-01-04 08:21:09 -0700973 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -0700974}
975
976
Brian5b01c5e2006-12-19 18:02:03 -0700977/**
978 * Called via ctx->Driver.LinkProgram()
979 */
980void
981_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -0700982{
Brian65a18442006-12-19 18:46:56 -0700983 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -0700984
Brian65a18442006-12-19 18:46:56 -0700985 shProg = _mesa_lookup_shader_program(ctx, program);
986 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700987 _mesa_error(ctx, GL_INVALID_VALUE, "glLinkProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -0700988 return;
989 }
990
Brianc1771912007-02-16 09:56:19 -0700991 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -0700992}
993
994
995/**
Brian5b01c5e2006-12-19 18:02:03 -0700996 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -0700997 */
Brian5b01c5e2006-12-19 18:02:03 -0700998void
999_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001000{
Brian3c008a02007-04-12 15:22:32 -06001001 struct gl_shader_program *shProg;
1002
Brian00d63aa2007-02-03 11:35:02 -07001003 if (ctx->Shader.CurrentProgram &&
1004 ctx->Shader.CurrentProgram->Name == program) {
1005 /* no-op */
1006 return;
1007 }
1008
1009 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1010
Brian5b01c5e2006-12-19 18:02:03 -07001011 if (program) {
Brian65a18442006-12-19 18:46:56 -07001012 shProg = _mesa_lookup_shader_program(ctx, program);
1013 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001014 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -07001015 "glUseProgramObjectARB(programObj)");
1016 return;
1017 }
Brian5b01c5e2006-12-19 18:02:03 -07001018 }
1019 else {
Brian3c008a02007-04-12 15:22:32 -06001020 shProg = NULL;
1021 }
1022
1023 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001024}
Brian34ae99d2006-12-18 08:28:54 -07001025
Brian5b01c5e2006-12-19 18:02:03 -07001026
1027/**
1028 * Called via ctx->Driver.Uniform().
1029 */
1030void
1031_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1032 const GLvoid *values, GLenum type)
1033{
Brian3a8e2772006-12-20 17:19:16 -07001034 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian98650bd2007-03-13 16:32:48 -06001035 GLint elems, i, k;
Brian3a8e2772006-12-20 17:19:16 -07001036
1037 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001038 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001039 return;
1040 }
1041
Brian223d7cb2007-01-23 16:37:51 -07001042 if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) {
Brian3a8e2772006-12-20 17:19:16 -07001043 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
1044 return;
1045 }
1046
1047 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1048
Brianfee9bbe2007-02-02 18:05:43 -07001049 /*
1050 * If we're setting a sampler, we must use glUniformi1()!
1051 */
1052 if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
1053 if (type != GL_INT || count != 1) {
1054 _mesa_error(ctx, GL_INVALID_OPERATION,
1055 "glUniform(only glUniform1i can be used "
1056 "to set sampler uniforms)");
1057 return;
1058 }
1059 }
1060
Brian52363952007-03-13 16:50:24 -06001061 if (count < 0) {
1062 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1063 return;
1064 }
1065
Brian98650bd2007-03-13 16:32:48 -06001066 switch (type) {
1067 case GL_FLOAT:
1068 case GL_INT:
1069 elems = 1;
1070 break;
1071 case GL_FLOAT_VEC2:
1072 case GL_INT_VEC2:
1073 elems = 2;
1074 break;
1075 case GL_FLOAT_VEC3:
1076 case GL_INT_VEC3:
1077 elems = 3;
1078 break;
1079 case GL_FLOAT_VEC4:
1080 case GL_INT_VEC4:
1081 elems = 4;
1082 break;
1083 default:
1084 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1085 return;
Brian89dc4852007-01-04 14:35:44 -07001086 }
Brian98650bd2007-03-13 16:32:48 -06001087
1088 if (count * elems > shProg->Uniforms->Parameters[location].Size) {
1089 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1090 return;
1091 }
1092
1093 for (k = 0; k < count; k++) {
1094 GLfloat *uniformVal = shProg->Uniforms->ParameterValues[location + k];
1095 if (type == GL_INT ||
1096 type == GL_INT_VEC2 ||
1097 type == GL_INT_VEC3 ||
1098 type == GL_INT_VEC4) {
Brian52363952007-03-13 16:50:24 -06001099 const GLint *iValues = ((const GLint *) values) + k * elems;
Brian98650bd2007-03-13 16:32:48 -06001100 for (i = 0; i < elems; i++) {
1101 uniformVal[i] = (GLfloat) iValues[i];
1102 }
1103 }
1104 else {
Brian52363952007-03-13 16:50:24 -06001105 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
Brian98650bd2007-03-13 16:32:48 -06001106 for (i = 0; i < elems; i++) {
1107 uniformVal[i] = fValues[i];
1108 }
Brian89dc4852007-01-04 14:35:44 -07001109 }
Brian5b01c5e2006-12-19 18:02:03 -07001110 }
Brian5cf73262007-01-05 16:02:45 -07001111
1112 if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
Briancec81ee2007-03-07 08:04:06 -07001113 if (shProg->VertexProgram)
1114 _slang_resolve_samplers(shProg, &shProg->VertexProgram->Base);
1115 if (shProg->FragmentProgram)
1116 _slang_resolve_samplers(shProg, &shProg->FragmentProgram->Base);
Brian5cf73262007-01-05 16:02:45 -07001117 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1118 }
Brian34ae99d2006-12-18 08:28:54 -07001119}
1120
1121
1122/**
Brian5b01c5e2006-12-19 18:02:03 -07001123 * Called by ctx->Driver.UniformMatrix().
Brian34ae99d2006-12-18 08:28:54 -07001124 */
Brian5b01c5e2006-12-19 18:02:03 -07001125void
1126_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1127 GLenum matrixType, GLint location, GLsizei count,
1128 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001129{
Brian3a8e2772006-12-20 17:19:16 -07001130 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
1131 if (!shProg || !shProg->LinkStatus) {
1132 _mesa_error(ctx, GL_INVALID_OPERATION,
1133 "glUniformMatrix(program not linked)");
1134 return;
1135 }
1136 if (location < 0 || location >= shProg->Uniforms->NumParameters) {
1137 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
1138 return;
1139 }
Brian34ae99d2006-12-18 08:28:54 -07001140 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001141 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001142 return;
1143 }
1144
1145 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1146
Brian3a8e2772006-12-20 17:19:16 -07001147 /*
1148 * Note: the _columns_ of a matrix are stored in program registers, not
1149 * the rows.
1150 */
1151 /* XXXX need to test 3x3 and 2x2 matrices... */
Brian34ae99d2006-12-18 08:28:54 -07001152 if (transpose) {
Brian3a8e2772006-12-20 17:19:16 -07001153 GLuint row, col;
1154 for (col = 0; col < cols; col++) {
1155 GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
1156 for (row = 0; row < rows; row++) {
Brian9f442472007-03-09 11:34:18 -07001157 v[row] = values[row * cols + col];
Brian34ae99d2006-12-18 08:28:54 -07001158 }
Brian34ae99d2006-12-18 08:28:54 -07001159 }
Brian34ae99d2006-12-18 08:28:54 -07001160 }
1161 else {
Brian3a8e2772006-12-20 17:19:16 -07001162 GLuint row, col;
1163 for (col = 0; col < cols; col++) {
1164 GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
1165 for (row = 0; row < rows; row++) {
Brian9f442472007-03-09 11:34:18 -07001166 v[row] = values[col * rows + row];
Brian3a8e2772006-12-20 17:19:16 -07001167 }
1168 }
Brian34ae99d2006-12-18 08:28:54 -07001169 }
1170}
1171
1172
Brian5b01c5e2006-12-19 18:02:03 -07001173void
1174_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001175{
Brian65a18442006-12-19 18:46:56 -07001176 struct gl_shader_program *shProg;
1177 shProg = _mesa_lookup_shader_program(ctx, program);
1178 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001179 _mesa_error(ctx, GL_INVALID_VALUE, "glValidateProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001180 return;
1181 }
Brian5b01c5e2006-12-19 18:02:03 -07001182 /* XXX temporary */
Brian65a18442006-12-19 18:46:56 -07001183 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001184
Brian5b01c5e2006-12-19 18:02:03 -07001185 /* From the GL spec:
1186 any two active samplers in the current program object are of
1187 different types, but refer to the same texture image unit,
1188
1189 any active sampler in the current program object refers to a texture
1190 image unit where fixed-function fragment processing accesses a
1191 texture target that does not match the sampler type, or
1192
1193 the sum of the number of active samplers in the program and the
1194 number of texture image units enabled for fixed-function fragment
1195 processing exceeds the combined limit on the total number of texture
1196 image units allowed.
1197 */
Brian34ae99d2006-12-18 08:28:54 -07001198}