blob: 418ef5c72391f42d5e3af304ab3fcdb30fe5b72e [file] [log] [blame]
Brian34ae99d2006-12-18 08:28:54 -07001/*
2 * Mesa 3-D graphics library
Brian5b01c5e2006-12-19 18:02:03 -07003 * Version: 6.5.3
Brian34ae99d2006-12-18 08:28:54 -07004 *
Brian5b01c5e2006-12-19 18:02:03 -07005 * Copyright (C) 2004-2007 Brian Paul All Rights Reserved.
Brian34ae99d2006-12-18 08:28:54 -07006 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25/**
26 * \file shader_api.c
Brian5b01c5e2006-12-19 18:02:03 -070027 * Implementation of GLSL-related API functions
Brian34ae99d2006-12-18 08:28:54 -070028 * \author Brian Paul
29 */
30
31/**
32 * XXX things to do:
33 * 1. Check that the right error code is generated for all _mesa_error() calls.
Brian5b01c5e2006-12-19 18:02:03 -070034 * 2. Insert FLUSH_VERTICES calls in various places
Brian34ae99d2006-12-18 08:28:54 -070035 */
36
37
38#include "glheader.h"
39#include "context.h"
40#include "hash.h"
Brian274ac7a2007-04-18 16:05:53 -060041#include "macros.h"
Brian34ae99d2006-12-18 08:28:54 -070042#include "program.h"
43#include "prog_parameter.h"
Brian3209c3e2007-01-09 17:49:24 -070044#include "prog_print.h"
45#include "prog_statevars.h"
Brian34ae99d2006-12-18 08:28:54 -070046#include "shader_api.h"
47
48#include "slang_compile.h"
49#include "slang_link.h"
50
51
52
Brianf2923612006-12-20 09:56:44 -070053/**
54 * Allocate a new gl_shader_program object, initialize it.
55 */
56struct gl_shader_program *
57_mesa_new_shader_program(GLcontext *ctx, GLuint name)
58{
59 struct gl_shader_program *shProg;
60 shProg = CALLOC_STRUCT(gl_shader_program);
61 if (shProg) {
Brianf3e8c322007-04-18 14:53:23 -060062 shProg->Type = GL_SHADER_PROGRAM_MESA;
Brianf2923612006-12-20 09:56:44 -070063 shProg->Name = name;
64 shProg->RefCount = 1;
Brian3209c3e2007-01-09 17:49:24 -070065 shProg->Attributes = _mesa_new_parameter_list();
Brianf2923612006-12-20 09:56:44 -070066 }
67 return shProg;
68}
69
70
Brianb9fbedd2007-03-26 09:23:44 -060071/**
Brian3c008a02007-04-12 15:22:32 -060072 * Clear (free) the shader program state that gets produced by linking.
Brianb9fbedd2007-03-26 09:23:44 -060073 */
Brianf2923612006-12-20 09:56:44 -070074void
Brian3c008a02007-04-12 15:22:32 -060075_mesa_clear_shader_program_data(GLcontext *ctx,
76 struct gl_shader_program *shProg)
Brianf2923612006-12-20 09:56:44 -070077{
Brianf2923612006-12-20 09:56:44 -070078 if (shProg->VertexProgram) {
79 if (shProg->VertexProgram->Base.Parameters == shProg->Uniforms) {
80 /* to prevent a double-free in the next call */
81 shProg->VertexProgram->Base.Parameters = NULL;
82 }
83 _mesa_delete_program(ctx, &shProg->VertexProgram->Base);
84 shProg->VertexProgram = NULL;
85 }
86
87 if (shProg->FragmentProgram) {
88 if (shProg->FragmentProgram->Base.Parameters == shProg->Uniforms) {
89 /* to prevent a double-free in the next call */
90 shProg->FragmentProgram->Base.Parameters = NULL;
91 }
92 _mesa_delete_program(ctx, &shProg->FragmentProgram->Base);
93 shProg->FragmentProgram = NULL;
94 }
95
Brianf2923612006-12-20 09:56:44 -070096 if (shProg->Uniforms) {
97 _mesa_free_parameter_list(shProg->Uniforms);
98 shProg->Uniforms = NULL;
99 }
100
101 if (shProg->Varying) {
102 _mesa_free_parameter_list(shProg->Varying);
103 shProg->Varying = NULL;
104 }
105}
106
107
Brianb9fbedd2007-03-26 09:23:44 -0600108/**
Brian3c008a02007-04-12 15:22:32 -0600109 * Free all the data that hangs off a shader program object, but not the
110 * object itself.
111 */
112void
113_mesa_free_shader_program_data(GLcontext *ctx,
114 struct gl_shader_program *shProg)
115{
116 GLuint i;
117
Brianf3e8c322007-04-18 14:53:23 -0600118 assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
Brian3c008a02007-04-12 15:22:32 -0600119
120 _mesa_clear_shader_program_data(ctx, shProg);
121
122 /* detach shaders */
123 for (i = 0; i < shProg->NumShaders; i++) {
124 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
125 }
126 if (shProg->Shaders) {
127 _mesa_free(shProg->Shaders);
128 shProg->Shaders = NULL;
129 }
130}
131
132
133/**
Brianb9fbedd2007-03-26 09:23:44 -0600134 * Free/delete a shader program object.
135 */
Brianf2923612006-12-20 09:56:44 -0700136void
137_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg)
138{
139 _mesa_free_shader_program_data(ctx, shProg);
Brianb9fbedd2007-03-26 09:23:44 -0600140 if (shProg->Shaders) {
141 _mesa_free(shProg->Shaders);
142 shProg->Shaders = NULL;
143 }
Brianf2923612006-12-20 09:56:44 -0700144 _mesa_free(shProg);
145}
146
147
148/**
Brian3c008a02007-04-12 15:22:32 -0600149 * Set ptr to point to shProg.
150 * If ptr is pointing to another object, decrement its refcount (and delete
151 * if refcount hits zero).
152 * Then set ptr to point to shProg, incrementing its refcount.
153 */
154/* XXX this could be static */
155void
156_mesa_reference_shader_program(GLcontext *ctx,
157 struct gl_shader_program **ptr,
158 struct gl_shader_program *shProg)
159{
160 assert(ptr);
161 if (*ptr == shProg) {
162 /* no-op */
163 return;
164 }
165 if (*ptr) {
166 /* Unreference the old shader program */
167 GLboolean deleteFlag = GL_FALSE;
168 struct gl_shader_program *old = *ptr;
169
170 ASSERT(old->RefCount > 0);
171 old->RefCount--;
172 /*printf("SHPROG DECR %p (%d) to %d\n",
173 (void*) old, old->Name, old->RefCount);*/
174 deleteFlag = (old->RefCount == 0);
175
176 if (deleteFlag) {
177 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
178 _mesa_free_shader_program(ctx, old);
179 }
180
181 *ptr = NULL;
182 }
183 assert(!*ptr);
184
185 if (shProg) {
186 shProg->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600187 /*printf("SHPROG INCR %p (%d) to %d\n",
188 (void*) shProg, shProg->Name, shProg->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600189 *ptr = shProg;
190 }
191}
192
193
194/**
Brianf2923612006-12-20 09:56:44 -0700195 * Lookup a GLSL program object.
196 */
197struct gl_shader_program *
198_mesa_lookup_shader_program(GLcontext *ctx, GLuint name)
199{
200 struct gl_shader_program *shProg;
201 if (name) {
202 shProg = (struct gl_shader_program *)
203 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
204 /* Note that both gl_shader and gl_shader_program objects are kept
205 * in the same hash table. Check the object's type to be sure it's
206 * what we're expecting.
207 */
Brianf3e8c322007-04-18 14:53:23 -0600208 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700209 return NULL;
210 }
211 return shProg;
212 }
213 return NULL;
214}
215
216
217/**
218 * Allocate a new gl_shader object, initialize it.
219 */
220struct gl_shader *
221_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
222{
223 struct gl_shader *shader;
224 assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
225 shader = CALLOC_STRUCT(gl_shader);
226 if (shader) {
227 shader->Type = type;
228 shader->Name = name;
229 shader->RefCount = 1;
230 }
231 return shader;
232}
233
234
235void
236_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh)
237{
238 GLuint i;
239 if (sh->Source)
240 _mesa_free((void *) sh->Source);
241 if (sh->InfoLog)
242 _mesa_free(sh->InfoLog);
243 for (i = 0; i < sh->NumPrograms; i++) {
244 assert(sh->Programs[i]);
245 _mesa_delete_program(ctx, sh->Programs[i]);
246 }
247 if (sh->Programs)
248 _mesa_free(sh->Programs);
249 _mesa_free(sh);
250}
251
252
253/**
Brian3c008a02007-04-12 15:22:32 -0600254 * Set ptr to point to sh.
255 * If ptr is pointing to another shader, decrement its refcount (and delete
256 * if refcount hits zero).
257 * Then set ptr to point to sh, incrementing its refcount.
258 */
259/* XXX this could be static */
260void
261_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr,
262 struct gl_shader *sh)
263{
264 assert(ptr);
265 if (*ptr == sh) {
266 /* no-op */
267 return;
268 }
269 if (*ptr) {
270 /* Unreference the old shader */
271 GLboolean deleteFlag = GL_FALSE;
272 struct gl_shader *old = *ptr;
273
274 ASSERT(old->RefCount > 0);
275 old->RefCount--;
Brian99193e42007-04-12 15:45:02 -0600276 /*printf("SHADER DECR %p (%d) to %d\n",
277 (void*) old, old->Name, old->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600278 deleteFlag = (old->RefCount == 0);
279
280 if (deleteFlag) {
281 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
282 _mesa_free_shader(ctx, old);
283 }
284
285 *ptr = NULL;
286 }
287 assert(!*ptr);
288
289 if (sh) {
290 /* reference new */
291 sh->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600292 /*printf("SHADER INCR %p (%d) to %d\n",
293 (void*) sh, sh->Name, sh->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600294 *ptr = sh;
295 }
296}
297
298
299/**
Brianf2923612006-12-20 09:56:44 -0700300 * Lookup a GLSL shader object.
301 */
302struct gl_shader *
303_mesa_lookup_shader(GLcontext *ctx, GLuint name)
304{
305 if (name) {
306 struct gl_shader *sh = (struct gl_shader *)
307 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
308 /* Note that both gl_shader and gl_shader_program objects are kept
309 * in the same hash table. Check the object's type to be sure it's
310 * what we're expecting.
311 */
Brianf3e8c322007-04-18 14:53:23 -0600312 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700313 return NULL;
314 }
315 return sh;
316 }
317 return NULL;
318}
319
320
Brianfa4d0362007-02-26 18:33:50 -0700321/**
322 * Initialize context's shader state.
323 */
Brianf2923612006-12-20 09:56:44 -0700324void
325_mesa_init_shader_state(GLcontext * ctx)
326{
Brianfa4d0362007-02-26 18:33:50 -0700327 /* Device drivers may override these to control what kind of instructions
328 * are generated by the GLSL compiler.
329 */
330 ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
Brian63556fa2007-03-23 14:47:46 -0600331 ctx->Shader.EmitCondCodes = GL_TRUE; /* XXX probably want GL_FALSE... */
Brianfa4d0362007-02-26 18:33:50 -0700332 ctx->Shader.EmitComments = GL_FALSE;
Brianf2923612006-12-20 09:56:44 -0700333}
334
335
Brian5b01c5e2006-12-19 18:02:03 -0700336/**
Brian935f93f2007-03-24 16:20:02 -0600337 * Free the per-context shader-related state.
338 */
339void
340_mesa_free_shader_state(GLcontext *ctx)
341{
Brian3c008a02007-04-12 15:22:32 -0600342 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
Brian935f93f2007-03-24 16:20:02 -0600343}
344
345
346/**
Brian5b01c5e2006-12-19 18:02:03 -0700347 * Copy string from <src> to <dst>, up to maxLength characters, returning
348 * length of <dst> in <length>.
349 * \param src the strings source
350 * \param maxLength max chars to copy
351 * \param length returns number of chars copied
352 * \param dst the string destination
353 */
354static void
355copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
356{
357 GLsizei len;
358 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
359 dst[len] = src[len];
360 if (maxLength > 0)
361 dst[len] = 0;
362 if (length)
363 *length = len;
364}
365
366
Brian5b01c5e2006-12-19 18:02:03 -0700367/**
368 * Called via ctx->Driver.AttachShader()
369 */
370void
371_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
372{
Brian65a18442006-12-19 18:46:56 -0700373 struct gl_shader_program *shProg
374 = _mesa_lookup_shader_program(ctx, program);
375 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
376 const GLuint n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700377 GLuint i;
378
Brian65a18442006-12-19 18:46:56 -0700379 if (!shProg || !sh) {
Brian43975832007-01-04 08:21:09 -0700380 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700381 "glAttachShader(bad program or shader name)");
382 return;
383 }
384
385 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700386 if (shProg->Shaders[i] == sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700387 /* already attached */
388 return;
Brian34ae99d2006-12-18 08:28:54 -0700389 }
390 }
Brian5b01c5e2006-12-19 18:02:03 -0700391
392 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700393 shProg->Shaders = (struct gl_shader **)
394 _mesa_realloc(shProg->Shaders,
395 n * sizeof(struct gl_shader *),
396 (n + 1) * sizeof(struct gl_shader *));
397 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700398 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
399 return;
400 }
401
402 /* append */
Brian3c008a02007-04-12 15:22:32 -0600403 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
404 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700405 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700406}
407
408
409void
410_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
411 const GLchar *name)
412{
Brian65a18442006-12-19 18:46:56 -0700413 struct gl_shader_program *shProg
414 = _mesa_lookup_shader_program(ctx, program);
Brianb7978af2007-01-09 19:17:17 -0700415 const GLint size = -1; /* unknown size */
416 GLint i, oldIndex;
Brian5b01c5e2006-12-19 18:02:03 -0700417
Brian65a18442006-12-19 18:46:56 -0700418 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700419 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700420 return;
421 }
422
Brian9e4bae92006-12-20 09:27:42 -0700423 if (!name)
424 return;
425
426 if (strncmp(name, "gl_", 3) == 0) {
427 _mesa_error(ctx, GL_INVALID_OPERATION,
428 "glBindAttribLocation(illegal name)");
429 return;
430 }
431
Brian9f660252007-04-11 09:00:56 -0600432 if (shProg->LinkStatus) {
433 /* get current index/location for the attribute */
434 oldIndex = _mesa_get_attrib_location(ctx, program, name);
435 }
436 else {
437 oldIndex = -1;
438 }
Brian3209c3e2007-01-09 17:49:24 -0700439
440 /* this will replace the current value if it's already in the list */
Brianb7978af2007-01-09 19:17:17 -0700441 i = _mesa_add_attribute(shProg->Attributes, name, size, index);
Brian3209c3e2007-01-09 17:49:24 -0700442 if (i < 0) {
443 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
444 }
445
Brian9f660252007-04-11 09:00:56 -0600446 if (shProg->VertexProgram && oldIndex >= 0 && oldIndex != index) {
447 /* If the index changed, need to search/replace references to that attribute
448 * in the vertex program.
449 */
Brian3209c3e2007-01-09 17:49:24 -0700450 _slang_remap_attribute(&shProg->VertexProgram->Base, oldIndex, index);
451 }
Brian34ae99d2006-12-18 08:28:54 -0700452}
453
454
Brian5b01c5e2006-12-19 18:02:03 -0700455GLuint
456_mesa_create_shader(GLcontext *ctx, GLenum type)
457{
Brian65a18442006-12-19 18:46:56 -0700458 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700459 GLuint name;
460
461 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
462
463 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700464 case GL_FRAGMENT_SHADER:
465 case GL_VERTEX_SHADER:
466 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700467 break;
468 default:
469 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
470 return 0;
471 }
472
Brian65a18442006-12-19 18:46:56 -0700473 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700474
475 return name;
476}
477
478
479GLuint
480_mesa_create_program(GLcontext *ctx)
481{
482 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700483 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700484
Brian65a18442006-12-19 18:46:56 -0700485 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
486 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700487
Brian65a18442006-12-19 18:46:56 -0700488 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700489
Brian3c008a02007-04-12 15:22:32 -0600490 assert(shProg->RefCount == 1);
491
Brian5b01c5e2006-12-19 18:02:03 -0700492 return name;
493}
494
495
Brian3c008a02007-04-12 15:22:32 -0600496/**
497 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
498 * DeleteProgramARB.
499 */
Brian5b01c5e2006-12-19 18:02:03 -0700500void
501_mesa_delete_program2(GLcontext *ctx, GLuint name)
502{
Brian3c008a02007-04-12 15:22:32 -0600503 /*
504 * NOTE: deleting shaders/programs works a bit differently than
505 * texture objects (and buffer objects, etc). Shader/program
506 * handles/IDs exist in the hash table until the object is really
507 * deleted (refcount==0). With texture objects, the handle/ID is
508 * removed from the hash table in glDeleteTextures() while the tex
509 * object itself might linger until its refcount goes to zero.
510 */
Brian65a18442006-12-19 18:46:56 -0700511 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700512
Brian65a18442006-12-19 18:46:56 -0700513 shProg = _mesa_lookup_shader_program(ctx, name);
514 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700515 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteProgram(name)");
Brian5b01c5e2006-12-19 18:02:03 -0700516 return;
517 }
518
Brian9e4bae92006-12-20 09:27:42 -0700519 shProg->DeletePending = GL_TRUE;
520
Brian3c008a02007-04-12 15:22:32 -0600521 /* effectively, decr shProg's refcount */
522 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700523}
524
525
526void
527_mesa_delete_shader(GLcontext *ctx, GLuint shader)
528{
Brian9e4bae92006-12-20 09:27:42 -0700529 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
530 if (!sh) {
531 return;
532 }
Brian5b01c5e2006-12-19 18:02:03 -0700533
Brian9e4bae92006-12-20 09:27:42 -0700534 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600535
536 /* effectively, decr sh's refcount */
537 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700538}
539
540
541void
542_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
543{
Brian65a18442006-12-19 18:46:56 -0700544 struct gl_shader_program *shProg
545 = _mesa_lookup_shader_program(ctx, program);
546 const GLuint n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700547 GLuint i, j;
548
Brian65a18442006-12-19 18:46:56 -0700549 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700550 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700551 "glDetachShader(bad program or shader name)");
552 return;
553 }
554
555 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700556 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700557 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600558 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700559
Brian3c008a02007-04-12 15:22:32 -0600560 /* derefernce */
561 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700562
Brian5b01c5e2006-12-19 18:02:03 -0700563 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700564 newList = (struct gl_shader **)
565 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700566 if (!newList) {
567 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
568 return;
569 }
570 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700571 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700572 }
573 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700574 newList[j++] = shProg->Shaders[i];
575 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700576
Brian65a18442006-12-19 18:46:56 -0700577 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600578 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600579
580#ifdef DEBUG
581 /* sanity check */
582 {
583 for (j = 0; j < shProg->NumShaders; j++) {
584 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
585 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
586 assert(shProg->Shaders[j]->RefCount > 0);
587 }
588 }
589#endif
590
Brian5b01c5e2006-12-19 18:02:03 -0700591 return;
592 }
593 }
594
595 /* not found */
Brian43975832007-01-04 08:21:09 -0700596 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700597 "glDetachShader(shader not found)");
598}
599
600
601void
602_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
603 GLsizei maxLength, GLsizei *length, GLint *size,
604 GLenum *type, GLchar *nameOut)
605{
606 static const GLenum vec_types[] = {
607 GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4
608 };
Brian65a18442006-12-19 18:46:56 -0700609 struct gl_shader_program *shProg
610 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700611 GLint sz;
612
Brian65a18442006-12-19 18:46:56 -0700613 if (!shProg) {
Brianaaa57412007-04-18 15:22:43 -0600614 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib");
Brian5b01c5e2006-12-19 18:02:03 -0700615 return;
616 }
617
Brian65a18442006-12-19 18:46:56 -0700618 if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600619 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700620 return;
621 }
622
623 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700624 shProg->Attributes->Parameters[index].Name);
625 sz = shProg->Attributes->Parameters[index].Size;
Brian5b01c5e2006-12-19 18:02:03 -0700626 if (size)
627 *size = sz;
628 if (type)
629 *type = vec_types[sz]; /* XXX this is a temporary hack */
630}
631
632
633/**
634 * Called via ctx->Driver.GetActiveUniform().
635 */
636void
637_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
638 GLsizei maxLength, GLsizei *length, GLint *size,
639 GLenum *type, GLchar *nameOut)
640{
Brian65a18442006-12-19 18:46:56 -0700641 struct gl_shader_program *shProg
642 = _mesa_lookup_shader_program(ctx, program);
Brian274ac7a2007-04-18 16:05:53 -0600643 GLuint ind, j;
Brian5b01c5e2006-12-19 18:02:03 -0700644
Brian65a18442006-12-19 18:46:56 -0700645 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700646 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform");
Brian5b01c5e2006-12-19 18:02:03 -0700647 return;
648 }
649
Brian65a18442006-12-19 18:46:56 -0700650 if (!shProg->Uniforms || index >= shProg->Uniforms->NumParameters) {
Brian5b01c5e2006-12-19 18:02:03 -0700651 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
652 return;
653 }
654
Brian274ac7a2007-04-18 16:05:53 -0600655 ind = 0;
656 for (j = 0; j < shProg->Uniforms->NumParameters; j++) {
657 if (shProg->Uniforms->Parameters[j].Type == PROGRAM_UNIFORM ||
658 shProg->Uniforms->Parameters[j].Type == PROGRAM_SAMPLER) {
659 if (ind == index) {
660 /* found it */
661 copy_string(nameOut, maxLength, length,
662 shProg->Uniforms->Parameters[j].Name);
Brian274ac7a2007-04-18 16:05:53 -0600663 if (size)
Brianc93e8832007-04-18 16:27:35 -0600664 *size = shProg->Uniforms->Parameters[j].Size;
Brian274ac7a2007-04-18 16:05:53 -0600665 if (type)
Brianc93e8832007-04-18 16:27:35 -0600666 *type = shProg->Uniforms->Parameters[j].DataType;
Brian274ac7a2007-04-18 16:05:53 -0600667 return;
668 }
669 ind++;
670 }
671 }
672
673 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700674}
675
676
677/**
678 * Called via ctx->Driver.GetAttachedShaders().
679 */
680void
681_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
682 GLsizei *count, GLuint *obj)
683{
Brian65a18442006-12-19 18:46:56 -0700684 struct gl_shader_program *shProg
685 = _mesa_lookup_shader_program(ctx, program);
686 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700687 GLint i;
Brian65a18442006-12-19 18:46:56 -0700688 for (i = 0; i < maxCount && i < shProg->NumShaders; i++) {
689 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700690 }
691 if (count)
692 *count = i;
693 }
694 else {
Brian43975832007-01-04 08:21:09 -0700695 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttachedShaders");
Brian5b01c5e2006-12-19 18:02:03 -0700696 }
697}
698
699
700GLint
701_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
702 const GLchar *name)
703{
Brian65a18442006-12-19 18:46:56 -0700704 struct gl_shader_program *shProg
705 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700706
Brian65a18442006-12-19 18:46:56 -0700707 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700708 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttribLocation");
Brian5b01c5e2006-12-19 18:02:03 -0700709 return -1;
710 }
711
Brian65a18442006-12-19 18:46:56 -0700712 if (!shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -0700713 _mesa_error(ctx, GL_INVALID_OPERATION,
714 "glGetAttribLocation(program not linked)");
715 return -1;
716 }
717
718 if (!name)
719 return -1;
720
Brian65a18442006-12-19 18:46:56 -0700721 if (shProg->Attributes) {
Brian3209c3e2007-01-09 17:49:24 -0700722 GLint i = _mesa_lookup_parameter_index(shProg->Attributes, -1, name);
723 if (i >= 0) {
Brian01a91eb2007-01-09 19:26:22 -0700724 return shProg->Attributes->Parameters[i].StateIndexes[0];
Brian5b01c5e2006-12-19 18:02:03 -0700725 }
726 }
727 return -1;
728}
729
730
731GLuint
732_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700733{
734#if 0
735 GET_CURRENT_CONTEXT(ctx);
736
737 switch (pname) {
738 case GL_PROGRAM_OBJECT_ARB:
739 {
Brian5b01c5e2006-12-19 18:02:03 -0700740 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700741
742 if (pro != NULL)
743 return (**pro)._container._generic.
744 GetName((struct gl2_generic_intf **) (pro));
745 }
746 break;
747 default:
748 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
749 }
750#endif
751 return 0;
752}
753
754
Brian5b01c5e2006-12-19 18:02:03 -0700755void
756_mesa_get_programiv(GLcontext *ctx, GLuint program,
757 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700758{
Brian65a18442006-12-19 18:46:56 -0700759 struct gl_shader_program *shProg
760 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700761
Brian65a18442006-12-19 18:46:56 -0700762 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700763 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700764 return;
765 }
766
Brian5b01c5e2006-12-19 18:02:03 -0700767 switch (pname) {
768 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700769 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700770 break;
771 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700772 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700773 break;
Brian5b01c5e2006-12-19 18:02:03 -0700774 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700775 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700776 break;
777 case GL_INFO_LOG_LENGTH:
Brian65a18442006-12-19 18:46:56 -0700778 *params = shProg->InfoLog ? strlen(shProg->InfoLog) : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700779 break;
780 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700781 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700782 break;
783 case GL_ACTIVE_ATTRIBUTES:
Brian3209c3e2007-01-09 17:49:24 -0700784 *params = shProg->Attributes ? shProg->Attributes->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700785 break;
786 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600787 *params = _mesa_longest_parameter_name(shProg->Attributes,
788 PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700789 break;
790 case GL_ACTIVE_UNIFORMS:
Brian274ac7a2007-04-18 16:05:53 -0600791 *params
792 = _mesa_num_parameters_of_type(shProg->Uniforms, PROGRAM_UNIFORM)
793 + _mesa_num_parameters_of_type(shProg->Uniforms, PROGRAM_SAMPLER);
Brian5b01c5e2006-12-19 18:02:03 -0700794 break;
795 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600796 *params = MAX2(
797 _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_UNIFORM),
798 _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_SAMPLER));
799 if (*params > 0)
800 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700801 break;
802 default:
Brian5b01c5e2006-12-19 18:02:03 -0700803 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
804 return;
Brian34ae99d2006-12-18 08:28:54 -0700805 }
Brian5b01c5e2006-12-19 18:02:03 -0700806}
Brian34ae99d2006-12-18 08:28:54 -0700807
Brian34ae99d2006-12-18 08:28:54 -0700808
Brian5b01c5e2006-12-19 18:02:03 -0700809void
810_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
811{
Brian65a18442006-12-19 18:46:56 -0700812 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700813
814 if (!shader) {
815 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderiv(shader)");
816 return;
817 }
Brian65a18442006-12-19 18:46:56 -0700818
Brian5b01c5e2006-12-19 18:02:03 -0700819 switch (pname) {
820 case GL_SHADER_TYPE:
821 *params = shader->Type;
822 break;
823 case GL_DELETE_STATUS:
824 *params = shader->DeletePending;
825 break;
826 case GL_COMPILE_STATUS:
827 *params = shader->CompileStatus;
828 break;
829 case GL_INFO_LOG_LENGTH:
830 *params = shader->InfoLog ? strlen(shader->InfoLog) : 0;
831 break;
832 case GL_SHADER_SOURCE_LENGTH:
833 *params = shader->Source ? strlen((char *) shader->Source) : 0;
834 break;
835 default:
836 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
837 return;
838 }
839}
840
841
842void
843_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
844 GLsizei *length, GLchar *infoLog)
845{
Brian65a18442006-12-19 18:46:56 -0700846 struct gl_shader_program *shProg
847 = _mesa_lookup_shader_program(ctx, program);
848 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700849 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
850 return;
851 }
Brian65a18442006-12-19 18:46:56 -0700852 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700853}
854
855
856void
857_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
858 GLsizei *length, GLchar *infoLog)
859{
Brian65a18442006-12-19 18:46:56 -0700860 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
861 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700862 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
863 return;
864 }
Brian65a18442006-12-19 18:46:56 -0700865 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700866}
867
868
869/**
870 * Called via ctx->Driver.GetShaderSource().
871 */
872void
873_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
874 GLsizei *length, GLchar *sourceOut)
875{
Brian65a18442006-12-19 18:46:56 -0700876 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
877 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700878 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderSource(shader)");
879 return;
880 }
Brian65a18442006-12-19 18:46:56 -0700881 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -0700882}
883
884
885/**
886 * Called via ctx->Driver.GetUniformfv().
887 */
888void
889_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
890 GLfloat *params)
891{
Brian65a18442006-12-19 18:46:56 -0700892 struct gl_shader_program *shProg
893 = _mesa_lookup_shader_program(ctx, program);
894 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700895 GLint i;
Brian65a18442006-12-19 18:46:56 -0700896 if (location >= 0 && location < shProg->Uniforms->NumParameters) {
897 for (i = 0; i < shProg->Uniforms->Parameters[location].Size; i++) {
898 params[i] = shProg->Uniforms->ParameterValues[location][i];
Brian5b01c5e2006-12-19 18:02:03 -0700899 }
900 }
901 else {
902 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(location)");
903 }
904 }
905 else {
Brian43975832007-01-04 08:21:09 -0700906 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700907 }
908}
909
910
911/**
912 * Called via ctx->Driver.GetUniformLocation().
913 */
914GLint
915_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
916{
Brian71623982007-01-30 16:55:03 -0700917 struct gl_shader_program *shProg
918 = _mesa_lookup_shader_program(ctx, program);
919 if (shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700920 GLuint loc;
Brian65a18442006-12-19 18:46:56 -0700921 for (loc = 0; loc < shProg->Uniforms->NumParameters; loc++) {
Brian5b01c5e2006-12-19 18:02:03 -0700922 const struct gl_program_parameter *u
Brian65a18442006-12-19 18:46:56 -0700923 = shProg->Uniforms->Parameters + loc;
Brian29053852006-12-21 11:21:26 -0700924 /* XXX this is a temporary simplification / short-cut.
925 * We need to handle things like "e.c[0].b" as seen in the
926 * GLSL orange book, page 189.
927 */
Brian5cf73262007-01-05 16:02:45 -0700928 if ((u->Type == PROGRAM_UNIFORM ||
929 u->Type == PROGRAM_SAMPLER) && !strcmp(u->Name, name)) {
Brian5b01c5e2006-12-19 18:02:03 -0700930 return loc;
931 }
932 }
933 }
934 return -1;
935
936}
937
938
939GLboolean
940_mesa_is_program(GLcontext *ctx, GLuint name)
941{
Brian65a18442006-12-19 18:46:56 -0700942 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
943 return shProg ? GL_TRUE : GL_FALSE;
Brian5b01c5e2006-12-19 18:02:03 -0700944}
945
946
947GLboolean
948_mesa_is_shader(GLcontext *ctx, GLuint name)
949{
Brian65a18442006-12-19 18:46:56 -0700950 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700951 return shader ? GL_TRUE : GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700952}
953
954
955
Brian5b01c5e2006-12-19 18:02:03 -0700956/**
957 * Called via ctx->Driver.ShaderSource()
958 */
959void
960_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -0700961{
Brian65a18442006-12-19 18:46:56 -0700962 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
963 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700964 _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSource(shaderObj)");
Brian34ae99d2006-12-18 08:28:54 -0700965 return;
966 }
967
Brian34ae99d2006-12-18 08:28:54 -0700968 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -0700969 if (sh->Source) {
970 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -0700971 }
Brian65a18442006-12-19 18:46:56 -0700972 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -0700973 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700974}
975
976
Brian5b01c5e2006-12-19 18:02:03 -0700977/**
978 * Called via ctx->Driver.CompileShader()
979 */
980void
981_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -0700982{
Brian65a18442006-12-19 18:46:56 -0700983 struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj);
Brian34ae99d2006-12-18 08:28:54 -0700984
Brian65a18442006-12-19 18:46:56 -0700985 if (!sh) {
Brian34ae99d2006-12-18 08:28:54 -0700986 _mesa_error(ctx, GL_INVALID_VALUE, "glCompileShader(shaderObj)");
987 return;
988 }
989
Brian43975832007-01-04 08:21:09 -0700990 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -0700991}
992
993
Brian5b01c5e2006-12-19 18:02:03 -0700994/**
995 * Called via ctx->Driver.LinkProgram()
996 */
997void
998_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -0700999{
Brian65a18442006-12-19 18:46:56 -07001000 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001001
Brian65a18442006-12-19 18:46:56 -07001002 shProg = _mesa_lookup_shader_program(ctx, program);
1003 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001004 _mesa_error(ctx, GL_INVALID_VALUE, "glLinkProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001005 return;
1006 }
1007
Brianc1771912007-02-16 09:56:19 -07001008 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001009}
1010
1011
1012/**
Brian5b01c5e2006-12-19 18:02:03 -07001013 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001014 */
Brian5b01c5e2006-12-19 18:02:03 -07001015void
1016_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001017{
Brian3c008a02007-04-12 15:22:32 -06001018 struct gl_shader_program *shProg;
1019
Brian00d63aa2007-02-03 11:35:02 -07001020 if (ctx->Shader.CurrentProgram &&
1021 ctx->Shader.CurrentProgram->Name == program) {
1022 /* no-op */
1023 return;
1024 }
1025
1026 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1027
Brian5b01c5e2006-12-19 18:02:03 -07001028 if (program) {
Brian65a18442006-12-19 18:46:56 -07001029 shProg = _mesa_lookup_shader_program(ctx, program);
1030 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001031 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -07001032 "glUseProgramObjectARB(programObj)");
1033 return;
1034 }
Brian5b01c5e2006-12-19 18:02:03 -07001035 }
1036 else {
Brian3c008a02007-04-12 15:22:32 -06001037 shProg = NULL;
1038 }
1039
1040 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001041}
Brian34ae99d2006-12-18 08:28:54 -07001042
Brian5b01c5e2006-12-19 18:02:03 -07001043
1044/**
1045 * Called via ctx->Driver.Uniform().
1046 */
1047void
1048_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1049 const GLvoid *values, GLenum type)
1050{
Brian3a8e2772006-12-20 17:19:16 -07001051 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian98650bd2007-03-13 16:32:48 -06001052 GLint elems, i, k;
Brian3a8e2772006-12-20 17:19:16 -07001053
1054 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001055 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001056 return;
1057 }
1058
Brian223d7cb2007-01-23 16:37:51 -07001059 if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) {
Brian3a8e2772006-12-20 17:19:16 -07001060 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
1061 return;
1062 }
1063
1064 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1065
Brianfee9bbe2007-02-02 18:05:43 -07001066 /*
1067 * If we're setting a sampler, we must use glUniformi1()!
1068 */
1069 if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
1070 if (type != GL_INT || count != 1) {
1071 _mesa_error(ctx, GL_INVALID_OPERATION,
1072 "glUniform(only glUniform1i can be used "
1073 "to set sampler uniforms)");
1074 return;
1075 }
1076 }
1077
Brian52363952007-03-13 16:50:24 -06001078 if (count < 0) {
1079 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1080 return;
1081 }
1082
Brian98650bd2007-03-13 16:32:48 -06001083 switch (type) {
1084 case GL_FLOAT:
1085 case GL_INT:
1086 elems = 1;
1087 break;
1088 case GL_FLOAT_VEC2:
1089 case GL_INT_VEC2:
1090 elems = 2;
1091 break;
1092 case GL_FLOAT_VEC3:
1093 case GL_INT_VEC3:
1094 elems = 3;
1095 break;
1096 case GL_FLOAT_VEC4:
1097 case GL_INT_VEC4:
1098 elems = 4;
1099 break;
1100 default:
1101 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1102 return;
Brian89dc4852007-01-04 14:35:44 -07001103 }
Brian98650bd2007-03-13 16:32:48 -06001104
1105 if (count * elems > shProg->Uniforms->Parameters[location].Size) {
1106 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1107 return;
1108 }
1109
1110 for (k = 0; k < count; k++) {
1111 GLfloat *uniformVal = shProg->Uniforms->ParameterValues[location + k];
1112 if (type == GL_INT ||
1113 type == GL_INT_VEC2 ||
1114 type == GL_INT_VEC3 ||
1115 type == GL_INT_VEC4) {
Brian52363952007-03-13 16:50:24 -06001116 const GLint *iValues = ((const GLint *) values) + k * elems;
Brian98650bd2007-03-13 16:32:48 -06001117 for (i = 0; i < elems; i++) {
1118 uniformVal[i] = (GLfloat) iValues[i];
1119 }
1120 }
1121 else {
Brian52363952007-03-13 16:50:24 -06001122 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
Brian98650bd2007-03-13 16:32:48 -06001123 for (i = 0; i < elems; i++) {
1124 uniformVal[i] = fValues[i];
1125 }
Brian89dc4852007-01-04 14:35:44 -07001126 }
Brian5b01c5e2006-12-19 18:02:03 -07001127 }
Brian5cf73262007-01-05 16:02:45 -07001128
1129 if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
Briancec81ee2007-03-07 08:04:06 -07001130 if (shProg->VertexProgram)
1131 _slang_resolve_samplers(shProg, &shProg->VertexProgram->Base);
1132 if (shProg->FragmentProgram)
1133 _slang_resolve_samplers(shProg, &shProg->FragmentProgram->Base);
Brian5cf73262007-01-05 16:02:45 -07001134 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1135 }
Brian34ae99d2006-12-18 08:28:54 -07001136}
1137
1138
1139/**
Brian5b01c5e2006-12-19 18:02:03 -07001140 * Called by ctx->Driver.UniformMatrix().
Brian34ae99d2006-12-18 08:28:54 -07001141 */
Brian5b01c5e2006-12-19 18:02:03 -07001142void
1143_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1144 GLenum matrixType, GLint location, GLsizei count,
1145 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001146{
Brian3a8e2772006-12-20 17:19:16 -07001147 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
1148 if (!shProg || !shProg->LinkStatus) {
1149 _mesa_error(ctx, GL_INVALID_OPERATION,
1150 "glUniformMatrix(program not linked)");
1151 return;
1152 }
1153 if (location < 0 || location >= shProg->Uniforms->NumParameters) {
1154 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
1155 return;
1156 }
Brian34ae99d2006-12-18 08:28:54 -07001157 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001158 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001159 return;
1160 }
1161
1162 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1163
Brian3a8e2772006-12-20 17:19:16 -07001164 /*
1165 * Note: the _columns_ of a matrix are stored in program registers, not
1166 * the rows.
1167 */
1168 /* XXXX need to test 3x3 and 2x2 matrices... */
Brian34ae99d2006-12-18 08:28:54 -07001169 if (transpose) {
Brian3a8e2772006-12-20 17:19:16 -07001170 GLuint row, col;
1171 for (col = 0; col < cols; col++) {
1172 GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
1173 for (row = 0; row < rows; row++) {
Brian9f442472007-03-09 11:34:18 -07001174 v[row] = values[row * cols + col];
Brian34ae99d2006-12-18 08:28:54 -07001175 }
Brian34ae99d2006-12-18 08:28:54 -07001176 }
Brian34ae99d2006-12-18 08:28:54 -07001177 }
1178 else {
Brian3a8e2772006-12-20 17:19:16 -07001179 GLuint row, col;
1180 for (col = 0; col < cols; col++) {
1181 GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
1182 for (row = 0; row < rows; row++) {
Brian9f442472007-03-09 11:34:18 -07001183 v[row] = values[col * rows + row];
Brian3a8e2772006-12-20 17:19:16 -07001184 }
1185 }
Brian34ae99d2006-12-18 08:28:54 -07001186 }
1187}
1188
1189
Brian5b01c5e2006-12-19 18:02:03 -07001190void
1191_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001192{
Brian65a18442006-12-19 18:46:56 -07001193 struct gl_shader_program *shProg;
1194 shProg = _mesa_lookup_shader_program(ctx, program);
1195 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001196 _mesa_error(ctx, GL_INVALID_VALUE, "glValidateProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001197 return;
1198 }
Brian5b01c5e2006-12-19 18:02:03 -07001199 /* XXX temporary */
Brian65a18442006-12-19 18:46:56 -07001200 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001201
Brian5b01c5e2006-12-19 18:02:03 -07001202 /* From the GL spec:
1203 any two active samplers in the current program object are of
1204 different types, but refer to the same texture image unit,
1205
1206 any active sampler in the current program object refers to a texture
1207 image unit where fixed-function fragment processing accesses a
1208 texture target that does not match the sampler type, or
1209
1210 the sum of the number of active samplers in the program and the
1211 number of texture image units enabled for fixed-function fragment
1212 processing exceeds the combined limit on the total number of texture
1213 image units allowed.
1214 */
Brian34ae99d2006-12-18 08:28:54 -07001215}