blob: c05d052f43e87c88ec4eef71bd29b2cc08a4d511 [file] [log] [blame]
Brian34ae99d2006-12-18 08:28:54 -07001/*
2 * Mesa 3-D graphics library
Brian Paul27341a92008-09-16 16:28:36 -06003 * Version: 7.2
Brian34ae99d2006-12-18 08:28:54 -07004 *
Brian Paul8c51e002008-08-11 15:09:47 -06005 * Copyright (C) 2004-2008 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
Brian Paulbbd28712008-09-18 12:26:54 -060038#include "main/glheader.h"
39#include "main/context.h"
40#include "main/hash.h"
41#include "main/macros.h"
42#include "shader/program.h"
43#include "shader/prog_parameter.h"
44#include "shader/prog_print.h"
45#include "shader/prog_statevars.h"
46#include "shader/prog_uniform.h"
Brianc223c6b2007-07-04 13:15:20 -060047#include "shader/shader_api.h"
48#include "shader/slang/slang_compile.h"
49#include "shader/slang/slang_link.h"
Brian34ae99d2006-12-18 08:28:54 -070050
51
52
Brian Paulbda6ad22008-08-06 12:45:14 -060053#ifndef GL_PROGRAM_BINARY_LENGTH_OES
54#define GL_PROGRAM_BINARY_LENGTH_OES 0x8741
55#endif
56
57
Brianf2923612006-12-20 09:56:44 -070058/**
59 * Allocate a new gl_shader_program object, initialize it.
60 */
Brian Paulfd59f192008-05-18 16:04:55 -060061static struct gl_shader_program *
Brianf2923612006-12-20 09:56:44 -070062_mesa_new_shader_program(GLcontext *ctx, GLuint name)
63{
64 struct gl_shader_program *shProg;
65 shProg = CALLOC_STRUCT(gl_shader_program);
66 if (shProg) {
Brianf3e8c322007-04-18 14:53:23 -060067 shProg->Type = GL_SHADER_PROGRAM_MESA;
Brianf2923612006-12-20 09:56:44 -070068 shProg->Name = name;
69 shProg->RefCount = 1;
Brian3209c3e2007-01-09 17:49:24 -070070 shProg->Attributes = _mesa_new_parameter_list();
Brianf2923612006-12-20 09:56:44 -070071 }
72 return shProg;
73}
74
75
Brianb9fbedd2007-03-26 09:23:44 -060076/**
Brian3c008a02007-04-12 15:22:32 -060077 * Clear (free) the shader program state that gets produced by linking.
Brianb9fbedd2007-03-26 09:23:44 -060078 */
Brianf2923612006-12-20 09:56:44 -070079void
Brian3c008a02007-04-12 15:22:32 -060080_mesa_clear_shader_program_data(GLcontext *ctx,
81 struct gl_shader_program *shProg)
Brianf2923612006-12-20 09:56:44 -070082{
Brian Paul8bdf5b62008-05-16 09:56:59 -060083 _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL);
84 _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL);
Brianf2923612006-12-20 09:56:44 -070085
Brianf2923612006-12-20 09:56:44 -070086 if (shProg->Uniforms) {
Brian Paulade50832008-05-14 16:09:46 -060087 _mesa_free_uniform_list(shProg->Uniforms);
Brianf2923612006-12-20 09:56:44 -070088 shProg->Uniforms = NULL;
89 }
90
91 if (shProg->Varying) {
92 _mesa_free_parameter_list(shProg->Varying);
93 shProg->Varying = NULL;
94 }
95}
96
97
Brianb9fbedd2007-03-26 09:23:44 -060098/**
Brian3c008a02007-04-12 15:22:32 -060099 * Free all the data that hangs off a shader program object, but not the
100 * object itself.
101 */
102void
103_mesa_free_shader_program_data(GLcontext *ctx,
104 struct gl_shader_program *shProg)
105{
106 GLuint i;
107
Brianf3e8c322007-04-18 14:53:23 -0600108 assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
Brian3c008a02007-04-12 15:22:32 -0600109
110 _mesa_clear_shader_program_data(ctx, shProg);
111
Brian4b7c6fc2007-04-19 15:23:34 -0600112 if (shProg->Attributes) {
113 _mesa_free_parameter_list(shProg->Attributes);
114 shProg->Attributes = NULL;
115 }
116
Brian3c008a02007-04-12 15:22:32 -0600117 /* detach shaders */
118 for (i = 0; i < shProg->NumShaders; i++) {
119 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
120 }
Xiang, Haihao63d8a842008-03-31 17:02:47 +0800121 shProg->NumShaders = 0;
122
Brian3c008a02007-04-12 15:22:32 -0600123 if (shProg->Shaders) {
124 _mesa_free(shProg->Shaders);
125 shProg->Shaders = NULL;
126 }
Alan Hourihaneeec20c32008-04-22 20:29:42 +0100127
128 if (shProg->InfoLog) {
129 _mesa_free(shProg->InfoLog);
130 shProg->InfoLog = NULL;
131 }
Brian3c008a02007-04-12 15:22:32 -0600132}
133
134
135/**
Brianb9fbedd2007-03-26 09:23:44 -0600136 * Free/delete a shader program object.
137 */
Brianf2923612006-12-20 09:56:44 -0700138void
139_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg)
140{
141 _mesa_free_shader_program_data(ctx, shProg);
Alan Hourihaneeec20c32008-04-22 20:29:42 +0100142
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--;
Brian Paul8bdf5b62008-05-16 09:56:59 -0600171#if 0
172 printf("ShaderProgram %p ID=%u RefCount-- to %d\n",
173 (void *) old, old->Name, old->RefCount);
174#endif
Brian3c008a02007-04-12 15:22:32 -0600175 deleteFlag = (old->RefCount == 0);
176
177 if (deleteFlag) {
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800178 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
Brian3c008a02007-04-12 15:22:32 -0600179 _mesa_free_shader_program(ctx, old);
180 }
181
182 *ptr = NULL;
183 }
184 assert(!*ptr);
185
186 if (shProg) {
187 shProg->RefCount++;
Brian Paul8bdf5b62008-05-16 09:56:59 -0600188#if 0
189 printf("ShaderProgram %p ID=%u RefCount++ to %d\n",
190 (void *) shProg, shProg->Name, shProg->RefCount);
191#endif
Brian3c008a02007-04-12 15:22:32 -0600192 *ptr = shProg;
193 }
194}
195
196
197/**
Brianf2923612006-12-20 09:56:44 -0700198 * Lookup a GLSL program object.
199 */
200struct gl_shader_program *
201_mesa_lookup_shader_program(GLcontext *ctx, GLuint name)
202{
203 struct gl_shader_program *shProg;
204 if (name) {
205 shProg = (struct gl_shader_program *)
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800206 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
Brianf2923612006-12-20 09:56:44 -0700207 /* Note that both gl_shader and gl_shader_program objects are kept
208 * in the same hash table. Check the object's type to be sure it's
209 * what we're expecting.
210 */
Brianf3e8c322007-04-18 14:53:23 -0600211 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700212 return NULL;
213 }
214 return shProg;
215 }
216 return NULL;
217}
218
219
220/**
Brian Paul530df582008-07-03 16:21:11 -0600221 * As above, but record an error if program is not found.
222 */
223static struct gl_shader_program *
224_mesa_lookup_shader_program_err(GLcontext *ctx, GLuint name,
225 const char *caller)
226{
227 if (!name) {
228 _mesa_error(ctx, GL_INVALID_VALUE, caller);
229 return NULL;
230 }
231 else {
232 struct gl_shader_program *shProg = (struct gl_shader_program *)
233 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
234 if (!shProg) {
235 _mesa_error(ctx, GL_INVALID_VALUE, caller);
236 return NULL;
237 }
238 if (shProg->Type != GL_SHADER_PROGRAM_MESA) {
239 _mesa_error(ctx, GL_INVALID_OPERATION, caller);
240 return NULL;
241 }
242 return shProg;
243 }
244}
245
246
247
248
249/**
Brianf2923612006-12-20 09:56:44 -0700250 * Allocate a new gl_shader object, initialize it.
251 */
252struct gl_shader *
253_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
254{
255 struct gl_shader *shader;
256 assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
257 shader = CALLOC_STRUCT(gl_shader);
258 if (shader) {
259 shader->Type = type;
260 shader->Name = name;
261 shader->RefCount = 1;
262 }
263 return shader;
264}
265
266
267void
268_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh)
269{
Brianf2923612006-12-20 09:56:44 -0700270 if (sh->Source)
271 _mesa_free((void *) sh->Source);
272 if (sh->InfoLog)
273 _mesa_free(sh->InfoLog);
Brian Paul3d500f02008-07-24 14:56:54 -0600274 _mesa_reference_program(ctx, &sh->Program, NULL);
Brianf2923612006-12-20 09:56:44 -0700275 _mesa_free(sh);
276}
277
278
279/**
Brian3c008a02007-04-12 15:22:32 -0600280 * Set ptr to point to sh.
281 * If ptr is pointing to another shader, decrement its refcount (and delete
282 * if refcount hits zero).
283 * Then set ptr to point to sh, incrementing its refcount.
284 */
285/* XXX this could be static */
286void
287_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr,
288 struct gl_shader *sh)
289{
290 assert(ptr);
291 if (*ptr == sh) {
292 /* no-op */
293 return;
294 }
295 if (*ptr) {
296 /* Unreference the old shader */
297 GLboolean deleteFlag = GL_FALSE;
298 struct gl_shader *old = *ptr;
299
300 ASSERT(old->RefCount > 0);
301 old->RefCount--;
Brian99193e42007-04-12 15:45:02 -0600302 /*printf("SHADER DECR %p (%d) to %d\n",
303 (void*) old, old->Name, old->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600304 deleteFlag = (old->RefCount == 0);
305
306 if (deleteFlag) {
307 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
308 _mesa_free_shader(ctx, old);
309 }
310
311 *ptr = NULL;
312 }
313 assert(!*ptr);
314
315 if (sh) {
316 /* reference new */
317 sh->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600318 /*printf("SHADER INCR %p (%d) to %d\n",
319 (void*) sh, sh->Name, sh->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600320 *ptr = sh;
321 }
322}
323
324
325/**
Brianf2923612006-12-20 09:56:44 -0700326 * Lookup a GLSL shader object.
327 */
328struct gl_shader *
329_mesa_lookup_shader(GLcontext *ctx, GLuint name)
330{
331 if (name) {
332 struct gl_shader *sh = (struct gl_shader *)
333 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
334 /* Note that both gl_shader and gl_shader_program objects are kept
335 * in the same hash table. Check the object's type to be sure it's
336 * what we're expecting.
337 */
Brianf3e8c322007-04-18 14:53:23 -0600338 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700339 return NULL;
340 }
341 return sh;
342 }
343 return NULL;
344}
345
346
Brianfa4d0362007-02-26 18:33:50 -0700347/**
Brian Paul530df582008-07-03 16:21:11 -0600348 * As above, but record an error if shader is not found.
349 */
350static struct gl_shader *
351_mesa_lookup_shader_err(GLcontext *ctx, GLuint name, const char *caller)
352{
353 if (!name) {
354 _mesa_error(ctx, GL_INVALID_VALUE, caller);
355 return NULL;
356 }
357 else {
358 struct gl_shader *sh = (struct gl_shader *)
359 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
360 if (!sh) {
361 _mesa_error(ctx, GL_INVALID_VALUE, caller);
362 return NULL;
363 }
364 if (sh->Type == GL_SHADER_PROGRAM_MESA) {
365 _mesa_error(ctx, GL_INVALID_OPERATION, caller);
366 return NULL;
367 }
368 return sh;
369 }
370}
371
372
373
374/**
Brianfa4d0362007-02-26 18:33:50 -0700375 * Initialize context's shader state.
376 */
Brianf2923612006-12-20 09:56:44 -0700377void
378_mesa_init_shader_state(GLcontext * ctx)
379{
Brianfa4d0362007-02-26 18:33:50 -0700380 /* Device drivers may override these to control what kind of instructions
381 * are generated by the GLSL compiler.
382 */
383 ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
Brian63556fa2007-03-23 14:47:46 -0600384 ctx->Shader.EmitCondCodes = GL_TRUE; /* XXX probably want GL_FALSE... */
Brianfa4d0362007-02-26 18:33:50 -0700385 ctx->Shader.EmitComments = GL_FALSE;
Brianf2923612006-12-20 09:56:44 -0700386}
387
388
Brian5b01c5e2006-12-19 18:02:03 -0700389/**
Brian935f93f2007-03-24 16:20:02 -0600390 * Free the per-context shader-related state.
391 */
392void
393_mesa_free_shader_state(GLcontext *ctx)
394{
Brian3c008a02007-04-12 15:22:32 -0600395 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
Brian935f93f2007-03-24 16:20:02 -0600396}
397
398
399/**
Brian5b01c5e2006-12-19 18:02:03 -0700400 * Copy string from <src> to <dst>, up to maxLength characters, returning
401 * length of <dst> in <length>.
402 * \param src the strings source
403 * \param maxLength max chars to copy
404 * \param length returns number of chars copied
405 * \param dst the string destination
406 */
407static void
408copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
409{
410 GLsizei len;
411 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
412 dst[len] = src[len];
413 if (maxLength > 0)
414 dst[len] = 0;
415 if (length)
416 *length = len;
417}
418
419
Brian Paul7acb7c12008-07-03 13:49:48 -0600420static GLboolean
421_mesa_is_program(GLcontext *ctx, GLuint name)
422{
423 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
424 return shProg ? GL_TRUE : GL_FALSE;
425}
426
427
428static GLboolean
429_mesa_is_shader(GLcontext *ctx, GLuint name)
430{
431 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
432 return shader ? GL_TRUE : GL_FALSE;
433}
434
435
Brian5b01c5e2006-12-19 18:02:03 -0700436/**
437 * Called via ctx->Driver.AttachShader()
438 */
Brian Paulfd59f192008-05-18 16:04:55 -0600439static void
Brian5b01c5e2006-12-19 18:02:03 -0700440_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
441{
Brian Paul530df582008-07-03 16:21:11 -0600442 struct gl_shader_program *shProg;
443 struct gl_shader *sh;
444 GLuint i, n;
Brian5b01c5e2006-12-19 18:02:03 -0700445
Brian Paul530df582008-07-03 16:21:11 -0600446 shProg = _mesa_lookup_shader_program_err(ctx, program, "glAttachShader");
447 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700448 return;
Brian5b01c5e2006-12-19 18:02:03 -0700449
Brian Paul530df582008-07-03 16:21:11 -0600450 sh = _mesa_lookup_shader_err(ctx, shader, "glAttachShader");
Brian Paul7acb7c12008-07-03 13:49:48 -0600451 if (!sh) {
Brian Paul7acb7c12008-07-03 13:49:48 -0600452 return;
453 }
454
Brian237b9852007-08-07 21:48:31 +0100455 n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700456 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700457 if (shProg->Shaders[i] == sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700458 /* already attached */
459 return;
Brian34ae99d2006-12-18 08:28:54 -0700460 }
461 }
Brian5b01c5e2006-12-19 18:02:03 -0700462
463 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700464 shProg->Shaders = (struct gl_shader **)
465 _mesa_realloc(shProg->Shaders,
466 n * sizeof(struct gl_shader *),
467 (n + 1) * sizeof(struct gl_shader *));
468 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700469 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
470 return;
471 }
472
473 /* append */
Brian3c008a02007-04-12 15:22:32 -0600474 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
475 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700476 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700477}
478
479
Brian Paulfd59f192008-05-18 16:04:55 -0600480static GLint
Brian Paul896c0cc2008-05-16 15:47:55 -0600481_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
482 const GLchar *name)
483{
484 struct gl_shader_program *shProg
Brian Paul530df582008-07-03 16:21:11 -0600485 = _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
Brian Paul896c0cc2008-05-16 15:47:55 -0600486
487 if (!shProg) {
Brian Paul896c0cc2008-05-16 15:47:55 -0600488 return -1;
489 }
490
491 if (!shProg->LinkStatus) {
492 _mesa_error(ctx, GL_INVALID_OPERATION,
493 "glGetAttribLocation(program not linked)");
494 return -1;
495 }
496
497 if (!name)
498 return -1;
499
Brian Paul27341a92008-09-16 16:28:36 -0600500 if (shProg->VertexProgram) {
501 const struct gl_program_parameter_list *attribs =
502 shProg->VertexProgram->Base.Attributes;
503 if (attribs) {
504 GLint i = _mesa_lookup_parameter_index(attribs, -1, name);
505 if (i >= 0) {
506 return attribs->Parameters[i].StateIndexes[0];
507 }
Brian Paul896c0cc2008-05-16 15:47:55 -0600508 }
509 }
510 return -1;
511}
512
513
Brian Paulfd59f192008-05-18 16:04:55 -0600514static void
Brian5b01c5e2006-12-19 18:02:03 -0700515_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
516 const GLchar *name)
517{
Brian Paul530df582008-07-03 16:21:11 -0600518 struct gl_shader_program *shProg;
Brianb7978af2007-01-09 19:17:17 -0700519 const GLint size = -1; /* unknown size */
Brian Paul6bc87492008-07-25 08:34:54 -0600520 GLint i, oldIndex;
Brian Paul6f1abb92008-07-29 17:27:22 -0600521 GLenum datatype = GL_FLOAT_VEC4;
Brian5b01c5e2006-12-19 18:02:03 -0700522
Brian Paul530df582008-07-03 16:21:11 -0600523 shProg = _mesa_lookup_shader_program_err(ctx, program,
524 "glBindAttribLocation");
Brian65a18442006-12-19 18:46:56 -0700525 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700526 return;
527 }
528
Brian9e4bae92006-12-20 09:27:42 -0700529 if (!name)
530 return;
531
532 if (strncmp(name, "gl_", 3) == 0) {
533 _mesa_error(ctx, GL_INVALID_OPERATION,
534 "glBindAttribLocation(illegal name)");
535 return;
536 }
537
Brian Paul7acb7c12008-07-03 13:49:48 -0600538 if (index >= ctx->Const.VertexProgram.MaxAttribs) {
539 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
540 return;
541 }
542
Brian Paul6bc87492008-07-25 08:34:54 -0600543 if (shProg->LinkStatus) {
544 /* get current index/location for the attribute */
545 oldIndex = _mesa_get_attrib_location(ctx, program, name);
546 }
547 else {
548 oldIndex = -1;
549 }
550
Brian3209c3e2007-01-09 17:49:24 -0700551 /* this will replace the current value if it's already in the list */
Brian Paulffbc66b2008-07-21 13:58:50 -0600552 i = _mesa_add_attribute(shProg->Attributes, name, size, datatype, index);
Brian3209c3e2007-01-09 17:49:24 -0700553 if (i < 0) {
554 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
Brian Paul6f1abb92008-07-29 17:27:22 -0600555 return;
Brian3209c3e2007-01-09 17:49:24 -0700556 }
557
Brian Paul27341a92008-09-16 16:28:36 -0600558 /*
559 * Note that this attribute binding won't go into effect until
560 * glLinkProgram is called again.
561 */
Brian34ae99d2006-12-18 08:28:54 -0700562}
563
564
Brian Paulfd59f192008-05-18 16:04:55 -0600565static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700566_mesa_create_shader(GLcontext *ctx, GLenum type)
567{
Brian65a18442006-12-19 18:46:56 -0700568 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700569 GLuint name;
570
571 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
572
573 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700574 case GL_FRAGMENT_SHADER:
575 case GL_VERTEX_SHADER:
576 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700577 break;
578 default:
579 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
580 return 0;
581 }
582
Brian65a18442006-12-19 18:46:56 -0700583 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700584
585 return name;
586}
587
588
Brian Paulfd59f192008-05-18 16:04:55 -0600589static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700590_mesa_create_program(GLcontext *ctx)
591{
592 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700593 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700594
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800595 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
Brian65a18442006-12-19 18:46:56 -0700596 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700597
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800598 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700599
Brian3c008a02007-04-12 15:22:32 -0600600 assert(shProg->RefCount == 1);
601
Brian5b01c5e2006-12-19 18:02:03 -0700602 return name;
603}
604
605
Brian3c008a02007-04-12 15:22:32 -0600606/**
607 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
608 * DeleteProgramARB.
609 */
Brian Paulfd59f192008-05-18 16:04:55 -0600610static void
Brian5b01c5e2006-12-19 18:02:03 -0700611_mesa_delete_program2(GLcontext *ctx, GLuint name)
612{
Brian3c008a02007-04-12 15:22:32 -0600613 /*
614 * NOTE: deleting shaders/programs works a bit differently than
615 * texture objects (and buffer objects, etc). Shader/program
616 * handles/IDs exist in the hash table until the object is really
617 * deleted (refcount==0). With texture objects, the handle/ID is
618 * removed from the hash table in glDeleteTextures() while the tex
619 * object itself might linger until its refcount goes to zero.
620 */
Brian65a18442006-12-19 18:46:56 -0700621 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700622
Brian Paul530df582008-07-03 16:21:11 -0600623 shProg = _mesa_lookup_shader_program_err(ctx, name, "glDeleteProgram");
624 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700625 return;
Brian5b01c5e2006-12-19 18:02:03 -0700626
Brian9e4bae92006-12-20 09:27:42 -0700627 shProg->DeletePending = GL_TRUE;
628
Brian3c008a02007-04-12 15:22:32 -0600629 /* effectively, decr shProg's refcount */
630 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700631}
632
633
Brian Paulfd59f192008-05-18 16:04:55 -0600634static void
Brian5b01c5e2006-12-19 18:02:03 -0700635_mesa_delete_shader(GLcontext *ctx, GLuint shader)
636{
Brian Paul530df582008-07-03 16:21:11 -0600637 struct gl_shader *sh;
638
639 sh = _mesa_lookup_shader_err(ctx, shader, "glDeleteShader");
640 if (!sh)
Brian9e4bae92006-12-20 09:27:42 -0700641 return;
Brian5b01c5e2006-12-19 18:02:03 -0700642
Brian9e4bae92006-12-20 09:27:42 -0700643 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600644
645 /* effectively, decr sh's refcount */
646 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700647}
648
649
Brian Paulfd59f192008-05-18 16:04:55 -0600650static void
Brian5b01c5e2006-12-19 18:02:03 -0700651_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
652{
Brian Paul530df582008-07-03 16:21:11 -0600653 struct gl_shader_program *shProg;
Brian237b9852007-08-07 21:48:31 +0100654 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700655 GLuint i, j;
656
Brian Paul530df582008-07-03 16:21:11 -0600657 shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader");
658 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700659 return;
Brian5b01c5e2006-12-19 18:02:03 -0700660
Brian237b9852007-08-07 21:48:31 +0100661 n = shProg->NumShaders;
662
Brian5b01c5e2006-12-19 18:02:03 -0700663 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700664 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700665 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600666 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700667
Brian Paul530df582008-07-03 16:21:11 -0600668 /* release */
Brian3c008a02007-04-12 15:22:32 -0600669 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700670
Brian5b01c5e2006-12-19 18:02:03 -0700671 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700672 newList = (struct gl_shader **)
673 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700674 if (!newList) {
675 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
676 return;
677 }
678 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700679 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700680 }
681 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700682 newList[j++] = shProg->Shaders[i];
683 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700684
Brian65a18442006-12-19 18:46:56 -0700685 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600686 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600687
688#ifdef DEBUG
689 /* sanity check */
690 {
691 for (j = 0; j < shProg->NumShaders; j++) {
692 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
693 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
694 assert(shProg->Shaders[j]->RefCount > 0);
695 }
696 }
697#endif
698
Brian5b01c5e2006-12-19 18:02:03 -0700699 return;
700 }
701 }
702
703 /* not found */
Brian Paul530df582008-07-03 16:21:11 -0600704 {
705 GLenum err;
706 if (_mesa_is_shader(ctx, shader))
707 err = GL_INVALID_OPERATION;
708 else if (_mesa_is_program(ctx, shader))
709 err = GL_INVALID_OPERATION;
710 else
711 err = GL_INVALID_VALUE;
712 _mesa_error(ctx, err, "glDetachProgram(shader)");
713 return;
714 }
Brian5b01c5e2006-12-19 18:02:03 -0700715}
716
717
Brian Paulffbc66b2008-07-21 13:58:50 -0600718static GLint
719sizeof_glsl_type(GLenum type)
720{
721 switch (type) {
722 case GL_FLOAT:
723 case GL_INT:
724 case GL_BOOL:
Brian Paul8c51e002008-08-11 15:09:47 -0600725 case GL_SAMPLER_1D:
726 case GL_SAMPLER_2D:
727 case GL_SAMPLER_3D:
728 case GL_SAMPLER_CUBE:
729 case GL_SAMPLER_1D_SHADOW:
730 case GL_SAMPLER_2D_SHADOW:
731 case GL_SAMPLER_2D_RECT_ARB:
732 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
733 case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
734 case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
735 case GL_SAMPLER_CUBE_SHADOW_EXT:
Brian Paulffbc66b2008-07-21 13:58:50 -0600736 return 1;
737 case GL_FLOAT_VEC2:
738 case GL_INT_VEC2:
739 case GL_BOOL_VEC2:
740 return 2;
741 case GL_FLOAT_VEC3:
742 case GL_INT_VEC3:
743 case GL_BOOL_VEC3:
744 return 3;
745 case GL_FLOAT_VEC4:
746 case GL_INT_VEC4:
747 case GL_BOOL_VEC4:
748 return 4;
749 case GL_FLOAT_MAT2:
750 case GL_FLOAT_MAT2x3:
751 case GL_FLOAT_MAT2x4:
752 return 8; /* two float[4] vectors */
753 case GL_FLOAT_MAT3:
754 case GL_FLOAT_MAT3x2:
755 case GL_FLOAT_MAT3x4:
756 return 12; /* three float[4] vectors */
757 case GL_FLOAT_MAT4:
758 case GL_FLOAT_MAT4x2:
759 case GL_FLOAT_MAT4x3:
760 return 16; /* four float[4] vectors */
761 default:
762 _mesa_problem(NULL, "Invalid type in sizeof_glsl_type()");
763 return 1;
764 }
765}
766
767
Brian Pauleda291e2008-08-06 16:26:47 -0600768static GLboolean
769is_boolean_type(GLenum type)
770{
771 switch (type) {
772 case GL_BOOL:
773 case GL_BOOL_VEC2:
774 case GL_BOOL_VEC3:
775 case GL_BOOL_VEC4:
776 return GL_TRUE;
777 default:
778 return GL_FALSE;
779 }
780}
781
782
783static GLboolean
784is_integer_type(GLenum type)
785{
786 switch (type) {
787 case GL_INT:
788 case GL_INT_VEC2:
789 case GL_INT_VEC3:
790 case GL_INT_VEC4:
791 return GL_TRUE;
792 default:
793 return GL_FALSE;
794 }
795}
796
797
Brian Paulfd59f192008-05-18 16:04:55 -0600798static void
Brian5b01c5e2006-12-19 18:02:03 -0700799_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
800 GLsizei maxLength, GLsizei *length, GLint *size,
801 GLenum *type, GLchar *nameOut)
802{
Brian Paul27341a92008-09-16 16:28:36 -0600803 const struct gl_program_parameter_list *attribs = NULL;
Brian Paul530df582008-07-03 16:21:11 -0600804 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700805
Brian Paul530df582008-07-03 16:21:11 -0600806 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
807 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700808 return;
Brian5b01c5e2006-12-19 18:02:03 -0700809
Brian Paul27341a92008-09-16 16:28:36 -0600810 if (shProg->VertexProgram)
811 attribs = shProg->VertexProgram->Base.Attributes;
812
813 if (!attribs || index >= attribs->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600814 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700815 return;
816 }
817
Brian Paul27341a92008-09-16 16:28:36 -0600818 copy_string(nameOut, maxLength, length, attribs->Parameters[index].Name);
819
Brian5b01c5e2006-12-19 18:02:03 -0700820 if (size)
Brian Paul27341a92008-09-16 16:28:36 -0600821 *size = attribs->Parameters[index].Size
822 / sizeof_glsl_type(attribs->Parameters[index].DataType);
823
Brian Paulade50832008-05-14 16:09:46 -0600824 if (type)
Brian Paul27341a92008-09-16 16:28:36 -0600825 *type = attribs->Parameters[index].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700826}
827
828
Brian Pauleda291e2008-08-06 16:26:47 -0600829static struct gl_program_parameter *
830get_uniform_parameter(const struct gl_shader_program *shProg, GLuint index)
831{
832 const struct gl_program *prog;
833 GLint progPos;
834
835 progPos = shProg->Uniforms->Uniforms[index].VertPos;
836 if (progPos >= 0) {
837 prog = &shProg->VertexProgram->Base;
838 }
839 else {
840 progPos = shProg->Uniforms->Uniforms[index].FragPos;
841 if (progPos >= 0) {
842 prog = &shProg->FragmentProgram->Base;
843 }
844 }
845
846 if (!prog || progPos < 0)
847 return NULL; /* should never happen */
848
849 return &prog->Parameters->Parameters[progPos];
850}
851
852
Brian5b01c5e2006-12-19 18:02:03 -0700853/**
854 * Called via ctx->Driver.GetActiveUniform().
855 */
Brian Paulfd59f192008-05-18 16:04:55 -0600856static void
Brian5b01c5e2006-12-19 18:02:03 -0700857_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
858 GLsizei maxLength, GLsizei *length, GLint *size,
859 GLenum *type, GLchar *nameOut)
860{
Brian Paul530df582008-07-03 16:21:11 -0600861 const struct gl_shader_program *shProg;
Brian Paulade50832008-05-14 16:09:46 -0600862 const struct gl_program *prog;
863 GLint progPos;
Brian5b01c5e2006-12-19 18:02:03 -0700864
Brian Paul530df582008-07-03 16:21:11 -0600865 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
866 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700867 return;
Brian5b01c5e2006-12-19 18:02:03 -0700868
Brian Paulade50832008-05-14 16:09:46 -0600869 if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
Brian5b01c5e2006-12-19 18:02:03 -0700870 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
871 return;
872 }
873
Brian Paulade50832008-05-14 16:09:46 -0600874 progPos = shProg->Uniforms->Uniforms[index].VertPos;
875 if (progPos >= 0) {
876 prog = &shProg->VertexProgram->Base;
877 }
878 else {
879 progPos = shProg->Uniforms->Uniforms[index].FragPos;
880 if (progPos >= 0) {
881 prog = &shProg->FragmentProgram->Base;
Brian274ac7a2007-04-18 16:05:53 -0600882 }
883 }
884
Brian Paulade50832008-05-14 16:09:46 -0600885 if (!prog || progPos < 0)
886 return; /* should never happen */
887
888 if (nameOut)
889 copy_string(nameOut, maxLength, length,
890 prog->Parameters->Parameters[progPos].Name);
891 if (size)
Brian Paulffbc66b2008-07-21 13:58:50 -0600892 *size = prog->Parameters->Parameters[progPos].Size
893 / sizeof_glsl_type(prog->Parameters->Parameters[progPos].DataType);
Brian Paulade50832008-05-14 16:09:46 -0600894 if (type)
895 *type = prog->Parameters->Parameters[progPos].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700896}
897
898
899/**
900 * Called via ctx->Driver.GetAttachedShaders().
901 */
Brian Paulfd59f192008-05-18 16:04:55 -0600902static void
Brian5b01c5e2006-12-19 18:02:03 -0700903_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
904 GLsizei *count, GLuint *obj)
905{
Brian Paul530df582008-07-03 16:21:11 -0600906 struct gl_shader_program *shProg =
907 _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders");
Brian65a18442006-12-19 18:46:56 -0700908 if (shProg) {
Brian Paul530df582008-07-03 16:21:11 -0600909 GLuint i;
910 for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) {
Brian65a18442006-12-19 18:46:56 -0700911 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700912 }
913 if (count)
914 *count = i;
915 }
Brian5b01c5e2006-12-19 18:02:03 -0700916}
917
918
Brian Paulfd59f192008-05-18 16:04:55 -0600919static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700920_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700921{
922#if 0
923 GET_CURRENT_CONTEXT(ctx);
924
925 switch (pname) {
926 case GL_PROGRAM_OBJECT_ARB:
927 {
Brian5b01c5e2006-12-19 18:02:03 -0700928 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700929
930 if (pro != NULL)
931 return (**pro)._container._generic.
932 GetName((struct gl2_generic_intf **) (pro));
933 }
934 break;
935 default:
936 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
937 }
938#endif
939 return 0;
940}
941
942
Brian Paulfd59f192008-05-18 16:04:55 -0600943static void
Brian5b01c5e2006-12-19 18:02:03 -0700944_mesa_get_programiv(GLcontext *ctx, GLuint program,
945 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700946{
Brian Paul27341a92008-09-16 16:28:36 -0600947 const struct gl_program_parameter_list *attribs;
Brian65a18442006-12-19 18:46:56 -0700948 struct gl_shader_program *shProg
949 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700950
Brian65a18442006-12-19 18:46:56 -0700951 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700952 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700953 return;
954 }
955
Brian Paul27341a92008-09-16 16:28:36 -0600956 if (shProg->VertexProgram)
957 attribs = shProg->VertexProgram->Base.Attributes;
958 else
959 attribs = NULL;
960
Brian5b01c5e2006-12-19 18:02:03 -0700961 switch (pname) {
962 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700963 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700964 break;
965 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700966 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700967 break;
Brian5b01c5e2006-12-19 18:02:03 -0700968 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700969 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700970 break;
971 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600972 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700973 break;
974 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700975 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700976 break;
977 case GL_ACTIVE_ATTRIBUTES:
Brian Paul27341a92008-09-16 16:28:36 -0600978 *params = attribs ? attribs->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700979 break;
980 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian Paul27341a92008-09-16 16:28:36 -0600981 *params = _mesa_longest_parameter_name(attribs, PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700982 break;
983 case GL_ACTIVE_UNIFORMS:
Brian Paulade50832008-05-14 16:09:46 -0600984 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700985 break;
986 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian Paulade50832008-05-14 16:09:46 -0600987 *params = _mesa_longest_uniform_name(shProg->Uniforms);
Brian274ac7a2007-04-18 16:05:53 -0600988 if (*params > 0)
989 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700990 break;
Brian Paulbda6ad22008-08-06 12:45:14 -0600991 case GL_PROGRAM_BINARY_LENGTH_OES:
992 *params = 0;
993 break;
Brian34ae99d2006-12-18 08:28:54 -0700994 default:
Brian5b01c5e2006-12-19 18:02:03 -0700995 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
996 return;
Brian34ae99d2006-12-18 08:28:54 -0700997 }
Brian5b01c5e2006-12-19 18:02:03 -0700998}
Brian34ae99d2006-12-18 08:28:54 -0700999
Brian34ae99d2006-12-18 08:28:54 -07001000
Brian Paulfd59f192008-05-18 16:04:55 -06001001static void
Brian5b01c5e2006-12-19 18:02:03 -07001002_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
1003{
Brian Paul530df582008-07-03 16:21:11 -06001004 struct gl_shader *shader = _mesa_lookup_shader_err(ctx, name, "glGetShaderiv");
Brian5b01c5e2006-12-19 18:02:03 -07001005
1006 if (!shader) {
Brian5b01c5e2006-12-19 18:02:03 -07001007 return;
1008 }
Brian65a18442006-12-19 18:46:56 -07001009
Brian5b01c5e2006-12-19 18:02:03 -07001010 switch (pname) {
1011 case GL_SHADER_TYPE:
1012 *params = shader->Type;
1013 break;
1014 case GL_DELETE_STATUS:
1015 *params = shader->DeletePending;
1016 break;
1017 case GL_COMPILE_STATUS:
1018 *params = shader->CompileStatus;
1019 break;
1020 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001021 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001022 break;
1023 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001024 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001025 break;
1026 default:
1027 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
1028 return;
1029 }
1030}
1031
1032
Brian Paulfd59f192008-05-18 16:04:55 -06001033static void
Brian5b01c5e2006-12-19 18:02:03 -07001034_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
1035 GLsizei *length, GLchar *infoLog)
1036{
Brian65a18442006-12-19 18:46:56 -07001037 struct gl_shader_program *shProg
1038 = _mesa_lookup_shader_program(ctx, program);
1039 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -07001040 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
1041 return;
1042 }
Brian65a18442006-12-19 18:46:56 -07001043 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -07001044}
1045
1046
Brian Paulfd59f192008-05-18 16:04:55 -06001047static void
Brian5b01c5e2006-12-19 18:02:03 -07001048_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
1049 GLsizei *length, GLchar *infoLog)
1050{
Brian65a18442006-12-19 18:46:56 -07001051 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
1052 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001053 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
1054 return;
1055 }
Brian65a18442006-12-19 18:46:56 -07001056 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -07001057}
1058
1059
1060/**
1061 * Called via ctx->Driver.GetShaderSource().
1062 */
Brian Paulfd59f192008-05-18 16:04:55 -06001063static void
Brian5b01c5e2006-12-19 18:02:03 -07001064_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
1065 GLsizei *length, GLchar *sourceOut)
1066{
Brian Paul530df582008-07-03 16:21:11 -06001067 struct gl_shader *sh;
1068 sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource");
Brian65a18442006-12-19 18:46:56 -07001069 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001070 return;
1071 }
Brian65a18442006-12-19 18:46:56 -07001072 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -07001073}
1074
1075
Brian Paul2be54a82008-07-08 16:17:04 -06001076#define MAX_UNIFORM_ELEMENTS 16
1077
Brian5b01c5e2006-12-19 18:02:03 -07001078/**
Brian Paul2be54a82008-07-08 16:17:04 -06001079 * Helper for GetUniformfv(), GetUniformiv()
1080 * Returns number of elements written to 'params' output.
Brian5b01c5e2006-12-19 18:02:03 -07001081 */
Brian Paul2be54a82008-07-08 16:17:04 -06001082static GLuint
1083get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1084 GLfloat *params)
Brian5b01c5e2006-12-19 18:02:03 -07001085{
Brian65a18442006-12-19 18:46:56 -07001086 struct gl_shader_program *shProg
Brian Paulbda6ad22008-08-06 12:45:14 -06001087 = _mesa_lookup_shader_program_err(ctx, program, "glGetUniform[if]v");
Brian65a18442006-12-19 18:46:56 -07001088 if (shProg) {
Brian Paul6cb12702008-06-28 16:48:31 -06001089 if (shProg->Uniforms &&
Brian Paul016701f2008-07-29 17:43:35 -06001090 location >= 0 && location < (GLint) shProg->Uniforms->NumUniforms) {
Brian Paul6cb12702008-06-28 16:48:31 -06001091 GLint progPos;
1092 GLuint i;
Brian Paulf2632212008-05-16 10:49:44 -06001093 const struct gl_program *prog = NULL;
Brian Paulade50832008-05-14 16:09:46 -06001094
1095 progPos = shProg->Uniforms->Uniforms[location].VertPos;
1096 if (progPos >= 0) {
1097 prog = &shProg->VertexProgram->Base;
Brian5b01c5e2006-12-19 18:02:03 -07001098 }
Brian Paulade50832008-05-14 16:09:46 -06001099 else {
1100 progPos = shProg->Uniforms->Uniforms[location].FragPos;
1101 if (progPos >= 0) {
1102 prog = &shProg->FragmentProgram->Base;
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001103 }
Brian Paulade50832008-05-14 16:09:46 -06001104 }
1105
Brian Paulf2632212008-05-16 10:49:44 -06001106 ASSERT(prog);
1107 if (prog) {
Brian Paul2be54a82008-07-08 16:17:04 -06001108 /* See uniformiv() below */
1109 assert(prog->Parameters->Parameters[progPos].Size <= MAX_UNIFORM_ELEMENTS);
1110
Brian Paulf2632212008-05-16 10:49:44 -06001111 for (i = 0; i < prog->Parameters->Parameters[progPos].Size; i++) {
1112 params[i] = prog->Parameters->ParameterValues[progPos][i];
1113 }
Brian Paul2be54a82008-07-08 16:17:04 -06001114 return prog->Parameters->Parameters[progPos].Size;
Brian Paulade50832008-05-14 16:09:46 -06001115 }
Brian5b01c5e2006-12-19 18:02:03 -07001116 }
1117 else {
Brian Paul6cb12702008-06-28 16:48:31 -06001118 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
Brian5b01c5e2006-12-19 18:02:03 -07001119 }
1120 }
Brian Paul2be54a82008-07-08 16:17:04 -06001121 return 0;
1122}
1123
1124
1125/**
1126 * Called via ctx->Driver.GetUniformfv().
1127 */
1128static void
1129_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1130 GLfloat *params)
1131{
1132 (void) get_uniformfv(ctx, program, location, params);
1133}
1134
1135
1136/**
1137 * Called via ctx->Driver.GetUniformiv().
1138 */
1139static void
1140_mesa_get_uniformiv(GLcontext *ctx, GLuint program, GLint location,
1141 GLint *params)
1142{
1143 GLfloat fparams[MAX_UNIFORM_ELEMENTS];
1144 GLuint n = get_uniformfv(ctx, program, location, fparams);
1145 GLuint i;
1146 assert(n <= MAX_UNIFORM_ELEMENTS);
1147 for (i = 0; i < n; i++) {
1148 params[i] = (GLint) fparams[i];
1149 }
Brian5b01c5e2006-12-19 18:02:03 -07001150}
1151
1152
1153/**
Brian Pauleda291e2008-08-06 16:26:47 -06001154 * The value returned by GetUniformLocation actually encodes two things:
1155 * 1. the index into the prog->Uniforms[] array for the uniform
1156 * 2. an offset in the prog->ParameterValues[] array for specifying array
1157 * elements or structure fields.
1158 * This function merges those two values.
1159 */
1160static void
1161merge_location_offset(GLint *location, GLint offset)
1162{
1163 *location = *location | (offset << 16);
1164}
1165
1166
1167/**
1168 * Seperate the uniform location and parameter offset. See above.
1169 */
1170static void
1171split_location_offset(GLint *location, GLint *offset)
1172{
1173 *offset = (*location >> 16);
1174 *location = *location & 0xffff;
1175}
1176
1177
1178/**
Brian5b01c5e2006-12-19 18:02:03 -07001179 * Called via ctx->Driver.GetUniformLocation().
Brian Pauleda291e2008-08-06 16:26:47 -06001180 *
1181 * The return value will encode two values, the uniform location and an
1182 * offset (used for arrays, structs).
Brian5b01c5e2006-12-19 18:02:03 -07001183 */
Brian Paulfd59f192008-05-18 16:04:55 -06001184static GLint
Brian5b01c5e2006-12-19 18:02:03 -07001185_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
1186{
Brian Pauleda291e2008-08-06 16:26:47 -06001187 GLint offset = 0, location = -1;
1188
Brian Paul530df582008-07-03 16:21:11 -06001189 struct gl_shader_program *shProg =
1190 _mesa_lookup_shader_program_err(ctx, program, "glGetUniformLocation");
1191
Brian Paulade50832008-05-14 16:09:46 -06001192 if (!shProg)
1193 return -1;
Brian5b01c5e2006-12-19 18:02:03 -07001194
Brian Paule06565b2008-07-04 09:58:55 -06001195 if (shProg->LinkStatus == GL_FALSE) {
1196 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
1197 return -1;
1198 }
1199
Brian Paul530df582008-07-03 16:21:11 -06001200 /* XXX we should return -1 if the uniform was declared, but not
1201 * actually used.
1202 */
1203
Brian Pauleda291e2008-08-06 16:26:47 -06001204 /* XXX we need to be able to parse uniform names for structs and arrays
1205 * such as:
1206 * mymatrix[1]
1207 * mystruct.field1
1208 */
1209
1210 {
1211 /* handle 1-dimension arrays here... */
1212 char *c = strchr(name, '[');
1213 if (c) {
1214 /* truncate name at [ */
1215 const GLint len = c - name;
1216 GLchar *newName = _mesa_malloc(len + 1);
1217 if (!newName)
1218 return -1; /* out of mem */
1219 _mesa_memcpy(newName, name, len);
1220 newName[len] = 0;
1221
1222 location = _mesa_lookup_uniform(shProg->Uniforms, newName);
1223 if (location >= 0) {
1224 const GLint element = _mesa_atoi(c + 1);
1225 if (element > 0) {
1226 /* get type of the uniform array element */
1227 struct gl_program_parameter *p;
1228 p = get_uniform_parameter(shProg, location);
1229 if (p) {
1230 GLint rows, cols;
1231 get_matrix_dims(p->DataType, &rows, &cols);
1232 if (rows < 1)
1233 rows = 1;
1234 offset = element * rows;
1235 }
1236 }
1237 }
1238
1239 _mesa_free(newName);
1240 }
1241 }
1242
1243 if (location < 0) {
1244 location = _mesa_lookup_uniform(shProg->Uniforms, name);
1245 }
1246
1247 if (location >= 0) {
1248 merge_location_offset(&location, offset);
1249 }
1250
1251 return location;
Brian5b01c5e2006-12-19 18:02:03 -07001252}
1253
1254
Brian34ae99d2006-12-18 08:28:54 -07001255
Brian5b01c5e2006-12-19 18:02:03 -07001256/**
1257 * Called via ctx->Driver.ShaderSource()
1258 */
Brian Paulfd59f192008-05-18 16:04:55 -06001259static void
Brian5b01c5e2006-12-19 18:02:03 -07001260_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -07001261{
Brian Paul530df582008-07-03 16:21:11 -06001262 struct gl_shader *sh;
1263
1264 sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource");
1265 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001266 return;
Brian34ae99d2006-12-18 08:28:54 -07001267
Brian34ae99d2006-12-18 08:28:54 -07001268 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -07001269 if (sh->Source) {
1270 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -07001271 }
Brian65a18442006-12-19 18:46:56 -07001272 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -07001273 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -07001274}
1275
1276
Brian5b01c5e2006-12-19 18:02:03 -07001277/**
1278 * Called via ctx->Driver.CompileShader()
1279 */
Brian Paulfd59f192008-05-18 16:04:55 -06001280static void
Brian5b01c5e2006-12-19 18:02:03 -07001281_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -07001282{
Brian Paul530df582008-07-03 16:21:11 -06001283 struct gl_shader *sh;
Brian34ae99d2006-12-18 08:28:54 -07001284
Brian Paul530df582008-07-03 16:21:11 -06001285 sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader");
1286 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001287 return;
Brian34ae99d2006-12-18 08:28:54 -07001288
Brian43975832007-01-04 08:21:09 -07001289 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -07001290}
1291
1292
Brian5b01c5e2006-12-19 18:02:03 -07001293/**
1294 * Called via ctx->Driver.LinkProgram()
1295 */
Brian Paulfd59f192008-05-18 16:04:55 -06001296static void
Brian5b01c5e2006-12-19 18:02:03 -07001297_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001298{
Brian65a18442006-12-19 18:46:56 -07001299 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001300
Brian Paul530df582008-07-03 16:21:11 -06001301 shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
1302 if (!shProg)
Brian34ae99d2006-12-18 08:28:54 -07001303 return;
Brian34ae99d2006-12-18 08:28:54 -07001304
Briandf43fb62008-05-06 23:08:51 -06001305 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1306
Brianc1771912007-02-16 09:56:19 -07001307 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001308}
1309
1310
1311/**
Brian5b01c5e2006-12-19 18:02:03 -07001312 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001313 */
Brian5b01c5e2006-12-19 18:02:03 -07001314void
1315_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001316{
Brian3c008a02007-04-12 15:22:32 -06001317 struct gl_shader_program *shProg;
1318
Brian00d63aa2007-02-03 11:35:02 -07001319 if (ctx->Shader.CurrentProgram &&
1320 ctx->Shader.CurrentProgram->Name == program) {
1321 /* no-op */
1322 return;
1323 }
1324
1325 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1326
Brian5b01c5e2006-12-19 18:02:03 -07001327 if (program) {
Brian Paul530df582008-07-03 16:21:11 -06001328 shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
Brian65a18442006-12-19 18:46:56 -07001329 if (!shProg) {
Brian Paul530df582008-07-03 16:21:11 -06001330 return;
1331 }
1332 if (!shProg->LinkStatus) {
1333 _mesa_error(ctx, GL_INVALID_OPERATION, "glUseProgram");
Brian5b01c5e2006-12-19 18:02:03 -07001334 return;
1335 }
Brian5b01c5e2006-12-19 18:02:03 -07001336 }
1337 else {
Brian3c008a02007-04-12 15:22:32 -06001338 shProg = NULL;
1339 }
1340
1341 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001342}
Brian34ae99d2006-12-18 08:28:54 -07001343
Brian5b01c5e2006-12-19 18:02:03 -07001344
Brian Paulade50832008-05-14 16:09:46 -06001345
1346/**
1347 * Update the vertex and fragment program's TexturesUsed arrays.
1348 */
1349static void
1350update_textures_used(struct gl_program *prog)
1351{
1352 GLuint s;
1353
1354 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1355
1356 for (s = 0; s < MAX_SAMPLERS; s++) {
1357 if (prog->SamplersUsed & (1 << s)) {
1358 GLuint u = prog->SamplerUnits[s];
1359 GLuint t = prog->SamplerTargets[s];
1360 assert(u < MAX_TEXTURE_IMAGE_UNITS);
1361 prog->TexturesUsed[u] |= (1 << t);
1362 }
1363 }
1364}
1365
1366
Brianb36749d2008-07-21 20:42:05 -06001367static GLboolean
1368is_sampler_type(GLenum type)
1369{
1370 switch (type) {
1371 case GL_SAMPLER_1D:
1372 case GL_SAMPLER_2D:
1373 case GL_SAMPLER_3D:
1374 case GL_SAMPLER_CUBE:
1375 case GL_SAMPLER_1D_SHADOW:
1376 case GL_SAMPLER_2D_SHADOW:
1377 case GL_SAMPLER_2D_RECT_ARB:
1378 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
1379 case GL_SAMPLER_1D_ARRAY_EXT:
1380 case GL_SAMPLER_2D_ARRAY_EXT:
1381 return GL_TRUE;
1382 default:
1383 return GL_FALSE;
1384 }
1385}
1386
1387
Brian Paulade50832008-05-14 16:09:46 -06001388/**
Brian Paulffbc66b2008-07-21 13:58:50 -06001389 * Check if the type given by userType is allowed to set a uniform of the
1390 * target type. Generally, equivalence is required, but setting Boolean
1391 * uniforms can be done with glUniformiv or glUniformfv.
1392 */
1393static GLboolean
1394compatible_types(GLenum userType, GLenum targetType)
1395{
1396 if (userType == targetType)
1397 return GL_TRUE;
1398
1399 if (targetType == GL_BOOL && (userType == GL_FLOAT || userType == GL_INT))
1400 return GL_TRUE;
1401
1402 if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 ||
1403 userType == GL_INT_VEC2))
1404 return GL_TRUE;
1405
1406 if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 ||
1407 userType == GL_INT_VEC3))
1408 return GL_TRUE;
1409
1410 if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 ||
1411 userType == GL_INT_VEC4))
1412 return GL_TRUE;
1413
Brianb36749d2008-07-21 20:42:05 -06001414 if (is_sampler_type(targetType) && userType == GL_INT)
1415 return GL_TRUE;
1416
Brian Paulffbc66b2008-07-21 13:58:50 -06001417 return GL_FALSE;
1418}
1419
1420
1421/**
Brian Paulade50832008-05-14 16:09:46 -06001422 * Set the value of a program's uniform variable.
1423 * \param program the program whose uniform to update
Brian Pauleda291e2008-08-06 16:26:47 -06001424 * \param index the index of the program parameter for the uniform
1425 * \param offset additional parameter slot offset (for arrays)
Brian Paulade50832008-05-14 16:09:46 -06001426 * \param type the datatype of the uniform
1427 * \param count the number of uniforms to set
1428 * \param elems number of elements per uniform
1429 * \param values the new values
1430 */
1431static void
Brian Pauleda291e2008-08-06 16:26:47 -06001432set_program_uniform(GLcontext *ctx, struct gl_program *program,
1433 GLint index, GLint offset,
1434 GLenum type, GLsizei count, GLint elems,
1435 const void *values)
Brian Paulade50832008-05-14 16:09:46 -06001436{
Brian Pauleda291e2008-08-06 16:26:47 -06001437 assert(offset >= 0);
1438
Brian Paulffbc66b2008-07-21 13:58:50 -06001439 if (!compatible_types(type,
Brian Pauleda291e2008-08-06 16:26:47 -06001440 program->Parameters->Parameters[index].DataType)) {
Brian Paulffbc66b2008-07-21 13:58:50 -06001441 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
1442 return;
1443 }
1444
Brian Pauleda291e2008-08-06 16:26:47 -06001445 if (index + offset > program->Parameters->Size) {
1446 /* out of bounds! */
1447 return;
1448 }
1449
1450 if (program->Parameters->Parameters[index].Type == PROGRAM_SAMPLER) {
Brian Paulade50832008-05-14 16:09:46 -06001451 /* This controls which texture unit which is used by a sampler */
1452 GLuint texUnit, sampler;
1453
1454 /* data type for setting samplers must be int */
1455 if (type != GL_INT || count != 1) {
1456 _mesa_error(ctx, GL_INVALID_OPERATION,
1457 "glUniform(only glUniform1i can be used "
1458 "to set sampler uniforms)");
1459 return;
1460 }
1461
Brian Pauleda291e2008-08-06 16:26:47 -06001462 sampler = (GLuint) program->Parameters->ParameterValues[index][0];
Brian Paulade50832008-05-14 16:09:46 -06001463 texUnit = ((GLuint *) values)[0];
1464
1465 /* check that the sampler (tex unit index) is legal */
1466 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1467 _mesa_error(ctx, GL_INVALID_VALUE,
1468 "glUniform1(invalid sampler/tex unit index)");
1469 return;
1470 }
1471
1472 /* This maps a sampler to a texture unit: */
1473 program->SamplerUnits[sampler] = texUnit;
1474 update_textures_used(program);
1475
1476 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1477 }
1478 else {
1479 /* ordinary uniform variable */
Brian Paul530df582008-07-03 16:21:11 -06001480 GLsizei k, i;
Brian Pauleda291e2008-08-06 16:26:47 -06001481 GLint slots = (program->Parameters->Parameters[index].Size + 3) / 4;
Brian Paulade50832008-05-14 16:09:46 -06001482
Brian Pauleda291e2008-08-06 16:26:47 -06001483 if (count * elems > (GLint) program->Parameters->Parameters[index].Size) {
Brian Paulade50832008-05-14 16:09:46 -06001484 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1485 return;
1486 }
1487
Brian Pauleda291e2008-08-06 16:26:47 -06001488 if (count > slots)
1489 count = slots;
1490
Brian Paulade50832008-05-14 16:09:46 -06001491 for (k = 0; k < count; k++) {
Brian Pauleda291e2008-08-06 16:26:47 -06001492 GLfloat *uniformVal = program->Parameters->ParameterValues[index + offset + k];
1493 if (is_integer_type(type)) {
Brian Paulade50832008-05-14 16:09:46 -06001494 const GLint *iValues = ((const GLint *) values) + k * elems;
1495 for (i = 0; i < elems; i++) {
1496 uniformVal[i] = (GLfloat) iValues[i];
1497 }
1498 }
1499 else {
1500 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1501 for (i = 0; i < elems; i++) {
1502 uniformVal[i] = fValues[i];
1503 }
1504 }
Brian Pauleda291e2008-08-06 16:26:47 -06001505
1506 /* if the uniform is bool-valued, convert to 1.0 or 0.0 */
1507 if (is_boolean_type(program->Parameters->Parameters[index].DataType)) {
1508 for (i = 0; i < elems; i++) {
1509 uniformVal[i] = uniformVal[i] ? 1.0 : 0.0;
1510 }
1511 }
Brian Paulade50832008-05-14 16:09:46 -06001512 }
1513 }
1514}
1515
1516
Brian5b01c5e2006-12-19 18:02:03 -07001517/**
1518 * Called via ctx->Driver.Uniform().
1519 */
Brian Paulfd59f192008-05-18 16:04:55 -06001520static void
Brian5b01c5e2006-12-19 18:02:03 -07001521_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1522 const GLvoid *values, GLenum type)
1523{
Brian3a8e2772006-12-20 17:19:16 -07001524 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Pauleda291e2008-08-06 16:26:47 -06001525 GLint elems, offset;
Brian3a8e2772006-12-20 17:19:16 -07001526
1527 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001528 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001529 return;
1530 }
1531
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001532 if (location == -1)
1533 return; /* The standard specifies this as a no-op */
1534
Brian Pauleda291e2008-08-06 16:26:47 -06001535 split_location_offset(&location, &offset);
1536
Brian Paulade50832008-05-14 16:09:46 -06001537 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
1538 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
Brian3a8e2772006-12-20 17:19:16 -07001539 return;
1540 }
1541
Brian52363952007-03-13 16:50:24 -06001542 if (count < 0) {
1543 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1544 return;
1545 }
1546
Brian98650bd2007-03-13 16:32:48 -06001547 switch (type) {
1548 case GL_FLOAT:
1549 case GL_INT:
1550 elems = 1;
1551 break;
1552 case GL_FLOAT_VEC2:
1553 case GL_INT_VEC2:
1554 elems = 2;
1555 break;
1556 case GL_FLOAT_VEC3:
1557 case GL_INT_VEC3:
1558 elems = 3;
1559 break;
1560 case GL_FLOAT_VEC4:
1561 case GL_INT_VEC4:
1562 elems = 4;
1563 break;
1564 default:
1565 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1566 return;
Brian89dc4852007-01-04 14:35:44 -07001567 }
Brian98650bd2007-03-13 16:32:48 -06001568
Brian Paulade50832008-05-14 16:09:46 -06001569 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
Brian98650bd2007-03-13 16:32:48 -06001570
Brian Paulade50832008-05-14 16:09:46 -06001571 /* A uniform var may be used by both a vertex shader and a fragment
1572 * shader. We may need to update one or both shader's uniform here:
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001573 */
Brian Paulade50832008-05-14 16:09:46 -06001574 if (shProg->VertexProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001575 /* convert uniform location to program parameter index */
1576 GLint index = shProg->Uniforms->Uniforms[location].VertPos;
1577 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001578 set_program_uniform(ctx, &shProg->VertexProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001579 index, offset, type, count, elems, values);
Bruce Merry2bf2a8c2007-12-21 23:18:40 +02001580 }
Brian5b01c5e2006-12-19 18:02:03 -07001581 }
Brian5cf73262007-01-05 16:02:45 -07001582
Brian Paulade50832008-05-14 16:09:46 -06001583 if (shProg->FragmentProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001584 /* convert uniform location to program parameter index */
1585 GLint index = shProg->Uniforms->Uniforms[location].FragPos;
1586 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001587 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001588 index, offset, type, count, elems, values);
Brian Paulade50832008-05-14 16:09:46 -06001589 }
1590 }
1591}
1592
1593
Brian Pauleda291e2008-08-06 16:26:47 -06001594/**
1595 * Set a matrix-valued program parameter.
1596 */
Brian Paulade50832008-05-14 16:09:46 -06001597static void
Brian Paulffbc66b2008-07-21 13:58:50 -06001598get_matrix_dims(GLenum type, GLint *rows, GLint *cols)
1599{
1600 switch (type) {
1601 case GL_FLOAT_MAT2:
1602 *rows = *cols = 2;
1603 break;
1604 case GL_FLOAT_MAT2x3:
1605 *rows = 3;
1606 *cols = 2;
1607 break;
1608 case GL_FLOAT_MAT2x4:
1609 *rows = 4;
1610 *cols = 2;
1611 break;
1612 case GL_FLOAT_MAT3:
1613 *rows = 3;
1614 *cols = 3;
1615 break;
1616 case GL_FLOAT_MAT3x2:
1617 *rows = 2;
1618 *cols = 3;
1619 break;
1620 case GL_FLOAT_MAT3x4:
1621 *rows = 4;
1622 *cols = 3;
1623 break;
1624 case GL_FLOAT_MAT4:
1625 *rows = 4;
1626 *cols = 4;
1627 break;
1628 case GL_FLOAT_MAT4x2:
1629 *rows = 2;
1630 *cols = 4;
1631 break;
1632 case GL_FLOAT_MAT4x3:
1633 *rows = 3;
1634 *cols = 4;
1635 break;
1636 default:
1637 *rows = *cols = 0;
1638 }
1639}
1640
1641
1642static void
Brian Paulade50832008-05-14 16:09:46 -06001643set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
Brian Pauleda291e2008-08-06 16:26:47 -06001644 GLuint index, GLuint offset,
1645 GLuint count, GLuint rows, GLuint cols,
Brian Paulade50832008-05-14 16:09:46 -06001646 GLboolean transpose, const GLfloat *values)
1647{
Brian Paulffbc66b2008-07-21 13:58:50 -06001648 GLuint mat, row, col;
Brian Pauleda291e2008-08-06 16:26:47 -06001649 GLuint dst = index + offset, src = 0;
Brian Paulffbc66b2008-07-21 13:58:50 -06001650 GLint nr, nc;
1651
1652 /* check that the number of rows, columns is correct */
Brian Pauleda291e2008-08-06 16:26:47 -06001653 get_matrix_dims(program->Parameters->Parameters[index].DataType, &nr, &nc);
Brian Paulffbc66b2008-07-21 13:58:50 -06001654 if (rows != nr || cols != nc) {
1655 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Pauleda291e2008-08-06 16:26:47 -06001656 "glUniformMatrix(matrix size mismatch)");
1657 return;
1658 }
1659
1660 if (index + offset > program->Parameters->Size) {
1661 /* out of bounds! */
Brian Paulffbc66b2008-07-21 13:58:50 -06001662 return;
1663 }
1664
Brian Paulade50832008-05-14 16:09:46 -06001665 /*
1666 * Note: the _columns_ of a matrix are stored in program registers, not
Brian Paulf45ed0e2008-07-18 12:51:39 -06001667 * the rows. So, the loops below look a little funny.
1668 * XXX could optimize this a bit...
Brian Paulade50832008-05-14 16:09:46 -06001669 */
Brian Paulf45ed0e2008-07-18 12:51:39 -06001670
1671 /* loop over matrices */
1672 for (mat = 0; mat < count; mat++) {
1673
1674 /* each matrix: */
Brian Paulade50832008-05-14 16:09:46 -06001675 for (col = 0; col < cols; col++) {
Brian Paulf45ed0e2008-07-18 12:51:39 -06001676 GLfloat *v = program->Parameters->ParameterValues[dst];
Brian Paulade50832008-05-14 16:09:46 -06001677 for (row = 0; row < rows; row++) {
Brian Paulf45ed0e2008-07-18 12:51:39 -06001678 if (transpose) {
1679 v[row] = values[src + row * cols + col];
1680 }
1681 else {
1682 v[row] = values[src + col * rows + row];
1683 }
Brian Paulade50832008-05-14 16:09:46 -06001684 }
Brian Paulf45ed0e2008-07-18 12:51:39 -06001685 dst++;
Brian Paulade50832008-05-14 16:09:46 -06001686 }
Brian Paulf45ed0e2008-07-18 12:51:39 -06001687
1688 src += rows * cols; /* next matrix */
Brian5cf73262007-01-05 16:02:45 -07001689 }
Brian34ae99d2006-12-18 08:28:54 -07001690}
1691
1692
1693/**
Brian5b01c5e2006-12-19 18:02:03 -07001694 * Called by ctx->Driver.UniformMatrix().
Brian Paulf45ed0e2008-07-18 12:51:39 -06001695 * Note: cols=2, rows=4 ==> array[2] of vec4
Brian34ae99d2006-12-18 08:28:54 -07001696 */
Brian Paulfd59f192008-05-18 16:04:55 -06001697static void
Brian5b01c5e2006-12-19 18:02:03 -07001698_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1699 GLenum matrixType, GLint location, GLsizei count,
1700 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001701{
Brian Pauleda291e2008-08-06 16:26:47 -06001702 GLint offset;
Brian3a8e2772006-12-20 17:19:16 -07001703 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paulade50832008-05-14 16:09:46 -06001704
Brian3a8e2772006-12-20 17:19:16 -07001705 if (!shProg || !shProg->LinkStatus) {
1706 _mesa_error(ctx, GL_INVALID_OPERATION,
1707 "glUniformMatrix(program not linked)");
1708 return;
1709 }
Brian Paulade50832008-05-14 16:09:46 -06001710
Bruce Merry89b80322007-12-21 15:20:17 +02001711 if (location == -1)
1712 return; /* The standard specifies this as a no-op */
Brian Paulade50832008-05-14 16:09:46 -06001713
Brian Pauleda291e2008-08-06 16:26:47 -06001714 split_location_offset(&location, &offset);
1715
Brian Paul016701f2008-07-29 17:43:35 -06001716 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian Paulade50832008-05-14 16:09:46 -06001717 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
Brian3a8e2772006-12-20 17:19:16 -07001718 return;
1719 }
Brian34ae99d2006-12-18 08:28:54 -07001720 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001721 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001722 return;
1723 }
1724
1725 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1726
Brian Paulade50832008-05-14 16:09:46 -06001727 if (shProg->VertexProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001728 /* convert uniform location to program parameter index */
1729 GLint index = shProg->Uniforms->Uniforms[location].VertPos;
1730 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001731 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001732 index, offset,
1733 count, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07001734 }
Brian Paulade50832008-05-14 16:09:46 -06001735 }
1736
1737 if (shProg->FragmentProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001738 /* convert uniform location to program parameter index */
1739 GLint index = shProg->Uniforms->Uniforms[location].FragPos;
1740 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001741 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001742 index, offset,
1743 count, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07001744 }
Brian34ae99d2006-12-18 08:28:54 -07001745 }
1746}
1747
1748
Brian Paulfd59f192008-05-18 16:04:55 -06001749static void
Brian5b01c5e2006-12-19 18:02:03 -07001750_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001751{
Brian65a18442006-12-19 18:46:56 -07001752 struct gl_shader_program *shProg;
Brian Paulbc985b52008-07-21 14:16:07 -06001753
1754 shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram");
Brian65a18442006-12-19 18:46:56 -07001755 if (!shProg) {
Brian34ae99d2006-12-18 08:28:54 -07001756 return;
1757 }
1758
Brian Paulbc985b52008-07-21 14:16:07 -06001759 if (!shProg->LinkStatus) {
1760 shProg->Validated = GL_FALSE;
1761 return;
1762 }
1763
1764 /* From the GL spec, a program is invalid if any of these are true:
1765
Brian5b01c5e2006-12-19 18:02:03 -07001766 any two active samplers in the current program object are of
1767 different types, but refer to the same texture image unit,
1768
1769 any active sampler in the current program object refers to a texture
1770 image unit where fixed-function fragment processing accesses a
1771 texture target that does not match the sampler type, or
1772
1773 the sum of the number of active samplers in the program and the
1774 number of texture image units enabled for fixed-function fragment
1775 processing exceeds the combined limit on the total number of texture
1776 image units allowed.
1777 */
Brian Paulbc985b52008-07-21 14:16:07 -06001778
1779 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001780}
Brian Paulfd59f192008-05-18 16:04:55 -06001781
1782
1783/**
1784 * Plug in Mesa's GLSL functions into the device driver function table.
1785 */
1786void
1787_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
1788{
1789 driver->AttachShader = _mesa_attach_shader;
1790 driver->BindAttribLocation = _mesa_bind_attrib_location;
1791 driver->CompileShader = _mesa_compile_shader;
1792 driver->CreateProgram = _mesa_create_program;
1793 driver->CreateShader = _mesa_create_shader;
1794 driver->DeleteProgram2 = _mesa_delete_program2;
1795 driver->DeleteShader = _mesa_delete_shader;
1796 driver->DetachShader = _mesa_detach_shader;
1797 driver->GetActiveAttrib = _mesa_get_active_attrib;
1798 driver->GetActiveUniform = _mesa_get_active_uniform;
1799 driver->GetAttachedShaders = _mesa_get_attached_shaders;
1800 driver->GetAttribLocation = _mesa_get_attrib_location;
1801 driver->GetHandle = _mesa_get_handle;
1802 driver->GetProgramiv = _mesa_get_programiv;
1803 driver->GetProgramInfoLog = _mesa_get_program_info_log;
1804 driver->GetShaderiv = _mesa_get_shaderiv;
1805 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
1806 driver->GetShaderSource = _mesa_get_shader_source;
1807 driver->GetUniformfv = _mesa_get_uniformfv;
Brian Paul2be54a82008-07-08 16:17:04 -06001808 driver->GetUniformiv = _mesa_get_uniformiv;
Brian Paulfd59f192008-05-18 16:04:55 -06001809 driver->GetUniformLocation = _mesa_get_uniform_location;
1810 driver->IsProgram = _mesa_is_program;
1811 driver->IsShader = _mesa_is_shader;
1812 driver->LinkProgram = _mesa_link_program;
1813 driver->ShaderSource = _mesa_shader_source;
1814 driver->Uniform = _mesa_uniform;
1815 driver->UniformMatrix = _mesa_uniform_matrix;
1816 driver->UseProgram = _mesa_use_program;
1817 driver->ValidateProgram = _mesa_validate_program;
1818}