blob: c3b49ed4d4bcd8f526eaff54f1d84ec61d04761b [file] [log] [blame]
Brian34ae99d2006-12-18 08:28:54 -07001/*
2 * Mesa 3-D graphics library
Brian Paulc90fca32009-08-25 17:42:47 -06003 * Version: 7.6
Brian34ae99d2006-12-18 08:28:54 -07004 *
Brian Paul8c51e002008-08-11 15:09:47 -06005 * Copyright (C) 2004-2008 Brian Paul All Rights Reserved.
Brian Paulc4ffbf02009-02-18 17:46:00 -07006 * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
Brian34ae99d2006-12-18 08:28:54 -07007 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26/**
27 * \file shader_api.c
Brian5b01c5e2006-12-19 18:02:03 -070028 * Implementation of GLSL-related API functions
Brian34ae99d2006-12-18 08:28:54 -070029 * \author Brian Paul
30 */
31
32/**
33 * XXX things to do:
34 * 1. Check that the right error code is generated for all _mesa_error() calls.
Brian5b01c5e2006-12-19 18:02:03 -070035 * 2. Insert FLUSH_VERTICES calls in various places
Brian34ae99d2006-12-18 08:28:54 -070036 */
37
38
Brian Paulbbd28712008-09-18 12:26:54 -060039#include "main/glheader.h"
40#include "main/context.h"
41#include "main/hash.h"
Brian Paulbbd28712008-09-18 12:26:54 -060042#include "shader/program.h"
43#include "shader/prog_parameter.h"
Brian Paulbbd28712008-09-18 12:26:54 -060044#include "shader/prog_statevars.h"
45#include "shader/prog_uniform.h"
Brianc223c6b2007-07-04 13:15:20 -060046#include "shader/shader_api.h"
47#include "shader/slang/slang_compile.h"
48#include "shader/slang/slang_link.h"
Ian Romanick905d8e02008-09-29 12:27:00 -070049#include "glapi/dispatch.h"
Brian34ae99d2006-12-18 08:28:54 -070050
51
Brianf2923612006-12-20 09:56:44 -070052/**
53 * Allocate a new gl_shader_program object, initialize it.
54 */
Brian Paulfd59f192008-05-18 16:04:55 -060055static struct gl_shader_program *
Brianf2923612006-12-20 09:56:44 -070056_mesa_new_shader_program(GLcontext *ctx, GLuint name)
57{
58 struct gl_shader_program *shProg;
59 shProg = CALLOC_STRUCT(gl_shader_program);
60 if (shProg) {
Brianf3e8c322007-04-18 14:53:23 -060061 shProg->Type = GL_SHADER_PROGRAM_MESA;
Brianf2923612006-12-20 09:56:44 -070062 shProg->Name = name;
63 shProg->RefCount = 1;
Brian3209c3e2007-01-09 17:49:24 -070064 shProg->Attributes = _mesa_new_parameter_list();
Brianf2923612006-12-20 09:56:44 -070065 }
66 return shProg;
67}
68
69
Brianb9fbedd2007-03-26 09:23:44 -060070/**
Brian3c008a02007-04-12 15:22:32 -060071 * Clear (free) the shader program state that gets produced by linking.
Brianb9fbedd2007-03-26 09:23:44 -060072 */
Brianf2923612006-12-20 09:56:44 -070073void
Brian3c008a02007-04-12 15:22:32 -060074_mesa_clear_shader_program_data(GLcontext *ctx,
75 struct gl_shader_program *shProg)
Brianf2923612006-12-20 09:56:44 -070076{
Brian Paul8bdf5b62008-05-16 09:56:59 -060077 _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL);
78 _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL);
Brianf2923612006-12-20 09:56:44 -070079
Brianf2923612006-12-20 09:56:44 -070080 if (shProg->Uniforms) {
Brian Paulade50832008-05-14 16:09:46 -060081 _mesa_free_uniform_list(shProg->Uniforms);
Brianf2923612006-12-20 09:56:44 -070082 shProg->Uniforms = NULL;
83 }
84
85 if (shProg->Varying) {
86 _mesa_free_parameter_list(shProg->Varying);
87 shProg->Varying = NULL;
88 }
89}
90
91
Brianb9fbedd2007-03-26 09:23:44 -060092/**
Brian3c008a02007-04-12 15:22:32 -060093 * Free all the data that hangs off a shader program object, but not the
94 * object itself.
95 */
96void
97_mesa_free_shader_program_data(GLcontext *ctx,
98 struct gl_shader_program *shProg)
99{
100 GLuint i;
101
Brianf3e8c322007-04-18 14:53:23 -0600102 assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
Brian3c008a02007-04-12 15:22:32 -0600103
104 _mesa_clear_shader_program_data(ctx, shProg);
105
Brian4b7c6fc2007-04-19 15:23:34 -0600106 if (shProg->Attributes) {
107 _mesa_free_parameter_list(shProg->Attributes);
108 shProg->Attributes = NULL;
109 }
110
Brian3c008a02007-04-12 15:22:32 -0600111 /* detach shaders */
112 for (i = 0; i < shProg->NumShaders; i++) {
113 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
114 }
Xiang, Haihao63d8a842008-03-31 17:02:47 +0800115 shProg->NumShaders = 0;
116
Brian3c008a02007-04-12 15:22:32 -0600117 if (shProg->Shaders) {
118 _mesa_free(shProg->Shaders);
119 shProg->Shaders = NULL;
120 }
Alan Hourihaneeec20c32008-04-22 20:29:42 +0100121
122 if (shProg->InfoLog) {
123 _mesa_free(shProg->InfoLog);
124 shProg->InfoLog = NULL;
125 }
Brian3c008a02007-04-12 15:22:32 -0600126}
127
128
129/**
Brianb9fbedd2007-03-26 09:23:44 -0600130 * Free/delete a shader program object.
131 */
Brianf2923612006-12-20 09:56:44 -0700132void
133_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg)
134{
135 _mesa_free_shader_program_data(ctx, shProg);
Alan Hourihaneeec20c32008-04-22 20:29:42 +0100136
Brianf2923612006-12-20 09:56:44 -0700137 _mesa_free(shProg);
138}
139
140
141/**
Brian3c008a02007-04-12 15:22:32 -0600142 * Set ptr to point to shProg.
143 * If ptr is pointing to another object, decrement its refcount (and delete
144 * if refcount hits zero).
145 * Then set ptr to point to shProg, incrementing its refcount.
146 */
147/* XXX this could be static */
148void
149_mesa_reference_shader_program(GLcontext *ctx,
150 struct gl_shader_program **ptr,
151 struct gl_shader_program *shProg)
152{
153 assert(ptr);
154 if (*ptr == shProg) {
155 /* no-op */
156 return;
157 }
158 if (*ptr) {
159 /* Unreference the old shader program */
160 GLboolean deleteFlag = GL_FALSE;
161 struct gl_shader_program *old = *ptr;
162
163 ASSERT(old->RefCount > 0);
164 old->RefCount--;
Brian Paul8bdf5b62008-05-16 09:56:59 -0600165#if 0
166 printf("ShaderProgram %p ID=%u RefCount-- to %d\n",
167 (void *) old, old->Name, old->RefCount);
168#endif
Brian3c008a02007-04-12 15:22:32 -0600169 deleteFlag = (old->RefCount == 0);
170
171 if (deleteFlag) {
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800172 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
Brian3c008a02007-04-12 15:22:32 -0600173 _mesa_free_shader_program(ctx, old);
174 }
175
176 *ptr = NULL;
177 }
178 assert(!*ptr);
179
180 if (shProg) {
181 shProg->RefCount++;
Brian Paul8bdf5b62008-05-16 09:56:59 -0600182#if 0
183 printf("ShaderProgram %p ID=%u RefCount++ to %d\n",
184 (void *) shProg, shProg->Name, shProg->RefCount);
185#endif
Brian3c008a02007-04-12 15:22:32 -0600186 *ptr = shProg;
187 }
188}
189
190
191/**
Brianf2923612006-12-20 09:56:44 -0700192 * Lookup a GLSL program object.
193 */
194struct gl_shader_program *
195_mesa_lookup_shader_program(GLcontext *ctx, GLuint name)
196{
197 struct gl_shader_program *shProg;
198 if (name) {
199 shProg = (struct gl_shader_program *)
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800200 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
Brianf2923612006-12-20 09:56:44 -0700201 /* Note that both gl_shader and gl_shader_program objects are kept
202 * in the same hash table. Check the object's type to be sure it's
203 * what we're expecting.
204 */
Brianf3e8c322007-04-18 14:53:23 -0600205 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700206 return NULL;
207 }
208 return shProg;
209 }
210 return NULL;
211}
212
213
214/**
Brian Paul530df582008-07-03 16:21:11 -0600215 * As above, but record an error if program is not found.
216 */
217static struct gl_shader_program *
218_mesa_lookup_shader_program_err(GLcontext *ctx, GLuint name,
219 const char *caller)
220{
221 if (!name) {
222 _mesa_error(ctx, GL_INVALID_VALUE, caller);
223 return NULL;
224 }
225 else {
226 struct gl_shader_program *shProg = (struct gl_shader_program *)
227 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
228 if (!shProg) {
229 _mesa_error(ctx, GL_INVALID_VALUE, caller);
230 return NULL;
231 }
232 if (shProg->Type != GL_SHADER_PROGRAM_MESA) {
233 _mesa_error(ctx, GL_INVALID_OPERATION, caller);
234 return NULL;
235 }
236 return shProg;
237 }
238}
239
240
241
242
243/**
Brianf2923612006-12-20 09:56:44 -0700244 * Allocate a new gl_shader object, initialize it.
245 */
246struct gl_shader *
247_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
248{
249 struct gl_shader *shader;
250 assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
251 shader = CALLOC_STRUCT(gl_shader);
252 if (shader) {
253 shader->Type = type;
254 shader->Name = name;
255 shader->RefCount = 1;
256 }
257 return shader;
258}
259
260
261void
262_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh)
263{
Brianf2923612006-12-20 09:56:44 -0700264 if (sh->Source)
265 _mesa_free((void *) sh->Source);
266 if (sh->InfoLog)
267 _mesa_free(sh->InfoLog);
Brian Paul3d500f02008-07-24 14:56:54 -0600268 _mesa_reference_program(ctx, &sh->Program, NULL);
Brianf2923612006-12-20 09:56:44 -0700269 _mesa_free(sh);
270}
271
272
273/**
Brian3c008a02007-04-12 15:22:32 -0600274 * Set ptr to point to sh.
275 * If ptr is pointing to another shader, decrement its refcount (and delete
276 * if refcount hits zero).
277 * Then set ptr to point to sh, incrementing its refcount.
278 */
279/* XXX this could be static */
280void
281_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr,
282 struct gl_shader *sh)
283{
284 assert(ptr);
285 if (*ptr == sh) {
286 /* no-op */
287 return;
288 }
289 if (*ptr) {
290 /* Unreference the old shader */
291 GLboolean deleteFlag = GL_FALSE;
292 struct gl_shader *old = *ptr;
293
294 ASSERT(old->RefCount > 0);
295 old->RefCount--;
Brian99193e42007-04-12 15:45:02 -0600296 /*printf("SHADER DECR %p (%d) to %d\n",
297 (void*) old, old->Name, old->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600298 deleteFlag = (old->RefCount == 0);
299
300 if (deleteFlag) {
301 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
302 _mesa_free_shader(ctx, old);
303 }
304
305 *ptr = NULL;
306 }
307 assert(!*ptr);
308
309 if (sh) {
310 /* reference new */
311 sh->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600312 /*printf("SHADER INCR %p (%d) to %d\n",
313 (void*) sh, sh->Name, sh->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600314 *ptr = sh;
315 }
316}
317
318
319/**
Brianf2923612006-12-20 09:56:44 -0700320 * Lookup a GLSL shader object.
321 */
322struct gl_shader *
323_mesa_lookup_shader(GLcontext *ctx, GLuint name)
324{
325 if (name) {
326 struct gl_shader *sh = (struct gl_shader *)
327 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
328 /* Note that both gl_shader and gl_shader_program objects are kept
329 * in the same hash table. Check the object's type to be sure it's
330 * what we're expecting.
331 */
Brianf3e8c322007-04-18 14:53:23 -0600332 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700333 return NULL;
334 }
335 return sh;
336 }
337 return NULL;
338}
339
340
Brianfa4d0362007-02-26 18:33:50 -0700341/**
Brian Paul530df582008-07-03 16:21:11 -0600342 * As above, but record an error if shader is not found.
343 */
344static struct gl_shader *
345_mesa_lookup_shader_err(GLcontext *ctx, GLuint name, const char *caller)
346{
347 if (!name) {
348 _mesa_error(ctx, GL_INVALID_VALUE, caller);
349 return NULL;
350 }
351 else {
352 struct gl_shader *sh = (struct gl_shader *)
353 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
354 if (!sh) {
355 _mesa_error(ctx, GL_INVALID_VALUE, caller);
356 return NULL;
357 }
358 if (sh->Type == GL_SHADER_PROGRAM_MESA) {
359 _mesa_error(ctx, GL_INVALID_OPERATION, caller);
360 return NULL;
361 }
362 return sh;
363 }
364}
365
366
Brian Paule01a03d2009-02-06 10:21:36 -0700367/**
368 * Return mask of GLSL_x flags by examining the MESA_GLSL env var.
369 */
370static GLbitfield
371get_shader_flags(void)
372{
373 GLbitfield flags = 0x0;
374 const char *env = _mesa_getenv("MESA_GLSL");
375
376 if (env) {
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800377 if (strstr(env, "dump"))
Brian Paule01a03d2009-02-06 10:21:36 -0700378 flags |= GLSL_DUMP;
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800379 if (strstr(env, "log"))
Brian Paule01a03d2009-02-06 10:21:36 -0700380 flags |= GLSL_LOG;
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800381 if (strstr(env, "nopvert"))
Brian Paulcb0de062009-09-29 10:22:32 -0600382 flags |= GLSL_NOP_VERT;
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800383 if (strstr(env, "nopfrag"))
Brian Paulcb0de062009-09-29 10:22:32 -0600384 flags |= GLSL_NOP_FRAG;
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800385 if (strstr(env, "nopt"))
Brian Paule01a03d2009-02-06 10:21:36 -0700386 flags |= GLSL_NO_OPT;
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800387 else if (strstr(env, "opt"))
Brian Paule01a03d2009-02-06 10:21:36 -0700388 flags |= GLSL_OPT;
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800389 if (strstr(env, "uniform"))
Brian Paule01a03d2009-02-06 10:21:36 -0700390 flags |= GLSL_UNIFORMS;
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800391 if (strstr(env, "useprog"))
Brian Paul2ee7fd82009-10-15 15:25:52 -0600392 flags |= GLSL_USE_PROG;
Brian Paule01a03d2009-02-06 10:21:36 -0700393 }
394
395 return flags;
396}
397
Brian Paul530df582008-07-03 16:21:11 -0600398
399/**
Brianfa4d0362007-02-26 18:33:50 -0700400 * Initialize context's shader state.
401 */
Brianf2923612006-12-20 09:56:44 -0700402void
403_mesa_init_shader_state(GLcontext * ctx)
404{
Brianfa4d0362007-02-26 18:33:50 -0700405 /* Device drivers may override these to control what kind of instructions
406 * are generated by the GLSL compiler.
407 */
408 ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
Brian Paul4031ea12009-06-17 11:57:39 -0600409 ctx->Shader.EmitContReturn = GL_TRUE;
Brian Paulc5c38352009-02-16 11:50:05 -0700410 ctx->Shader.EmitCondCodes = GL_FALSE;
Brianfa4d0362007-02-26 18:33:50 -0700411 ctx->Shader.EmitComments = GL_FALSE;
Brian Paule01a03d2009-02-06 10:21:36 -0700412 ctx->Shader.Flags = get_shader_flags();
Brian Paul65fc2ca2009-03-19 10:25:24 -0600413
414 /* Default pragma settings */
415 ctx->Shader.DefaultPragmas.IgnoreOptimize = GL_FALSE;
416 ctx->Shader.DefaultPragmas.IgnoreDebug = GL_FALSE;
417 ctx->Shader.DefaultPragmas.Optimize = GL_TRUE;
418 ctx->Shader.DefaultPragmas.Debug = GL_FALSE;
Brianf2923612006-12-20 09:56:44 -0700419}
420
421
Brian5b01c5e2006-12-19 18:02:03 -0700422/**
Brian935f93f2007-03-24 16:20:02 -0600423 * Free the per-context shader-related state.
424 */
425void
426_mesa_free_shader_state(GLcontext *ctx)
427{
Brian3c008a02007-04-12 15:22:32 -0600428 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
Brian935f93f2007-03-24 16:20:02 -0600429}
430
431
432/**
Brian5b01c5e2006-12-19 18:02:03 -0700433 * Copy string from <src> to <dst>, up to maxLength characters, returning
434 * length of <dst> in <length>.
435 * \param src the strings source
436 * \param maxLength max chars to copy
437 * \param length returns number of chars copied
438 * \param dst the string destination
439 */
440static void
441copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
442{
443 GLsizei len;
444 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
445 dst[len] = src[len];
446 if (maxLength > 0)
447 dst[len] = 0;
448 if (length)
449 *length = len;
450}
451
452
Brian Paul7acb7c12008-07-03 13:49:48 -0600453static GLboolean
454_mesa_is_program(GLcontext *ctx, GLuint name)
455{
456 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
457 return shProg ? GL_TRUE : GL_FALSE;
458}
459
460
461static GLboolean
462_mesa_is_shader(GLcontext *ctx, GLuint name)
463{
464 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
465 return shader ? GL_TRUE : GL_FALSE;
466}
467
468
Brian5b01c5e2006-12-19 18:02:03 -0700469/**
470 * Called via ctx->Driver.AttachShader()
471 */
Brian Paulfd59f192008-05-18 16:04:55 -0600472static void
Brian5b01c5e2006-12-19 18:02:03 -0700473_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
474{
Brian Paul530df582008-07-03 16:21:11 -0600475 struct gl_shader_program *shProg;
476 struct gl_shader *sh;
477 GLuint i, n;
Brian5b01c5e2006-12-19 18:02:03 -0700478
Brian Paul530df582008-07-03 16:21:11 -0600479 shProg = _mesa_lookup_shader_program_err(ctx, program, "glAttachShader");
480 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700481 return;
Brian5b01c5e2006-12-19 18:02:03 -0700482
Brian Paul530df582008-07-03 16:21:11 -0600483 sh = _mesa_lookup_shader_err(ctx, shader, "glAttachShader");
Brian Paul7acb7c12008-07-03 13:49:48 -0600484 if (!sh) {
Brian Paul7acb7c12008-07-03 13:49:48 -0600485 return;
486 }
487
Brian237b9852007-08-07 21:48:31 +0100488 n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700489 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700490 if (shProg->Shaders[i] == sh) {
Ian Romanickd806d452008-09-29 12:18:06 -0700491 /* The shader is already attched to this program. The
492 * GL_ARB_shader_objects spec says:
493 *
494 * "The error INVALID_OPERATION is generated by AttachObjectARB
495 * if <obj> is already attached to <containerObj>."
496 */
497 _mesa_error(ctx, GL_INVALID_OPERATION, "glAttachShader");
Brian5b01c5e2006-12-19 18:02:03 -0700498 return;
Brian34ae99d2006-12-18 08:28:54 -0700499 }
500 }
Brian5b01c5e2006-12-19 18:02:03 -0700501
502 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700503 shProg->Shaders = (struct gl_shader **)
504 _mesa_realloc(shProg->Shaders,
505 n * sizeof(struct gl_shader *),
506 (n + 1) * sizeof(struct gl_shader *));
507 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700508 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
509 return;
510 }
511
512 /* append */
Brian3c008a02007-04-12 15:22:32 -0600513 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
514 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700515 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700516}
517
518
Brian Paulfd59f192008-05-18 16:04:55 -0600519static GLint
Brian Paul896c0cc2008-05-16 15:47:55 -0600520_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
521 const GLchar *name)
522{
523 struct gl_shader_program *shProg
Brian Paul530df582008-07-03 16:21:11 -0600524 = _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
Brian Paul896c0cc2008-05-16 15:47:55 -0600525
526 if (!shProg) {
Brian Paul896c0cc2008-05-16 15:47:55 -0600527 return -1;
528 }
529
530 if (!shProg->LinkStatus) {
531 _mesa_error(ctx, GL_INVALID_OPERATION,
532 "glGetAttribLocation(program not linked)");
533 return -1;
534 }
535
536 if (!name)
537 return -1;
538
Brian Paul27341a92008-09-16 16:28:36 -0600539 if (shProg->VertexProgram) {
540 const struct gl_program_parameter_list *attribs =
541 shProg->VertexProgram->Base.Attributes;
542 if (attribs) {
543 GLint i = _mesa_lookup_parameter_index(attribs, -1, name);
544 if (i >= 0) {
545 return attribs->Parameters[i].StateIndexes[0];
546 }
Brian Paul896c0cc2008-05-16 15:47:55 -0600547 }
548 }
549 return -1;
550}
551
552
Brian Paulfd59f192008-05-18 16:04:55 -0600553static void
Brian5b01c5e2006-12-19 18:02:03 -0700554_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
555 const GLchar *name)
556{
Brian Paul530df582008-07-03 16:21:11 -0600557 struct gl_shader_program *shProg;
Brianb7978af2007-01-09 19:17:17 -0700558 const GLint size = -1; /* unknown size */
Brian Paul6bc87492008-07-25 08:34:54 -0600559 GLint i, oldIndex;
Brian Paul6f1abb92008-07-29 17:27:22 -0600560 GLenum datatype = GL_FLOAT_VEC4;
Brian5b01c5e2006-12-19 18:02:03 -0700561
Brian Paul530df582008-07-03 16:21:11 -0600562 shProg = _mesa_lookup_shader_program_err(ctx, program,
563 "glBindAttribLocation");
Brian65a18442006-12-19 18:46:56 -0700564 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700565 return;
566 }
567
Brian9e4bae92006-12-20 09:27:42 -0700568 if (!name)
569 return;
570
571 if (strncmp(name, "gl_", 3) == 0) {
572 _mesa_error(ctx, GL_INVALID_OPERATION,
573 "glBindAttribLocation(illegal name)");
574 return;
575 }
576
Brian Paul7acb7c12008-07-03 13:49:48 -0600577 if (index >= ctx->Const.VertexProgram.MaxAttribs) {
578 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
579 return;
580 }
581
Brian Paul6bc87492008-07-25 08:34:54 -0600582 if (shProg->LinkStatus) {
583 /* get current index/location for the attribute */
584 oldIndex = _mesa_get_attrib_location(ctx, program, name);
585 }
586 else {
587 oldIndex = -1;
588 }
589
Brian3209c3e2007-01-09 17:49:24 -0700590 /* this will replace the current value if it's already in the list */
Brian Paulffbc66b2008-07-21 13:58:50 -0600591 i = _mesa_add_attribute(shProg->Attributes, name, size, datatype, index);
Brian3209c3e2007-01-09 17:49:24 -0700592 if (i < 0) {
593 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
Brian Paul6f1abb92008-07-29 17:27:22 -0600594 return;
Brian3209c3e2007-01-09 17:49:24 -0700595 }
596
Brian Paul27341a92008-09-16 16:28:36 -0600597 /*
598 * Note that this attribute binding won't go into effect until
599 * glLinkProgram is called again.
600 */
Brian34ae99d2006-12-18 08:28:54 -0700601}
602
603
Brian Paulfd59f192008-05-18 16:04:55 -0600604static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700605_mesa_create_shader(GLcontext *ctx, GLenum type)
606{
Brian65a18442006-12-19 18:46:56 -0700607 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700608 GLuint name;
609
610 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
611
612 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700613 case GL_FRAGMENT_SHADER:
614 case GL_VERTEX_SHADER:
615 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700616 break;
617 default:
618 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
619 return 0;
620 }
621
Brian65a18442006-12-19 18:46:56 -0700622 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700623
624 return name;
625}
626
627
Brian Paulfd59f192008-05-18 16:04:55 -0600628static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700629_mesa_create_program(GLcontext *ctx)
630{
631 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700632 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700633
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800634 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
Brian65a18442006-12-19 18:46:56 -0700635 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700636
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800637 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700638
Brian3c008a02007-04-12 15:22:32 -0600639 assert(shProg->RefCount == 1);
640
Brian5b01c5e2006-12-19 18:02:03 -0700641 return name;
642}
643
644
Brian3c008a02007-04-12 15:22:32 -0600645/**
646 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
647 * DeleteProgramARB.
648 */
Brian Paulfd59f192008-05-18 16:04:55 -0600649static void
Brian5b01c5e2006-12-19 18:02:03 -0700650_mesa_delete_program2(GLcontext *ctx, GLuint name)
651{
Brian3c008a02007-04-12 15:22:32 -0600652 /*
653 * NOTE: deleting shaders/programs works a bit differently than
654 * texture objects (and buffer objects, etc). Shader/program
655 * handles/IDs exist in the hash table until the object is really
656 * deleted (refcount==0). With texture objects, the handle/ID is
657 * removed from the hash table in glDeleteTextures() while the tex
658 * object itself might linger until its refcount goes to zero.
659 */
Brian65a18442006-12-19 18:46:56 -0700660 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700661
Brian Paul530df582008-07-03 16:21:11 -0600662 shProg = _mesa_lookup_shader_program_err(ctx, name, "glDeleteProgram");
663 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700664 return;
Brian5b01c5e2006-12-19 18:02:03 -0700665
Brian9e4bae92006-12-20 09:27:42 -0700666 shProg->DeletePending = GL_TRUE;
667
Brian3c008a02007-04-12 15:22:32 -0600668 /* effectively, decr shProg's refcount */
669 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700670}
671
672
Brian Paulfd59f192008-05-18 16:04:55 -0600673static void
Brian5b01c5e2006-12-19 18:02:03 -0700674_mesa_delete_shader(GLcontext *ctx, GLuint shader)
675{
Brian Paul530df582008-07-03 16:21:11 -0600676 struct gl_shader *sh;
677
678 sh = _mesa_lookup_shader_err(ctx, shader, "glDeleteShader");
679 if (!sh)
Brian9e4bae92006-12-20 09:27:42 -0700680 return;
Brian5b01c5e2006-12-19 18:02:03 -0700681
Brian9e4bae92006-12-20 09:27:42 -0700682 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600683
684 /* effectively, decr sh's refcount */
685 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700686}
687
688
Brian Paulfd59f192008-05-18 16:04:55 -0600689static void
Brian5b01c5e2006-12-19 18:02:03 -0700690_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
691{
Brian Paul530df582008-07-03 16:21:11 -0600692 struct gl_shader_program *shProg;
Brian237b9852007-08-07 21:48:31 +0100693 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700694 GLuint i, j;
695
Brian Paul530df582008-07-03 16:21:11 -0600696 shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader");
697 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700698 return;
Brian5b01c5e2006-12-19 18:02:03 -0700699
Brian237b9852007-08-07 21:48:31 +0100700 n = shProg->NumShaders;
701
Brian5b01c5e2006-12-19 18:02:03 -0700702 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700703 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700704 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600705 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700706
Brian Paul530df582008-07-03 16:21:11 -0600707 /* release */
Brian3c008a02007-04-12 15:22:32 -0600708 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700709
Brian5b01c5e2006-12-19 18:02:03 -0700710 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700711 newList = (struct gl_shader **)
712 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700713 if (!newList) {
714 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
715 return;
716 }
717 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700718 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700719 }
720 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700721 newList[j++] = shProg->Shaders[i];
722 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700723
Brian65a18442006-12-19 18:46:56 -0700724 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600725 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600726
727#ifdef DEBUG
728 /* sanity check */
729 {
730 for (j = 0; j < shProg->NumShaders; j++) {
731 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
732 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
733 assert(shProg->Shaders[j]->RefCount > 0);
734 }
735 }
736#endif
737
Brian5b01c5e2006-12-19 18:02:03 -0700738 return;
739 }
740 }
741
742 /* not found */
Brian Paul530df582008-07-03 16:21:11 -0600743 {
744 GLenum err;
745 if (_mesa_is_shader(ctx, shader))
746 err = GL_INVALID_OPERATION;
747 else if (_mesa_is_program(ctx, shader))
748 err = GL_INVALID_OPERATION;
749 else
750 err = GL_INVALID_VALUE;
751 _mesa_error(ctx, err, "glDetachProgram(shader)");
752 return;
753 }
Brian5b01c5e2006-12-19 18:02:03 -0700754}
755
756
Brian Paulffbc66b2008-07-21 13:58:50 -0600757static GLint
758sizeof_glsl_type(GLenum type)
759{
760 switch (type) {
761 case GL_FLOAT:
762 case GL_INT:
763 case GL_BOOL:
Brian Paul8c51e002008-08-11 15:09:47 -0600764 case GL_SAMPLER_1D:
765 case GL_SAMPLER_2D:
766 case GL_SAMPLER_3D:
767 case GL_SAMPLER_CUBE:
768 case GL_SAMPLER_1D_SHADOW:
769 case GL_SAMPLER_2D_SHADOW:
770 case GL_SAMPLER_2D_RECT_ARB:
771 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
772 case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
773 case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
774 case GL_SAMPLER_CUBE_SHADOW_EXT:
Brian Paulffbc66b2008-07-21 13:58:50 -0600775 return 1;
776 case GL_FLOAT_VEC2:
777 case GL_INT_VEC2:
778 case GL_BOOL_VEC2:
779 return 2;
780 case GL_FLOAT_VEC3:
781 case GL_INT_VEC3:
782 case GL_BOOL_VEC3:
783 return 3;
784 case GL_FLOAT_VEC4:
785 case GL_INT_VEC4:
786 case GL_BOOL_VEC4:
787 return 4;
788 case GL_FLOAT_MAT2:
789 case GL_FLOAT_MAT2x3:
790 case GL_FLOAT_MAT2x4:
791 return 8; /* two float[4] vectors */
792 case GL_FLOAT_MAT3:
793 case GL_FLOAT_MAT3x2:
794 case GL_FLOAT_MAT3x4:
795 return 12; /* three float[4] vectors */
796 case GL_FLOAT_MAT4:
797 case GL_FLOAT_MAT4x2:
798 case GL_FLOAT_MAT4x3:
799 return 16; /* four float[4] vectors */
800 default:
801 _mesa_problem(NULL, "Invalid type in sizeof_glsl_type()");
802 return 1;
803 }
804}
805
806
Brian Pauleda291e2008-08-06 16:26:47 -0600807static GLboolean
808is_boolean_type(GLenum type)
809{
810 switch (type) {
811 case GL_BOOL:
812 case GL_BOOL_VEC2:
813 case GL_BOOL_VEC3:
814 case GL_BOOL_VEC4:
815 return GL_TRUE;
816 default:
817 return GL_FALSE;
818 }
819}
820
821
822static GLboolean
823is_integer_type(GLenum type)
824{
825 switch (type) {
826 case GL_INT:
827 case GL_INT_VEC2:
828 case GL_INT_VEC3:
829 case GL_INT_VEC4:
830 return GL_TRUE;
831 default:
832 return GL_FALSE;
833 }
834}
835
836
Brian Paulc4ffbf02009-02-18 17:46:00 -0700837static GLboolean
838is_sampler_type(GLenum type)
839{
840 switch (type) {
841 case GL_SAMPLER_1D:
842 case GL_SAMPLER_2D:
843 case GL_SAMPLER_3D:
844 case GL_SAMPLER_CUBE:
845 case GL_SAMPLER_1D_SHADOW:
846 case GL_SAMPLER_2D_SHADOW:
847 case GL_SAMPLER_2D_RECT_ARB:
848 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
849 case GL_SAMPLER_1D_ARRAY_EXT:
850 case GL_SAMPLER_2D_ARRAY_EXT:
851 return GL_TRUE;
852 default:
853 return GL_FALSE;
854 }
855}
856
857
Brian Paulfd59f192008-05-18 16:04:55 -0600858static void
Brian5b01c5e2006-12-19 18:02:03 -0700859_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
860 GLsizei maxLength, GLsizei *length, GLint *size,
861 GLenum *type, GLchar *nameOut)
862{
Brian Paul27341a92008-09-16 16:28:36 -0600863 const struct gl_program_parameter_list *attribs = NULL;
Brian Paul530df582008-07-03 16:21:11 -0600864 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700865
Brian Paul530df582008-07-03 16:21:11 -0600866 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
867 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700868 return;
Brian5b01c5e2006-12-19 18:02:03 -0700869
Brian Paul27341a92008-09-16 16:28:36 -0600870 if (shProg->VertexProgram)
871 attribs = shProg->VertexProgram->Base.Attributes;
872
873 if (!attribs || index >= attribs->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600874 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700875 return;
876 }
877
Brian Paul27341a92008-09-16 16:28:36 -0600878 copy_string(nameOut, maxLength, length, attribs->Parameters[index].Name);
879
Brian5b01c5e2006-12-19 18:02:03 -0700880 if (size)
Brian Paul27341a92008-09-16 16:28:36 -0600881 *size = attribs->Parameters[index].Size
882 / sizeof_glsl_type(attribs->Parameters[index].DataType);
883
Brian Paulade50832008-05-14 16:09:46 -0600884 if (type)
Brian Paul27341a92008-09-16 16:28:36 -0600885 *type = attribs->Parameters[index].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700886}
887
888
Brian Pauleda291e2008-08-06 16:26:47 -0600889static struct gl_program_parameter *
890get_uniform_parameter(const struct gl_shader_program *shProg, GLuint index)
891{
Brian Paula531a5c2009-08-13 13:44:01 -0600892 const struct gl_program *prog = NULL;
Brian Pauleda291e2008-08-06 16:26:47 -0600893 GLint progPos;
894
895 progPos = shProg->Uniforms->Uniforms[index].VertPos;
896 if (progPos >= 0) {
897 prog = &shProg->VertexProgram->Base;
898 }
899 else {
900 progPos = shProg->Uniforms->Uniforms[index].FragPos;
901 if (progPos >= 0) {
902 prog = &shProg->FragmentProgram->Base;
903 }
904 }
905
906 if (!prog || progPos < 0)
907 return NULL; /* should never happen */
908
909 return &prog->Parameters->Parameters[progPos];
910}
911
912
Brian5b01c5e2006-12-19 18:02:03 -0700913/**
914 * Called via ctx->Driver.GetActiveUniform().
915 */
Brian Paulfd59f192008-05-18 16:04:55 -0600916static void
Brian5b01c5e2006-12-19 18:02:03 -0700917_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
918 GLsizei maxLength, GLsizei *length, GLint *size,
919 GLenum *type, GLchar *nameOut)
920{
Brian Paul530df582008-07-03 16:21:11 -0600921 const struct gl_shader_program *shProg;
Brian Paula531a5c2009-08-13 13:44:01 -0600922 const struct gl_program *prog = NULL;
Brian Paul369d1852009-02-11 08:16:14 -0700923 const struct gl_program_parameter *param;
Brian Paulade50832008-05-14 16:09:46 -0600924 GLint progPos;
Brian5b01c5e2006-12-19 18:02:03 -0700925
Brian Paul530df582008-07-03 16:21:11 -0600926 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
927 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700928 return;
Brian5b01c5e2006-12-19 18:02:03 -0700929
Brian Paulade50832008-05-14 16:09:46 -0600930 if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
Brian5b01c5e2006-12-19 18:02:03 -0700931 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
932 return;
933 }
934
Brian Paulade50832008-05-14 16:09:46 -0600935 progPos = shProg->Uniforms->Uniforms[index].VertPos;
936 if (progPos >= 0) {
937 prog = &shProg->VertexProgram->Base;
938 }
939 else {
940 progPos = shProg->Uniforms->Uniforms[index].FragPos;
941 if (progPos >= 0) {
942 prog = &shProg->FragmentProgram->Base;
Brian274ac7a2007-04-18 16:05:53 -0600943 }
944 }
945
Brian Paulade50832008-05-14 16:09:46 -0600946 if (!prog || progPos < 0)
947 return; /* should never happen */
948
Brian Paul369d1852009-02-11 08:16:14 -0700949 ASSERT(progPos < prog->Parameters->NumParameters);
950 param = &prog->Parameters->Parameters[progPos];
951
952 if (nameOut) {
953 copy_string(nameOut, maxLength, length, param->Name);
954 }
955
956 if (size) {
957 GLint typeSize = sizeof_glsl_type(param->DataType);
Brian Paul20fbb242010-01-27 17:03:04 -0700958 if ((GLint) param->Size > typeSize) {
Brian Paul369d1852009-02-11 08:16:14 -0700959 /* This is an array.
960 * Array elements are placed on vector[4] boundaries so they're
961 * a multiple of four floats. We round typeSize up to next multiple
962 * of four to get the right size below.
963 */
964 typeSize = (typeSize + 3) & ~3;
965 }
966 /* Note that the returned size is in units of the <type>, not bytes */
967 *size = param->Size / typeSize;
968 }
969
970 if (type) {
971 *type = param->DataType;
972 }
Brian5b01c5e2006-12-19 18:02:03 -0700973}
974
975
976/**
977 * Called via ctx->Driver.GetAttachedShaders().
978 */
Brian Paulfd59f192008-05-18 16:04:55 -0600979static void
Brian5b01c5e2006-12-19 18:02:03 -0700980_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
981 GLsizei *count, GLuint *obj)
982{
Brian Paul530df582008-07-03 16:21:11 -0600983 struct gl_shader_program *shProg =
984 _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders");
Brian65a18442006-12-19 18:46:56 -0700985 if (shProg) {
Brian Paul530df582008-07-03 16:21:11 -0600986 GLuint i;
987 for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) {
Brian65a18442006-12-19 18:46:56 -0700988 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700989 }
990 if (count)
991 *count = i;
992 }
Brian5b01c5e2006-12-19 18:02:03 -0700993}
994
995
Brian Paulfd59f192008-05-18 16:04:55 -0600996static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700997_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700998{
Ian Romanick905d8e02008-09-29 12:27:00 -0700999 GLint handle = 0;
1000
1001 if (pname == GL_PROGRAM_OBJECT_ARB) {
1002 CALL_GetIntegerv(ctx->Exec, (GL_CURRENT_PROGRAM, &handle));
1003 } else {
Brian34ae99d2006-12-18 08:28:54 -07001004 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
1005 }
Ian Romanick905d8e02008-09-29 12:27:00 -07001006
1007 return handle;
Brian34ae99d2006-12-18 08:28:54 -07001008}
1009
1010
Brian Paulfd59f192008-05-18 16:04:55 -06001011static void
Brian5b01c5e2006-12-19 18:02:03 -07001012_mesa_get_programiv(GLcontext *ctx, GLuint program,
1013 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -07001014{
Brian Paul27341a92008-09-16 16:28:36 -06001015 const struct gl_program_parameter_list *attribs;
Brian65a18442006-12-19 18:46:56 -07001016 struct gl_shader_program *shProg
1017 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -07001018
Brian65a18442006-12-19 18:46:56 -07001019 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -07001020 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -07001021 return;
1022 }
1023
Brian Paul27341a92008-09-16 16:28:36 -06001024 if (shProg->VertexProgram)
1025 attribs = shProg->VertexProgram->Base.Attributes;
1026 else
1027 attribs = NULL;
1028
Brian5b01c5e2006-12-19 18:02:03 -07001029 switch (pname) {
1030 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -07001031 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -07001032 break;
1033 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -07001034 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -07001035 break;
Brian5b01c5e2006-12-19 18:02:03 -07001036 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -07001037 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -07001038 break;
1039 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001040 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001041 break;
1042 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -07001043 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -07001044 break;
1045 case GL_ACTIVE_ATTRIBUTES:
Brian Paul27341a92008-09-16 16:28:36 -06001046 *params = attribs ? attribs->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001047 break;
1048 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian Paul27341a92008-09-16 16:28:36 -06001049 *params = _mesa_longest_parameter_name(attribs, PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -07001050 break;
1051 case GL_ACTIVE_UNIFORMS:
Brian Paulade50832008-05-14 16:09:46 -06001052 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001053 break;
1054 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian Paulade50832008-05-14 16:09:46 -06001055 *params = _mesa_longest_uniform_name(shProg->Uniforms);
Brian274ac7a2007-04-18 16:05:53 -06001056 if (*params > 0)
1057 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -07001058 break;
Brian Paulbda6ad22008-08-06 12:45:14 -06001059 case GL_PROGRAM_BINARY_LENGTH_OES:
1060 *params = 0;
1061 break;
Brian34ae99d2006-12-18 08:28:54 -07001062 default:
Brian5b01c5e2006-12-19 18:02:03 -07001063 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
1064 return;
Brian34ae99d2006-12-18 08:28:54 -07001065 }
Brian5b01c5e2006-12-19 18:02:03 -07001066}
Brian34ae99d2006-12-18 08:28:54 -07001067
Brian34ae99d2006-12-18 08:28:54 -07001068
Brian Paulfd59f192008-05-18 16:04:55 -06001069static void
Brian5b01c5e2006-12-19 18:02:03 -07001070_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
1071{
Brian Paul530df582008-07-03 16:21:11 -06001072 struct gl_shader *shader = _mesa_lookup_shader_err(ctx, name, "glGetShaderiv");
Brian5b01c5e2006-12-19 18:02:03 -07001073
1074 if (!shader) {
Brian5b01c5e2006-12-19 18:02:03 -07001075 return;
1076 }
Brian65a18442006-12-19 18:46:56 -07001077
Brian5b01c5e2006-12-19 18:02:03 -07001078 switch (pname) {
1079 case GL_SHADER_TYPE:
1080 *params = shader->Type;
1081 break;
1082 case GL_DELETE_STATUS:
1083 *params = shader->DeletePending;
1084 break;
1085 case GL_COMPILE_STATUS:
1086 *params = shader->CompileStatus;
1087 break;
1088 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001089 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001090 break;
1091 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001092 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001093 break;
1094 default:
1095 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
1096 return;
1097 }
1098}
1099
1100
Brian Paulfd59f192008-05-18 16:04:55 -06001101static void
Brian5b01c5e2006-12-19 18:02:03 -07001102_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
1103 GLsizei *length, GLchar *infoLog)
1104{
Brian65a18442006-12-19 18:46:56 -07001105 struct gl_shader_program *shProg
1106 = _mesa_lookup_shader_program(ctx, program);
1107 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -07001108 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
1109 return;
1110 }
Brian65a18442006-12-19 18:46:56 -07001111 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -07001112}
1113
1114
Brian Paulfd59f192008-05-18 16:04:55 -06001115static void
Brian5b01c5e2006-12-19 18:02:03 -07001116_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
1117 GLsizei *length, GLchar *infoLog)
1118{
Brian65a18442006-12-19 18:46:56 -07001119 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
1120 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001121 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
1122 return;
1123 }
Brian65a18442006-12-19 18:46:56 -07001124 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -07001125}
1126
1127
1128/**
1129 * Called via ctx->Driver.GetShaderSource().
1130 */
Brian Paulfd59f192008-05-18 16:04:55 -06001131static void
Brian5b01c5e2006-12-19 18:02:03 -07001132_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
1133 GLsizei *length, GLchar *sourceOut)
1134{
Brian Paul530df582008-07-03 16:21:11 -06001135 struct gl_shader *sh;
1136 sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource");
Brian65a18442006-12-19 18:46:56 -07001137 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001138 return;
1139 }
Brian65a18442006-12-19 18:46:56 -07001140 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -07001141}
1142
1143
Brian Paul5b982362008-08-06 13:07:09 -06001144static void
1145get_matrix_dims(GLenum type, GLint *rows, GLint *cols)
1146{
1147 switch (type) {
1148 case GL_FLOAT_MAT2:
1149 *rows = *cols = 2;
1150 break;
1151 case GL_FLOAT_MAT2x3:
1152 *rows = 3;
1153 *cols = 2;
1154 break;
1155 case GL_FLOAT_MAT2x4:
1156 *rows = 4;
1157 *cols = 2;
1158 break;
1159 case GL_FLOAT_MAT3:
1160 *rows = 3;
1161 *cols = 3;
1162 break;
1163 case GL_FLOAT_MAT3x2:
1164 *rows = 2;
1165 *cols = 3;
1166 break;
1167 case GL_FLOAT_MAT3x4:
1168 *rows = 4;
1169 *cols = 3;
1170 break;
1171 case GL_FLOAT_MAT4:
1172 *rows = 4;
1173 *cols = 4;
1174 break;
1175 case GL_FLOAT_MAT4x2:
1176 *rows = 2;
1177 *cols = 4;
1178 break;
1179 case GL_FLOAT_MAT4x3:
1180 *rows = 3;
1181 *cols = 4;
1182 break;
1183 default:
1184 *rows = *cols = 0;
1185 }
1186}
1187
1188
1189/**
1190 * Determine the number of rows and columns occupied by a uniform
Brian Paulea9568d2008-09-16 08:55:54 -06001191 * according to its datatype. For non-matrix types (such as GL_FLOAT_VEC4),
1192 * the number of rows = 1 and cols = number of elements in the vector.
Brian Paul5b982362008-08-06 13:07:09 -06001193 */
1194static void
1195get_uniform_rows_cols(const struct gl_program_parameter *p,
1196 GLint *rows, GLint *cols)
1197{
1198 get_matrix_dims(p->DataType, rows, cols);
1199 if (*rows == 0 && *cols == 0) {
1200 /* not a matrix type, probably a float or vector */
Brian Paulea9568d2008-09-16 08:55:54 -06001201 if (p->Size <= 4) {
1202 *rows = 1;
1203 *cols = p->Size;
1204 }
1205 else {
1206 *rows = p->Size / 4 + 1;
1207 if (p->Size % 4 == 0)
1208 *cols = 4;
1209 else
1210 *cols = p->Size % 4;
1211 }
Brian Paul5b982362008-08-06 13:07:09 -06001212 }
1213}
1214
1215
Brian5b01c5e2006-12-19 18:02:03 -07001216/**
Brian Paul4ef7a932009-02-11 09:03:16 -07001217 * Helper for get_uniform[fi]v() functions.
1218 * Given a shader program name and uniform location, return a pointer
1219 * to the shader program and return the program parameter position.
Brian5b01c5e2006-12-19 18:02:03 -07001220 */
Brian Paul4ef7a932009-02-11 09:03:16 -07001221static void
1222lookup_uniform_parameter(GLcontext *ctx, GLuint program, GLint location,
1223 struct gl_program **progOut, GLint *paramPosOut)
Brian5b01c5e2006-12-19 18:02:03 -07001224{
Brian65a18442006-12-19 18:46:56 -07001225 struct gl_shader_program *shProg
Brian Paulbda6ad22008-08-06 12:45:14 -06001226 = _mesa_lookup_shader_program_err(ctx, program, "glGetUniform[if]v");
Brian Paul4ef7a932009-02-11 09:03:16 -07001227 struct gl_program *prog = NULL;
1228 GLint progPos = -1;
Brian Paulade50832008-05-14 16:09:46 -06001229
Brian Paul4ef7a932009-02-11 09:03:16 -07001230 /* if shProg is NULL, we'll have already recorded an error */
1231
1232 if (shProg) {
1233 if (!shProg->Uniforms ||
1234 location < 0 ||
1235 location >= (GLint) shProg->Uniforms->NumUniforms) {
1236 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
1237 }
1238 else {
1239 /* OK, find the gl_program and program parameter location */
Brian Paulade50832008-05-14 16:09:46 -06001240 progPos = shProg->Uniforms->Uniforms[location].VertPos;
1241 if (progPos >= 0) {
1242 prog = &shProg->VertexProgram->Base;
Brian5b01c5e2006-12-19 18:02:03 -07001243 }
Brian Paulade50832008-05-14 16:09:46 -06001244 else {
1245 progPos = shProg->Uniforms->Uniforms[location].FragPos;
1246 if (progPos >= 0) {
1247 prog = &shProg->FragmentProgram->Base;
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001248 }
Brian Paulade50832008-05-14 16:09:46 -06001249 }
Brian5b01c5e2006-12-19 18:02:03 -07001250 }
1251 }
Brian Paul4ef7a932009-02-11 09:03:16 -07001252
1253 *progOut = prog;
1254 *paramPosOut = progPos;
Brian Paul2be54a82008-07-08 16:17:04 -06001255}
1256
1257
1258/**
1259 * Called via ctx->Driver.GetUniformfv().
1260 */
1261static void
1262_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1263 GLfloat *params)
1264{
Brian Paul4ef7a932009-02-11 09:03:16 -07001265 struct gl_program *prog;
1266 GLint paramPos;
1267
1268 lookup_uniform_parameter(ctx, program, location, &prog, &paramPos);
1269
1270 if (prog) {
1271 const struct gl_program_parameter *p =
1272 &prog->Parameters->Parameters[paramPos];
1273 GLint rows, cols, i, j, k;
1274
1275 get_uniform_rows_cols(p, &rows, &cols);
1276
1277 k = 0;
1278 for (i = 0; i < rows; i++) {
1279 for (j = 0; j < cols; j++ ) {
1280 params[k++] = prog->Parameters->ParameterValues[paramPos+i][j];
1281 }
1282 }
1283 }
Brian Paul2be54a82008-07-08 16:17:04 -06001284}
1285
1286
1287/**
1288 * Called via ctx->Driver.GetUniformiv().
Brian Paul4ef7a932009-02-11 09:03:16 -07001289 * \sa _mesa_get_uniformfv, only difference is a cast.
Brian Paul2be54a82008-07-08 16:17:04 -06001290 */
1291static void
1292_mesa_get_uniformiv(GLcontext *ctx, GLuint program, GLint location,
1293 GLint *params)
1294{
Brian Paul4ef7a932009-02-11 09:03:16 -07001295 struct gl_program *prog;
1296 GLint paramPos;
1297
1298 lookup_uniform_parameter(ctx, program, location, &prog, &paramPos);
1299
1300 if (prog) {
1301 const struct gl_program_parameter *p =
1302 &prog->Parameters->Parameters[paramPos];
1303 GLint rows, cols, i, j, k;
1304
1305 get_uniform_rows_cols(p, &rows, &cols);
1306
1307 k = 0;
1308 for (i = 0; i < rows; i++) {
1309 for (j = 0; j < cols; j++ ) {
1310 params[k++] = (GLint) prog->Parameters->ParameterValues[paramPos+i][j];
1311 }
1312 }
Brian Paul2be54a82008-07-08 16:17:04 -06001313 }
Brian5b01c5e2006-12-19 18:02:03 -07001314}
1315
1316
1317/**
Brian Pauleda291e2008-08-06 16:26:47 -06001318 * The value returned by GetUniformLocation actually encodes two things:
1319 * 1. the index into the prog->Uniforms[] array for the uniform
1320 * 2. an offset in the prog->ParameterValues[] array for specifying array
1321 * elements or structure fields.
1322 * This function merges those two values.
1323 */
1324static void
1325merge_location_offset(GLint *location, GLint offset)
1326{
1327 *location = *location | (offset << 16);
1328}
1329
1330
1331/**
1332 * Seperate the uniform location and parameter offset. See above.
1333 */
1334static void
1335split_location_offset(GLint *location, GLint *offset)
1336{
1337 *offset = (*location >> 16);
1338 *location = *location & 0xffff;
1339}
1340
1341
1342/**
Brian5b01c5e2006-12-19 18:02:03 -07001343 * Called via ctx->Driver.GetUniformLocation().
Brian Pauleda291e2008-08-06 16:26:47 -06001344 *
1345 * The return value will encode two values, the uniform location and an
1346 * offset (used for arrays, structs).
Brian5b01c5e2006-12-19 18:02:03 -07001347 */
Brian Paulfd59f192008-05-18 16:04:55 -06001348static GLint
Brian5b01c5e2006-12-19 18:02:03 -07001349_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
1350{
Brian Pauleda291e2008-08-06 16:26:47 -06001351 GLint offset = 0, location = -1;
1352
Brian Paul530df582008-07-03 16:21:11 -06001353 struct gl_shader_program *shProg =
1354 _mesa_lookup_shader_program_err(ctx, program, "glGetUniformLocation");
1355
Brian Paulade50832008-05-14 16:09:46 -06001356 if (!shProg)
1357 return -1;
Brian5b01c5e2006-12-19 18:02:03 -07001358
Brian Paule06565b2008-07-04 09:58:55 -06001359 if (shProg->LinkStatus == GL_FALSE) {
1360 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
1361 return -1;
1362 }
1363
Brian Paul530df582008-07-03 16:21:11 -06001364 /* XXX we should return -1 if the uniform was declared, but not
1365 * actually used.
1366 */
1367
Brian Pauleda291e2008-08-06 16:26:47 -06001368 /* XXX we need to be able to parse uniform names for structs and arrays
1369 * such as:
1370 * mymatrix[1]
1371 * mystruct.field1
1372 */
1373
1374 {
1375 /* handle 1-dimension arrays here... */
1376 char *c = strchr(name, '[');
1377 if (c) {
1378 /* truncate name at [ */
1379 const GLint len = c - name;
1380 GLchar *newName = _mesa_malloc(len + 1);
1381 if (!newName)
1382 return -1; /* out of mem */
1383 _mesa_memcpy(newName, name, len);
1384 newName[len] = 0;
1385
1386 location = _mesa_lookup_uniform(shProg->Uniforms, newName);
1387 if (location >= 0) {
1388 const GLint element = _mesa_atoi(c + 1);
1389 if (element > 0) {
1390 /* get type of the uniform array element */
1391 struct gl_program_parameter *p;
1392 p = get_uniform_parameter(shProg, location);
1393 if (p) {
1394 GLint rows, cols;
1395 get_matrix_dims(p->DataType, &rows, &cols);
1396 if (rows < 1)
1397 rows = 1;
1398 offset = element * rows;
1399 }
1400 }
1401 }
1402
1403 _mesa_free(newName);
1404 }
1405 }
1406
1407 if (location < 0) {
1408 location = _mesa_lookup_uniform(shProg->Uniforms, name);
1409 }
1410
1411 if (location >= 0) {
1412 merge_location_offset(&location, offset);
1413 }
1414
1415 return location;
Brian5b01c5e2006-12-19 18:02:03 -07001416}
1417
1418
Brian34ae99d2006-12-18 08:28:54 -07001419
Brian5b01c5e2006-12-19 18:02:03 -07001420/**
1421 * Called via ctx->Driver.ShaderSource()
1422 */
Brian Paulfd59f192008-05-18 16:04:55 -06001423static void
Brian5b01c5e2006-12-19 18:02:03 -07001424_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -07001425{
Brian Paul530df582008-07-03 16:21:11 -06001426 struct gl_shader *sh;
1427
1428 sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource");
1429 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001430 return;
Brian34ae99d2006-12-18 08:28:54 -07001431
Brian34ae99d2006-12-18 08:28:54 -07001432 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -07001433 if (sh->Source) {
1434 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -07001435 }
Brian65a18442006-12-19 18:46:56 -07001436 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -07001437 sh->CompileStatus = GL_FALSE;
Brian Paulf7783ba2009-08-04 15:35:48 -06001438#ifdef DEBUG
1439 sh->SourceChecksum = _mesa_str_checksum(sh->Source);
1440#endif
Brian34ae99d2006-12-18 08:28:54 -07001441}
1442
1443
Brian5b01c5e2006-12-19 18:02:03 -07001444/**
1445 * Called via ctx->Driver.CompileShader()
1446 */
Brian Paulfd59f192008-05-18 16:04:55 -06001447static void
Brian5b01c5e2006-12-19 18:02:03 -07001448_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -07001449{
Brian Paul530df582008-07-03 16:21:11 -06001450 struct gl_shader *sh;
Brian34ae99d2006-12-18 08:28:54 -07001451
Brian Paul530df582008-07-03 16:21:11 -06001452 sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader");
1453 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001454 return;
Brian34ae99d2006-12-18 08:28:54 -07001455
Brian Paul65fc2ca2009-03-19 10:25:24 -06001456 /* set default pragma state for shader */
1457 sh->Pragmas = ctx->Shader.DefaultPragmas;
1458
Brian Paulcb136e02009-01-22 10:34:15 -07001459 /* this call will set the sh->CompileStatus field to indicate if
1460 * compilation was successful.
1461 */
1462 (void) _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -07001463}
1464
1465
Brian5b01c5e2006-12-19 18:02:03 -07001466/**
1467 * Called via ctx->Driver.LinkProgram()
1468 */
Brian Paulfd59f192008-05-18 16:04:55 -06001469static void
Brian5b01c5e2006-12-19 18:02:03 -07001470_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001471{
Brian65a18442006-12-19 18:46:56 -07001472 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001473
Brian Paul530df582008-07-03 16:21:11 -06001474 shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
1475 if (!shProg)
Brian34ae99d2006-12-18 08:28:54 -07001476 return;
Brian34ae99d2006-12-18 08:28:54 -07001477
Briandf43fb62008-05-06 23:08:51 -06001478 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1479
Brianc1771912007-02-16 09:56:19 -07001480 _slang_link(ctx, program, shProg);
Brian Paulac3c8e32009-09-14 17:32:03 -06001481
1482 /* debug code */
1483 if (0) {
1484 GLuint i;
1485
1486 _mesa_printf("Link %u shaders in program %u: %s\n",
1487 shProg->NumShaders, shProg->Name,
1488 shProg->LinkStatus ? "Success" : "Failed");
1489
1490 for (i = 0; i < shProg->NumShaders; i++) {
1491 _mesa_printf(" shader %u, type 0x%x\n",
1492 shProg->Shaders[i]->Name,
1493 shProg->Shaders[i]->Type);
1494 }
1495 }
Brian34ae99d2006-12-18 08:28:54 -07001496}
1497
1498
1499/**
Brian Paul346250b2009-10-23 16:31:48 -06001500 * Print basic shader info (for debug).
1501 */
1502static void
1503print_shader_info(const struct gl_shader_program *shProg)
1504{
1505 GLuint i;
1506
1507 _mesa_printf("Mesa: glUseProgram(%u)\n", shProg->Name);
1508 for (i = 0; i < shProg->NumShaders; i++) {
1509 const char *s;
1510 switch (shProg->Shaders[i]->Type) {
1511 case GL_VERTEX_SHADER:
1512 s = "vertex";
1513 break;
1514 case GL_FRAGMENT_SHADER:
1515 s = "fragment";
1516 break;
1517 case GL_GEOMETRY_SHADER:
1518 s = "geometry";
1519 break;
1520 default:
1521 s = "";
1522 }
1523 _mesa_printf(" %s shader %u, checksum %u\n", s,
1524 shProg->Shaders[i]->Name,
1525 shProg->Shaders[i]->SourceChecksum);
1526 }
1527 if (shProg->VertexProgram)
1528 _mesa_printf(" vert prog %u\n", shProg->VertexProgram->Base.Id);
1529 if (shProg->FragmentProgram)
1530 _mesa_printf(" frag prog %u\n", shProg->FragmentProgram->Base.Id);
1531}
1532
1533
1534/**
Brian5b01c5e2006-12-19 18:02:03 -07001535 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001536 */
Brian5b01c5e2006-12-19 18:02:03 -07001537void
1538_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001539{
Brian3c008a02007-04-12 15:22:32 -06001540 struct gl_shader_program *shProg;
1541
Brian00d63aa2007-02-03 11:35:02 -07001542 if (ctx->Shader.CurrentProgram &&
1543 ctx->Shader.CurrentProgram->Name == program) {
1544 /* no-op */
1545 return;
1546 }
1547
Brian5b01c5e2006-12-19 18:02:03 -07001548 if (program) {
Brian Paul530df582008-07-03 16:21:11 -06001549 shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
Brian65a18442006-12-19 18:46:56 -07001550 if (!shProg) {
Brian Paul530df582008-07-03 16:21:11 -06001551 return;
1552 }
1553 if (!shProg->LinkStatus) {
Brian Paul621c9992009-02-18 13:28:12 -07001554 _mesa_error(ctx, GL_INVALID_OPERATION,
1555 "glUseProgram(program %u not linked)", program);
Brian5b01c5e2006-12-19 18:02:03 -07001556 return;
1557 }
Brian Paul4eda17d2009-03-13 09:11:42 -06001558
1559 /* debug code */
Brian Paul2ee7fd82009-10-15 15:25:52 -06001560 if (ctx->Shader.Flags & GLSL_USE_PROG) {
Brian Paul346250b2009-10-23 16:31:48 -06001561 print_shader_info(shProg);
Brian Paul4eda17d2009-03-13 09:11:42 -06001562 }
Brian5b01c5e2006-12-19 18:02:03 -07001563 }
1564 else {
Brian3c008a02007-04-12 15:22:32 -06001565 shProg = NULL;
1566 }
1567
Brian Paulb44304e2009-10-27 20:09:33 -06001568 if (ctx->Shader.CurrentProgram != shProg) {
1569 FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
1570 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
1571 }
Brian5b01c5e2006-12-19 18:02:03 -07001572}
Brian34ae99d2006-12-18 08:28:54 -07001573
Brian5b01c5e2006-12-19 18:02:03 -07001574
Brian Paulade50832008-05-14 16:09:46 -06001575
1576/**
Brian Paul517401a2008-11-06 15:04:11 -07001577 * Update the vertex/fragment program's TexturesUsed array.
1578 *
1579 * This needs to be called after glUniform(set sampler var) is called.
1580 * A call to glUniform(samplerVar, value) causes a sampler to point to a
1581 * particular texture unit. We know the sampler's texture target
1582 * (1D/2D/3D/etc) from compile time but the sampler's texture unit is
1583 * set by glUniform() calls.
1584 *
1585 * So, scan the program->SamplerUnits[] and program->SamplerTargets[]
1586 * information to update the prog->TexturesUsed[] values.
1587 * Each value of TexturesUsed[unit] is one of zero, TEXTURE_1D_INDEX,
1588 * TEXTURE_2D_INDEX, TEXTURE_3D_INDEX, etc.
1589 * We'll use that info for state validation before rendering.
Brian Paulade50832008-05-14 16:09:46 -06001590 */
Brian Paul517401a2008-11-06 15:04:11 -07001591void
1592_mesa_update_shader_textures_used(struct gl_program *prog)
Brian Paulade50832008-05-14 16:09:46 -06001593{
1594 GLuint s;
1595
1596 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1597
1598 for (s = 0; s < MAX_SAMPLERS; s++) {
1599 if (prog->SamplersUsed & (1 << s)) {
Brian Paulf05344f2009-08-26 10:58:06 -06001600 GLuint unit = prog->SamplerUnits[s];
1601 GLuint tgt = prog->SamplerTargets[s];
1602 assert(unit < MAX_TEXTURE_IMAGE_UNITS);
1603 assert(tgt < NUM_TEXTURE_TARGETS);
1604 prog->TexturesUsed[unit] |= (1 << tgt);
Brian Paulade50832008-05-14 16:09:46 -06001605 }
1606 }
1607}
1608
1609
1610/**
Brian Paulffbc66b2008-07-21 13:58:50 -06001611 * Check if the type given by userType is allowed to set a uniform of the
1612 * target type. Generally, equivalence is required, but setting Boolean
1613 * uniforms can be done with glUniformiv or glUniformfv.
1614 */
1615static GLboolean
1616compatible_types(GLenum userType, GLenum targetType)
1617{
1618 if (userType == targetType)
1619 return GL_TRUE;
1620
1621 if (targetType == GL_BOOL && (userType == GL_FLOAT || userType == GL_INT))
1622 return GL_TRUE;
1623
1624 if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 ||
1625 userType == GL_INT_VEC2))
1626 return GL_TRUE;
1627
1628 if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 ||
1629 userType == GL_INT_VEC3))
1630 return GL_TRUE;
1631
1632 if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 ||
1633 userType == GL_INT_VEC4))
1634 return GL_TRUE;
1635
Brianb36749d2008-07-21 20:42:05 -06001636 if (is_sampler_type(targetType) && userType == GL_INT)
1637 return GL_TRUE;
1638
Brian Paulffbc66b2008-07-21 13:58:50 -06001639 return GL_FALSE;
1640}
1641
1642
1643/**
Brian Paulade50832008-05-14 16:09:46 -06001644 * Set the value of a program's uniform variable.
1645 * \param program the program whose uniform to update
Brian Pauleda291e2008-08-06 16:26:47 -06001646 * \param index the index of the program parameter for the uniform
1647 * \param offset additional parameter slot offset (for arrays)
Brian Paulc4ffbf02009-02-18 17:46:00 -07001648 * \param type the incoming datatype of 'values'
Brian Paulade50832008-05-14 16:09:46 -06001649 * \param count the number of uniforms to set
Brian Paulc4ffbf02009-02-18 17:46:00 -07001650 * \param elems number of elements per uniform (1, 2, 3 or 4)
1651 * \param values the new values, of datatype 'type'
Brian Paulade50832008-05-14 16:09:46 -06001652 */
1653static void
Brian Pauleda291e2008-08-06 16:26:47 -06001654set_program_uniform(GLcontext *ctx, struct gl_program *program,
1655 GLint index, GLint offset,
1656 GLenum type, GLsizei count, GLint elems,
1657 const void *values)
Brian Paulade50832008-05-14 16:09:46 -06001658{
Brian Paul6df38e62009-08-26 14:35:45 -06001659 const struct gl_program_parameter *param =
Brian Paul949e7382008-11-05 09:17:55 -07001660 &program->Parameters->Parameters[index];
1661
Brian Pauleda291e2008-08-06 16:26:47 -06001662 assert(offset >= 0);
Brian Paulc4ffbf02009-02-18 17:46:00 -07001663 assert(elems >= 1);
1664 assert(elems <= 4);
Brian Pauleda291e2008-08-06 16:26:47 -06001665
Brian Paul949e7382008-11-05 09:17:55 -07001666 if (!compatible_types(type, param->DataType)) {
Brian Paulffbc66b2008-07-21 13:58:50 -06001667 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
1668 return;
1669 }
1670
Michal Krolc5c71302008-08-07 16:23:15 +02001671 if (index + offset > (GLint) program->Parameters->Size) {
Brian Pauleda291e2008-08-06 16:26:47 -06001672 /* out of bounds! */
1673 return;
1674 }
1675
Brian Paul949e7382008-11-05 09:17:55 -07001676 if (param->Type == PROGRAM_SAMPLER) {
Brian Paulade50832008-05-14 16:09:46 -06001677 /* This controls which texture unit which is used by a sampler */
Brian Paulbabb5ba2009-08-26 14:29:50 -06001678 GLboolean changed = GL_FALSE;
Brian Paul2b4f0212009-02-11 09:12:34 -07001679 GLint i;
Brian Paulade50832008-05-14 16:09:46 -06001680
Brian Paul6df38e62009-08-26 14:35:45 -06001681 /* this should have been caught by the compatible_types() check */
1682 ASSERT(type == GL_INT);
Brian Paulade50832008-05-14 16:09:46 -06001683
Brian Paul6df38e62009-08-26 14:35:45 -06001684 /* loop over number of samplers to change */
Brian Paul2b4f0212009-02-11 09:12:34 -07001685 for (i = 0; i < count; i++) {
Brian Paul04d17072009-08-26 11:39:24 -06001686 GLuint sampler =
1687 (GLuint) program->Parameters->ParameterValues[index + offset + i][0];
1688 GLuint texUnit = ((GLuint *) values)[i];
Brian Paulade50832008-05-14 16:09:46 -06001689
Brian Paul2b4f0212009-02-11 09:12:34 -07001690 /* check that the sampler (tex unit index) is legal */
1691 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1692 _mesa_error(ctx, GL_INVALID_VALUE,
1693 "glUniform1(invalid sampler/tex unit index)");
1694 return;
1695 }
1696
1697 /* This maps a sampler to a texture unit: */
1698 if (sampler < MAX_SAMPLERS) {
Brian Paul04d17072009-08-26 11:39:24 -06001699#if 0
1700 _mesa_printf("Set program %p sampler %d '%s' to unit %u\n",
1701 program, sampler, param->Name, texUnit);
1702#endif
Brian Paulbabb5ba2009-08-26 14:29:50 -06001703 if (program->SamplerUnits[sampler] != texUnit) {
1704 program->SamplerUnits[sampler] = texUnit;
1705 changed = GL_TRUE;
1706 }
Brian Paul2b4f0212009-02-11 09:12:34 -07001707 }
Brian Paulade50832008-05-14 16:09:46 -06001708 }
1709
Brian Paulbabb5ba2009-08-26 14:29:50 -06001710 if (changed) {
1711 /* When a sampler's value changes it usually requires rewriting
1712 * a GPU program's TEX instructions since there may not be a
1713 * sampler->texture lookup table. We signal this with the
1714 * ProgramStringNotify() callback.
1715 */
1716 FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM);
1717 _mesa_update_shader_textures_used(program);
Brian Paul4ac9c802010-02-04 16:49:35 -07001718 /* Do we need to care about the return value here?
1719 * This should not be the first time the driver was notified of
1720 * this program.
1721 */
1722 (void) ctx->Driver.ProgramStringNotify(ctx, program->Target, program);
Brian Paulbabb5ba2009-08-26 14:29:50 -06001723 }
Brian Paulade50832008-05-14 16:09:46 -06001724 }
1725 else {
1726 /* ordinary uniform variable */
Brian Paul6df38e62009-08-26 14:35:45 -06001727 const GLboolean isUniformBool = is_boolean_type(param->DataType);
1728 const GLboolean areIntValues = is_integer_type(type);
Brian Paul2c1ea072009-02-11 08:46:21 -07001729 const GLint slots = (param->Size + 3) / 4;
1730 const GLint typeSize = sizeof_glsl_type(param->DataType);
Brian Paul6df38e62009-08-26 14:35:45 -06001731 GLsizei k, i;
Brian Paulade50832008-05-14 16:09:46 -06001732
Brian Paul20fbb242010-01-27 17:03:04 -07001733 if ((GLint) param->Size > typeSize) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001734 /* an array */
1735 /* we'll ignore extra data below */
1736 }
1737 else {
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001738 /* non-array: count must be at most one; count == 0 is handled by the loop below */
1739 if (count > 1) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001740 _mesa_error(ctx, GL_INVALID_OPERATION,
1741 "glUniform(uniform is not an array)");
1742 return;
1743 }
Brian Paulade50832008-05-14 16:09:46 -06001744 }
1745
Brian Paulc4ffbf02009-02-18 17:46:00 -07001746 /* loop over number of array elements */
Brian Paulade50832008-05-14 16:09:46 -06001747 for (k = 0; k < count; k++) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001748 GLfloat *uniformVal;
1749
Brian Paulb9d8f712009-02-18 17:40:44 -07001750 if (offset + k >= slots) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001751 /* Extra array data is ignored */
1752 break;
1753 }
1754
Brian Paulc4ffbf02009-02-18 17:46:00 -07001755 /* uniformVal (the destination) is always float[4] */
Brian Paul2c1ea072009-02-11 08:46:21 -07001756 uniformVal = program->Parameters->ParameterValues[index + offset + k];
Brian Paulc4ffbf02009-02-18 17:46:00 -07001757
1758 if (areIntValues) {
1759 /* convert user's ints to floats */
Brian Paulade50832008-05-14 16:09:46 -06001760 const GLint *iValues = ((const GLint *) values) + k * elems;
1761 for (i = 0; i < elems; i++) {
1762 uniformVal[i] = (GLfloat) iValues[i];
1763 }
1764 }
1765 else {
1766 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1767 for (i = 0; i < elems; i++) {
1768 uniformVal[i] = fValues[i];
1769 }
1770 }
Brian Pauleda291e2008-08-06 16:26:47 -06001771
1772 /* if the uniform is bool-valued, convert to 1.0 or 0.0 */
Brian Paulc4ffbf02009-02-18 17:46:00 -07001773 if (isUniformBool) {
Brian Pauleda291e2008-08-06 16:26:47 -06001774 for (i = 0; i < elems; i++) {
Michal Krolc5c71302008-08-07 16:23:15 +02001775 uniformVal[i] = uniformVal[i] ? 1.0f : 0.0f;
Brian Pauleda291e2008-08-06 16:26:47 -06001776 }
1777 }
Brian Paulade50832008-05-14 16:09:46 -06001778 }
1779 }
1780}
1781
1782
Brian5b01c5e2006-12-19 18:02:03 -07001783/**
1784 * Called via ctx->Driver.Uniform().
1785 */
Brian Paulfd59f192008-05-18 16:04:55 -06001786static void
Brian5b01c5e2006-12-19 18:02:03 -07001787_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1788 const GLvoid *values, GLenum type)
1789{
Brian3a8e2772006-12-20 17:19:16 -07001790 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paul2d76a0d2008-11-10 12:33:17 -07001791 struct gl_uniform *uniform;
Brian Pauleda291e2008-08-06 16:26:47 -06001792 GLint elems, offset;
Brian Paule01a03d2009-02-06 10:21:36 -07001793 GLenum basicType;
Brian3a8e2772006-12-20 17:19:16 -07001794
1795 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001796 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001797 return;
1798 }
1799
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001800 if (location == -1)
1801 return; /* The standard specifies this as a no-op */
1802
Brian Paul234f03e2009-02-11 09:05:08 -07001803 if (location < -1) {
1804 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(location)");
1805 return;
1806 }
1807
Brian Pauleda291e2008-08-06 16:26:47 -06001808 split_location_offset(&location, &offset);
1809
Brian Paulade50832008-05-14 16:09:46 -06001810 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
1811 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
Brian3a8e2772006-12-20 17:19:16 -07001812 return;
1813 }
1814
Brian52363952007-03-13 16:50:24 -06001815 if (count < 0) {
1816 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1817 return;
1818 }
1819
Brian98650bd2007-03-13 16:32:48 -06001820 switch (type) {
1821 case GL_FLOAT:
Brian Paule01a03d2009-02-06 10:21:36 -07001822 basicType = GL_FLOAT;
1823 elems = 1;
1824 break;
Brian98650bd2007-03-13 16:32:48 -06001825 case GL_INT:
Brian Paule01a03d2009-02-06 10:21:36 -07001826 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001827 elems = 1;
1828 break;
1829 case GL_FLOAT_VEC2:
Brian Paule01a03d2009-02-06 10:21:36 -07001830 basicType = GL_FLOAT;
1831 elems = 2;
1832 break;
Brian98650bd2007-03-13 16:32:48 -06001833 case GL_INT_VEC2:
Brian Paule01a03d2009-02-06 10:21:36 -07001834 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001835 elems = 2;
1836 break;
1837 case GL_FLOAT_VEC3:
Brian Paule01a03d2009-02-06 10:21:36 -07001838 basicType = GL_FLOAT;
1839 elems = 3;
1840 break;
Brian98650bd2007-03-13 16:32:48 -06001841 case GL_INT_VEC3:
Brian Paule01a03d2009-02-06 10:21:36 -07001842 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001843 elems = 3;
1844 break;
1845 case GL_FLOAT_VEC4:
Brian Paule01a03d2009-02-06 10:21:36 -07001846 basicType = GL_FLOAT;
1847 elems = 4;
1848 break;
Brian98650bd2007-03-13 16:32:48 -06001849 case GL_INT_VEC4:
Brian Paule01a03d2009-02-06 10:21:36 -07001850 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001851 elems = 4;
1852 break;
1853 default:
1854 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1855 return;
Brian89dc4852007-01-04 14:35:44 -07001856 }
Brian98650bd2007-03-13 16:32:48 -06001857
Brian Paul027ed1b2009-04-24 09:43:44 -06001858 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
Brian98650bd2007-03-13 16:32:48 -06001859
Brian Paul2d76a0d2008-11-10 12:33:17 -07001860 uniform = &shProg->Uniforms->Uniforms[location];
1861
Brian Paule01a03d2009-02-06 10:21:36 -07001862 if (ctx->Shader.Flags & GLSL_UNIFORMS) {
1863 GLint i;
1864 _mesa_printf("Mesa: set program %u uniform %s (loc %d) to: ",
1865 shProg->Name, uniform->Name, location);
1866 if (basicType == GL_INT) {
1867 const GLint *v = (const GLint *) values;
1868 for (i = 0; i < count * elems; i++) {
1869 _mesa_printf("%d ", v[i]);
1870 }
1871 }
1872 else {
1873 const GLfloat *v = (const GLfloat *) values;
1874 for (i = 0; i < count * elems; i++) {
1875 _mesa_printf("%g ", v[i]);
1876 }
1877 }
1878 _mesa_printf("\n");
1879 }
1880
Brian Paulade50832008-05-14 16:09:46 -06001881 /* A uniform var may be used by both a vertex shader and a fragment
1882 * shader. We may need to update one or both shader's uniform here:
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001883 */
Brian Paulade50832008-05-14 16:09:46 -06001884 if (shProg->VertexProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001885 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07001886 GLint index = uniform->VertPos;
Brian Pauleda291e2008-08-06 16:26:47 -06001887 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001888 set_program_uniform(ctx, &shProg->VertexProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001889 index, offset, type, count, elems, values);
Bruce Merry2bf2a8c2007-12-21 23:18:40 +02001890 }
Brian5b01c5e2006-12-19 18:02:03 -07001891 }
Brian5cf73262007-01-05 16:02:45 -07001892
Brian Paulade50832008-05-14 16:09:46 -06001893 if (shProg->FragmentProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001894 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07001895 GLint index = uniform->FragPos;
Brian Pauleda291e2008-08-06 16:26:47 -06001896 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001897 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001898 index, offset, type, count, elems, values);
Brian Paulade50832008-05-14 16:09:46 -06001899 }
1900 }
Brian Paul949e7382008-11-05 09:17:55 -07001901
Brian Paul2d76a0d2008-11-10 12:33:17 -07001902 uniform->Initialized = GL_TRUE;
Brian Paulade50832008-05-14 16:09:46 -06001903}
1904
1905
Brian Pauleda291e2008-08-06 16:26:47 -06001906/**
1907 * Set a matrix-valued program parameter.
1908 */
Brian Paulade50832008-05-14 16:09:46 -06001909static void
1910set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
Brian Pauleda291e2008-08-06 16:26:47 -06001911 GLuint index, GLuint offset,
1912 GLuint count, GLuint rows, GLuint cols,
Brian Paulade50832008-05-14 16:09:46 -06001913 GLboolean transpose, const GLfloat *values)
1914{
Brian Paulffbc66b2008-07-21 13:58:50 -06001915 GLuint mat, row, col;
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001916 GLuint src = 0;
1917 const struct gl_program_parameter * param = &program->Parameters->Parameters[index];
Brian Paul20fbb242010-01-27 17:03:04 -07001918 const GLuint slots = (param->Size + 3) / 4;
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001919 const GLint typeSize = sizeof_glsl_type(param->DataType);
Brian Paulffbc66b2008-07-21 13:58:50 -06001920 GLint nr, nc;
1921
1922 /* check that the number of rows, columns is correct */
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001923 get_matrix_dims(param->DataType, &nr, &nc);
Brian Paulffbc66b2008-07-21 13:58:50 -06001924 if (rows != nr || cols != nc) {
1925 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Pauleda291e2008-08-06 16:26:47 -06001926 "glUniformMatrix(matrix size mismatch)");
1927 return;
1928 }
1929
Brian Paul20fbb242010-01-27 17:03:04 -07001930 if ((GLint) param->Size <= typeSize) {
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001931 /* non-array: count must be at most one; count == 0 is handled by the loop below */
1932 if (count > 1) {
1933 _mesa_error(ctx, GL_INVALID_OPERATION,
1934 "glUniformMatrix(uniform is not an array)");
1935 return;
1936 }
Brian Paulffbc66b2008-07-21 13:58:50 -06001937 }
1938
Brian Paulade50832008-05-14 16:09:46 -06001939 /*
1940 * Note: the _columns_ of a matrix are stored in program registers, not
Brian Paulf45ed0e2008-07-18 12:51:39 -06001941 * the rows. So, the loops below look a little funny.
1942 * XXX could optimize this a bit...
Brian Paulade50832008-05-14 16:09:46 -06001943 */
Brian Paulf45ed0e2008-07-18 12:51:39 -06001944
1945 /* loop over matrices */
1946 for (mat = 0; mat < count; mat++) {
1947
1948 /* each matrix: */
Brian Paulade50832008-05-14 16:09:46 -06001949 for (col = 0; col < cols; col++) {
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001950 GLfloat *v;
1951 if (offset >= slots) {
1952 /* Ignore writes beyond the end of (the used part of) an array */
1953 return;
1954 }
1955 v = program->Parameters->ParameterValues[index + offset];
Brian Paulade50832008-05-14 16:09:46 -06001956 for (row = 0; row < rows; row++) {
Brian Paulf45ed0e2008-07-18 12:51:39 -06001957 if (transpose) {
1958 v[row] = values[src + row * cols + col];
1959 }
1960 else {
1961 v[row] = values[src + col * rows + row];
1962 }
Brian Paulade50832008-05-14 16:09:46 -06001963 }
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001964
1965 offset++;
Brian Paulade50832008-05-14 16:09:46 -06001966 }
Brian Paulf45ed0e2008-07-18 12:51:39 -06001967
1968 src += rows * cols; /* next matrix */
Brian5cf73262007-01-05 16:02:45 -07001969 }
Brian34ae99d2006-12-18 08:28:54 -07001970}
1971
1972
1973/**
Brian5b01c5e2006-12-19 18:02:03 -07001974 * Called by ctx->Driver.UniformMatrix().
Brian Paulf45ed0e2008-07-18 12:51:39 -06001975 * Note: cols=2, rows=4 ==> array[2] of vec4
Brian34ae99d2006-12-18 08:28:54 -07001976 */
Brian Paulfd59f192008-05-18 16:04:55 -06001977static void
Brian5b01c5e2006-12-19 18:02:03 -07001978_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
Brian Paul0115a4f2009-04-14 20:00:28 -06001979 GLint location, GLsizei count,
Brian5b01c5e2006-12-19 18:02:03 -07001980 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001981{
Brian3a8e2772006-12-20 17:19:16 -07001982 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paul2d76a0d2008-11-10 12:33:17 -07001983 struct gl_uniform *uniform;
1984 GLint offset;
Brian Paulade50832008-05-14 16:09:46 -06001985
Brian3a8e2772006-12-20 17:19:16 -07001986 if (!shProg || !shProg->LinkStatus) {
1987 _mesa_error(ctx, GL_INVALID_OPERATION,
1988 "glUniformMatrix(program not linked)");
1989 return;
1990 }
Brian Paulade50832008-05-14 16:09:46 -06001991
Bruce Merry89b80322007-12-21 15:20:17 +02001992 if (location == -1)
1993 return; /* The standard specifies this as a no-op */
Brian Paulade50832008-05-14 16:09:46 -06001994
Brian Paul234f03e2009-02-11 09:05:08 -07001995 if (location < -1) {
1996 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(location)");
1997 return;
1998 }
1999
Brian Pauleda291e2008-08-06 16:26:47 -06002000 split_location_offset(&location, &offset);
2001
Brian Paul016701f2008-07-29 17:43:35 -06002002 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian Paulade50832008-05-14 16:09:46 -06002003 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
Brian3a8e2772006-12-20 17:19:16 -07002004 return;
2005 }
Brian34ae99d2006-12-18 08:28:54 -07002006 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07002007 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07002008 return;
2009 }
2010
Brian Paul027ed1b2009-04-24 09:43:44 -06002011 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
Brian34ae99d2006-12-18 08:28:54 -07002012
Brian Paul2d76a0d2008-11-10 12:33:17 -07002013 uniform = &shProg->Uniforms->Uniforms[location];
2014
Brian Paulade50832008-05-14 16:09:46 -06002015 if (shProg->VertexProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06002016 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07002017 GLint index = uniform->VertPos;
Brian Pauleda291e2008-08-06 16:26:47 -06002018 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06002019 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06002020 index, offset,
2021 count, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07002022 }
Brian Paulade50832008-05-14 16:09:46 -06002023 }
2024
2025 if (shProg->FragmentProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06002026 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07002027 GLint index = uniform->FragPos;
Brian Pauleda291e2008-08-06 16:26:47 -06002028 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06002029 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06002030 index, offset,
2031 count, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07002032 }
Brian34ae99d2006-12-18 08:28:54 -07002033 }
Brian Paul949e7382008-11-05 09:17:55 -07002034
Brian Paul2d76a0d2008-11-10 12:33:17 -07002035 uniform->Initialized = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07002036}
2037
2038
Brian Paulc90fca32009-08-25 17:42:47 -06002039/**
2040 * Validate a program's samplers.
2041 * Specifically, check that there aren't two samplers of different types
2042 * pointing to the same texture unit.
2043 * \return GL_TRUE if valid, GL_FALSE if invalid
2044 */
2045static GLboolean
2046validate_samplers(GLcontext *ctx, const struct gl_program *prog, char *errMsg)
Brian34ae99d2006-12-18 08:28:54 -07002047{
Brian Paulc90fca32009-08-25 17:42:47 -06002048 static const char *targetName[] = {
2049 "TEXTURE_2D_ARRAY",
2050 "TEXTURE_1D_ARRAY",
2051 "TEXTURE_CUBE",
2052 "TEXTURE_3D",
2053 "TEXTURE_RECT",
2054 "TEXTURE_2D",
2055 "TEXTURE_1D",
2056 };
2057 GLint targetUsed[MAX_TEXTURE_IMAGE_UNITS];
2058 GLbitfield samplersUsed = prog->SamplersUsed;
2059 GLuint i;
Brian Paulbc985b52008-07-21 14:16:07 -06002060
Brian Paulc90fca32009-08-25 17:42:47 -06002061 assert(Elements(targetName) == NUM_TEXTURE_TARGETS);
2062
2063 if (samplersUsed == 0x0)
2064 return GL_TRUE;
2065
2066 for (i = 0; i < Elements(targetUsed); i++)
2067 targetUsed[i] = -1;
2068
2069 /* walk over bits which are set in 'samplers' */
2070 while (samplersUsed) {
2071 GLuint unit;
2072 gl_texture_index target;
2073 GLint sampler = _mesa_ffs(samplersUsed) - 1;
2074 assert(sampler >= 0);
2075 assert(sampler < MAX_TEXTURE_IMAGE_UNITS);
2076 unit = prog->SamplerUnits[sampler];
2077 target = prog->SamplerTargets[sampler];
2078 if (targetUsed[unit] != -1 && targetUsed[unit] != target) {
2079 _mesa_snprintf(errMsg, 100,
2080 "Texture unit %d is accessed both as %s and %s",
2081 unit, targetName[targetUsed[unit]], targetName[target]);
2082 return GL_FALSE;
2083 }
2084 targetUsed[unit] = target;
2085 samplersUsed ^= (1 << sampler);
Brian34ae99d2006-12-18 08:28:54 -07002086 }
2087
Brian Paulc90fca32009-08-25 17:42:47 -06002088 return GL_TRUE;
2089}
2090
2091
2092/**
2093 * Do validation of the given shader program.
2094 * \param errMsg returns error message if validation fails.
2095 * \return GL_TRUE if valid, GL_FALSE if invalid (and set errMsg)
2096 */
2097GLboolean
2098_mesa_validate_shader_program(GLcontext *ctx,
2099 const struct gl_shader_program *shProg,
2100 char *errMsg)
2101{
2102 const struct gl_vertex_program *vp = shProg->VertexProgram;
2103 const struct gl_fragment_program *fp = shProg->FragmentProgram;
2104
Brian Paulbc985b52008-07-21 14:16:07 -06002105 if (!shProg->LinkStatus) {
Brian Paulc90fca32009-08-25 17:42:47 -06002106 return GL_FALSE;
Brian Paulbc985b52008-07-21 14:16:07 -06002107 }
2108
2109 /* From the GL spec, a program is invalid if any of these are true:
2110
Brian5b01c5e2006-12-19 18:02:03 -07002111 any two active samplers in the current program object are of
2112 different types, but refer to the same texture image unit,
2113
2114 any active sampler in the current program object refers to a texture
2115 image unit where fixed-function fragment processing accesses a
2116 texture target that does not match the sampler type, or
2117
2118 the sum of the number of active samplers in the program and the
2119 number of texture image units enabled for fixed-function fragment
2120 processing exceeds the combined limit on the total number of texture
2121 image units allowed.
2122 */
Brian Paulbc985b52008-07-21 14:16:07 -06002123
Brian Paulc90fca32009-08-25 17:42:47 -06002124
2125 /*
2126 * Check: any two active samplers in the current program object are of
2127 * different types, but refer to the same texture image unit,
2128 */
2129 if (vp && !validate_samplers(ctx, &vp->Base, errMsg)) {
2130 return GL_FALSE;
2131 }
2132 if (fp && !validate_samplers(ctx, &fp->Base, errMsg)) {
2133 return GL_FALSE;
2134 }
2135
2136 return GL_TRUE;
2137}
2138
2139
2140/**
2141 * Called via glValidateProgram()
2142 */
2143static void
2144_mesa_validate_program(GLcontext *ctx, GLuint program)
2145{
2146 struct gl_shader_program *shProg;
2147 char errMsg[100];
2148
2149 shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram");
2150 if (!shProg) {
2151 return;
2152 }
2153
2154 shProg->Validated = _mesa_validate_shader_program(ctx, shProg, errMsg);
2155 if (!shProg->Validated) {
2156 /* update info log */
2157 if (shProg->InfoLog) {
2158 _mesa_free(shProg->InfoLog);
2159 }
2160 shProg->InfoLog = _mesa_strdup(errMsg);
2161 }
Brian34ae99d2006-12-18 08:28:54 -07002162}
Brian Paulfd59f192008-05-18 16:04:55 -06002163
2164
2165/**
2166 * Plug in Mesa's GLSL functions into the device driver function table.
2167 */
2168void
2169_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
2170{
2171 driver->AttachShader = _mesa_attach_shader;
2172 driver->BindAttribLocation = _mesa_bind_attrib_location;
2173 driver->CompileShader = _mesa_compile_shader;
2174 driver->CreateProgram = _mesa_create_program;
2175 driver->CreateShader = _mesa_create_shader;
2176 driver->DeleteProgram2 = _mesa_delete_program2;
2177 driver->DeleteShader = _mesa_delete_shader;
2178 driver->DetachShader = _mesa_detach_shader;
2179 driver->GetActiveAttrib = _mesa_get_active_attrib;
2180 driver->GetActiveUniform = _mesa_get_active_uniform;
2181 driver->GetAttachedShaders = _mesa_get_attached_shaders;
2182 driver->GetAttribLocation = _mesa_get_attrib_location;
2183 driver->GetHandle = _mesa_get_handle;
2184 driver->GetProgramiv = _mesa_get_programiv;
2185 driver->GetProgramInfoLog = _mesa_get_program_info_log;
2186 driver->GetShaderiv = _mesa_get_shaderiv;
2187 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
2188 driver->GetShaderSource = _mesa_get_shader_source;
2189 driver->GetUniformfv = _mesa_get_uniformfv;
Brian Paul2be54a82008-07-08 16:17:04 -06002190 driver->GetUniformiv = _mesa_get_uniformiv;
Brian Paulfd59f192008-05-18 16:04:55 -06002191 driver->GetUniformLocation = _mesa_get_uniform_location;
2192 driver->IsProgram = _mesa_is_program;
2193 driver->IsShader = _mesa_is_shader;
2194 driver->LinkProgram = _mesa_link_program;
2195 driver->ShaderSource = _mesa_shader_source;
2196 driver->Uniform = _mesa_uniform;
2197 driver->UniformMatrix = _mesa_uniform_matrix;
2198 driver->UseProgram = _mesa_use_program;
2199 driver->ValidateProgram = _mesa_validate_program;
2200}