blob: 3c530d17271b3964fc44370b752e054eca450c7f [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 Paul5b982362008-08-06 13:07:09 -06001076static void
1077get_matrix_dims(GLenum type, GLint *rows, GLint *cols)
1078{
1079 switch (type) {
1080 case GL_FLOAT_MAT2:
1081 *rows = *cols = 2;
1082 break;
1083 case GL_FLOAT_MAT2x3:
1084 *rows = 3;
1085 *cols = 2;
1086 break;
1087 case GL_FLOAT_MAT2x4:
1088 *rows = 4;
1089 *cols = 2;
1090 break;
1091 case GL_FLOAT_MAT3:
1092 *rows = 3;
1093 *cols = 3;
1094 break;
1095 case GL_FLOAT_MAT3x2:
1096 *rows = 2;
1097 *cols = 3;
1098 break;
1099 case GL_FLOAT_MAT3x4:
1100 *rows = 4;
1101 *cols = 3;
1102 break;
1103 case GL_FLOAT_MAT4:
1104 *rows = 4;
1105 *cols = 4;
1106 break;
1107 case GL_FLOAT_MAT4x2:
1108 *rows = 2;
1109 *cols = 4;
1110 break;
1111 case GL_FLOAT_MAT4x3:
1112 *rows = 3;
1113 *cols = 4;
1114 break;
1115 default:
1116 *rows = *cols = 0;
1117 }
1118}
1119
1120
1121/**
1122 * Determine the number of rows and columns occupied by a uniform
1123 * according to its datatype.
1124 */
1125static void
1126get_uniform_rows_cols(const struct gl_program_parameter *p,
1127 GLint *rows, GLint *cols)
1128{
1129 get_matrix_dims(p->DataType, rows, cols);
1130 if (*rows == 0 && *cols == 0) {
1131 /* not a matrix type, probably a float or vector */
1132 *rows = p->Size / 4 + 1;
1133 if (p->Size % 4 == 0)
1134 *cols = 4;
1135 else
1136 *cols = p->Size % 4;
1137 }
1138}
1139
1140
Brian Paul2be54a82008-07-08 16:17:04 -06001141#define MAX_UNIFORM_ELEMENTS 16
1142
Brian5b01c5e2006-12-19 18:02:03 -07001143/**
Brian Paul2be54a82008-07-08 16:17:04 -06001144 * Helper for GetUniformfv(), GetUniformiv()
1145 * Returns number of elements written to 'params' output.
Brian5b01c5e2006-12-19 18:02:03 -07001146 */
Brian Paul2be54a82008-07-08 16:17:04 -06001147static GLuint
1148get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1149 GLfloat *params)
Brian5b01c5e2006-12-19 18:02:03 -07001150{
Brian65a18442006-12-19 18:46:56 -07001151 struct gl_shader_program *shProg
Brian Paulbda6ad22008-08-06 12:45:14 -06001152 = _mesa_lookup_shader_program_err(ctx, program, "glGetUniform[if]v");
Brian65a18442006-12-19 18:46:56 -07001153 if (shProg) {
Brian Paul6cb12702008-06-28 16:48:31 -06001154 if (shProg->Uniforms &&
Brian Paul016701f2008-07-29 17:43:35 -06001155 location >= 0 && location < (GLint) shProg->Uniforms->NumUniforms) {
Brian Paul6cb12702008-06-28 16:48:31 -06001156 GLint progPos;
Brian Paulf2632212008-05-16 10:49:44 -06001157 const struct gl_program *prog = NULL;
Brian Paulade50832008-05-14 16:09:46 -06001158
1159 progPos = shProg->Uniforms->Uniforms[location].VertPos;
1160 if (progPos >= 0) {
1161 prog = &shProg->VertexProgram->Base;
Brian5b01c5e2006-12-19 18:02:03 -07001162 }
Brian Paulade50832008-05-14 16:09:46 -06001163 else {
1164 progPos = shProg->Uniforms->Uniforms[location].FragPos;
1165 if (progPos >= 0) {
1166 prog = &shProg->FragmentProgram->Base;
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001167 }
Brian Paulade50832008-05-14 16:09:46 -06001168 }
1169
Brian Paulf2632212008-05-16 10:49:44 -06001170 ASSERT(prog);
1171 if (prog) {
Brian Paul5b982362008-08-06 13:07:09 -06001172 const struct gl_program_parameter *p =
1173 &prog->Parameters->Parameters[progPos];
1174 GLint rows, cols, i, j, k;
Brian Paul2be54a82008-07-08 16:17:04 -06001175
Brian Paul5b982362008-08-06 13:07:09 -06001176 /* See uniformiv() below */
1177 assert(p->Size <= MAX_UNIFORM_ELEMENTS);
1178
1179 get_uniform_rows_cols(p, &rows, &cols);
1180
1181 k = 0;
1182 for (i = 0; i < rows; i++) {
1183 for (j = 0; j < cols; j++ ) {
1184 params[k++] = prog->Parameters->ParameterValues[progPos+i][j];
1185 }
Brian Paulf2632212008-05-16 10:49:44 -06001186 }
Brian Paul5b982362008-08-06 13:07:09 -06001187
1188 return p->Size;
Brian Paulade50832008-05-14 16:09:46 -06001189 }
Brian5b01c5e2006-12-19 18:02:03 -07001190 }
1191 else {
Brian Paul6cb12702008-06-28 16:48:31 -06001192 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
Brian5b01c5e2006-12-19 18:02:03 -07001193 }
1194 }
Brian Paul2be54a82008-07-08 16:17:04 -06001195 return 0;
1196}
1197
1198
1199/**
1200 * Called via ctx->Driver.GetUniformfv().
1201 */
1202static void
1203_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1204 GLfloat *params)
1205{
1206 (void) get_uniformfv(ctx, program, location, params);
1207}
1208
1209
1210/**
1211 * Called via ctx->Driver.GetUniformiv().
1212 */
1213static void
1214_mesa_get_uniformiv(GLcontext *ctx, GLuint program, GLint location,
1215 GLint *params)
1216{
1217 GLfloat fparams[MAX_UNIFORM_ELEMENTS];
1218 GLuint n = get_uniformfv(ctx, program, location, fparams);
1219 GLuint i;
1220 assert(n <= MAX_UNIFORM_ELEMENTS);
1221 for (i = 0; i < n; i++) {
1222 params[i] = (GLint) fparams[i];
1223 }
Brian5b01c5e2006-12-19 18:02:03 -07001224}
1225
1226
1227/**
Brian Pauleda291e2008-08-06 16:26:47 -06001228 * The value returned by GetUniformLocation actually encodes two things:
1229 * 1. the index into the prog->Uniforms[] array for the uniform
1230 * 2. an offset in the prog->ParameterValues[] array for specifying array
1231 * elements or structure fields.
1232 * This function merges those two values.
1233 */
1234static void
1235merge_location_offset(GLint *location, GLint offset)
1236{
1237 *location = *location | (offset << 16);
1238}
1239
1240
1241/**
1242 * Seperate the uniform location and parameter offset. See above.
1243 */
1244static void
1245split_location_offset(GLint *location, GLint *offset)
1246{
1247 *offset = (*location >> 16);
1248 *location = *location & 0xffff;
1249}
1250
1251
1252/**
Brian5b01c5e2006-12-19 18:02:03 -07001253 * Called via ctx->Driver.GetUniformLocation().
Brian Pauleda291e2008-08-06 16:26:47 -06001254 *
1255 * The return value will encode two values, the uniform location and an
1256 * offset (used for arrays, structs).
Brian5b01c5e2006-12-19 18:02:03 -07001257 */
Brian Paulfd59f192008-05-18 16:04:55 -06001258static GLint
Brian5b01c5e2006-12-19 18:02:03 -07001259_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
1260{
Brian Pauleda291e2008-08-06 16:26:47 -06001261 GLint offset = 0, location = -1;
1262
Brian Paul530df582008-07-03 16:21:11 -06001263 struct gl_shader_program *shProg =
1264 _mesa_lookup_shader_program_err(ctx, program, "glGetUniformLocation");
1265
Brian Paulade50832008-05-14 16:09:46 -06001266 if (!shProg)
1267 return -1;
Brian5b01c5e2006-12-19 18:02:03 -07001268
Brian Paule06565b2008-07-04 09:58:55 -06001269 if (shProg->LinkStatus == GL_FALSE) {
1270 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
1271 return -1;
1272 }
1273
Brian Paul530df582008-07-03 16:21:11 -06001274 /* XXX we should return -1 if the uniform was declared, but not
1275 * actually used.
1276 */
1277
Brian Pauleda291e2008-08-06 16:26:47 -06001278 /* XXX we need to be able to parse uniform names for structs and arrays
1279 * such as:
1280 * mymatrix[1]
1281 * mystruct.field1
1282 */
1283
1284 {
1285 /* handle 1-dimension arrays here... */
1286 char *c = strchr(name, '[');
1287 if (c) {
1288 /* truncate name at [ */
1289 const GLint len = c - name;
1290 GLchar *newName = _mesa_malloc(len + 1);
1291 if (!newName)
1292 return -1; /* out of mem */
1293 _mesa_memcpy(newName, name, len);
1294 newName[len] = 0;
1295
1296 location = _mesa_lookup_uniform(shProg->Uniforms, newName);
1297 if (location >= 0) {
1298 const GLint element = _mesa_atoi(c + 1);
1299 if (element > 0) {
1300 /* get type of the uniform array element */
1301 struct gl_program_parameter *p;
1302 p = get_uniform_parameter(shProg, location);
1303 if (p) {
1304 GLint rows, cols;
1305 get_matrix_dims(p->DataType, &rows, &cols);
1306 if (rows < 1)
1307 rows = 1;
1308 offset = element * rows;
1309 }
1310 }
1311 }
1312
1313 _mesa_free(newName);
1314 }
1315 }
1316
1317 if (location < 0) {
1318 location = _mesa_lookup_uniform(shProg->Uniforms, name);
1319 }
1320
1321 if (location >= 0) {
1322 merge_location_offset(&location, offset);
1323 }
1324
1325 return location;
Brian5b01c5e2006-12-19 18:02:03 -07001326}
1327
1328
Brian34ae99d2006-12-18 08:28:54 -07001329
Brian5b01c5e2006-12-19 18:02:03 -07001330/**
1331 * Called via ctx->Driver.ShaderSource()
1332 */
Brian Paulfd59f192008-05-18 16:04:55 -06001333static void
Brian5b01c5e2006-12-19 18:02:03 -07001334_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -07001335{
Brian Paul530df582008-07-03 16:21:11 -06001336 struct gl_shader *sh;
1337
1338 sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource");
1339 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001340 return;
Brian34ae99d2006-12-18 08:28:54 -07001341
Brian34ae99d2006-12-18 08:28:54 -07001342 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -07001343 if (sh->Source) {
1344 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -07001345 }
Brian65a18442006-12-19 18:46:56 -07001346 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -07001347 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -07001348}
1349
1350
Brian5b01c5e2006-12-19 18:02:03 -07001351/**
1352 * Called via ctx->Driver.CompileShader()
1353 */
Brian Paulfd59f192008-05-18 16:04:55 -06001354static void
Brian5b01c5e2006-12-19 18:02:03 -07001355_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -07001356{
Brian Paul530df582008-07-03 16:21:11 -06001357 struct gl_shader *sh;
Brian34ae99d2006-12-18 08:28:54 -07001358
Brian Paul530df582008-07-03 16:21:11 -06001359 sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader");
1360 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001361 return;
Brian34ae99d2006-12-18 08:28:54 -07001362
Brian43975832007-01-04 08:21:09 -07001363 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -07001364}
1365
1366
Brian5b01c5e2006-12-19 18:02:03 -07001367/**
1368 * Called via ctx->Driver.LinkProgram()
1369 */
Brian Paulfd59f192008-05-18 16:04:55 -06001370static void
Brian5b01c5e2006-12-19 18:02:03 -07001371_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001372{
Brian65a18442006-12-19 18:46:56 -07001373 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001374
Brian Paul530df582008-07-03 16:21:11 -06001375 shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
1376 if (!shProg)
Brian34ae99d2006-12-18 08:28:54 -07001377 return;
Brian34ae99d2006-12-18 08:28:54 -07001378
Briandf43fb62008-05-06 23:08:51 -06001379 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1380
Brianc1771912007-02-16 09:56:19 -07001381 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001382}
1383
1384
1385/**
Brian5b01c5e2006-12-19 18:02:03 -07001386 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001387 */
Brian5b01c5e2006-12-19 18:02:03 -07001388void
1389_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001390{
Brian3c008a02007-04-12 15:22:32 -06001391 struct gl_shader_program *shProg;
1392
Brian00d63aa2007-02-03 11:35:02 -07001393 if (ctx->Shader.CurrentProgram &&
1394 ctx->Shader.CurrentProgram->Name == program) {
1395 /* no-op */
1396 return;
1397 }
1398
1399 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1400
Brian5b01c5e2006-12-19 18:02:03 -07001401 if (program) {
Brian Paul530df582008-07-03 16:21:11 -06001402 shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
Brian65a18442006-12-19 18:46:56 -07001403 if (!shProg) {
Brian Paul530df582008-07-03 16:21:11 -06001404 return;
1405 }
1406 if (!shProg->LinkStatus) {
1407 _mesa_error(ctx, GL_INVALID_OPERATION, "glUseProgram");
Brian5b01c5e2006-12-19 18:02:03 -07001408 return;
1409 }
Brian5b01c5e2006-12-19 18:02:03 -07001410 }
1411 else {
Brian3c008a02007-04-12 15:22:32 -06001412 shProg = NULL;
1413 }
1414
1415 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001416}
Brian34ae99d2006-12-18 08:28:54 -07001417
Brian5b01c5e2006-12-19 18:02:03 -07001418
Brian Paulade50832008-05-14 16:09:46 -06001419
1420/**
1421 * Update the vertex and fragment program's TexturesUsed arrays.
1422 */
1423static void
1424update_textures_used(struct gl_program *prog)
1425{
1426 GLuint s;
1427
1428 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1429
1430 for (s = 0; s < MAX_SAMPLERS; s++) {
1431 if (prog->SamplersUsed & (1 << s)) {
1432 GLuint u = prog->SamplerUnits[s];
1433 GLuint t = prog->SamplerTargets[s];
1434 assert(u < MAX_TEXTURE_IMAGE_UNITS);
1435 prog->TexturesUsed[u] |= (1 << t);
1436 }
1437 }
1438}
1439
1440
Brianb36749d2008-07-21 20:42:05 -06001441static GLboolean
1442is_sampler_type(GLenum type)
1443{
1444 switch (type) {
1445 case GL_SAMPLER_1D:
1446 case GL_SAMPLER_2D:
1447 case GL_SAMPLER_3D:
1448 case GL_SAMPLER_CUBE:
1449 case GL_SAMPLER_1D_SHADOW:
1450 case GL_SAMPLER_2D_SHADOW:
1451 case GL_SAMPLER_2D_RECT_ARB:
1452 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
1453 case GL_SAMPLER_1D_ARRAY_EXT:
1454 case GL_SAMPLER_2D_ARRAY_EXT:
1455 return GL_TRUE;
1456 default:
1457 return GL_FALSE;
1458 }
1459}
1460
1461
Brian Paulade50832008-05-14 16:09:46 -06001462/**
Brian Paulffbc66b2008-07-21 13:58:50 -06001463 * Check if the type given by userType is allowed to set a uniform of the
1464 * target type. Generally, equivalence is required, but setting Boolean
1465 * uniforms can be done with glUniformiv or glUniformfv.
1466 */
1467static GLboolean
1468compatible_types(GLenum userType, GLenum targetType)
1469{
1470 if (userType == targetType)
1471 return GL_TRUE;
1472
1473 if (targetType == GL_BOOL && (userType == GL_FLOAT || userType == GL_INT))
1474 return GL_TRUE;
1475
1476 if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 ||
1477 userType == GL_INT_VEC2))
1478 return GL_TRUE;
1479
1480 if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 ||
1481 userType == GL_INT_VEC3))
1482 return GL_TRUE;
1483
1484 if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 ||
1485 userType == GL_INT_VEC4))
1486 return GL_TRUE;
1487
Brianb36749d2008-07-21 20:42:05 -06001488 if (is_sampler_type(targetType) && userType == GL_INT)
1489 return GL_TRUE;
1490
Brian Paulffbc66b2008-07-21 13:58:50 -06001491 return GL_FALSE;
1492}
1493
1494
1495/**
Brian Paulade50832008-05-14 16:09:46 -06001496 * Set the value of a program's uniform variable.
1497 * \param program the program whose uniform to update
Brian Pauleda291e2008-08-06 16:26:47 -06001498 * \param index the index of the program parameter for the uniform
1499 * \param offset additional parameter slot offset (for arrays)
Brian Paulade50832008-05-14 16:09:46 -06001500 * \param type the datatype of the uniform
1501 * \param count the number of uniforms to set
1502 * \param elems number of elements per uniform
1503 * \param values the new values
1504 */
1505static void
Brian Pauleda291e2008-08-06 16:26:47 -06001506set_program_uniform(GLcontext *ctx, struct gl_program *program,
1507 GLint index, GLint offset,
1508 GLenum type, GLsizei count, GLint elems,
1509 const void *values)
Brian Paulade50832008-05-14 16:09:46 -06001510{
Brian Pauleda291e2008-08-06 16:26:47 -06001511 assert(offset >= 0);
1512
Brian Paulffbc66b2008-07-21 13:58:50 -06001513 if (!compatible_types(type,
Brian Pauleda291e2008-08-06 16:26:47 -06001514 program->Parameters->Parameters[index].DataType)) {
Brian Paulffbc66b2008-07-21 13:58:50 -06001515 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
1516 return;
1517 }
1518
Brian Pauleda291e2008-08-06 16:26:47 -06001519 if (index + offset > program->Parameters->Size) {
1520 /* out of bounds! */
1521 return;
1522 }
1523
1524 if (program->Parameters->Parameters[index].Type == PROGRAM_SAMPLER) {
Brian Paulade50832008-05-14 16:09:46 -06001525 /* This controls which texture unit which is used by a sampler */
1526 GLuint texUnit, sampler;
1527
1528 /* data type for setting samplers must be int */
1529 if (type != GL_INT || count != 1) {
1530 _mesa_error(ctx, GL_INVALID_OPERATION,
1531 "glUniform(only glUniform1i can be used "
1532 "to set sampler uniforms)");
1533 return;
1534 }
1535
Brian Pauleda291e2008-08-06 16:26:47 -06001536 sampler = (GLuint) program->Parameters->ParameterValues[index][0];
Brian Paulade50832008-05-14 16:09:46 -06001537 texUnit = ((GLuint *) values)[0];
1538
1539 /* check that the sampler (tex unit index) is legal */
1540 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1541 _mesa_error(ctx, GL_INVALID_VALUE,
1542 "glUniform1(invalid sampler/tex unit index)");
1543 return;
1544 }
1545
1546 /* This maps a sampler to a texture unit: */
1547 program->SamplerUnits[sampler] = texUnit;
1548 update_textures_used(program);
1549
1550 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1551 }
1552 else {
1553 /* ordinary uniform variable */
Brian Paul530df582008-07-03 16:21:11 -06001554 GLsizei k, i;
Brian Pauleda291e2008-08-06 16:26:47 -06001555 GLint slots = (program->Parameters->Parameters[index].Size + 3) / 4;
Brian Paulade50832008-05-14 16:09:46 -06001556
Brian Pauleda291e2008-08-06 16:26:47 -06001557 if (count * elems > (GLint) program->Parameters->Parameters[index].Size) {
Brian Paulade50832008-05-14 16:09:46 -06001558 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1559 return;
1560 }
1561
Brian Pauleda291e2008-08-06 16:26:47 -06001562 if (count > slots)
1563 count = slots;
1564
Brian Paulade50832008-05-14 16:09:46 -06001565 for (k = 0; k < count; k++) {
Brian Pauleda291e2008-08-06 16:26:47 -06001566 GLfloat *uniformVal = program->Parameters->ParameterValues[index + offset + k];
1567 if (is_integer_type(type)) {
Brian Paulade50832008-05-14 16:09:46 -06001568 const GLint *iValues = ((const GLint *) values) + k * elems;
1569 for (i = 0; i < elems; i++) {
1570 uniformVal[i] = (GLfloat) iValues[i];
1571 }
1572 }
1573 else {
1574 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1575 for (i = 0; i < elems; i++) {
1576 uniformVal[i] = fValues[i];
1577 }
1578 }
Brian Pauleda291e2008-08-06 16:26:47 -06001579
1580 /* if the uniform is bool-valued, convert to 1.0 or 0.0 */
1581 if (is_boolean_type(program->Parameters->Parameters[index].DataType)) {
1582 for (i = 0; i < elems; i++) {
1583 uniformVal[i] = uniformVal[i] ? 1.0 : 0.0;
1584 }
1585 }
Brian Paulade50832008-05-14 16:09:46 -06001586 }
1587 }
1588}
1589
1590
Brian5b01c5e2006-12-19 18:02:03 -07001591/**
1592 * Called via ctx->Driver.Uniform().
1593 */
Brian Paulfd59f192008-05-18 16:04:55 -06001594static void
Brian5b01c5e2006-12-19 18:02:03 -07001595_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1596 const GLvoid *values, GLenum type)
1597{
Brian3a8e2772006-12-20 17:19:16 -07001598 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Pauleda291e2008-08-06 16:26:47 -06001599 GLint elems, offset;
Brian3a8e2772006-12-20 17:19:16 -07001600
1601 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001602 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001603 return;
1604 }
1605
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001606 if (location == -1)
1607 return; /* The standard specifies this as a no-op */
1608
Brian Pauleda291e2008-08-06 16:26:47 -06001609 split_location_offset(&location, &offset);
1610
Brian Paulade50832008-05-14 16:09:46 -06001611 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
1612 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
Brian3a8e2772006-12-20 17:19:16 -07001613 return;
1614 }
1615
Brian52363952007-03-13 16:50:24 -06001616 if (count < 0) {
1617 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1618 return;
1619 }
1620
Brian98650bd2007-03-13 16:32:48 -06001621 switch (type) {
1622 case GL_FLOAT:
1623 case GL_INT:
1624 elems = 1;
1625 break;
1626 case GL_FLOAT_VEC2:
1627 case GL_INT_VEC2:
1628 elems = 2;
1629 break;
1630 case GL_FLOAT_VEC3:
1631 case GL_INT_VEC3:
1632 elems = 3;
1633 break;
1634 case GL_FLOAT_VEC4:
1635 case GL_INT_VEC4:
1636 elems = 4;
1637 break;
1638 default:
1639 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1640 return;
Brian89dc4852007-01-04 14:35:44 -07001641 }
Brian98650bd2007-03-13 16:32:48 -06001642
Brian Paulade50832008-05-14 16:09:46 -06001643 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
Brian98650bd2007-03-13 16:32:48 -06001644
Brian Paulade50832008-05-14 16:09:46 -06001645 /* A uniform var may be used by both a vertex shader and a fragment
1646 * shader. We may need to update one or both shader's uniform here:
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001647 */
Brian Paulade50832008-05-14 16:09:46 -06001648 if (shProg->VertexProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001649 /* convert uniform location to program parameter index */
1650 GLint index = shProg->Uniforms->Uniforms[location].VertPos;
1651 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001652 set_program_uniform(ctx, &shProg->VertexProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001653 index, offset, type, count, elems, values);
Bruce Merry2bf2a8c2007-12-21 23:18:40 +02001654 }
Brian5b01c5e2006-12-19 18:02:03 -07001655 }
Brian5cf73262007-01-05 16:02:45 -07001656
Brian Paulade50832008-05-14 16:09:46 -06001657 if (shProg->FragmentProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001658 /* convert uniform location to program parameter index */
1659 GLint index = shProg->Uniforms->Uniforms[location].FragPos;
1660 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001661 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001662 index, offset, type, count, elems, values);
Brian Paulade50832008-05-14 16:09:46 -06001663 }
1664 }
1665}
1666
1667
Brian Pauleda291e2008-08-06 16:26:47 -06001668/**
1669 * Set a matrix-valued program parameter.
1670 */
Brian Paulade50832008-05-14 16:09:46 -06001671static void
1672set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
Brian Pauleda291e2008-08-06 16:26:47 -06001673 GLuint index, GLuint offset,
1674 GLuint count, GLuint rows, GLuint cols,
Brian Paulade50832008-05-14 16:09:46 -06001675 GLboolean transpose, const GLfloat *values)
1676{
Brian Paulffbc66b2008-07-21 13:58:50 -06001677 GLuint mat, row, col;
Brian Pauleda291e2008-08-06 16:26:47 -06001678 GLuint dst = index + offset, src = 0;
Brian Paulffbc66b2008-07-21 13:58:50 -06001679 GLint nr, nc;
1680
1681 /* check that the number of rows, columns is correct */
Brian Pauleda291e2008-08-06 16:26:47 -06001682 get_matrix_dims(program->Parameters->Parameters[index].DataType, &nr, &nc);
Brian Paulffbc66b2008-07-21 13:58:50 -06001683 if (rows != nr || cols != nc) {
1684 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Pauleda291e2008-08-06 16:26:47 -06001685 "glUniformMatrix(matrix size mismatch)");
1686 return;
1687 }
1688
1689 if (index + offset > program->Parameters->Size) {
1690 /* out of bounds! */
Brian Paulffbc66b2008-07-21 13:58:50 -06001691 return;
1692 }
1693
Brian Paulade50832008-05-14 16:09:46 -06001694 /*
1695 * Note: the _columns_ of a matrix are stored in program registers, not
Brian Paulf45ed0e2008-07-18 12:51:39 -06001696 * the rows. So, the loops below look a little funny.
1697 * XXX could optimize this a bit...
Brian Paulade50832008-05-14 16:09:46 -06001698 */
Brian Paulf45ed0e2008-07-18 12:51:39 -06001699
1700 /* loop over matrices */
1701 for (mat = 0; mat < count; mat++) {
1702
1703 /* each matrix: */
Brian Paulade50832008-05-14 16:09:46 -06001704 for (col = 0; col < cols; col++) {
Brian Paulf45ed0e2008-07-18 12:51:39 -06001705 GLfloat *v = program->Parameters->ParameterValues[dst];
Brian Paulade50832008-05-14 16:09:46 -06001706 for (row = 0; row < rows; row++) {
Brian Paulf45ed0e2008-07-18 12:51:39 -06001707 if (transpose) {
1708 v[row] = values[src + row * cols + col];
1709 }
1710 else {
1711 v[row] = values[src + col * rows + row];
1712 }
Brian Paulade50832008-05-14 16:09:46 -06001713 }
Brian Paulf45ed0e2008-07-18 12:51:39 -06001714 dst++;
Brian Paulade50832008-05-14 16:09:46 -06001715 }
Brian Paulf45ed0e2008-07-18 12:51:39 -06001716
1717 src += rows * cols; /* next matrix */
Brian5cf73262007-01-05 16:02:45 -07001718 }
Brian34ae99d2006-12-18 08:28:54 -07001719}
1720
1721
1722/**
Brian5b01c5e2006-12-19 18:02:03 -07001723 * Called by ctx->Driver.UniformMatrix().
Brian Paulf45ed0e2008-07-18 12:51:39 -06001724 * Note: cols=2, rows=4 ==> array[2] of vec4
Brian34ae99d2006-12-18 08:28:54 -07001725 */
Brian Paulfd59f192008-05-18 16:04:55 -06001726static void
Brian5b01c5e2006-12-19 18:02:03 -07001727_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1728 GLenum matrixType, GLint location, GLsizei count,
1729 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001730{
Brian Pauleda291e2008-08-06 16:26:47 -06001731 GLint offset;
Brian3a8e2772006-12-20 17:19:16 -07001732 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paulade50832008-05-14 16:09:46 -06001733
Brian3a8e2772006-12-20 17:19:16 -07001734 if (!shProg || !shProg->LinkStatus) {
1735 _mesa_error(ctx, GL_INVALID_OPERATION,
1736 "glUniformMatrix(program not linked)");
1737 return;
1738 }
Brian Paulade50832008-05-14 16:09:46 -06001739
Bruce Merry89b80322007-12-21 15:20:17 +02001740 if (location == -1)
1741 return; /* The standard specifies this as a no-op */
Brian Paulade50832008-05-14 16:09:46 -06001742
Brian Pauleda291e2008-08-06 16:26:47 -06001743 split_location_offset(&location, &offset);
1744
Brian Paul016701f2008-07-29 17:43:35 -06001745 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian Paulade50832008-05-14 16:09:46 -06001746 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
Brian3a8e2772006-12-20 17:19:16 -07001747 return;
1748 }
Brian34ae99d2006-12-18 08:28:54 -07001749 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001750 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001751 return;
1752 }
1753
1754 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1755
Brian Paulade50832008-05-14 16:09:46 -06001756 if (shProg->VertexProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001757 /* convert uniform location to program parameter index */
1758 GLint index = shProg->Uniforms->Uniforms[location].VertPos;
1759 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001760 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001761 index, offset,
1762 count, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07001763 }
Brian Paulade50832008-05-14 16:09:46 -06001764 }
1765
1766 if (shProg->FragmentProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001767 /* convert uniform location to program parameter index */
1768 GLint index = shProg->Uniforms->Uniforms[location].FragPos;
1769 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001770 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001771 index, offset,
1772 count, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07001773 }
Brian34ae99d2006-12-18 08:28:54 -07001774 }
1775}
1776
1777
Brian Paulfd59f192008-05-18 16:04:55 -06001778static void
Brian5b01c5e2006-12-19 18:02:03 -07001779_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001780{
Brian65a18442006-12-19 18:46:56 -07001781 struct gl_shader_program *shProg;
Brian Paulbc985b52008-07-21 14:16:07 -06001782
1783 shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram");
Brian65a18442006-12-19 18:46:56 -07001784 if (!shProg) {
Brian34ae99d2006-12-18 08:28:54 -07001785 return;
1786 }
1787
Brian Paulbc985b52008-07-21 14:16:07 -06001788 if (!shProg->LinkStatus) {
1789 shProg->Validated = GL_FALSE;
1790 return;
1791 }
1792
1793 /* From the GL spec, a program is invalid if any of these are true:
1794
Brian5b01c5e2006-12-19 18:02:03 -07001795 any two active samplers in the current program object are of
1796 different types, but refer to the same texture image unit,
1797
1798 any active sampler in the current program object refers to a texture
1799 image unit where fixed-function fragment processing accesses a
1800 texture target that does not match the sampler type, or
1801
1802 the sum of the number of active samplers in the program and the
1803 number of texture image units enabled for fixed-function fragment
1804 processing exceeds the combined limit on the total number of texture
1805 image units allowed.
1806 */
Brian Paulbc985b52008-07-21 14:16:07 -06001807
1808 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001809}
Brian Paulfd59f192008-05-18 16:04:55 -06001810
1811
1812/**
1813 * Plug in Mesa's GLSL functions into the device driver function table.
1814 */
1815void
1816_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
1817{
1818 driver->AttachShader = _mesa_attach_shader;
1819 driver->BindAttribLocation = _mesa_bind_attrib_location;
1820 driver->CompileShader = _mesa_compile_shader;
1821 driver->CreateProgram = _mesa_create_program;
1822 driver->CreateShader = _mesa_create_shader;
1823 driver->DeleteProgram2 = _mesa_delete_program2;
1824 driver->DeleteShader = _mesa_delete_shader;
1825 driver->DetachShader = _mesa_detach_shader;
1826 driver->GetActiveAttrib = _mesa_get_active_attrib;
1827 driver->GetActiveUniform = _mesa_get_active_uniform;
1828 driver->GetAttachedShaders = _mesa_get_attached_shaders;
1829 driver->GetAttribLocation = _mesa_get_attrib_location;
1830 driver->GetHandle = _mesa_get_handle;
1831 driver->GetProgramiv = _mesa_get_programiv;
1832 driver->GetProgramInfoLog = _mesa_get_program_info_log;
1833 driver->GetShaderiv = _mesa_get_shaderiv;
1834 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
1835 driver->GetShaderSource = _mesa_get_shader_source;
1836 driver->GetUniformfv = _mesa_get_uniformfv;
Brian Paul2be54a82008-07-08 16:17:04 -06001837 driver->GetUniformiv = _mesa_get_uniformiv;
Brian Paulfd59f192008-05-18 16:04:55 -06001838 driver->GetUniformLocation = _mesa_get_uniform_location;
1839 driver->IsProgram = _mesa_is_program;
1840 driver->IsShader = _mesa_is_shader;
1841 driver->LinkProgram = _mesa_link_program;
1842 driver->ShaderSource = _mesa_shader_source;
1843 driver->Uniform = _mesa_uniform;
1844 driver->UniformMatrix = _mesa_uniform_matrix;
1845 driver->UseProgram = _mesa_use_program;
1846 driver->ValidateProgram = _mesa_validate_program;
1847}