blob: 3ab590351a7b592f83148824aa79696dc4244692 [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) {
Ian Romanickd806d452008-09-29 12:18:06 -0700458 /* The shader is already attched to this program. The
459 * GL_ARB_shader_objects spec says:
460 *
461 * "The error INVALID_OPERATION is generated by AttachObjectARB
462 * if <obj> is already attached to <containerObj>."
463 */
464 _mesa_error(ctx, GL_INVALID_OPERATION, "glAttachShader");
Brian5b01c5e2006-12-19 18:02:03 -0700465 return;
Brian34ae99d2006-12-18 08:28:54 -0700466 }
467 }
Brian5b01c5e2006-12-19 18:02:03 -0700468
469 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700470 shProg->Shaders = (struct gl_shader **)
471 _mesa_realloc(shProg->Shaders,
472 n * sizeof(struct gl_shader *),
473 (n + 1) * sizeof(struct gl_shader *));
474 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700475 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
476 return;
477 }
478
479 /* append */
Brian3c008a02007-04-12 15:22:32 -0600480 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
481 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700482 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700483}
484
485
Brian Paulfd59f192008-05-18 16:04:55 -0600486static GLint
Brian Paul896c0cc2008-05-16 15:47:55 -0600487_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
488 const GLchar *name)
489{
490 struct gl_shader_program *shProg
Brian Paul530df582008-07-03 16:21:11 -0600491 = _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
Brian Paul896c0cc2008-05-16 15:47:55 -0600492
493 if (!shProg) {
Brian Paul896c0cc2008-05-16 15:47:55 -0600494 return -1;
495 }
496
497 if (!shProg->LinkStatus) {
498 _mesa_error(ctx, GL_INVALID_OPERATION,
499 "glGetAttribLocation(program not linked)");
500 return -1;
501 }
502
503 if (!name)
504 return -1;
505
Brian Paul27341a92008-09-16 16:28:36 -0600506 if (shProg->VertexProgram) {
507 const struct gl_program_parameter_list *attribs =
508 shProg->VertexProgram->Base.Attributes;
509 if (attribs) {
510 GLint i = _mesa_lookup_parameter_index(attribs, -1, name);
511 if (i >= 0) {
512 return attribs->Parameters[i].StateIndexes[0];
513 }
Brian Paul896c0cc2008-05-16 15:47:55 -0600514 }
515 }
516 return -1;
517}
518
519
Brian Paulfd59f192008-05-18 16:04:55 -0600520static void
Brian5b01c5e2006-12-19 18:02:03 -0700521_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
522 const GLchar *name)
523{
Brian Paul530df582008-07-03 16:21:11 -0600524 struct gl_shader_program *shProg;
Brianb7978af2007-01-09 19:17:17 -0700525 const GLint size = -1; /* unknown size */
Brian Paul6bc87492008-07-25 08:34:54 -0600526 GLint i, oldIndex;
Brian Paul6f1abb92008-07-29 17:27:22 -0600527 GLenum datatype = GL_FLOAT_VEC4;
Brian5b01c5e2006-12-19 18:02:03 -0700528
Brian Paul530df582008-07-03 16:21:11 -0600529 shProg = _mesa_lookup_shader_program_err(ctx, program,
530 "glBindAttribLocation");
Brian65a18442006-12-19 18:46:56 -0700531 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700532 return;
533 }
534
Brian9e4bae92006-12-20 09:27:42 -0700535 if (!name)
536 return;
537
538 if (strncmp(name, "gl_", 3) == 0) {
539 _mesa_error(ctx, GL_INVALID_OPERATION,
540 "glBindAttribLocation(illegal name)");
541 return;
542 }
543
Brian Paul7acb7c12008-07-03 13:49:48 -0600544 if (index >= ctx->Const.VertexProgram.MaxAttribs) {
545 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
546 return;
547 }
548
Brian Paul6bc87492008-07-25 08:34:54 -0600549 if (shProg->LinkStatus) {
550 /* get current index/location for the attribute */
551 oldIndex = _mesa_get_attrib_location(ctx, program, name);
552 }
553 else {
554 oldIndex = -1;
555 }
556
Brian3209c3e2007-01-09 17:49:24 -0700557 /* this will replace the current value if it's already in the list */
Brian Paulffbc66b2008-07-21 13:58:50 -0600558 i = _mesa_add_attribute(shProg->Attributes, name, size, datatype, index);
Brian3209c3e2007-01-09 17:49:24 -0700559 if (i < 0) {
560 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
Brian Paul6f1abb92008-07-29 17:27:22 -0600561 return;
Brian3209c3e2007-01-09 17:49:24 -0700562 }
563
Brian Paul27341a92008-09-16 16:28:36 -0600564 /*
565 * Note that this attribute binding won't go into effect until
566 * glLinkProgram is called again.
567 */
Brian34ae99d2006-12-18 08:28:54 -0700568}
569
570
Brian Paulfd59f192008-05-18 16:04:55 -0600571static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700572_mesa_create_shader(GLcontext *ctx, GLenum type)
573{
Brian65a18442006-12-19 18:46:56 -0700574 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700575 GLuint name;
576
577 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
578
579 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700580 case GL_FRAGMENT_SHADER:
581 case GL_VERTEX_SHADER:
582 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700583 break;
584 default:
585 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
586 return 0;
587 }
588
Brian65a18442006-12-19 18:46:56 -0700589 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700590
591 return name;
592}
593
594
Brian Paulfd59f192008-05-18 16:04:55 -0600595static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700596_mesa_create_program(GLcontext *ctx)
597{
598 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700599 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700600
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800601 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
Brian65a18442006-12-19 18:46:56 -0700602 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700603
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800604 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700605
Brian3c008a02007-04-12 15:22:32 -0600606 assert(shProg->RefCount == 1);
607
Brian5b01c5e2006-12-19 18:02:03 -0700608 return name;
609}
610
611
Brian3c008a02007-04-12 15:22:32 -0600612/**
613 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
614 * DeleteProgramARB.
615 */
Brian Paulfd59f192008-05-18 16:04:55 -0600616static void
Brian5b01c5e2006-12-19 18:02:03 -0700617_mesa_delete_program2(GLcontext *ctx, GLuint name)
618{
Brian3c008a02007-04-12 15:22:32 -0600619 /*
620 * NOTE: deleting shaders/programs works a bit differently than
621 * texture objects (and buffer objects, etc). Shader/program
622 * handles/IDs exist in the hash table until the object is really
623 * deleted (refcount==0). With texture objects, the handle/ID is
624 * removed from the hash table in glDeleteTextures() while the tex
625 * object itself might linger until its refcount goes to zero.
626 */
Brian65a18442006-12-19 18:46:56 -0700627 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700628
Brian Paul530df582008-07-03 16:21:11 -0600629 shProg = _mesa_lookup_shader_program_err(ctx, name, "glDeleteProgram");
630 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700631 return;
Brian5b01c5e2006-12-19 18:02:03 -0700632
Brian9e4bae92006-12-20 09:27:42 -0700633 shProg->DeletePending = GL_TRUE;
634
Brian3c008a02007-04-12 15:22:32 -0600635 /* effectively, decr shProg's refcount */
636 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700637}
638
639
Brian Paulfd59f192008-05-18 16:04:55 -0600640static void
Brian5b01c5e2006-12-19 18:02:03 -0700641_mesa_delete_shader(GLcontext *ctx, GLuint shader)
642{
Brian Paul530df582008-07-03 16:21:11 -0600643 struct gl_shader *sh;
644
645 sh = _mesa_lookup_shader_err(ctx, shader, "glDeleteShader");
646 if (!sh)
Brian9e4bae92006-12-20 09:27:42 -0700647 return;
Brian5b01c5e2006-12-19 18:02:03 -0700648
Brian9e4bae92006-12-20 09:27:42 -0700649 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600650
651 /* effectively, decr sh's refcount */
652 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700653}
654
655
Brian Paulfd59f192008-05-18 16:04:55 -0600656static void
Brian5b01c5e2006-12-19 18:02:03 -0700657_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
658{
Brian Paul530df582008-07-03 16:21:11 -0600659 struct gl_shader_program *shProg;
Brian237b9852007-08-07 21:48:31 +0100660 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700661 GLuint i, j;
662
Brian Paul530df582008-07-03 16:21:11 -0600663 shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader");
664 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700665 return;
Brian5b01c5e2006-12-19 18:02:03 -0700666
Brian237b9852007-08-07 21:48:31 +0100667 n = shProg->NumShaders;
668
Brian5b01c5e2006-12-19 18:02:03 -0700669 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700670 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700671 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600672 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700673
Brian Paul530df582008-07-03 16:21:11 -0600674 /* release */
Brian3c008a02007-04-12 15:22:32 -0600675 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700676
Brian5b01c5e2006-12-19 18:02:03 -0700677 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700678 newList = (struct gl_shader **)
679 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700680 if (!newList) {
681 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
682 return;
683 }
684 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700685 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700686 }
687 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700688 newList[j++] = shProg->Shaders[i];
689 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700690
Brian65a18442006-12-19 18:46:56 -0700691 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600692 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600693
694#ifdef DEBUG
695 /* sanity check */
696 {
697 for (j = 0; j < shProg->NumShaders; j++) {
698 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
699 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
700 assert(shProg->Shaders[j]->RefCount > 0);
701 }
702 }
703#endif
704
Brian5b01c5e2006-12-19 18:02:03 -0700705 return;
706 }
707 }
708
709 /* not found */
Brian Paul530df582008-07-03 16:21:11 -0600710 {
711 GLenum err;
712 if (_mesa_is_shader(ctx, shader))
713 err = GL_INVALID_OPERATION;
714 else if (_mesa_is_program(ctx, shader))
715 err = GL_INVALID_OPERATION;
716 else
717 err = GL_INVALID_VALUE;
718 _mesa_error(ctx, err, "glDetachProgram(shader)");
719 return;
720 }
Brian5b01c5e2006-12-19 18:02:03 -0700721}
722
723
Brian Paulffbc66b2008-07-21 13:58:50 -0600724static GLint
725sizeof_glsl_type(GLenum type)
726{
727 switch (type) {
728 case GL_FLOAT:
729 case GL_INT:
730 case GL_BOOL:
Brian Paul8c51e002008-08-11 15:09:47 -0600731 case GL_SAMPLER_1D:
732 case GL_SAMPLER_2D:
733 case GL_SAMPLER_3D:
734 case GL_SAMPLER_CUBE:
735 case GL_SAMPLER_1D_SHADOW:
736 case GL_SAMPLER_2D_SHADOW:
737 case GL_SAMPLER_2D_RECT_ARB:
738 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
739 case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
740 case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
741 case GL_SAMPLER_CUBE_SHADOW_EXT:
Brian Paulffbc66b2008-07-21 13:58:50 -0600742 return 1;
743 case GL_FLOAT_VEC2:
744 case GL_INT_VEC2:
745 case GL_BOOL_VEC2:
746 return 2;
747 case GL_FLOAT_VEC3:
748 case GL_INT_VEC3:
749 case GL_BOOL_VEC3:
750 return 3;
751 case GL_FLOAT_VEC4:
752 case GL_INT_VEC4:
753 case GL_BOOL_VEC4:
754 return 4;
755 case GL_FLOAT_MAT2:
756 case GL_FLOAT_MAT2x3:
757 case GL_FLOAT_MAT2x4:
758 return 8; /* two float[4] vectors */
759 case GL_FLOAT_MAT3:
760 case GL_FLOAT_MAT3x2:
761 case GL_FLOAT_MAT3x4:
762 return 12; /* three float[4] vectors */
763 case GL_FLOAT_MAT4:
764 case GL_FLOAT_MAT4x2:
765 case GL_FLOAT_MAT4x3:
766 return 16; /* four float[4] vectors */
767 default:
768 _mesa_problem(NULL, "Invalid type in sizeof_glsl_type()");
769 return 1;
770 }
771}
772
773
Brian Pauleda291e2008-08-06 16:26:47 -0600774static GLboolean
775is_boolean_type(GLenum type)
776{
777 switch (type) {
778 case GL_BOOL:
779 case GL_BOOL_VEC2:
780 case GL_BOOL_VEC3:
781 case GL_BOOL_VEC4:
782 return GL_TRUE;
783 default:
784 return GL_FALSE;
785 }
786}
787
788
789static GLboolean
790is_integer_type(GLenum type)
791{
792 switch (type) {
793 case GL_INT:
794 case GL_INT_VEC2:
795 case GL_INT_VEC3:
796 case GL_INT_VEC4:
797 return GL_TRUE;
798 default:
799 return GL_FALSE;
800 }
801}
802
803
Brian Paulfd59f192008-05-18 16:04:55 -0600804static void
Brian5b01c5e2006-12-19 18:02:03 -0700805_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
806 GLsizei maxLength, GLsizei *length, GLint *size,
807 GLenum *type, GLchar *nameOut)
808{
Brian Paul27341a92008-09-16 16:28:36 -0600809 const struct gl_program_parameter_list *attribs = NULL;
Brian Paul530df582008-07-03 16:21:11 -0600810 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700811
Brian Paul530df582008-07-03 16:21:11 -0600812 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
813 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700814 return;
Brian5b01c5e2006-12-19 18:02:03 -0700815
Brian Paul27341a92008-09-16 16:28:36 -0600816 if (shProg->VertexProgram)
817 attribs = shProg->VertexProgram->Base.Attributes;
818
819 if (!attribs || index >= attribs->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600820 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700821 return;
822 }
823
Brian Paul27341a92008-09-16 16:28:36 -0600824 copy_string(nameOut, maxLength, length, attribs->Parameters[index].Name);
825
Brian5b01c5e2006-12-19 18:02:03 -0700826 if (size)
Brian Paul27341a92008-09-16 16:28:36 -0600827 *size = attribs->Parameters[index].Size
828 / sizeof_glsl_type(attribs->Parameters[index].DataType);
829
Brian Paulade50832008-05-14 16:09:46 -0600830 if (type)
Brian Paul27341a92008-09-16 16:28:36 -0600831 *type = attribs->Parameters[index].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700832}
833
834
Brian Pauleda291e2008-08-06 16:26:47 -0600835static struct gl_program_parameter *
836get_uniform_parameter(const struct gl_shader_program *shProg, GLuint index)
837{
838 const struct gl_program *prog;
839 GLint progPos;
840
841 progPos = shProg->Uniforms->Uniforms[index].VertPos;
842 if (progPos >= 0) {
843 prog = &shProg->VertexProgram->Base;
844 }
845 else {
846 progPos = shProg->Uniforms->Uniforms[index].FragPos;
847 if (progPos >= 0) {
848 prog = &shProg->FragmentProgram->Base;
849 }
850 }
851
852 if (!prog || progPos < 0)
853 return NULL; /* should never happen */
854
855 return &prog->Parameters->Parameters[progPos];
856}
857
858
Brian5b01c5e2006-12-19 18:02:03 -0700859/**
860 * Called via ctx->Driver.GetActiveUniform().
861 */
Brian Paulfd59f192008-05-18 16:04:55 -0600862static void
Brian5b01c5e2006-12-19 18:02:03 -0700863_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
864 GLsizei maxLength, GLsizei *length, GLint *size,
865 GLenum *type, GLchar *nameOut)
866{
Brian Paul530df582008-07-03 16:21:11 -0600867 const struct gl_shader_program *shProg;
Brian Paulade50832008-05-14 16:09:46 -0600868 const struct gl_program *prog;
869 GLint progPos;
Brian5b01c5e2006-12-19 18:02:03 -0700870
Brian Paul530df582008-07-03 16:21:11 -0600871 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
872 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700873 return;
Brian5b01c5e2006-12-19 18:02:03 -0700874
Brian Paulade50832008-05-14 16:09:46 -0600875 if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
Brian5b01c5e2006-12-19 18:02:03 -0700876 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
877 return;
878 }
879
Brian Paulade50832008-05-14 16:09:46 -0600880 progPos = shProg->Uniforms->Uniforms[index].VertPos;
881 if (progPos >= 0) {
882 prog = &shProg->VertexProgram->Base;
883 }
884 else {
885 progPos = shProg->Uniforms->Uniforms[index].FragPos;
886 if (progPos >= 0) {
887 prog = &shProg->FragmentProgram->Base;
Brian274ac7a2007-04-18 16:05:53 -0600888 }
889 }
890
Brian Paulade50832008-05-14 16:09:46 -0600891 if (!prog || progPos < 0)
892 return; /* should never happen */
893
894 if (nameOut)
895 copy_string(nameOut, maxLength, length,
896 prog->Parameters->Parameters[progPos].Name);
897 if (size)
Brian Paulffbc66b2008-07-21 13:58:50 -0600898 *size = prog->Parameters->Parameters[progPos].Size
899 / sizeof_glsl_type(prog->Parameters->Parameters[progPos].DataType);
Brian Paulade50832008-05-14 16:09:46 -0600900 if (type)
901 *type = prog->Parameters->Parameters[progPos].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700902}
903
904
905/**
906 * Called via ctx->Driver.GetAttachedShaders().
907 */
Brian Paulfd59f192008-05-18 16:04:55 -0600908static void
Brian5b01c5e2006-12-19 18:02:03 -0700909_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
910 GLsizei *count, GLuint *obj)
911{
Brian Paul530df582008-07-03 16:21:11 -0600912 struct gl_shader_program *shProg =
913 _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders");
Brian65a18442006-12-19 18:46:56 -0700914 if (shProg) {
Brian Paul530df582008-07-03 16:21:11 -0600915 GLuint i;
916 for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) {
Brian65a18442006-12-19 18:46:56 -0700917 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700918 }
919 if (count)
920 *count = i;
921 }
Brian5b01c5e2006-12-19 18:02:03 -0700922}
923
924
Brian Paulfd59f192008-05-18 16:04:55 -0600925static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700926_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700927{
928#if 0
929 GET_CURRENT_CONTEXT(ctx);
930
931 switch (pname) {
932 case GL_PROGRAM_OBJECT_ARB:
933 {
Brian5b01c5e2006-12-19 18:02:03 -0700934 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700935
936 if (pro != NULL)
937 return (**pro)._container._generic.
938 GetName((struct gl2_generic_intf **) (pro));
939 }
940 break;
941 default:
942 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
943 }
944#endif
945 return 0;
946}
947
948
Brian Paulfd59f192008-05-18 16:04:55 -0600949static void
Brian5b01c5e2006-12-19 18:02:03 -0700950_mesa_get_programiv(GLcontext *ctx, GLuint program,
951 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700952{
Brian Paul27341a92008-09-16 16:28:36 -0600953 const struct gl_program_parameter_list *attribs;
Brian65a18442006-12-19 18:46:56 -0700954 struct gl_shader_program *shProg
955 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700956
Brian65a18442006-12-19 18:46:56 -0700957 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700958 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700959 return;
960 }
961
Brian Paul27341a92008-09-16 16:28:36 -0600962 if (shProg->VertexProgram)
963 attribs = shProg->VertexProgram->Base.Attributes;
964 else
965 attribs = NULL;
966
Brian5b01c5e2006-12-19 18:02:03 -0700967 switch (pname) {
968 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700969 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700970 break;
971 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700972 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700973 break;
Brian5b01c5e2006-12-19 18:02:03 -0700974 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700975 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700976 break;
977 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600978 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700979 break;
980 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700981 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700982 break;
983 case GL_ACTIVE_ATTRIBUTES:
Brian Paul27341a92008-09-16 16:28:36 -0600984 *params = attribs ? attribs->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700985 break;
986 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian Paul27341a92008-09-16 16:28:36 -0600987 *params = _mesa_longest_parameter_name(attribs, PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700988 break;
989 case GL_ACTIVE_UNIFORMS:
Brian Paulade50832008-05-14 16:09:46 -0600990 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700991 break;
992 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian Paulade50832008-05-14 16:09:46 -0600993 *params = _mesa_longest_uniform_name(shProg->Uniforms);
Brian274ac7a2007-04-18 16:05:53 -0600994 if (*params > 0)
995 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700996 break;
Brian Paulbda6ad22008-08-06 12:45:14 -0600997 case GL_PROGRAM_BINARY_LENGTH_OES:
998 *params = 0;
999 break;
Brian34ae99d2006-12-18 08:28:54 -07001000 default:
Brian5b01c5e2006-12-19 18:02:03 -07001001 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
1002 return;
Brian34ae99d2006-12-18 08:28:54 -07001003 }
Brian5b01c5e2006-12-19 18:02:03 -07001004}
Brian34ae99d2006-12-18 08:28:54 -07001005
Brian34ae99d2006-12-18 08:28:54 -07001006
Brian Paulfd59f192008-05-18 16:04:55 -06001007static void
Brian5b01c5e2006-12-19 18:02:03 -07001008_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
1009{
Brian Paul530df582008-07-03 16:21:11 -06001010 struct gl_shader *shader = _mesa_lookup_shader_err(ctx, name, "glGetShaderiv");
Brian5b01c5e2006-12-19 18:02:03 -07001011
1012 if (!shader) {
Brian5b01c5e2006-12-19 18:02:03 -07001013 return;
1014 }
Brian65a18442006-12-19 18:46:56 -07001015
Brian5b01c5e2006-12-19 18:02:03 -07001016 switch (pname) {
1017 case GL_SHADER_TYPE:
1018 *params = shader->Type;
1019 break;
1020 case GL_DELETE_STATUS:
1021 *params = shader->DeletePending;
1022 break;
1023 case GL_COMPILE_STATUS:
1024 *params = shader->CompileStatus;
1025 break;
1026 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001027 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001028 break;
1029 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001030 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001031 break;
1032 default:
1033 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
1034 return;
1035 }
1036}
1037
1038
Brian Paulfd59f192008-05-18 16:04:55 -06001039static void
Brian5b01c5e2006-12-19 18:02:03 -07001040_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
1041 GLsizei *length, GLchar *infoLog)
1042{
Brian65a18442006-12-19 18:46:56 -07001043 struct gl_shader_program *shProg
1044 = _mesa_lookup_shader_program(ctx, program);
1045 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -07001046 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
1047 return;
1048 }
Brian65a18442006-12-19 18:46:56 -07001049 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -07001050}
1051
1052
Brian Paulfd59f192008-05-18 16:04:55 -06001053static void
Brian5b01c5e2006-12-19 18:02:03 -07001054_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
1055 GLsizei *length, GLchar *infoLog)
1056{
Brian65a18442006-12-19 18:46:56 -07001057 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
1058 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001059 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
1060 return;
1061 }
Brian65a18442006-12-19 18:46:56 -07001062 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -07001063}
1064
1065
1066/**
1067 * Called via ctx->Driver.GetShaderSource().
1068 */
Brian Paulfd59f192008-05-18 16:04:55 -06001069static void
Brian5b01c5e2006-12-19 18:02:03 -07001070_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
1071 GLsizei *length, GLchar *sourceOut)
1072{
Brian Paul530df582008-07-03 16:21:11 -06001073 struct gl_shader *sh;
1074 sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource");
Brian65a18442006-12-19 18:46:56 -07001075 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001076 return;
1077 }
Brian65a18442006-12-19 18:46:56 -07001078 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -07001079}
1080
1081
Brian Paul5b982362008-08-06 13:07:09 -06001082static void
1083get_matrix_dims(GLenum type, GLint *rows, GLint *cols)
1084{
1085 switch (type) {
1086 case GL_FLOAT_MAT2:
1087 *rows = *cols = 2;
1088 break;
1089 case GL_FLOAT_MAT2x3:
1090 *rows = 3;
1091 *cols = 2;
1092 break;
1093 case GL_FLOAT_MAT2x4:
1094 *rows = 4;
1095 *cols = 2;
1096 break;
1097 case GL_FLOAT_MAT3:
1098 *rows = 3;
1099 *cols = 3;
1100 break;
1101 case GL_FLOAT_MAT3x2:
1102 *rows = 2;
1103 *cols = 3;
1104 break;
1105 case GL_FLOAT_MAT3x4:
1106 *rows = 4;
1107 *cols = 3;
1108 break;
1109 case GL_FLOAT_MAT4:
1110 *rows = 4;
1111 *cols = 4;
1112 break;
1113 case GL_FLOAT_MAT4x2:
1114 *rows = 2;
1115 *cols = 4;
1116 break;
1117 case GL_FLOAT_MAT4x3:
1118 *rows = 3;
1119 *cols = 4;
1120 break;
1121 default:
1122 *rows = *cols = 0;
1123 }
1124}
1125
1126
1127/**
1128 * Determine the number of rows and columns occupied by a uniform
1129 * according to its datatype.
1130 */
1131static void
1132get_uniform_rows_cols(const struct gl_program_parameter *p,
1133 GLint *rows, GLint *cols)
1134{
1135 get_matrix_dims(p->DataType, rows, cols);
1136 if (*rows == 0 && *cols == 0) {
1137 /* not a matrix type, probably a float or vector */
1138 *rows = p->Size / 4 + 1;
1139 if (p->Size % 4 == 0)
1140 *cols = 4;
1141 else
1142 *cols = p->Size % 4;
1143 }
1144}
1145
1146
Brian Paul2be54a82008-07-08 16:17:04 -06001147#define MAX_UNIFORM_ELEMENTS 16
1148
Brian5b01c5e2006-12-19 18:02:03 -07001149/**
Brian Paul2be54a82008-07-08 16:17:04 -06001150 * Helper for GetUniformfv(), GetUniformiv()
1151 * Returns number of elements written to 'params' output.
Brian5b01c5e2006-12-19 18:02:03 -07001152 */
Brian Paul2be54a82008-07-08 16:17:04 -06001153static GLuint
1154get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1155 GLfloat *params)
Brian5b01c5e2006-12-19 18:02:03 -07001156{
Brian65a18442006-12-19 18:46:56 -07001157 struct gl_shader_program *shProg
Brian Paulbda6ad22008-08-06 12:45:14 -06001158 = _mesa_lookup_shader_program_err(ctx, program, "glGetUniform[if]v");
Brian65a18442006-12-19 18:46:56 -07001159 if (shProg) {
Brian Paul6cb12702008-06-28 16:48:31 -06001160 if (shProg->Uniforms &&
Brian Paul016701f2008-07-29 17:43:35 -06001161 location >= 0 && location < (GLint) shProg->Uniforms->NumUniforms) {
Brian Paul6cb12702008-06-28 16:48:31 -06001162 GLint progPos;
Brian Paulf2632212008-05-16 10:49:44 -06001163 const struct gl_program *prog = NULL;
Brian Paulade50832008-05-14 16:09:46 -06001164
1165 progPos = shProg->Uniforms->Uniforms[location].VertPos;
1166 if (progPos >= 0) {
1167 prog = &shProg->VertexProgram->Base;
Brian5b01c5e2006-12-19 18:02:03 -07001168 }
Brian Paulade50832008-05-14 16:09:46 -06001169 else {
1170 progPos = shProg->Uniforms->Uniforms[location].FragPos;
1171 if (progPos >= 0) {
1172 prog = &shProg->FragmentProgram->Base;
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001173 }
Brian Paulade50832008-05-14 16:09:46 -06001174 }
1175
Brian Paulf2632212008-05-16 10:49:44 -06001176 ASSERT(prog);
1177 if (prog) {
Brian Paul5b982362008-08-06 13:07:09 -06001178 const struct gl_program_parameter *p =
1179 &prog->Parameters->Parameters[progPos];
1180 GLint rows, cols, i, j, k;
Brian Paul2be54a82008-07-08 16:17:04 -06001181
Brian Paul5b982362008-08-06 13:07:09 -06001182 /* See uniformiv() below */
1183 assert(p->Size <= MAX_UNIFORM_ELEMENTS);
1184
1185 get_uniform_rows_cols(p, &rows, &cols);
1186
1187 k = 0;
1188 for (i = 0; i < rows; i++) {
1189 for (j = 0; j < cols; j++ ) {
1190 params[k++] = prog->Parameters->ParameterValues[progPos+i][j];
1191 }
Brian Paulf2632212008-05-16 10:49:44 -06001192 }
Brian Paul5b982362008-08-06 13:07:09 -06001193
1194 return p->Size;
Brian Paulade50832008-05-14 16:09:46 -06001195 }
Brian5b01c5e2006-12-19 18:02:03 -07001196 }
1197 else {
Brian Paul6cb12702008-06-28 16:48:31 -06001198 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
Brian5b01c5e2006-12-19 18:02:03 -07001199 }
1200 }
Brian Paul2be54a82008-07-08 16:17:04 -06001201 return 0;
1202}
1203
1204
1205/**
1206 * Called via ctx->Driver.GetUniformfv().
1207 */
1208static void
1209_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1210 GLfloat *params)
1211{
1212 (void) get_uniformfv(ctx, program, location, params);
1213}
1214
1215
1216/**
1217 * Called via ctx->Driver.GetUniformiv().
1218 */
1219static void
1220_mesa_get_uniformiv(GLcontext *ctx, GLuint program, GLint location,
1221 GLint *params)
1222{
1223 GLfloat fparams[MAX_UNIFORM_ELEMENTS];
1224 GLuint n = get_uniformfv(ctx, program, location, fparams);
1225 GLuint i;
1226 assert(n <= MAX_UNIFORM_ELEMENTS);
1227 for (i = 0; i < n; i++) {
1228 params[i] = (GLint) fparams[i];
1229 }
Brian5b01c5e2006-12-19 18:02:03 -07001230}
1231
1232
1233/**
Brian Pauleda291e2008-08-06 16:26:47 -06001234 * The value returned by GetUniformLocation actually encodes two things:
1235 * 1. the index into the prog->Uniforms[] array for the uniform
1236 * 2. an offset in the prog->ParameterValues[] array for specifying array
1237 * elements or structure fields.
1238 * This function merges those two values.
1239 */
1240static void
1241merge_location_offset(GLint *location, GLint offset)
1242{
1243 *location = *location | (offset << 16);
1244}
1245
1246
1247/**
1248 * Seperate the uniform location and parameter offset. See above.
1249 */
1250static void
1251split_location_offset(GLint *location, GLint *offset)
1252{
1253 *offset = (*location >> 16);
1254 *location = *location & 0xffff;
1255}
1256
1257
1258/**
Brian5b01c5e2006-12-19 18:02:03 -07001259 * Called via ctx->Driver.GetUniformLocation().
Brian Pauleda291e2008-08-06 16:26:47 -06001260 *
1261 * The return value will encode two values, the uniform location and an
1262 * offset (used for arrays, structs).
Brian5b01c5e2006-12-19 18:02:03 -07001263 */
Brian Paulfd59f192008-05-18 16:04:55 -06001264static GLint
Brian5b01c5e2006-12-19 18:02:03 -07001265_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
1266{
Brian Pauleda291e2008-08-06 16:26:47 -06001267 GLint offset = 0, location = -1;
1268
Brian Paul530df582008-07-03 16:21:11 -06001269 struct gl_shader_program *shProg =
1270 _mesa_lookup_shader_program_err(ctx, program, "glGetUniformLocation");
1271
Brian Paulade50832008-05-14 16:09:46 -06001272 if (!shProg)
1273 return -1;
Brian5b01c5e2006-12-19 18:02:03 -07001274
Brian Paule06565b2008-07-04 09:58:55 -06001275 if (shProg->LinkStatus == GL_FALSE) {
1276 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
1277 return -1;
1278 }
1279
Brian Paul530df582008-07-03 16:21:11 -06001280 /* XXX we should return -1 if the uniform was declared, but not
1281 * actually used.
1282 */
1283
Brian Pauleda291e2008-08-06 16:26:47 -06001284 /* XXX we need to be able to parse uniform names for structs and arrays
1285 * such as:
1286 * mymatrix[1]
1287 * mystruct.field1
1288 */
1289
1290 {
1291 /* handle 1-dimension arrays here... */
1292 char *c = strchr(name, '[');
1293 if (c) {
1294 /* truncate name at [ */
1295 const GLint len = c - name;
1296 GLchar *newName = _mesa_malloc(len + 1);
1297 if (!newName)
1298 return -1; /* out of mem */
1299 _mesa_memcpy(newName, name, len);
1300 newName[len] = 0;
1301
1302 location = _mesa_lookup_uniform(shProg->Uniforms, newName);
1303 if (location >= 0) {
1304 const GLint element = _mesa_atoi(c + 1);
1305 if (element > 0) {
1306 /* get type of the uniform array element */
1307 struct gl_program_parameter *p;
1308 p = get_uniform_parameter(shProg, location);
1309 if (p) {
1310 GLint rows, cols;
1311 get_matrix_dims(p->DataType, &rows, &cols);
1312 if (rows < 1)
1313 rows = 1;
1314 offset = element * rows;
1315 }
1316 }
1317 }
1318
1319 _mesa_free(newName);
1320 }
1321 }
1322
1323 if (location < 0) {
1324 location = _mesa_lookup_uniform(shProg->Uniforms, name);
1325 }
1326
1327 if (location >= 0) {
1328 merge_location_offset(&location, offset);
1329 }
1330
1331 return location;
Brian5b01c5e2006-12-19 18:02:03 -07001332}
1333
1334
Brian34ae99d2006-12-18 08:28:54 -07001335
Brian5b01c5e2006-12-19 18:02:03 -07001336/**
1337 * Called via ctx->Driver.ShaderSource()
1338 */
Brian Paulfd59f192008-05-18 16:04:55 -06001339static void
Brian5b01c5e2006-12-19 18:02:03 -07001340_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -07001341{
Brian Paul530df582008-07-03 16:21:11 -06001342 struct gl_shader *sh;
1343
1344 sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource");
1345 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001346 return;
Brian34ae99d2006-12-18 08:28:54 -07001347
Brian34ae99d2006-12-18 08:28:54 -07001348 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -07001349 if (sh->Source) {
1350 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -07001351 }
Brian65a18442006-12-19 18:46:56 -07001352 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -07001353 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -07001354}
1355
1356
Brian5b01c5e2006-12-19 18:02:03 -07001357/**
1358 * Called via ctx->Driver.CompileShader()
1359 */
Brian Paulfd59f192008-05-18 16:04:55 -06001360static void
Brian5b01c5e2006-12-19 18:02:03 -07001361_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -07001362{
Brian Paul530df582008-07-03 16:21:11 -06001363 struct gl_shader *sh;
Brian34ae99d2006-12-18 08:28:54 -07001364
Brian Paul530df582008-07-03 16:21:11 -06001365 sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader");
1366 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001367 return;
Brian34ae99d2006-12-18 08:28:54 -07001368
Brian43975832007-01-04 08:21:09 -07001369 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -07001370}
1371
1372
Brian5b01c5e2006-12-19 18:02:03 -07001373/**
1374 * Called via ctx->Driver.LinkProgram()
1375 */
Brian Paulfd59f192008-05-18 16:04:55 -06001376static void
Brian5b01c5e2006-12-19 18:02:03 -07001377_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001378{
Brian65a18442006-12-19 18:46:56 -07001379 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001380
Brian Paul530df582008-07-03 16:21:11 -06001381 shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
1382 if (!shProg)
Brian34ae99d2006-12-18 08:28:54 -07001383 return;
Brian34ae99d2006-12-18 08:28:54 -07001384
Briandf43fb62008-05-06 23:08:51 -06001385 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1386
Brianc1771912007-02-16 09:56:19 -07001387 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001388}
1389
1390
1391/**
Brian5b01c5e2006-12-19 18:02:03 -07001392 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001393 */
Brian5b01c5e2006-12-19 18:02:03 -07001394void
1395_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001396{
Brian3c008a02007-04-12 15:22:32 -06001397 struct gl_shader_program *shProg;
1398
Brian00d63aa2007-02-03 11:35:02 -07001399 if (ctx->Shader.CurrentProgram &&
1400 ctx->Shader.CurrentProgram->Name == program) {
1401 /* no-op */
1402 return;
1403 }
1404
1405 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1406
Brian5b01c5e2006-12-19 18:02:03 -07001407 if (program) {
Brian Paul530df582008-07-03 16:21:11 -06001408 shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
Brian65a18442006-12-19 18:46:56 -07001409 if (!shProg) {
Brian Paul530df582008-07-03 16:21:11 -06001410 return;
1411 }
1412 if (!shProg->LinkStatus) {
1413 _mesa_error(ctx, GL_INVALID_OPERATION, "glUseProgram");
Brian5b01c5e2006-12-19 18:02:03 -07001414 return;
1415 }
Brian5b01c5e2006-12-19 18:02:03 -07001416 }
1417 else {
Brian3c008a02007-04-12 15:22:32 -06001418 shProg = NULL;
1419 }
1420
1421 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001422}
Brian34ae99d2006-12-18 08:28:54 -07001423
Brian5b01c5e2006-12-19 18:02:03 -07001424
Brian Paulade50832008-05-14 16:09:46 -06001425
1426/**
1427 * Update the vertex and fragment program's TexturesUsed arrays.
1428 */
1429static void
1430update_textures_used(struct gl_program *prog)
1431{
1432 GLuint s;
1433
1434 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1435
1436 for (s = 0; s < MAX_SAMPLERS; s++) {
1437 if (prog->SamplersUsed & (1 << s)) {
1438 GLuint u = prog->SamplerUnits[s];
1439 GLuint t = prog->SamplerTargets[s];
1440 assert(u < MAX_TEXTURE_IMAGE_UNITS);
1441 prog->TexturesUsed[u] |= (1 << t);
1442 }
1443 }
1444}
1445
1446
Brianb36749d2008-07-21 20:42:05 -06001447static GLboolean
1448is_sampler_type(GLenum type)
1449{
1450 switch (type) {
1451 case GL_SAMPLER_1D:
1452 case GL_SAMPLER_2D:
1453 case GL_SAMPLER_3D:
1454 case GL_SAMPLER_CUBE:
1455 case GL_SAMPLER_1D_SHADOW:
1456 case GL_SAMPLER_2D_SHADOW:
1457 case GL_SAMPLER_2D_RECT_ARB:
1458 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
1459 case GL_SAMPLER_1D_ARRAY_EXT:
1460 case GL_SAMPLER_2D_ARRAY_EXT:
1461 return GL_TRUE;
1462 default:
1463 return GL_FALSE;
1464 }
1465}
1466
1467
Brian Paulade50832008-05-14 16:09:46 -06001468/**
Brian Paulffbc66b2008-07-21 13:58:50 -06001469 * Check if the type given by userType is allowed to set a uniform of the
1470 * target type. Generally, equivalence is required, but setting Boolean
1471 * uniforms can be done with glUniformiv or glUniformfv.
1472 */
1473static GLboolean
1474compatible_types(GLenum userType, GLenum targetType)
1475{
1476 if (userType == targetType)
1477 return GL_TRUE;
1478
1479 if (targetType == GL_BOOL && (userType == GL_FLOAT || userType == GL_INT))
1480 return GL_TRUE;
1481
1482 if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 ||
1483 userType == GL_INT_VEC2))
1484 return GL_TRUE;
1485
1486 if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 ||
1487 userType == GL_INT_VEC3))
1488 return GL_TRUE;
1489
1490 if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 ||
1491 userType == GL_INT_VEC4))
1492 return GL_TRUE;
1493
Brianb36749d2008-07-21 20:42:05 -06001494 if (is_sampler_type(targetType) && userType == GL_INT)
1495 return GL_TRUE;
1496
Brian Paulffbc66b2008-07-21 13:58:50 -06001497 return GL_FALSE;
1498}
1499
1500
1501/**
Brian Paulade50832008-05-14 16:09:46 -06001502 * Set the value of a program's uniform variable.
1503 * \param program the program whose uniform to update
Brian Pauleda291e2008-08-06 16:26:47 -06001504 * \param index the index of the program parameter for the uniform
1505 * \param offset additional parameter slot offset (for arrays)
Brian Paulade50832008-05-14 16:09:46 -06001506 * \param type the datatype of the uniform
1507 * \param count the number of uniforms to set
1508 * \param elems number of elements per uniform
1509 * \param values the new values
1510 */
1511static void
Brian Pauleda291e2008-08-06 16:26:47 -06001512set_program_uniform(GLcontext *ctx, struct gl_program *program,
1513 GLint index, GLint offset,
1514 GLenum type, GLsizei count, GLint elems,
1515 const void *values)
Brian Paulade50832008-05-14 16:09:46 -06001516{
Brian Pauleda291e2008-08-06 16:26:47 -06001517 assert(offset >= 0);
1518
Brian Paulffbc66b2008-07-21 13:58:50 -06001519 if (!compatible_types(type,
Brian Pauleda291e2008-08-06 16:26:47 -06001520 program->Parameters->Parameters[index].DataType)) {
Brian Paulffbc66b2008-07-21 13:58:50 -06001521 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
1522 return;
1523 }
1524
Brian Pauleda291e2008-08-06 16:26:47 -06001525 if (index + offset > program->Parameters->Size) {
1526 /* out of bounds! */
1527 return;
1528 }
1529
1530 if (program->Parameters->Parameters[index].Type == PROGRAM_SAMPLER) {
Brian Paulade50832008-05-14 16:09:46 -06001531 /* This controls which texture unit which is used by a sampler */
1532 GLuint texUnit, sampler;
1533
1534 /* data type for setting samplers must be int */
1535 if (type != GL_INT || count != 1) {
1536 _mesa_error(ctx, GL_INVALID_OPERATION,
1537 "glUniform(only glUniform1i can be used "
1538 "to set sampler uniforms)");
1539 return;
1540 }
1541
Brian Pauleda291e2008-08-06 16:26:47 -06001542 sampler = (GLuint) program->Parameters->ParameterValues[index][0];
Brian Paulade50832008-05-14 16:09:46 -06001543 texUnit = ((GLuint *) values)[0];
1544
1545 /* check that the sampler (tex unit index) is legal */
1546 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1547 _mesa_error(ctx, GL_INVALID_VALUE,
1548 "glUniform1(invalid sampler/tex unit index)");
1549 return;
1550 }
1551
1552 /* This maps a sampler to a texture unit: */
1553 program->SamplerUnits[sampler] = texUnit;
1554 update_textures_used(program);
1555
1556 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1557 }
1558 else {
1559 /* ordinary uniform variable */
Brian Paul530df582008-07-03 16:21:11 -06001560 GLsizei k, i;
Brian Pauleda291e2008-08-06 16:26:47 -06001561 GLint slots = (program->Parameters->Parameters[index].Size + 3) / 4;
Brian Paulade50832008-05-14 16:09:46 -06001562
Brian Pauleda291e2008-08-06 16:26:47 -06001563 if (count * elems > (GLint) program->Parameters->Parameters[index].Size) {
Brian Paulade50832008-05-14 16:09:46 -06001564 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1565 return;
1566 }
1567
Brian Pauleda291e2008-08-06 16:26:47 -06001568 if (count > slots)
1569 count = slots;
1570
Brian Paulade50832008-05-14 16:09:46 -06001571 for (k = 0; k < count; k++) {
Brian Pauleda291e2008-08-06 16:26:47 -06001572 GLfloat *uniformVal = program->Parameters->ParameterValues[index + offset + k];
1573 if (is_integer_type(type)) {
Brian Paulade50832008-05-14 16:09:46 -06001574 const GLint *iValues = ((const GLint *) values) + k * elems;
1575 for (i = 0; i < elems; i++) {
1576 uniformVal[i] = (GLfloat) iValues[i];
1577 }
1578 }
1579 else {
1580 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1581 for (i = 0; i < elems; i++) {
1582 uniformVal[i] = fValues[i];
1583 }
1584 }
Brian Pauleda291e2008-08-06 16:26:47 -06001585
1586 /* if the uniform is bool-valued, convert to 1.0 or 0.0 */
1587 if (is_boolean_type(program->Parameters->Parameters[index].DataType)) {
1588 for (i = 0; i < elems; i++) {
1589 uniformVal[i] = uniformVal[i] ? 1.0 : 0.0;
1590 }
1591 }
Brian Paulade50832008-05-14 16:09:46 -06001592 }
1593 }
1594}
1595
1596
Brian5b01c5e2006-12-19 18:02:03 -07001597/**
1598 * Called via ctx->Driver.Uniform().
1599 */
Brian Paulfd59f192008-05-18 16:04:55 -06001600static void
Brian5b01c5e2006-12-19 18:02:03 -07001601_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1602 const GLvoid *values, GLenum type)
1603{
Brian3a8e2772006-12-20 17:19:16 -07001604 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Pauleda291e2008-08-06 16:26:47 -06001605 GLint elems, offset;
Brian3a8e2772006-12-20 17:19:16 -07001606
1607 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001608 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001609 return;
1610 }
1611
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001612 if (location == -1)
1613 return; /* The standard specifies this as a no-op */
1614
Brian Pauleda291e2008-08-06 16:26:47 -06001615 split_location_offset(&location, &offset);
1616
Brian Paulade50832008-05-14 16:09:46 -06001617 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
1618 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
Brian3a8e2772006-12-20 17:19:16 -07001619 return;
1620 }
1621
Brian52363952007-03-13 16:50:24 -06001622 if (count < 0) {
1623 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1624 return;
1625 }
1626
Brian98650bd2007-03-13 16:32:48 -06001627 switch (type) {
1628 case GL_FLOAT:
1629 case GL_INT:
1630 elems = 1;
1631 break;
1632 case GL_FLOAT_VEC2:
1633 case GL_INT_VEC2:
1634 elems = 2;
1635 break;
1636 case GL_FLOAT_VEC3:
1637 case GL_INT_VEC3:
1638 elems = 3;
1639 break;
1640 case GL_FLOAT_VEC4:
1641 case GL_INT_VEC4:
1642 elems = 4;
1643 break;
1644 default:
1645 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1646 return;
Brian89dc4852007-01-04 14:35:44 -07001647 }
Brian98650bd2007-03-13 16:32:48 -06001648
Brian Paulade50832008-05-14 16:09:46 -06001649 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
Brian98650bd2007-03-13 16:32:48 -06001650
Brian Paulade50832008-05-14 16:09:46 -06001651 /* A uniform var may be used by both a vertex shader and a fragment
1652 * shader. We may need to update one or both shader's uniform here:
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001653 */
Brian Paulade50832008-05-14 16:09:46 -06001654 if (shProg->VertexProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001655 /* convert uniform location to program parameter index */
1656 GLint index = shProg->Uniforms->Uniforms[location].VertPos;
1657 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001658 set_program_uniform(ctx, &shProg->VertexProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001659 index, offset, type, count, elems, values);
Bruce Merry2bf2a8c2007-12-21 23:18:40 +02001660 }
Brian5b01c5e2006-12-19 18:02:03 -07001661 }
Brian5cf73262007-01-05 16:02:45 -07001662
Brian Paulade50832008-05-14 16:09:46 -06001663 if (shProg->FragmentProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001664 /* convert uniform location to program parameter index */
1665 GLint index = shProg->Uniforms->Uniforms[location].FragPos;
1666 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001667 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001668 index, offset, type, count, elems, values);
Brian Paulade50832008-05-14 16:09:46 -06001669 }
1670 }
1671}
1672
1673
Brian Pauleda291e2008-08-06 16:26:47 -06001674/**
1675 * Set a matrix-valued program parameter.
1676 */
Brian Paulade50832008-05-14 16:09:46 -06001677static void
1678set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
Brian Pauleda291e2008-08-06 16:26:47 -06001679 GLuint index, GLuint offset,
1680 GLuint count, GLuint rows, GLuint cols,
Brian Paulade50832008-05-14 16:09:46 -06001681 GLboolean transpose, const GLfloat *values)
1682{
Brian Paulffbc66b2008-07-21 13:58:50 -06001683 GLuint mat, row, col;
Brian Pauleda291e2008-08-06 16:26:47 -06001684 GLuint dst = index + offset, src = 0;
Brian Paulffbc66b2008-07-21 13:58:50 -06001685 GLint nr, nc;
1686
1687 /* check that the number of rows, columns is correct */
Brian Pauleda291e2008-08-06 16:26:47 -06001688 get_matrix_dims(program->Parameters->Parameters[index].DataType, &nr, &nc);
Brian Paulffbc66b2008-07-21 13:58:50 -06001689 if (rows != nr || cols != nc) {
1690 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Pauleda291e2008-08-06 16:26:47 -06001691 "glUniformMatrix(matrix size mismatch)");
1692 return;
1693 }
1694
1695 if (index + offset > program->Parameters->Size) {
1696 /* out of bounds! */
Brian Paulffbc66b2008-07-21 13:58:50 -06001697 return;
1698 }
1699
Brian Paulade50832008-05-14 16:09:46 -06001700 /*
1701 * Note: the _columns_ of a matrix are stored in program registers, not
Brian Paulf45ed0e2008-07-18 12:51:39 -06001702 * the rows. So, the loops below look a little funny.
1703 * XXX could optimize this a bit...
Brian Paulade50832008-05-14 16:09:46 -06001704 */
Brian Paulf45ed0e2008-07-18 12:51:39 -06001705
1706 /* loop over matrices */
1707 for (mat = 0; mat < count; mat++) {
1708
1709 /* each matrix: */
Brian Paulade50832008-05-14 16:09:46 -06001710 for (col = 0; col < cols; col++) {
Brian Paulf45ed0e2008-07-18 12:51:39 -06001711 GLfloat *v = program->Parameters->ParameterValues[dst];
Brian Paulade50832008-05-14 16:09:46 -06001712 for (row = 0; row < rows; row++) {
Brian Paulf45ed0e2008-07-18 12:51:39 -06001713 if (transpose) {
1714 v[row] = values[src + row * cols + col];
1715 }
1716 else {
1717 v[row] = values[src + col * rows + row];
1718 }
Brian Paulade50832008-05-14 16:09:46 -06001719 }
Brian Paulf45ed0e2008-07-18 12:51:39 -06001720 dst++;
Brian Paulade50832008-05-14 16:09:46 -06001721 }
Brian Paulf45ed0e2008-07-18 12:51:39 -06001722
1723 src += rows * cols; /* next matrix */
Brian5cf73262007-01-05 16:02:45 -07001724 }
Brian34ae99d2006-12-18 08:28:54 -07001725}
1726
1727
1728/**
Brian5b01c5e2006-12-19 18:02:03 -07001729 * Called by ctx->Driver.UniformMatrix().
Brian Paulf45ed0e2008-07-18 12:51:39 -06001730 * Note: cols=2, rows=4 ==> array[2] of vec4
Brian34ae99d2006-12-18 08:28:54 -07001731 */
Brian Paulfd59f192008-05-18 16:04:55 -06001732static void
Brian5b01c5e2006-12-19 18:02:03 -07001733_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1734 GLenum matrixType, GLint location, GLsizei count,
1735 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001736{
Brian Pauleda291e2008-08-06 16:26:47 -06001737 GLint offset;
Brian3a8e2772006-12-20 17:19:16 -07001738 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paulade50832008-05-14 16:09:46 -06001739
Brian3a8e2772006-12-20 17:19:16 -07001740 if (!shProg || !shProg->LinkStatus) {
1741 _mesa_error(ctx, GL_INVALID_OPERATION,
1742 "glUniformMatrix(program not linked)");
1743 return;
1744 }
Brian Paulade50832008-05-14 16:09:46 -06001745
Bruce Merry89b80322007-12-21 15:20:17 +02001746 if (location == -1)
1747 return; /* The standard specifies this as a no-op */
Brian Paulade50832008-05-14 16:09:46 -06001748
Brian Pauleda291e2008-08-06 16:26:47 -06001749 split_location_offset(&location, &offset);
1750
Brian Paul016701f2008-07-29 17:43:35 -06001751 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian Paulade50832008-05-14 16:09:46 -06001752 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
Brian3a8e2772006-12-20 17:19:16 -07001753 return;
1754 }
Brian34ae99d2006-12-18 08:28:54 -07001755 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001756 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001757 return;
1758 }
1759
1760 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1761
Brian Paulade50832008-05-14 16:09:46 -06001762 if (shProg->VertexProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001763 /* convert uniform location to program parameter index */
1764 GLint index = shProg->Uniforms->Uniforms[location].VertPos;
1765 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001766 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001767 index, offset,
1768 count, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07001769 }
Brian Paulade50832008-05-14 16:09:46 -06001770 }
1771
1772 if (shProg->FragmentProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001773 /* convert uniform location to program parameter index */
1774 GLint index = shProg->Uniforms->Uniforms[location].FragPos;
1775 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001776 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001777 index, offset,
1778 count, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07001779 }
Brian34ae99d2006-12-18 08:28:54 -07001780 }
1781}
1782
1783
Brian Paulfd59f192008-05-18 16:04:55 -06001784static void
Brian5b01c5e2006-12-19 18:02:03 -07001785_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001786{
Brian65a18442006-12-19 18:46:56 -07001787 struct gl_shader_program *shProg;
Brian Paulbc985b52008-07-21 14:16:07 -06001788
1789 shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram");
Brian65a18442006-12-19 18:46:56 -07001790 if (!shProg) {
Brian34ae99d2006-12-18 08:28:54 -07001791 return;
1792 }
1793
Brian Paulbc985b52008-07-21 14:16:07 -06001794 if (!shProg->LinkStatus) {
1795 shProg->Validated = GL_FALSE;
1796 return;
1797 }
1798
1799 /* From the GL spec, a program is invalid if any of these are true:
1800
Brian5b01c5e2006-12-19 18:02:03 -07001801 any two active samplers in the current program object are of
1802 different types, but refer to the same texture image unit,
1803
1804 any active sampler in the current program object refers to a texture
1805 image unit where fixed-function fragment processing accesses a
1806 texture target that does not match the sampler type, or
1807
1808 the sum of the number of active samplers in the program and the
1809 number of texture image units enabled for fixed-function fragment
1810 processing exceeds the combined limit on the total number of texture
1811 image units allowed.
1812 */
Brian Paulbc985b52008-07-21 14:16:07 -06001813
1814 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001815}
Brian Paulfd59f192008-05-18 16:04:55 -06001816
1817
1818/**
1819 * Plug in Mesa's GLSL functions into the device driver function table.
1820 */
1821void
1822_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
1823{
1824 driver->AttachShader = _mesa_attach_shader;
1825 driver->BindAttribLocation = _mesa_bind_attrib_location;
1826 driver->CompileShader = _mesa_compile_shader;
1827 driver->CreateProgram = _mesa_create_program;
1828 driver->CreateShader = _mesa_create_shader;
1829 driver->DeleteProgram2 = _mesa_delete_program2;
1830 driver->DeleteShader = _mesa_delete_shader;
1831 driver->DetachShader = _mesa_detach_shader;
1832 driver->GetActiveAttrib = _mesa_get_active_attrib;
1833 driver->GetActiveUniform = _mesa_get_active_uniform;
1834 driver->GetAttachedShaders = _mesa_get_attached_shaders;
1835 driver->GetAttribLocation = _mesa_get_attrib_location;
1836 driver->GetHandle = _mesa_get_handle;
1837 driver->GetProgramiv = _mesa_get_programiv;
1838 driver->GetProgramInfoLog = _mesa_get_program_info_log;
1839 driver->GetShaderiv = _mesa_get_shaderiv;
1840 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
1841 driver->GetShaderSource = _mesa_get_shader_source;
1842 driver->GetUniformfv = _mesa_get_uniformfv;
Brian Paul2be54a82008-07-08 16:17:04 -06001843 driver->GetUniformiv = _mesa_get_uniformiv;
Brian Paulfd59f192008-05-18 16:04:55 -06001844 driver->GetUniformLocation = _mesa_get_uniform_location;
1845 driver->IsProgram = _mesa_is_program;
1846 driver->IsShader = _mesa_is_shader;
1847 driver->LinkProgram = _mesa_link_program;
1848 driver->ShaderSource = _mesa_shader_source;
1849 driver->Uniform = _mesa_uniform;
1850 driver->UniformMatrix = _mesa_uniform_matrix;
1851 driver->UseProgram = _mesa_use_program;
1852 driver->ValidateProgram = _mesa_validate_program;
1853}