blob: 0c4f4837fbfc711cea1c3e1ef5c84b7150a9bd2b [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;
Brian5b01c5e2006-12-19 18:02:03 -0700578 return;
579 }
580 }
581
582 /* not found */
Brian43975832007-01-04 08:21:09 -0700583 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700584 "glDetachShader(shader not found)");
585}
586
587
588void
589_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
590 GLsizei maxLength, GLsizei *length, GLint *size,
591 GLenum *type, GLchar *nameOut)
592{
593 static const GLenum vec_types[] = {
594 GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4
595 };
Brian65a18442006-12-19 18:46:56 -0700596 struct gl_shader_program *shProg
597 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700598 GLint sz;
599
Brian65a18442006-12-19 18:46:56 -0700600 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700601 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform");
Brian5b01c5e2006-12-19 18:02:03 -0700602 return;
603 }
604
Brian65a18442006-12-19 18:46:56 -0700605 if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) {
Brian5b01c5e2006-12-19 18:02:03 -0700606 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
607 return;
608 }
609
610 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700611 shProg->Attributes->Parameters[index].Name);
612 sz = shProg->Attributes->Parameters[index].Size;
Brian5b01c5e2006-12-19 18:02:03 -0700613 if (size)
614 *size = sz;
615 if (type)
616 *type = vec_types[sz]; /* XXX this is a temporary hack */
617}
618
619
620/**
621 * Called via ctx->Driver.GetActiveUniform().
622 */
623void
624_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
625 GLsizei maxLength, GLsizei *length, GLint *size,
626 GLenum *type, GLchar *nameOut)
627{
628 static const GLenum vec_types[] = {
629 GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4
630 };
Brian65a18442006-12-19 18:46:56 -0700631 struct gl_shader_program *shProg
632 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700633 GLint sz;
634
Brian65a18442006-12-19 18:46:56 -0700635 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700636 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform");
Brian5b01c5e2006-12-19 18:02:03 -0700637 return;
638 }
639
Brian65a18442006-12-19 18:46:56 -0700640 if (!shProg->Uniforms || index >= shProg->Uniforms->NumParameters) {
Brian5b01c5e2006-12-19 18:02:03 -0700641 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
642 return;
643 }
644
645 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700646 shProg->Uniforms->Parameters[index].Name);
647 sz = shProg->Uniforms->Parameters[index].Size;
Brian5b01c5e2006-12-19 18:02:03 -0700648 if (size)
649 *size = sz;
650 if (type)
651 *type = vec_types[sz]; /* XXX this is a temporary hack */
652}
653
654
655/**
656 * Called via ctx->Driver.GetAttachedShaders().
657 */
658void
659_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
660 GLsizei *count, GLuint *obj)
661{
Brian65a18442006-12-19 18:46:56 -0700662 struct gl_shader_program *shProg
663 = _mesa_lookup_shader_program(ctx, program);
664 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700665 GLint i;
Brian65a18442006-12-19 18:46:56 -0700666 for (i = 0; i < maxCount && i < shProg->NumShaders; i++) {
667 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700668 }
669 if (count)
670 *count = i;
671 }
672 else {
Brian43975832007-01-04 08:21:09 -0700673 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttachedShaders");
Brian5b01c5e2006-12-19 18:02:03 -0700674 }
675}
676
677
678GLint
679_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
680 const GLchar *name)
681{
Brian65a18442006-12-19 18:46:56 -0700682 struct gl_shader_program *shProg
683 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700684
Brian65a18442006-12-19 18:46:56 -0700685 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700686 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttribLocation");
Brian5b01c5e2006-12-19 18:02:03 -0700687 return -1;
688 }
689
Brian65a18442006-12-19 18:46:56 -0700690 if (!shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -0700691 _mesa_error(ctx, GL_INVALID_OPERATION,
692 "glGetAttribLocation(program not linked)");
693 return -1;
694 }
695
696 if (!name)
697 return -1;
698
Brian65a18442006-12-19 18:46:56 -0700699 if (shProg->Attributes) {
Brian3209c3e2007-01-09 17:49:24 -0700700 GLint i = _mesa_lookup_parameter_index(shProg->Attributes, -1, name);
701 if (i >= 0) {
Brian01a91eb2007-01-09 19:26:22 -0700702 return shProg->Attributes->Parameters[i].StateIndexes[0];
Brian5b01c5e2006-12-19 18:02:03 -0700703 }
704 }
705 return -1;
706}
707
708
709GLuint
710_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700711{
712#if 0
713 GET_CURRENT_CONTEXT(ctx);
714
715 switch (pname) {
716 case GL_PROGRAM_OBJECT_ARB:
717 {
Brian5b01c5e2006-12-19 18:02:03 -0700718 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700719
720 if (pro != NULL)
721 return (**pro)._container._generic.
722 GetName((struct gl2_generic_intf **) (pro));
723 }
724 break;
725 default:
726 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
727 }
728#endif
729 return 0;
730}
731
732
Brian5b01c5e2006-12-19 18:02:03 -0700733void
734_mesa_get_programiv(GLcontext *ctx, GLuint program,
735 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700736{
Brian65a18442006-12-19 18:46:56 -0700737 struct gl_shader_program *shProg
738 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700739
Brian65a18442006-12-19 18:46:56 -0700740 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700741 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700742 return;
743 }
744
Brian5b01c5e2006-12-19 18:02:03 -0700745 switch (pname) {
746 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700747 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700748 break;
749 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700750 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700751 break;
Brian5b01c5e2006-12-19 18:02:03 -0700752 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700753 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700754 break;
755 case GL_INFO_LOG_LENGTH:
Brian65a18442006-12-19 18:46:56 -0700756 *params = shProg->InfoLog ? strlen(shProg->InfoLog) : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700757 break;
758 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700759 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700760 break;
761 case GL_ACTIVE_ATTRIBUTES:
Brian3209c3e2007-01-09 17:49:24 -0700762 *params = shProg->Attributes ? shProg->Attributes->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700763 break;
764 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian6d3d9c12007-04-18 14:19:17 -0600765 *params = _mesa_longest_parameter_name(shProg->Attributes, PROGRAM_INPUT);
Brian5b01c5e2006-12-19 18:02:03 -0700766 break;
767 case GL_ACTIVE_UNIFORMS:
Brian65a18442006-12-19 18:46:56 -0700768 *params = shProg->Uniforms ? shProg->Uniforms->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700769 break;
770 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian6d3d9c12007-04-18 14:19:17 -0600771 *params = _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_UNIFORM);
Brian34ae99d2006-12-18 08:28:54 -0700772 break;
773 default:
Brian5b01c5e2006-12-19 18:02:03 -0700774 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
775 return;
Brian34ae99d2006-12-18 08:28:54 -0700776 }
Brian5b01c5e2006-12-19 18:02:03 -0700777}
Brian34ae99d2006-12-18 08:28:54 -0700778
Brian34ae99d2006-12-18 08:28:54 -0700779
Brian5b01c5e2006-12-19 18:02:03 -0700780void
781_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
782{
Brian65a18442006-12-19 18:46:56 -0700783 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700784
785 if (!shader) {
786 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderiv(shader)");
787 return;
788 }
Brian65a18442006-12-19 18:46:56 -0700789
Brian5b01c5e2006-12-19 18:02:03 -0700790 switch (pname) {
791 case GL_SHADER_TYPE:
792 *params = shader->Type;
793 break;
794 case GL_DELETE_STATUS:
795 *params = shader->DeletePending;
796 break;
797 case GL_COMPILE_STATUS:
798 *params = shader->CompileStatus;
799 break;
800 case GL_INFO_LOG_LENGTH:
801 *params = shader->InfoLog ? strlen(shader->InfoLog) : 0;
802 break;
803 case GL_SHADER_SOURCE_LENGTH:
804 *params = shader->Source ? strlen((char *) shader->Source) : 0;
805 break;
806 default:
807 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
808 return;
809 }
810}
811
812
813void
814_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
815 GLsizei *length, GLchar *infoLog)
816{
Brian65a18442006-12-19 18:46:56 -0700817 struct gl_shader_program *shProg
818 = _mesa_lookup_shader_program(ctx, program);
819 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700820 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
821 return;
822 }
Brian65a18442006-12-19 18:46:56 -0700823 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700824}
825
826
827void
828_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
829 GLsizei *length, GLchar *infoLog)
830{
Brian65a18442006-12-19 18:46:56 -0700831 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
832 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700833 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
834 return;
835 }
Brian65a18442006-12-19 18:46:56 -0700836 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700837}
838
839
840/**
841 * Called via ctx->Driver.GetShaderSource().
842 */
843void
844_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
845 GLsizei *length, GLchar *sourceOut)
846{
Brian65a18442006-12-19 18:46:56 -0700847 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
848 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700849 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderSource(shader)");
850 return;
851 }
Brian65a18442006-12-19 18:46:56 -0700852 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -0700853}
854
855
856/**
857 * Called via ctx->Driver.GetUniformfv().
858 */
859void
860_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
861 GLfloat *params)
862{
Brian65a18442006-12-19 18:46:56 -0700863 struct gl_shader_program *shProg
864 = _mesa_lookup_shader_program(ctx, program);
865 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700866 GLint i;
Brian65a18442006-12-19 18:46:56 -0700867 if (location >= 0 && location < shProg->Uniforms->NumParameters) {
868 for (i = 0; i < shProg->Uniforms->Parameters[location].Size; i++) {
869 params[i] = shProg->Uniforms->ParameterValues[location][i];
Brian5b01c5e2006-12-19 18:02:03 -0700870 }
871 }
872 else {
873 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(location)");
874 }
875 }
876 else {
Brian43975832007-01-04 08:21:09 -0700877 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700878 }
879}
880
881
882/**
883 * Called via ctx->Driver.GetUniformLocation().
884 */
885GLint
886_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
887{
Brian71623982007-01-30 16:55:03 -0700888 struct gl_shader_program *shProg
889 = _mesa_lookup_shader_program(ctx, program);
890 if (shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700891 GLuint loc;
Brian65a18442006-12-19 18:46:56 -0700892 for (loc = 0; loc < shProg->Uniforms->NumParameters; loc++) {
Brian5b01c5e2006-12-19 18:02:03 -0700893 const struct gl_program_parameter *u
Brian65a18442006-12-19 18:46:56 -0700894 = shProg->Uniforms->Parameters + loc;
Brian29053852006-12-21 11:21:26 -0700895 /* XXX this is a temporary simplification / short-cut.
896 * We need to handle things like "e.c[0].b" as seen in the
897 * GLSL orange book, page 189.
898 */
Brian5cf73262007-01-05 16:02:45 -0700899 if ((u->Type == PROGRAM_UNIFORM ||
900 u->Type == PROGRAM_SAMPLER) && !strcmp(u->Name, name)) {
Brian5b01c5e2006-12-19 18:02:03 -0700901 return loc;
902 }
903 }
904 }
905 return -1;
906
907}
908
909
910GLboolean
911_mesa_is_program(GLcontext *ctx, GLuint name)
912{
Brian65a18442006-12-19 18:46:56 -0700913 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
914 return shProg ? GL_TRUE : GL_FALSE;
Brian5b01c5e2006-12-19 18:02:03 -0700915}
916
917
918GLboolean
919_mesa_is_shader(GLcontext *ctx, GLuint name)
920{
Brian65a18442006-12-19 18:46:56 -0700921 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700922 return shader ? GL_TRUE : GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700923}
924
925
926
Brian5b01c5e2006-12-19 18:02:03 -0700927/**
928 * Called via ctx->Driver.ShaderSource()
929 */
930void
931_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -0700932{
Brian65a18442006-12-19 18:46:56 -0700933 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
934 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700935 _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSource(shaderObj)");
Brian34ae99d2006-12-18 08:28:54 -0700936 return;
937 }
938
Brian34ae99d2006-12-18 08:28:54 -0700939 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -0700940 if (sh->Source) {
941 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -0700942 }
Brian65a18442006-12-19 18:46:56 -0700943 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -0700944 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700945}
946
947
Brian5b01c5e2006-12-19 18:02:03 -0700948/**
949 * Called via ctx->Driver.CompileShader()
950 */
951void
952_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -0700953{
Brian65a18442006-12-19 18:46:56 -0700954 struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj);
Brian34ae99d2006-12-18 08:28:54 -0700955
Brian65a18442006-12-19 18:46:56 -0700956 if (!sh) {
Brian34ae99d2006-12-18 08:28:54 -0700957 _mesa_error(ctx, GL_INVALID_VALUE, "glCompileShader(shaderObj)");
958 return;
959 }
960
Brian43975832007-01-04 08:21:09 -0700961 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -0700962}
963
964
Brian5b01c5e2006-12-19 18:02:03 -0700965/**
966 * Called via ctx->Driver.LinkProgram()
967 */
968void
969_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -0700970{
Brian65a18442006-12-19 18:46:56 -0700971 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -0700972
Brian65a18442006-12-19 18:46:56 -0700973 shProg = _mesa_lookup_shader_program(ctx, program);
974 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700975 _mesa_error(ctx, GL_INVALID_VALUE, "glLinkProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -0700976 return;
977 }
978
Brianc1771912007-02-16 09:56:19 -0700979 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -0700980}
981
982
983/**
Brian5b01c5e2006-12-19 18:02:03 -0700984 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -0700985 */
Brian5b01c5e2006-12-19 18:02:03 -0700986void
987_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -0700988{
Brian3c008a02007-04-12 15:22:32 -0600989 struct gl_shader_program *shProg;
990
Brian00d63aa2007-02-03 11:35:02 -0700991 if (ctx->Shader.CurrentProgram &&
992 ctx->Shader.CurrentProgram->Name == program) {
993 /* no-op */
994 return;
995 }
996
997 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
998
Brian5b01c5e2006-12-19 18:02:03 -0700999 if (program) {
Brian65a18442006-12-19 18:46:56 -07001000 shProg = _mesa_lookup_shader_program(ctx, program);
1001 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001002 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -07001003 "glUseProgramObjectARB(programObj)");
1004 return;
1005 }
Brian5b01c5e2006-12-19 18:02:03 -07001006 }
1007 else {
Brian3c008a02007-04-12 15:22:32 -06001008 shProg = NULL;
1009 }
1010
1011 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001012}
Brian34ae99d2006-12-18 08:28:54 -07001013
Brian5b01c5e2006-12-19 18:02:03 -07001014
1015/**
1016 * Called via ctx->Driver.Uniform().
1017 */
1018void
1019_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1020 const GLvoid *values, GLenum type)
1021{
Brian3a8e2772006-12-20 17:19:16 -07001022 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian98650bd2007-03-13 16:32:48 -06001023 GLint elems, i, k;
Brian3a8e2772006-12-20 17:19:16 -07001024
1025 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001026 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001027 return;
1028 }
1029
Brian223d7cb2007-01-23 16:37:51 -07001030 if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) {
Brian3a8e2772006-12-20 17:19:16 -07001031 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
1032 return;
1033 }
1034
1035 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1036
Brianfee9bbe2007-02-02 18:05:43 -07001037 /*
1038 * If we're setting a sampler, we must use glUniformi1()!
1039 */
1040 if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
1041 if (type != GL_INT || count != 1) {
1042 _mesa_error(ctx, GL_INVALID_OPERATION,
1043 "glUniform(only glUniform1i can be used "
1044 "to set sampler uniforms)");
1045 return;
1046 }
1047 }
1048
Brian52363952007-03-13 16:50:24 -06001049 if (count < 0) {
1050 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1051 return;
1052 }
1053
Brian98650bd2007-03-13 16:32:48 -06001054 switch (type) {
1055 case GL_FLOAT:
1056 case GL_INT:
1057 elems = 1;
1058 break;
1059 case GL_FLOAT_VEC2:
1060 case GL_INT_VEC2:
1061 elems = 2;
1062 break;
1063 case GL_FLOAT_VEC3:
1064 case GL_INT_VEC3:
1065 elems = 3;
1066 break;
1067 case GL_FLOAT_VEC4:
1068 case GL_INT_VEC4:
1069 elems = 4;
1070 break;
1071 default:
1072 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1073 return;
Brian89dc4852007-01-04 14:35:44 -07001074 }
Brian98650bd2007-03-13 16:32:48 -06001075
1076 if (count * elems > shProg->Uniforms->Parameters[location].Size) {
1077 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1078 return;
1079 }
1080
1081 for (k = 0; k < count; k++) {
1082 GLfloat *uniformVal = shProg->Uniforms->ParameterValues[location + k];
1083 if (type == GL_INT ||
1084 type == GL_INT_VEC2 ||
1085 type == GL_INT_VEC3 ||
1086 type == GL_INT_VEC4) {
Brian52363952007-03-13 16:50:24 -06001087 const GLint *iValues = ((const GLint *) values) + k * elems;
Brian98650bd2007-03-13 16:32:48 -06001088 for (i = 0; i < elems; i++) {
1089 uniformVal[i] = (GLfloat) iValues[i];
1090 }
1091 }
1092 else {
Brian52363952007-03-13 16:50:24 -06001093 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
Brian98650bd2007-03-13 16:32:48 -06001094 for (i = 0; i < elems; i++) {
1095 uniformVal[i] = fValues[i];
1096 }
Brian89dc4852007-01-04 14:35:44 -07001097 }
Brian5b01c5e2006-12-19 18:02:03 -07001098 }
Brian5cf73262007-01-05 16:02:45 -07001099
1100 if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
Briancec81ee2007-03-07 08:04:06 -07001101 if (shProg->VertexProgram)
1102 _slang_resolve_samplers(shProg, &shProg->VertexProgram->Base);
1103 if (shProg->FragmentProgram)
1104 _slang_resolve_samplers(shProg, &shProg->FragmentProgram->Base);
Brian5cf73262007-01-05 16:02:45 -07001105 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1106 }
Brian34ae99d2006-12-18 08:28:54 -07001107}
1108
1109
1110/**
Brian5b01c5e2006-12-19 18:02:03 -07001111 * Called by ctx->Driver.UniformMatrix().
Brian34ae99d2006-12-18 08:28:54 -07001112 */
Brian5b01c5e2006-12-19 18:02:03 -07001113void
1114_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1115 GLenum matrixType, GLint location, GLsizei count,
1116 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001117{
Brian3a8e2772006-12-20 17:19:16 -07001118 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
1119 if (!shProg || !shProg->LinkStatus) {
1120 _mesa_error(ctx, GL_INVALID_OPERATION,
1121 "glUniformMatrix(program not linked)");
1122 return;
1123 }
1124 if (location < 0 || location >= shProg->Uniforms->NumParameters) {
1125 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
1126 return;
1127 }
Brian34ae99d2006-12-18 08:28:54 -07001128 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001129 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001130 return;
1131 }
1132
1133 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1134
Brian3a8e2772006-12-20 17:19:16 -07001135 /*
1136 * Note: the _columns_ of a matrix are stored in program registers, not
1137 * the rows.
1138 */
1139 /* XXXX need to test 3x3 and 2x2 matrices... */
Brian34ae99d2006-12-18 08:28:54 -07001140 if (transpose) {
Brian3a8e2772006-12-20 17:19:16 -07001141 GLuint row, col;
1142 for (col = 0; col < cols; col++) {
1143 GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
1144 for (row = 0; row < rows; row++) {
Brian9f442472007-03-09 11:34:18 -07001145 v[row] = values[row * cols + col];
Brian34ae99d2006-12-18 08:28:54 -07001146 }
Brian34ae99d2006-12-18 08:28:54 -07001147 }
Brian34ae99d2006-12-18 08:28:54 -07001148 }
1149 else {
Brian3a8e2772006-12-20 17:19:16 -07001150 GLuint row, col;
1151 for (col = 0; col < cols; col++) {
1152 GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
1153 for (row = 0; row < rows; row++) {
Brian9f442472007-03-09 11:34:18 -07001154 v[row] = values[col * rows + row];
Brian3a8e2772006-12-20 17:19:16 -07001155 }
1156 }
Brian34ae99d2006-12-18 08:28:54 -07001157 }
1158}
1159
1160
Brian5b01c5e2006-12-19 18:02:03 -07001161void
1162_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001163{
Brian65a18442006-12-19 18:46:56 -07001164 struct gl_shader_program *shProg;
1165 shProg = _mesa_lookup_shader_program(ctx, program);
1166 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001167 _mesa_error(ctx, GL_INVALID_VALUE, "glValidateProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001168 return;
1169 }
Brian5b01c5e2006-12-19 18:02:03 -07001170 /* XXX temporary */
Brian65a18442006-12-19 18:46:56 -07001171 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001172
Brian5b01c5e2006-12-19 18:02:03 -07001173 /* From the GL spec:
1174 any two active samplers in the current program object are of
1175 different types, but refer to the same texture image unit,
1176
1177 any active sampler in the current program object refers to a texture
1178 image unit where fixed-function fragment processing accesses a
1179 texture target that does not match the sampler type, or
1180
1181 the sum of the number of active samplers in the program and the
1182 number of texture image units enabled for fixed-function fragment
1183 processing exceeds the combined limit on the total number of texture
1184 image units allowed.
1185 */
Brian34ae99d2006-12-18 08:28:54 -07001186}