blob: e883f8b8be1ffe43d66b439d1dfa83f7d73b3076 [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"
Ian Romanick905d8e02008-09-29 12:27:00 -070050#include "glapi/dispatch.h"
Brian34ae99d2006-12-18 08:28:54 -070051
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{
Ian Romanick905d8e02008-09-29 12:27:00 -0700928 GLint handle = 0;
929
930 if (pname == GL_PROGRAM_OBJECT_ARB) {
931 CALL_GetIntegerv(ctx->Exec, (GL_CURRENT_PROGRAM, &handle));
932 } else {
Brian34ae99d2006-12-18 08:28:54 -0700933 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
934 }
Ian Romanick905d8e02008-09-29 12:27:00 -0700935
936 return handle;
Brian34ae99d2006-12-18 08:28:54 -0700937}
938
939
Brian Paulfd59f192008-05-18 16:04:55 -0600940static void
Brian5b01c5e2006-12-19 18:02:03 -0700941_mesa_get_programiv(GLcontext *ctx, GLuint program,
942 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700943{
Brian Paul27341a92008-09-16 16:28:36 -0600944 const struct gl_program_parameter_list *attribs;
Brian65a18442006-12-19 18:46:56 -0700945 struct gl_shader_program *shProg
946 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700947
Brian65a18442006-12-19 18:46:56 -0700948 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700949 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700950 return;
951 }
952
Brian Paul27341a92008-09-16 16:28:36 -0600953 if (shProg->VertexProgram)
954 attribs = shProg->VertexProgram->Base.Attributes;
955 else
956 attribs = NULL;
957
Brian5b01c5e2006-12-19 18:02:03 -0700958 switch (pname) {
959 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700960 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700961 break;
962 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700963 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700964 break;
Brian5b01c5e2006-12-19 18:02:03 -0700965 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700966 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700967 break;
968 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600969 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700970 break;
971 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700972 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700973 break;
974 case GL_ACTIVE_ATTRIBUTES:
Brian Paul27341a92008-09-16 16:28:36 -0600975 *params = attribs ? attribs->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700976 break;
977 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian Paul27341a92008-09-16 16:28:36 -0600978 *params = _mesa_longest_parameter_name(attribs, PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700979 break;
980 case GL_ACTIVE_UNIFORMS:
Brian Paulade50832008-05-14 16:09:46 -0600981 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700982 break;
983 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian Paulade50832008-05-14 16:09:46 -0600984 *params = _mesa_longest_uniform_name(shProg->Uniforms);
Brian274ac7a2007-04-18 16:05:53 -0600985 if (*params > 0)
986 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700987 break;
Brian Paulbda6ad22008-08-06 12:45:14 -0600988 case GL_PROGRAM_BINARY_LENGTH_OES:
989 *params = 0;
990 break;
Brian34ae99d2006-12-18 08:28:54 -0700991 default:
Brian5b01c5e2006-12-19 18:02:03 -0700992 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
993 return;
Brian34ae99d2006-12-18 08:28:54 -0700994 }
Brian5b01c5e2006-12-19 18:02:03 -0700995}
Brian34ae99d2006-12-18 08:28:54 -0700996
Brian34ae99d2006-12-18 08:28:54 -0700997
Brian Paulfd59f192008-05-18 16:04:55 -0600998static void
Brian5b01c5e2006-12-19 18:02:03 -0700999_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
1000{
Brian Paul530df582008-07-03 16:21:11 -06001001 struct gl_shader *shader = _mesa_lookup_shader_err(ctx, name, "glGetShaderiv");
Brian5b01c5e2006-12-19 18:02:03 -07001002
1003 if (!shader) {
Brian5b01c5e2006-12-19 18:02:03 -07001004 return;
1005 }
Brian65a18442006-12-19 18:46:56 -07001006
Brian5b01c5e2006-12-19 18:02:03 -07001007 switch (pname) {
1008 case GL_SHADER_TYPE:
1009 *params = shader->Type;
1010 break;
1011 case GL_DELETE_STATUS:
1012 *params = shader->DeletePending;
1013 break;
1014 case GL_COMPILE_STATUS:
1015 *params = shader->CompileStatus;
1016 break;
1017 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001018 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001019 break;
1020 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001021 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001022 break;
1023 default:
1024 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
1025 return;
1026 }
1027}
1028
1029
Brian Paulfd59f192008-05-18 16:04:55 -06001030static void
Brian5b01c5e2006-12-19 18:02:03 -07001031_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
1032 GLsizei *length, GLchar *infoLog)
1033{
Brian65a18442006-12-19 18:46:56 -07001034 struct gl_shader_program *shProg
1035 = _mesa_lookup_shader_program(ctx, program);
1036 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -07001037 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
1038 return;
1039 }
Brian65a18442006-12-19 18:46:56 -07001040 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -07001041}
1042
1043
Brian Paulfd59f192008-05-18 16:04:55 -06001044static void
Brian5b01c5e2006-12-19 18:02:03 -07001045_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
1046 GLsizei *length, GLchar *infoLog)
1047{
Brian65a18442006-12-19 18:46:56 -07001048 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
1049 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001050 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
1051 return;
1052 }
Brian65a18442006-12-19 18:46:56 -07001053 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -07001054}
1055
1056
1057/**
1058 * Called via ctx->Driver.GetShaderSource().
1059 */
Brian Paulfd59f192008-05-18 16:04:55 -06001060static void
Brian5b01c5e2006-12-19 18:02:03 -07001061_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
1062 GLsizei *length, GLchar *sourceOut)
1063{
Brian Paul530df582008-07-03 16:21:11 -06001064 struct gl_shader *sh;
1065 sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource");
Brian65a18442006-12-19 18:46:56 -07001066 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001067 return;
1068 }
Brian65a18442006-12-19 18:46:56 -07001069 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -07001070}
1071
1072
Brian Paul5b982362008-08-06 13:07:09 -06001073static void
1074get_matrix_dims(GLenum type, GLint *rows, GLint *cols)
1075{
1076 switch (type) {
1077 case GL_FLOAT_MAT2:
1078 *rows = *cols = 2;
1079 break;
1080 case GL_FLOAT_MAT2x3:
1081 *rows = 3;
1082 *cols = 2;
1083 break;
1084 case GL_FLOAT_MAT2x4:
1085 *rows = 4;
1086 *cols = 2;
1087 break;
1088 case GL_FLOAT_MAT3:
1089 *rows = 3;
1090 *cols = 3;
1091 break;
1092 case GL_FLOAT_MAT3x2:
1093 *rows = 2;
1094 *cols = 3;
1095 break;
1096 case GL_FLOAT_MAT3x4:
1097 *rows = 4;
1098 *cols = 3;
1099 break;
1100 case GL_FLOAT_MAT4:
1101 *rows = 4;
1102 *cols = 4;
1103 break;
1104 case GL_FLOAT_MAT4x2:
1105 *rows = 2;
1106 *cols = 4;
1107 break;
1108 case GL_FLOAT_MAT4x3:
1109 *rows = 3;
1110 *cols = 4;
1111 break;
1112 default:
1113 *rows = *cols = 0;
1114 }
1115}
1116
1117
1118/**
1119 * Determine the number of rows and columns occupied by a uniform
1120 * according to its datatype.
1121 */
1122static void
1123get_uniform_rows_cols(const struct gl_program_parameter *p,
1124 GLint *rows, GLint *cols)
1125{
1126 get_matrix_dims(p->DataType, rows, cols);
1127 if (*rows == 0 && *cols == 0) {
1128 /* not a matrix type, probably a float or vector */
1129 *rows = p->Size / 4 + 1;
1130 if (p->Size % 4 == 0)
1131 *cols = 4;
1132 else
1133 *cols = p->Size % 4;
1134 }
1135}
1136
1137
Brian Paul2be54a82008-07-08 16:17:04 -06001138#define MAX_UNIFORM_ELEMENTS 16
1139
Brian5b01c5e2006-12-19 18:02:03 -07001140/**
Brian Paul2be54a82008-07-08 16:17:04 -06001141 * Helper for GetUniformfv(), GetUniformiv()
1142 * Returns number of elements written to 'params' output.
Brian5b01c5e2006-12-19 18:02:03 -07001143 */
Brian Paul2be54a82008-07-08 16:17:04 -06001144static GLuint
1145get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1146 GLfloat *params)
Brian5b01c5e2006-12-19 18:02:03 -07001147{
Brian65a18442006-12-19 18:46:56 -07001148 struct gl_shader_program *shProg
Brian Paulbda6ad22008-08-06 12:45:14 -06001149 = _mesa_lookup_shader_program_err(ctx, program, "glGetUniform[if]v");
Brian65a18442006-12-19 18:46:56 -07001150 if (shProg) {
Brian Paul6cb12702008-06-28 16:48:31 -06001151 if (shProg->Uniforms &&
Brian Paul016701f2008-07-29 17:43:35 -06001152 location >= 0 && location < (GLint) shProg->Uniforms->NumUniforms) {
Brian Paul6cb12702008-06-28 16:48:31 -06001153 GLint progPos;
Brian Paulf2632212008-05-16 10:49:44 -06001154 const struct gl_program *prog = NULL;
Brian Paulade50832008-05-14 16:09:46 -06001155
1156 progPos = shProg->Uniforms->Uniforms[location].VertPos;
1157 if (progPos >= 0) {
1158 prog = &shProg->VertexProgram->Base;
Brian5b01c5e2006-12-19 18:02:03 -07001159 }
Brian Paulade50832008-05-14 16:09:46 -06001160 else {
1161 progPos = shProg->Uniforms->Uniforms[location].FragPos;
1162 if (progPos >= 0) {
1163 prog = &shProg->FragmentProgram->Base;
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001164 }
Brian Paulade50832008-05-14 16:09:46 -06001165 }
1166
Brian Paulf2632212008-05-16 10:49:44 -06001167 ASSERT(prog);
1168 if (prog) {
Brian Paul5b982362008-08-06 13:07:09 -06001169 const struct gl_program_parameter *p =
1170 &prog->Parameters->Parameters[progPos];
1171 GLint rows, cols, i, j, k;
Brian Paul2be54a82008-07-08 16:17:04 -06001172
Brian Paul5b982362008-08-06 13:07:09 -06001173 /* See uniformiv() below */
1174 assert(p->Size <= MAX_UNIFORM_ELEMENTS);
1175
1176 get_uniform_rows_cols(p, &rows, &cols);
1177
1178 k = 0;
1179 for (i = 0; i < rows; i++) {
1180 for (j = 0; j < cols; j++ ) {
1181 params[k++] = prog->Parameters->ParameterValues[progPos+i][j];
1182 }
Brian Paulf2632212008-05-16 10:49:44 -06001183 }
Brian Paul5b982362008-08-06 13:07:09 -06001184
1185 return p->Size;
Brian Paulade50832008-05-14 16:09:46 -06001186 }
Brian5b01c5e2006-12-19 18:02:03 -07001187 }
1188 else {
Brian Paul6cb12702008-06-28 16:48:31 -06001189 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
Brian5b01c5e2006-12-19 18:02:03 -07001190 }
1191 }
Brian Paul2be54a82008-07-08 16:17:04 -06001192 return 0;
1193}
1194
1195
1196/**
1197 * Called via ctx->Driver.GetUniformfv().
1198 */
1199static void
1200_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1201 GLfloat *params)
1202{
1203 (void) get_uniformfv(ctx, program, location, params);
1204}
1205
1206
1207/**
1208 * Called via ctx->Driver.GetUniformiv().
1209 */
1210static void
1211_mesa_get_uniformiv(GLcontext *ctx, GLuint program, GLint location,
1212 GLint *params)
1213{
1214 GLfloat fparams[MAX_UNIFORM_ELEMENTS];
1215 GLuint n = get_uniformfv(ctx, program, location, fparams);
1216 GLuint i;
1217 assert(n <= MAX_UNIFORM_ELEMENTS);
1218 for (i = 0; i < n; i++) {
1219 params[i] = (GLint) fparams[i];
1220 }
Brian5b01c5e2006-12-19 18:02:03 -07001221}
1222
1223
1224/**
Brian Pauleda291e2008-08-06 16:26:47 -06001225 * The value returned by GetUniformLocation actually encodes two things:
1226 * 1. the index into the prog->Uniforms[] array for the uniform
1227 * 2. an offset in the prog->ParameterValues[] array for specifying array
1228 * elements or structure fields.
1229 * This function merges those two values.
1230 */
1231static void
1232merge_location_offset(GLint *location, GLint offset)
1233{
1234 *location = *location | (offset << 16);
1235}
1236
1237
1238/**
1239 * Seperate the uniform location and parameter offset. See above.
1240 */
1241static void
1242split_location_offset(GLint *location, GLint *offset)
1243{
1244 *offset = (*location >> 16);
1245 *location = *location & 0xffff;
1246}
1247
1248
1249/**
Brian5b01c5e2006-12-19 18:02:03 -07001250 * Called via ctx->Driver.GetUniformLocation().
Brian Pauleda291e2008-08-06 16:26:47 -06001251 *
1252 * The return value will encode two values, the uniform location and an
1253 * offset (used for arrays, structs).
Brian5b01c5e2006-12-19 18:02:03 -07001254 */
Brian Paulfd59f192008-05-18 16:04:55 -06001255static GLint
Brian5b01c5e2006-12-19 18:02:03 -07001256_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
1257{
Brian Pauleda291e2008-08-06 16:26:47 -06001258 GLint offset = 0, location = -1;
1259
Brian Paul530df582008-07-03 16:21:11 -06001260 struct gl_shader_program *shProg =
1261 _mesa_lookup_shader_program_err(ctx, program, "glGetUniformLocation");
1262
Brian Paulade50832008-05-14 16:09:46 -06001263 if (!shProg)
1264 return -1;
Brian5b01c5e2006-12-19 18:02:03 -07001265
Brian Paule06565b2008-07-04 09:58:55 -06001266 if (shProg->LinkStatus == GL_FALSE) {
1267 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
1268 return -1;
1269 }
1270
Brian Paul530df582008-07-03 16:21:11 -06001271 /* XXX we should return -1 if the uniform was declared, but not
1272 * actually used.
1273 */
1274
Brian Pauleda291e2008-08-06 16:26:47 -06001275 /* XXX we need to be able to parse uniform names for structs and arrays
1276 * such as:
1277 * mymatrix[1]
1278 * mystruct.field1
1279 */
1280
1281 {
1282 /* handle 1-dimension arrays here... */
1283 char *c = strchr(name, '[');
1284 if (c) {
1285 /* truncate name at [ */
1286 const GLint len = c - name;
1287 GLchar *newName = _mesa_malloc(len + 1);
1288 if (!newName)
1289 return -1; /* out of mem */
1290 _mesa_memcpy(newName, name, len);
1291 newName[len] = 0;
1292
1293 location = _mesa_lookup_uniform(shProg->Uniforms, newName);
1294 if (location >= 0) {
1295 const GLint element = _mesa_atoi(c + 1);
1296 if (element > 0) {
1297 /* get type of the uniform array element */
1298 struct gl_program_parameter *p;
1299 p = get_uniform_parameter(shProg, location);
1300 if (p) {
1301 GLint rows, cols;
1302 get_matrix_dims(p->DataType, &rows, &cols);
1303 if (rows < 1)
1304 rows = 1;
1305 offset = element * rows;
1306 }
1307 }
1308 }
1309
1310 _mesa_free(newName);
1311 }
1312 }
1313
1314 if (location < 0) {
1315 location = _mesa_lookup_uniform(shProg->Uniforms, name);
1316 }
1317
1318 if (location >= 0) {
1319 merge_location_offset(&location, offset);
1320 }
1321
1322 return location;
Brian5b01c5e2006-12-19 18:02:03 -07001323}
1324
1325
Brian34ae99d2006-12-18 08:28:54 -07001326
Brian5b01c5e2006-12-19 18:02:03 -07001327/**
1328 * Called via ctx->Driver.ShaderSource()
1329 */
Brian Paulfd59f192008-05-18 16:04:55 -06001330static void
Brian5b01c5e2006-12-19 18:02:03 -07001331_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -07001332{
Brian Paul530df582008-07-03 16:21:11 -06001333 struct gl_shader *sh;
1334
1335 sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource");
1336 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001337 return;
Brian34ae99d2006-12-18 08:28:54 -07001338
Brian34ae99d2006-12-18 08:28:54 -07001339 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -07001340 if (sh->Source) {
1341 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -07001342 }
Brian65a18442006-12-19 18:46:56 -07001343 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -07001344 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -07001345}
1346
1347
Brian5b01c5e2006-12-19 18:02:03 -07001348/**
1349 * Called via ctx->Driver.CompileShader()
1350 */
Brian Paulfd59f192008-05-18 16:04:55 -06001351static void
Brian5b01c5e2006-12-19 18:02:03 -07001352_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -07001353{
Brian Paul530df582008-07-03 16:21:11 -06001354 struct gl_shader *sh;
Brian34ae99d2006-12-18 08:28:54 -07001355
Brian Paul530df582008-07-03 16:21:11 -06001356 sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader");
1357 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001358 return;
Brian34ae99d2006-12-18 08:28:54 -07001359
Brian43975832007-01-04 08:21:09 -07001360 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -07001361}
1362
1363
Brian5b01c5e2006-12-19 18:02:03 -07001364/**
1365 * Called via ctx->Driver.LinkProgram()
1366 */
Brian Paulfd59f192008-05-18 16:04:55 -06001367static void
Brian5b01c5e2006-12-19 18:02:03 -07001368_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001369{
Brian65a18442006-12-19 18:46:56 -07001370 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001371
Brian Paul530df582008-07-03 16:21:11 -06001372 shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
1373 if (!shProg)
Brian34ae99d2006-12-18 08:28:54 -07001374 return;
Brian34ae99d2006-12-18 08:28:54 -07001375
Briandf43fb62008-05-06 23:08:51 -06001376 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1377
Brianc1771912007-02-16 09:56:19 -07001378 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001379}
1380
1381
1382/**
Brian5b01c5e2006-12-19 18:02:03 -07001383 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001384 */
Brian5b01c5e2006-12-19 18:02:03 -07001385void
1386_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001387{
Brian3c008a02007-04-12 15:22:32 -06001388 struct gl_shader_program *shProg;
1389
Brian00d63aa2007-02-03 11:35:02 -07001390 if (ctx->Shader.CurrentProgram &&
1391 ctx->Shader.CurrentProgram->Name == program) {
1392 /* no-op */
1393 return;
1394 }
1395
1396 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1397
Brian5b01c5e2006-12-19 18:02:03 -07001398 if (program) {
Brian Paul530df582008-07-03 16:21:11 -06001399 shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
Brian65a18442006-12-19 18:46:56 -07001400 if (!shProg) {
Brian Paul530df582008-07-03 16:21:11 -06001401 return;
1402 }
1403 if (!shProg->LinkStatus) {
1404 _mesa_error(ctx, GL_INVALID_OPERATION, "glUseProgram");
Brian5b01c5e2006-12-19 18:02:03 -07001405 return;
1406 }
Brian5b01c5e2006-12-19 18:02:03 -07001407 }
1408 else {
Brian3c008a02007-04-12 15:22:32 -06001409 shProg = NULL;
1410 }
1411
1412 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001413}
Brian34ae99d2006-12-18 08:28:54 -07001414
Brian5b01c5e2006-12-19 18:02:03 -07001415
Brian Paulade50832008-05-14 16:09:46 -06001416
1417/**
Brian Paul517401a2008-11-06 15:04:11 -07001418 * Update the vertex/fragment program's TexturesUsed array.
1419 *
1420 * This needs to be called after glUniform(set sampler var) is called.
1421 * A call to glUniform(samplerVar, value) causes a sampler to point to a
1422 * particular texture unit. We know the sampler's texture target
1423 * (1D/2D/3D/etc) from compile time but the sampler's texture unit is
1424 * set by glUniform() calls.
1425 *
1426 * So, scan the program->SamplerUnits[] and program->SamplerTargets[]
1427 * information to update the prog->TexturesUsed[] values.
1428 * Each value of TexturesUsed[unit] is one of zero, TEXTURE_1D_INDEX,
1429 * TEXTURE_2D_INDEX, TEXTURE_3D_INDEX, etc.
1430 * We'll use that info for state validation before rendering.
Brian Paulade50832008-05-14 16:09:46 -06001431 */
Brian Paul517401a2008-11-06 15:04:11 -07001432void
1433_mesa_update_shader_textures_used(struct gl_program *prog)
Brian Paulade50832008-05-14 16:09:46 -06001434{
1435 GLuint s;
1436
1437 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1438
1439 for (s = 0; s < MAX_SAMPLERS; s++) {
1440 if (prog->SamplersUsed & (1 << s)) {
1441 GLuint u = prog->SamplerUnits[s];
1442 GLuint t = prog->SamplerTargets[s];
1443 assert(u < MAX_TEXTURE_IMAGE_UNITS);
1444 prog->TexturesUsed[u] |= (1 << t);
1445 }
1446 }
1447}
1448
1449
Brianb36749d2008-07-21 20:42:05 -06001450static GLboolean
1451is_sampler_type(GLenum type)
1452{
1453 switch (type) {
1454 case GL_SAMPLER_1D:
1455 case GL_SAMPLER_2D:
1456 case GL_SAMPLER_3D:
1457 case GL_SAMPLER_CUBE:
1458 case GL_SAMPLER_1D_SHADOW:
1459 case GL_SAMPLER_2D_SHADOW:
1460 case GL_SAMPLER_2D_RECT_ARB:
1461 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
1462 case GL_SAMPLER_1D_ARRAY_EXT:
1463 case GL_SAMPLER_2D_ARRAY_EXT:
1464 return GL_TRUE;
1465 default:
1466 return GL_FALSE;
1467 }
1468}
1469
1470
Brian Paulade50832008-05-14 16:09:46 -06001471/**
Brian Paulffbc66b2008-07-21 13:58:50 -06001472 * Check if the type given by userType is allowed to set a uniform of the
1473 * target type. Generally, equivalence is required, but setting Boolean
1474 * uniforms can be done with glUniformiv or glUniformfv.
1475 */
1476static GLboolean
1477compatible_types(GLenum userType, GLenum targetType)
1478{
1479 if (userType == targetType)
1480 return GL_TRUE;
1481
1482 if (targetType == GL_BOOL && (userType == GL_FLOAT || userType == GL_INT))
1483 return GL_TRUE;
1484
1485 if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 ||
1486 userType == GL_INT_VEC2))
1487 return GL_TRUE;
1488
1489 if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 ||
1490 userType == GL_INT_VEC3))
1491 return GL_TRUE;
1492
1493 if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 ||
1494 userType == GL_INT_VEC4))
1495 return GL_TRUE;
1496
Brianb36749d2008-07-21 20:42:05 -06001497 if (is_sampler_type(targetType) && userType == GL_INT)
1498 return GL_TRUE;
1499
Brian Paulffbc66b2008-07-21 13:58:50 -06001500 return GL_FALSE;
1501}
1502
1503
1504/**
Brian Paulade50832008-05-14 16:09:46 -06001505 * Set the value of a program's uniform variable.
1506 * \param program the program whose uniform to update
Brian Pauleda291e2008-08-06 16:26:47 -06001507 * \param index the index of the program parameter for the uniform
1508 * \param offset additional parameter slot offset (for arrays)
Brian Paulade50832008-05-14 16:09:46 -06001509 * \param type the datatype of the uniform
1510 * \param count the number of uniforms to set
1511 * \param elems number of elements per uniform
1512 * \param values the new values
1513 */
1514static void
Brian Pauleda291e2008-08-06 16:26:47 -06001515set_program_uniform(GLcontext *ctx, struct gl_program *program,
1516 GLint index, GLint offset,
1517 GLenum type, GLsizei count, GLint elems,
1518 const void *values)
Brian Paulade50832008-05-14 16:09:46 -06001519{
Brian Paul949e7382008-11-05 09:17:55 -07001520 struct gl_program_parameter *param =
1521 &program->Parameters->Parameters[index];
1522
Brian Pauleda291e2008-08-06 16:26:47 -06001523 assert(offset >= 0);
1524
Brian Paul949e7382008-11-05 09:17:55 -07001525 if (!compatible_types(type, param->DataType)) {
Brian Paulffbc66b2008-07-21 13:58:50 -06001526 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
1527 return;
1528 }
1529
Brian Pauleda291e2008-08-06 16:26:47 -06001530 if (index + offset > program->Parameters->Size) {
1531 /* out of bounds! */
1532 return;
1533 }
1534
Brian Paul949e7382008-11-05 09:17:55 -07001535 if (param->Type == PROGRAM_SAMPLER) {
Brian Paulade50832008-05-14 16:09:46 -06001536 /* This controls which texture unit which is used by a sampler */
1537 GLuint texUnit, sampler;
1538
1539 /* data type for setting samplers must be int */
1540 if (type != GL_INT || count != 1) {
1541 _mesa_error(ctx, GL_INVALID_OPERATION,
1542 "glUniform(only glUniform1i can be used "
1543 "to set sampler uniforms)");
1544 return;
1545 }
1546
Brian Pauleda291e2008-08-06 16:26:47 -06001547 sampler = (GLuint) program->Parameters->ParameterValues[index][0];
Brian Paulade50832008-05-14 16:09:46 -06001548 texUnit = ((GLuint *) values)[0];
1549
1550 /* check that the sampler (tex unit index) is legal */
1551 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1552 _mesa_error(ctx, GL_INVALID_VALUE,
1553 "glUniform1(invalid sampler/tex unit index)");
1554 return;
1555 }
1556
1557 /* This maps a sampler to a texture unit: */
1558 program->SamplerUnits[sampler] = texUnit;
Brian Paul517401a2008-11-06 15:04:11 -07001559 _mesa_update_shader_textures_used(program);
Brian Paulade50832008-05-14 16:09:46 -06001560
1561 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1562 }
1563 else {
1564 /* ordinary uniform variable */
Brian Paul530df582008-07-03 16:21:11 -06001565 GLsizei k, i;
Brian Paul949e7382008-11-05 09:17:55 -07001566 GLint slots = (param->Size + 3) / 4;
Brian Paulade50832008-05-14 16:09:46 -06001567
Brian Paul949e7382008-11-05 09:17:55 -07001568 if (count * elems > (GLint) param->Size) {
Brian Paulade50832008-05-14 16:09:46 -06001569 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1570 return;
1571 }
1572
Brian Pauleda291e2008-08-06 16:26:47 -06001573 if (count > slots)
1574 count = slots;
1575
Brian Paulade50832008-05-14 16:09:46 -06001576 for (k = 0; k < count; k++) {
Brian Paul949e7382008-11-05 09:17:55 -07001577 GLfloat *uniformVal =
1578 program->Parameters->ParameterValues[index + offset + k];
Brian Pauleda291e2008-08-06 16:26:47 -06001579 if (is_integer_type(type)) {
Brian Paulade50832008-05-14 16:09:46 -06001580 const GLint *iValues = ((const GLint *) values) + k * elems;
1581 for (i = 0; i < elems; i++) {
1582 uniformVal[i] = (GLfloat) iValues[i];
1583 }
1584 }
1585 else {
1586 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1587 for (i = 0; i < elems; i++) {
1588 uniformVal[i] = fValues[i];
1589 }
1590 }
Brian Pauleda291e2008-08-06 16:26:47 -06001591
1592 /* if the uniform is bool-valued, convert to 1.0 or 0.0 */
Brian Paul949e7382008-11-05 09:17:55 -07001593 if (is_boolean_type(param->DataType)) {
Brian Pauleda291e2008-08-06 16:26:47 -06001594 for (i = 0; i < elems; i++) {
1595 uniformVal[i] = uniformVal[i] ? 1.0 : 0.0;
1596 }
1597 }
Brian Paulade50832008-05-14 16:09:46 -06001598 }
1599 }
1600}
1601
1602
Brian5b01c5e2006-12-19 18:02:03 -07001603/**
1604 * Called via ctx->Driver.Uniform().
1605 */
Brian Paulfd59f192008-05-18 16:04:55 -06001606static void
Brian5b01c5e2006-12-19 18:02:03 -07001607_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1608 const GLvoid *values, GLenum type)
1609{
Brian3a8e2772006-12-20 17:19:16 -07001610 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Pauleda291e2008-08-06 16:26:47 -06001611 GLint elems, offset;
Brian3a8e2772006-12-20 17:19:16 -07001612
1613 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001614 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001615 return;
1616 }
1617
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001618 if (location == -1)
1619 return; /* The standard specifies this as a no-op */
1620
Brian Pauleda291e2008-08-06 16:26:47 -06001621 split_location_offset(&location, &offset);
1622
Brian Paulade50832008-05-14 16:09:46 -06001623 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
1624 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
Brian3a8e2772006-12-20 17:19:16 -07001625 return;
1626 }
1627
Brian52363952007-03-13 16:50:24 -06001628 if (count < 0) {
1629 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1630 return;
1631 }
1632
Brian98650bd2007-03-13 16:32:48 -06001633 switch (type) {
1634 case GL_FLOAT:
1635 case GL_INT:
1636 elems = 1;
1637 break;
1638 case GL_FLOAT_VEC2:
1639 case GL_INT_VEC2:
1640 elems = 2;
1641 break;
1642 case GL_FLOAT_VEC3:
1643 case GL_INT_VEC3:
1644 elems = 3;
1645 break;
1646 case GL_FLOAT_VEC4:
1647 case GL_INT_VEC4:
1648 elems = 4;
1649 break;
1650 default:
1651 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1652 return;
Brian89dc4852007-01-04 14:35:44 -07001653 }
Brian98650bd2007-03-13 16:32:48 -06001654
Brian Paulade50832008-05-14 16:09:46 -06001655 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
Brian98650bd2007-03-13 16:32:48 -06001656
Brian Paulade50832008-05-14 16:09:46 -06001657 /* A uniform var may be used by both a vertex shader and a fragment
1658 * shader. We may need to update one or both shader's uniform here:
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001659 */
Brian Paulade50832008-05-14 16:09:46 -06001660 if (shProg->VertexProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001661 /* convert uniform location to program parameter index */
1662 GLint index = shProg->Uniforms->Uniforms[location].VertPos;
1663 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001664 set_program_uniform(ctx, &shProg->VertexProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001665 index, offset, type, count, elems, values);
Bruce Merry2bf2a8c2007-12-21 23:18:40 +02001666 }
Brian5b01c5e2006-12-19 18:02:03 -07001667 }
Brian5cf73262007-01-05 16:02:45 -07001668
Brian Paulade50832008-05-14 16:09:46 -06001669 if (shProg->FragmentProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001670 /* convert uniform location to program parameter index */
1671 GLint index = shProg->Uniforms->Uniforms[location].FragPos;
1672 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001673 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001674 index, offset, type, count, elems, values);
Brian Paulade50832008-05-14 16:09:46 -06001675 }
1676 }
Brian Paul949e7382008-11-05 09:17:55 -07001677
1678 shProg->Uniforms->Uniforms[location].Initialized = GL_TRUE;
Brian Paulade50832008-05-14 16:09:46 -06001679}
1680
1681
Brian Pauleda291e2008-08-06 16:26:47 -06001682/**
1683 * Set a matrix-valued program parameter.
1684 */
Brian Paulade50832008-05-14 16:09:46 -06001685static void
1686set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
Brian Pauleda291e2008-08-06 16:26:47 -06001687 GLuint index, GLuint offset,
1688 GLuint count, GLuint rows, GLuint cols,
Brian Paulade50832008-05-14 16:09:46 -06001689 GLboolean transpose, const GLfloat *values)
1690{
Brian Paulffbc66b2008-07-21 13:58:50 -06001691 GLuint mat, row, col;
Brian Pauleda291e2008-08-06 16:26:47 -06001692 GLuint dst = index + offset, src = 0;
Brian Paulffbc66b2008-07-21 13:58:50 -06001693 GLint nr, nc;
1694
1695 /* check that the number of rows, columns is correct */
Brian Pauleda291e2008-08-06 16:26:47 -06001696 get_matrix_dims(program->Parameters->Parameters[index].DataType, &nr, &nc);
Brian Paulffbc66b2008-07-21 13:58:50 -06001697 if (rows != nr || cols != nc) {
1698 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Pauleda291e2008-08-06 16:26:47 -06001699 "glUniformMatrix(matrix size mismatch)");
1700 return;
1701 }
1702
1703 if (index + offset > program->Parameters->Size) {
1704 /* out of bounds! */
Brian Paulffbc66b2008-07-21 13:58:50 -06001705 return;
1706 }
1707
Brian Paulade50832008-05-14 16:09:46 -06001708 /*
1709 * Note: the _columns_ of a matrix are stored in program registers, not
Brian Paulf45ed0e2008-07-18 12:51:39 -06001710 * the rows. So, the loops below look a little funny.
1711 * XXX could optimize this a bit...
Brian Paulade50832008-05-14 16:09:46 -06001712 */
Brian Paulf45ed0e2008-07-18 12:51:39 -06001713
1714 /* loop over matrices */
1715 for (mat = 0; mat < count; mat++) {
1716
1717 /* each matrix: */
Brian Paulade50832008-05-14 16:09:46 -06001718 for (col = 0; col < cols; col++) {
Brian Paulf45ed0e2008-07-18 12:51:39 -06001719 GLfloat *v = program->Parameters->ParameterValues[dst];
Brian Paulade50832008-05-14 16:09:46 -06001720 for (row = 0; row < rows; row++) {
Brian Paulf45ed0e2008-07-18 12:51:39 -06001721 if (transpose) {
1722 v[row] = values[src + row * cols + col];
1723 }
1724 else {
1725 v[row] = values[src + col * rows + row];
1726 }
Brian Paulade50832008-05-14 16:09:46 -06001727 }
Brian Paulf45ed0e2008-07-18 12:51:39 -06001728 dst++;
Brian Paulade50832008-05-14 16:09:46 -06001729 }
Brian Paulf45ed0e2008-07-18 12:51:39 -06001730
1731 src += rows * cols; /* next matrix */
Brian5cf73262007-01-05 16:02:45 -07001732 }
Brian34ae99d2006-12-18 08:28:54 -07001733}
1734
1735
1736/**
Brian5b01c5e2006-12-19 18:02:03 -07001737 * Called by ctx->Driver.UniformMatrix().
Brian Paulf45ed0e2008-07-18 12:51:39 -06001738 * Note: cols=2, rows=4 ==> array[2] of vec4
Brian34ae99d2006-12-18 08:28:54 -07001739 */
Brian Paulfd59f192008-05-18 16:04:55 -06001740static void
Brian5b01c5e2006-12-19 18:02:03 -07001741_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1742 GLenum matrixType, GLint location, GLsizei count,
1743 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001744{
Brian Pauleda291e2008-08-06 16:26:47 -06001745 GLint offset;
Brian3a8e2772006-12-20 17:19:16 -07001746 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paulade50832008-05-14 16:09:46 -06001747
Brian3a8e2772006-12-20 17:19:16 -07001748 if (!shProg || !shProg->LinkStatus) {
1749 _mesa_error(ctx, GL_INVALID_OPERATION,
1750 "glUniformMatrix(program not linked)");
1751 return;
1752 }
Brian Paulade50832008-05-14 16:09:46 -06001753
Bruce Merry89b80322007-12-21 15:20:17 +02001754 if (location == -1)
1755 return; /* The standard specifies this as a no-op */
Brian Paulade50832008-05-14 16:09:46 -06001756
Brian Pauleda291e2008-08-06 16:26:47 -06001757 split_location_offset(&location, &offset);
1758
Brian Paul016701f2008-07-29 17:43:35 -06001759 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian Paulade50832008-05-14 16:09:46 -06001760 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
Brian3a8e2772006-12-20 17:19:16 -07001761 return;
1762 }
Brian34ae99d2006-12-18 08:28:54 -07001763 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001764 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001765 return;
1766 }
1767
1768 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1769
Brian Paulade50832008-05-14 16:09:46 -06001770 if (shProg->VertexProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001771 /* convert uniform location to program parameter index */
1772 GLint index = shProg->Uniforms->Uniforms[location].VertPos;
1773 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001774 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001775 index, offset,
1776 count, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07001777 }
Brian Paulade50832008-05-14 16:09:46 -06001778 }
1779
1780 if (shProg->FragmentProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001781 /* convert uniform location to program parameter index */
1782 GLint index = shProg->Uniforms->Uniforms[location].FragPos;
1783 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001784 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001785 index, offset,
1786 count, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07001787 }
Brian34ae99d2006-12-18 08:28:54 -07001788 }
Brian Paul949e7382008-11-05 09:17:55 -07001789
1790 shProg->Uniforms->Uniforms[location].Initialized = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001791}
1792
1793
Brian Paulfd59f192008-05-18 16:04:55 -06001794static void
Brian5b01c5e2006-12-19 18:02:03 -07001795_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001796{
Brian65a18442006-12-19 18:46:56 -07001797 struct gl_shader_program *shProg;
Brian Paulbc985b52008-07-21 14:16:07 -06001798
1799 shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram");
Brian65a18442006-12-19 18:46:56 -07001800 if (!shProg) {
Brian34ae99d2006-12-18 08:28:54 -07001801 return;
1802 }
1803
Brian Paulbc985b52008-07-21 14:16:07 -06001804 if (!shProg->LinkStatus) {
1805 shProg->Validated = GL_FALSE;
1806 return;
1807 }
1808
1809 /* From the GL spec, a program is invalid if any of these are true:
1810
Brian5b01c5e2006-12-19 18:02:03 -07001811 any two active samplers in the current program object are of
1812 different types, but refer to the same texture image unit,
1813
1814 any active sampler in the current program object refers to a texture
1815 image unit where fixed-function fragment processing accesses a
1816 texture target that does not match the sampler type, or
1817
1818 the sum of the number of active samplers in the program and the
1819 number of texture image units enabled for fixed-function fragment
1820 processing exceeds the combined limit on the total number of texture
1821 image units allowed.
1822 */
Brian Paulbc985b52008-07-21 14:16:07 -06001823
1824 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001825}
Brian Paulfd59f192008-05-18 16:04:55 -06001826
1827
1828/**
1829 * Plug in Mesa's GLSL functions into the device driver function table.
1830 */
1831void
1832_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
1833{
1834 driver->AttachShader = _mesa_attach_shader;
1835 driver->BindAttribLocation = _mesa_bind_attrib_location;
1836 driver->CompileShader = _mesa_compile_shader;
1837 driver->CreateProgram = _mesa_create_program;
1838 driver->CreateShader = _mesa_create_shader;
1839 driver->DeleteProgram2 = _mesa_delete_program2;
1840 driver->DeleteShader = _mesa_delete_shader;
1841 driver->DetachShader = _mesa_detach_shader;
1842 driver->GetActiveAttrib = _mesa_get_active_attrib;
1843 driver->GetActiveUniform = _mesa_get_active_uniform;
1844 driver->GetAttachedShaders = _mesa_get_attached_shaders;
1845 driver->GetAttribLocation = _mesa_get_attrib_location;
1846 driver->GetHandle = _mesa_get_handle;
1847 driver->GetProgramiv = _mesa_get_programiv;
1848 driver->GetProgramInfoLog = _mesa_get_program_info_log;
1849 driver->GetShaderiv = _mesa_get_shaderiv;
1850 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
1851 driver->GetShaderSource = _mesa_get_shader_source;
1852 driver->GetUniformfv = _mesa_get_uniformfv;
Brian Paul2be54a82008-07-08 16:17:04 -06001853 driver->GetUniformiv = _mesa_get_uniformiv;
Brian Paulfd59f192008-05-18 16:04:55 -06001854 driver->GetUniformLocation = _mesa_get_uniform_location;
1855 driver->IsProgram = _mesa_is_program;
1856 driver->IsShader = _mesa_is_shader;
1857 driver->LinkProgram = _mesa_link_program;
1858 driver->ShaderSource = _mesa_shader_source;
1859 driver->Uniform = _mesa_uniform;
1860 driver->UniformMatrix = _mesa_uniform_matrix;
1861 driver->UseProgram = _mesa_use_program;
1862 driver->ValidateProgram = _mesa_validate_program;
1863}