blob: b282d7af60af7f32e473b22b5928ed6cee932ebc [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"
42#include "main/macros.h"
43#include "shader/program.h"
44#include "shader/prog_parameter.h"
45#include "shader/prog_print.h"
46#include "shader/prog_statevars.h"
47#include "shader/prog_uniform.h"
Brianc223c6b2007-07-04 13:15:20 -060048#include "shader/shader_api.h"
49#include "shader/slang/slang_compile.h"
50#include "shader/slang/slang_link.h"
Ian Romanick905d8e02008-09-29 12:27:00 -070051#include "glapi/dispatch.h"
Brian34ae99d2006-12-18 08:28:54 -070052
53
Brianf2923612006-12-20 09:56:44 -070054/**
55 * Allocate a new gl_shader_program object, initialize it.
56 */
Brian Paulfd59f192008-05-18 16:04:55 -060057static struct gl_shader_program *
Brianf2923612006-12-20 09:56:44 -070058_mesa_new_shader_program(GLcontext *ctx, GLuint name)
59{
60 struct gl_shader_program *shProg;
61 shProg = CALLOC_STRUCT(gl_shader_program);
62 if (shProg) {
Brianf3e8c322007-04-18 14:53:23 -060063 shProg->Type = GL_SHADER_PROGRAM_MESA;
Brianf2923612006-12-20 09:56:44 -070064 shProg->Name = name;
65 shProg->RefCount = 1;
Brian3209c3e2007-01-09 17:49:24 -070066 shProg->Attributes = _mesa_new_parameter_list();
Brianf2923612006-12-20 09:56:44 -070067 }
68 return shProg;
69}
70
71
Brianb9fbedd2007-03-26 09:23:44 -060072/**
Brian3c008a02007-04-12 15:22:32 -060073 * Clear (free) the shader program state that gets produced by linking.
Brianb9fbedd2007-03-26 09:23:44 -060074 */
Brianf2923612006-12-20 09:56:44 -070075void
Brian3c008a02007-04-12 15:22:32 -060076_mesa_clear_shader_program_data(GLcontext *ctx,
77 struct gl_shader_program *shProg)
Brianf2923612006-12-20 09:56:44 -070078{
Brian Paul8bdf5b62008-05-16 09:56:59 -060079 _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL);
80 _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL);
Brianf2923612006-12-20 09:56:44 -070081
Brianf2923612006-12-20 09:56:44 -070082 if (shProg->Uniforms) {
Brian Paulade50832008-05-14 16:09:46 -060083 _mesa_free_uniform_list(shProg->Uniforms);
Brianf2923612006-12-20 09:56:44 -070084 shProg->Uniforms = NULL;
85 }
86
87 if (shProg->Varying) {
88 _mesa_free_parameter_list(shProg->Varying);
89 shProg->Varying = NULL;
90 }
91}
92
93
Brianb9fbedd2007-03-26 09:23:44 -060094/**
Brian3c008a02007-04-12 15:22:32 -060095 * Free all the data that hangs off a shader program object, but not the
96 * object itself.
97 */
98void
99_mesa_free_shader_program_data(GLcontext *ctx,
100 struct gl_shader_program *shProg)
101{
102 GLuint i;
103
Brianf3e8c322007-04-18 14:53:23 -0600104 assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
Brian3c008a02007-04-12 15:22:32 -0600105
106 _mesa_clear_shader_program_data(ctx, shProg);
107
Brian4b7c6fc2007-04-19 15:23:34 -0600108 if (shProg->Attributes) {
109 _mesa_free_parameter_list(shProg->Attributes);
110 shProg->Attributes = NULL;
111 }
112
Brian3c008a02007-04-12 15:22:32 -0600113 /* detach shaders */
114 for (i = 0; i < shProg->NumShaders; i++) {
115 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
116 }
Xiang, Haihao63d8a842008-03-31 17:02:47 +0800117 shProg->NumShaders = 0;
118
Brian3c008a02007-04-12 15:22:32 -0600119 if (shProg->Shaders) {
120 _mesa_free(shProg->Shaders);
121 shProg->Shaders = NULL;
122 }
Alan Hourihaneeec20c32008-04-22 20:29:42 +0100123
124 if (shProg->InfoLog) {
125 _mesa_free(shProg->InfoLog);
126 shProg->InfoLog = NULL;
127 }
Brian3c008a02007-04-12 15:22:32 -0600128}
129
130
131/**
Brianb9fbedd2007-03-26 09:23:44 -0600132 * Free/delete a shader program object.
133 */
Brianf2923612006-12-20 09:56:44 -0700134void
135_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg)
136{
137 _mesa_free_shader_program_data(ctx, shProg);
Alan Hourihaneeec20c32008-04-22 20:29:42 +0100138
Brianf2923612006-12-20 09:56:44 -0700139 _mesa_free(shProg);
140}
141
142
143/**
Brian3c008a02007-04-12 15:22:32 -0600144 * Set ptr to point to shProg.
145 * If ptr is pointing to another object, decrement its refcount (and delete
146 * if refcount hits zero).
147 * Then set ptr to point to shProg, incrementing its refcount.
148 */
149/* XXX this could be static */
150void
151_mesa_reference_shader_program(GLcontext *ctx,
152 struct gl_shader_program **ptr,
153 struct gl_shader_program *shProg)
154{
155 assert(ptr);
156 if (*ptr == shProg) {
157 /* no-op */
158 return;
159 }
160 if (*ptr) {
161 /* Unreference the old shader program */
162 GLboolean deleteFlag = GL_FALSE;
163 struct gl_shader_program *old = *ptr;
164
165 ASSERT(old->RefCount > 0);
166 old->RefCount--;
Brian Paul8bdf5b62008-05-16 09:56:59 -0600167#if 0
168 printf("ShaderProgram %p ID=%u RefCount-- to %d\n",
169 (void *) old, old->Name, old->RefCount);
170#endif
Brian3c008a02007-04-12 15:22:32 -0600171 deleteFlag = (old->RefCount == 0);
172
173 if (deleteFlag) {
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800174 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
Brian3c008a02007-04-12 15:22:32 -0600175 _mesa_free_shader_program(ctx, old);
176 }
177
178 *ptr = NULL;
179 }
180 assert(!*ptr);
181
182 if (shProg) {
183 shProg->RefCount++;
Brian Paul8bdf5b62008-05-16 09:56:59 -0600184#if 0
185 printf("ShaderProgram %p ID=%u RefCount++ to %d\n",
186 (void *) shProg, shProg->Name, shProg->RefCount);
187#endif
Brian3c008a02007-04-12 15:22:32 -0600188 *ptr = shProg;
189 }
190}
191
192
193/**
Brianf2923612006-12-20 09:56:44 -0700194 * Lookup a GLSL program object.
195 */
196struct gl_shader_program *
197_mesa_lookup_shader_program(GLcontext *ctx, GLuint name)
198{
199 struct gl_shader_program *shProg;
200 if (name) {
201 shProg = (struct gl_shader_program *)
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800202 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
Brianf2923612006-12-20 09:56:44 -0700203 /* Note that both gl_shader and gl_shader_program objects are kept
204 * in the same hash table. Check the object's type to be sure it's
205 * what we're expecting.
206 */
Brianf3e8c322007-04-18 14:53:23 -0600207 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700208 return NULL;
209 }
210 return shProg;
211 }
212 return NULL;
213}
214
215
216/**
Brian Paul530df582008-07-03 16:21:11 -0600217 * As above, but record an error if program is not found.
218 */
219static struct gl_shader_program *
220_mesa_lookup_shader_program_err(GLcontext *ctx, GLuint name,
221 const char *caller)
222{
223 if (!name) {
224 _mesa_error(ctx, GL_INVALID_VALUE, caller);
225 return NULL;
226 }
227 else {
228 struct gl_shader_program *shProg = (struct gl_shader_program *)
229 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
230 if (!shProg) {
231 _mesa_error(ctx, GL_INVALID_VALUE, caller);
232 return NULL;
233 }
234 if (shProg->Type != GL_SHADER_PROGRAM_MESA) {
235 _mesa_error(ctx, GL_INVALID_OPERATION, caller);
236 return NULL;
237 }
238 return shProg;
239 }
240}
241
242
243
244
245/**
Brianf2923612006-12-20 09:56:44 -0700246 * Allocate a new gl_shader object, initialize it.
247 */
248struct gl_shader *
249_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
250{
251 struct gl_shader *shader;
252 assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
253 shader = CALLOC_STRUCT(gl_shader);
254 if (shader) {
255 shader->Type = type;
256 shader->Name = name;
257 shader->RefCount = 1;
258 }
259 return shader;
260}
261
262
263void
264_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh)
265{
Brianf2923612006-12-20 09:56:44 -0700266 if (sh->Source)
267 _mesa_free((void *) sh->Source);
268 if (sh->InfoLog)
269 _mesa_free(sh->InfoLog);
Brian Paul3d500f02008-07-24 14:56:54 -0600270 _mesa_reference_program(ctx, &sh->Program, NULL);
Brianf2923612006-12-20 09:56:44 -0700271 _mesa_free(sh);
272}
273
274
275/**
Brian3c008a02007-04-12 15:22:32 -0600276 * Set ptr to point to sh.
277 * If ptr is pointing to another shader, decrement its refcount (and delete
278 * if refcount hits zero).
279 * Then set ptr to point to sh, incrementing its refcount.
280 */
281/* XXX this could be static */
282void
283_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr,
284 struct gl_shader *sh)
285{
286 assert(ptr);
287 if (*ptr == sh) {
288 /* no-op */
289 return;
290 }
291 if (*ptr) {
292 /* Unreference the old shader */
293 GLboolean deleteFlag = GL_FALSE;
294 struct gl_shader *old = *ptr;
295
296 ASSERT(old->RefCount > 0);
297 old->RefCount--;
Brian99193e42007-04-12 15:45:02 -0600298 /*printf("SHADER DECR %p (%d) to %d\n",
299 (void*) old, old->Name, old->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600300 deleteFlag = (old->RefCount == 0);
301
302 if (deleteFlag) {
303 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
304 _mesa_free_shader(ctx, old);
305 }
306
307 *ptr = NULL;
308 }
309 assert(!*ptr);
310
311 if (sh) {
312 /* reference new */
313 sh->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600314 /*printf("SHADER INCR %p (%d) to %d\n",
315 (void*) sh, sh->Name, sh->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600316 *ptr = sh;
317 }
318}
319
320
321/**
Brianf2923612006-12-20 09:56:44 -0700322 * Lookup a GLSL shader object.
323 */
324struct gl_shader *
325_mesa_lookup_shader(GLcontext *ctx, GLuint name)
326{
327 if (name) {
328 struct gl_shader *sh = (struct gl_shader *)
329 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
330 /* Note that both gl_shader and gl_shader_program objects are kept
331 * in the same hash table. Check the object's type to be sure it's
332 * what we're expecting.
333 */
Brianf3e8c322007-04-18 14:53:23 -0600334 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700335 return NULL;
336 }
337 return sh;
338 }
339 return NULL;
340}
341
342
Brianfa4d0362007-02-26 18:33:50 -0700343/**
Brian Paul530df582008-07-03 16:21:11 -0600344 * As above, but record an error if shader is not found.
345 */
346static struct gl_shader *
347_mesa_lookup_shader_err(GLcontext *ctx, GLuint name, const char *caller)
348{
349 if (!name) {
350 _mesa_error(ctx, GL_INVALID_VALUE, caller);
351 return NULL;
352 }
353 else {
354 struct gl_shader *sh = (struct gl_shader *)
355 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
356 if (!sh) {
357 _mesa_error(ctx, GL_INVALID_VALUE, caller);
358 return NULL;
359 }
360 if (sh->Type == GL_SHADER_PROGRAM_MESA) {
361 _mesa_error(ctx, GL_INVALID_OPERATION, caller);
362 return NULL;
363 }
364 return sh;
365 }
366}
367
368
Brian Paule01a03d2009-02-06 10:21:36 -0700369/**
370 * Return mask of GLSL_x flags by examining the MESA_GLSL env var.
371 */
372static GLbitfield
373get_shader_flags(void)
374{
375 GLbitfield flags = 0x0;
376 const char *env = _mesa_getenv("MESA_GLSL");
377
378 if (env) {
379 if (_mesa_strstr(env, "dump"))
380 flags |= GLSL_DUMP;
381 if (_mesa_strstr(env, "log"))
382 flags |= GLSL_LOG;
383 if (_mesa_strstr(env, "nopt"))
384 flags |= GLSL_NO_OPT;
385 else if (_mesa_strstr(env, "opt"))
386 flags |= GLSL_OPT;
387 if (_mesa_strstr(env, "uniform"))
388 flags |= GLSL_UNIFORMS;
389 }
390
391 return flags;
392}
393
Brian Paul530df582008-07-03 16:21:11 -0600394
395/**
Brianfa4d0362007-02-26 18:33:50 -0700396 * Initialize context's shader state.
397 */
Brianf2923612006-12-20 09:56:44 -0700398void
399_mesa_init_shader_state(GLcontext * ctx)
400{
Brianfa4d0362007-02-26 18:33:50 -0700401 /* Device drivers may override these to control what kind of instructions
402 * are generated by the GLSL compiler.
403 */
404 ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
Brian Paul4031ea12009-06-17 11:57:39 -0600405 ctx->Shader.EmitContReturn = GL_TRUE;
Brian Paulc5c38352009-02-16 11:50:05 -0700406 ctx->Shader.EmitCondCodes = GL_FALSE;
Brianfa4d0362007-02-26 18:33:50 -0700407 ctx->Shader.EmitComments = GL_FALSE;
Brian Paule01a03d2009-02-06 10:21:36 -0700408 ctx->Shader.Flags = get_shader_flags();
Brian Paul65fc2ca2009-03-19 10:25:24 -0600409
410 /* Default pragma settings */
411 ctx->Shader.DefaultPragmas.IgnoreOptimize = GL_FALSE;
412 ctx->Shader.DefaultPragmas.IgnoreDebug = GL_FALSE;
413 ctx->Shader.DefaultPragmas.Optimize = GL_TRUE;
414 ctx->Shader.DefaultPragmas.Debug = GL_FALSE;
Brianf2923612006-12-20 09:56:44 -0700415}
416
417
Brian5b01c5e2006-12-19 18:02:03 -0700418/**
Brian935f93f2007-03-24 16:20:02 -0600419 * Free the per-context shader-related state.
420 */
421void
422_mesa_free_shader_state(GLcontext *ctx)
423{
Brian3c008a02007-04-12 15:22:32 -0600424 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
Brian935f93f2007-03-24 16:20:02 -0600425}
426
427
428/**
Brian5b01c5e2006-12-19 18:02:03 -0700429 * Copy string from <src> to <dst>, up to maxLength characters, returning
430 * length of <dst> in <length>.
431 * \param src the strings source
432 * \param maxLength max chars to copy
433 * \param length returns number of chars copied
434 * \param dst the string destination
435 */
436static void
437copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
438{
439 GLsizei len;
440 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
441 dst[len] = src[len];
442 if (maxLength > 0)
443 dst[len] = 0;
444 if (length)
445 *length = len;
446}
447
448
Brian Paul7acb7c12008-07-03 13:49:48 -0600449static GLboolean
450_mesa_is_program(GLcontext *ctx, GLuint name)
451{
452 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
453 return shProg ? GL_TRUE : GL_FALSE;
454}
455
456
457static GLboolean
458_mesa_is_shader(GLcontext *ctx, GLuint name)
459{
460 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
461 return shader ? GL_TRUE : GL_FALSE;
462}
463
464
Brian5b01c5e2006-12-19 18:02:03 -0700465/**
466 * Called via ctx->Driver.AttachShader()
467 */
Brian Paulfd59f192008-05-18 16:04:55 -0600468static void
Brian5b01c5e2006-12-19 18:02:03 -0700469_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
470{
Brian Paul530df582008-07-03 16:21:11 -0600471 struct gl_shader_program *shProg;
472 struct gl_shader *sh;
473 GLuint i, n;
Brian5b01c5e2006-12-19 18:02:03 -0700474
Brian Paul530df582008-07-03 16:21:11 -0600475 shProg = _mesa_lookup_shader_program_err(ctx, program, "glAttachShader");
476 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700477 return;
Brian5b01c5e2006-12-19 18:02:03 -0700478
Brian Paul530df582008-07-03 16:21:11 -0600479 sh = _mesa_lookup_shader_err(ctx, shader, "glAttachShader");
Brian Paul7acb7c12008-07-03 13:49:48 -0600480 if (!sh) {
Brian Paul7acb7c12008-07-03 13:49:48 -0600481 return;
482 }
483
Brian237b9852007-08-07 21:48:31 +0100484 n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700485 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700486 if (shProg->Shaders[i] == sh) {
Ian Romanickd806d452008-09-29 12:18:06 -0700487 /* The shader is already attched to this program. The
488 * GL_ARB_shader_objects spec says:
489 *
490 * "The error INVALID_OPERATION is generated by AttachObjectARB
491 * if <obj> is already attached to <containerObj>."
492 */
493 _mesa_error(ctx, GL_INVALID_OPERATION, "glAttachShader");
Brian5b01c5e2006-12-19 18:02:03 -0700494 return;
Brian34ae99d2006-12-18 08:28:54 -0700495 }
496 }
Brian5b01c5e2006-12-19 18:02:03 -0700497
498 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700499 shProg->Shaders = (struct gl_shader **)
500 _mesa_realloc(shProg->Shaders,
501 n * sizeof(struct gl_shader *),
502 (n + 1) * sizeof(struct gl_shader *));
503 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700504 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
505 return;
506 }
507
508 /* append */
Brian3c008a02007-04-12 15:22:32 -0600509 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
510 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700511 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700512}
513
514
Brian Paulfd59f192008-05-18 16:04:55 -0600515static GLint
Brian Paul896c0cc2008-05-16 15:47:55 -0600516_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
517 const GLchar *name)
518{
519 struct gl_shader_program *shProg
Brian Paul530df582008-07-03 16:21:11 -0600520 = _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
Brian Paul896c0cc2008-05-16 15:47:55 -0600521
522 if (!shProg) {
Brian Paul896c0cc2008-05-16 15:47:55 -0600523 return -1;
524 }
525
526 if (!shProg->LinkStatus) {
527 _mesa_error(ctx, GL_INVALID_OPERATION,
528 "glGetAttribLocation(program not linked)");
529 return -1;
530 }
531
532 if (!name)
533 return -1;
534
Brian Paul27341a92008-09-16 16:28:36 -0600535 if (shProg->VertexProgram) {
536 const struct gl_program_parameter_list *attribs =
537 shProg->VertexProgram->Base.Attributes;
538 if (attribs) {
539 GLint i = _mesa_lookup_parameter_index(attribs, -1, name);
540 if (i >= 0) {
541 return attribs->Parameters[i].StateIndexes[0];
542 }
Brian Paul896c0cc2008-05-16 15:47:55 -0600543 }
544 }
545 return -1;
546}
547
548
Brian Paulfd59f192008-05-18 16:04:55 -0600549static void
Brian5b01c5e2006-12-19 18:02:03 -0700550_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
551 const GLchar *name)
552{
Brian Paul530df582008-07-03 16:21:11 -0600553 struct gl_shader_program *shProg;
Brianb7978af2007-01-09 19:17:17 -0700554 const GLint size = -1; /* unknown size */
Brian Paul6bc87492008-07-25 08:34:54 -0600555 GLint i, oldIndex;
Brian Paul6f1abb92008-07-29 17:27:22 -0600556 GLenum datatype = GL_FLOAT_VEC4;
Brian5b01c5e2006-12-19 18:02:03 -0700557
Brian Paul530df582008-07-03 16:21:11 -0600558 shProg = _mesa_lookup_shader_program_err(ctx, program,
559 "glBindAttribLocation");
Brian65a18442006-12-19 18:46:56 -0700560 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700561 return;
562 }
563
Brian9e4bae92006-12-20 09:27:42 -0700564 if (!name)
565 return;
566
567 if (strncmp(name, "gl_", 3) == 0) {
568 _mesa_error(ctx, GL_INVALID_OPERATION,
569 "glBindAttribLocation(illegal name)");
570 return;
571 }
572
Brian Paul7acb7c12008-07-03 13:49:48 -0600573 if (index >= ctx->Const.VertexProgram.MaxAttribs) {
574 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
575 return;
576 }
577
Brian Paul6bc87492008-07-25 08:34:54 -0600578 if (shProg->LinkStatus) {
579 /* get current index/location for the attribute */
580 oldIndex = _mesa_get_attrib_location(ctx, program, name);
581 }
582 else {
583 oldIndex = -1;
584 }
585
Brian3209c3e2007-01-09 17:49:24 -0700586 /* this will replace the current value if it's already in the list */
Brian Paulffbc66b2008-07-21 13:58:50 -0600587 i = _mesa_add_attribute(shProg->Attributes, name, size, datatype, index);
Brian3209c3e2007-01-09 17:49:24 -0700588 if (i < 0) {
589 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
Brian Paul6f1abb92008-07-29 17:27:22 -0600590 return;
Brian3209c3e2007-01-09 17:49:24 -0700591 }
592
Brian Paul27341a92008-09-16 16:28:36 -0600593 /*
594 * Note that this attribute binding won't go into effect until
595 * glLinkProgram is called again.
596 */
Brian34ae99d2006-12-18 08:28:54 -0700597}
598
599
Brian Paulfd59f192008-05-18 16:04:55 -0600600static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700601_mesa_create_shader(GLcontext *ctx, GLenum type)
602{
Brian65a18442006-12-19 18:46:56 -0700603 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700604 GLuint name;
605
606 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
607
608 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700609 case GL_FRAGMENT_SHADER:
610 case GL_VERTEX_SHADER:
611 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700612 break;
613 default:
614 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
615 return 0;
616 }
617
Brian65a18442006-12-19 18:46:56 -0700618 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700619
620 return name;
621}
622
623
Brian Paulfd59f192008-05-18 16:04:55 -0600624static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700625_mesa_create_program(GLcontext *ctx)
626{
627 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700628 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700629
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800630 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
Brian65a18442006-12-19 18:46:56 -0700631 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700632
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800633 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700634
Brian3c008a02007-04-12 15:22:32 -0600635 assert(shProg->RefCount == 1);
636
Brian5b01c5e2006-12-19 18:02:03 -0700637 return name;
638}
639
640
Brian3c008a02007-04-12 15:22:32 -0600641/**
642 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
643 * DeleteProgramARB.
644 */
Brian Paulfd59f192008-05-18 16:04:55 -0600645static void
Brian5b01c5e2006-12-19 18:02:03 -0700646_mesa_delete_program2(GLcontext *ctx, GLuint name)
647{
Brian3c008a02007-04-12 15:22:32 -0600648 /*
649 * NOTE: deleting shaders/programs works a bit differently than
650 * texture objects (and buffer objects, etc). Shader/program
651 * handles/IDs exist in the hash table until the object is really
652 * deleted (refcount==0). With texture objects, the handle/ID is
653 * removed from the hash table in glDeleteTextures() while the tex
654 * object itself might linger until its refcount goes to zero.
655 */
Brian65a18442006-12-19 18:46:56 -0700656 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700657
Brian Paul530df582008-07-03 16:21:11 -0600658 shProg = _mesa_lookup_shader_program_err(ctx, name, "glDeleteProgram");
659 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700660 return;
Brian5b01c5e2006-12-19 18:02:03 -0700661
Brian9e4bae92006-12-20 09:27:42 -0700662 shProg->DeletePending = GL_TRUE;
663
Brian3c008a02007-04-12 15:22:32 -0600664 /* effectively, decr shProg's refcount */
665 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700666}
667
668
Brian Paulfd59f192008-05-18 16:04:55 -0600669static void
Brian5b01c5e2006-12-19 18:02:03 -0700670_mesa_delete_shader(GLcontext *ctx, GLuint shader)
671{
Brian Paul530df582008-07-03 16:21:11 -0600672 struct gl_shader *sh;
673
674 sh = _mesa_lookup_shader_err(ctx, shader, "glDeleteShader");
675 if (!sh)
Brian9e4bae92006-12-20 09:27:42 -0700676 return;
Brian5b01c5e2006-12-19 18:02:03 -0700677
Brian9e4bae92006-12-20 09:27:42 -0700678 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600679
680 /* effectively, decr sh's refcount */
681 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700682}
683
684
Brian Paulfd59f192008-05-18 16:04:55 -0600685static void
Brian5b01c5e2006-12-19 18:02:03 -0700686_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
687{
Brian Paul530df582008-07-03 16:21:11 -0600688 struct gl_shader_program *shProg;
Brian237b9852007-08-07 21:48:31 +0100689 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700690 GLuint i, j;
691
Brian Paul530df582008-07-03 16:21:11 -0600692 shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader");
693 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700694 return;
Brian5b01c5e2006-12-19 18:02:03 -0700695
Brian237b9852007-08-07 21:48:31 +0100696 n = shProg->NumShaders;
697
Brian5b01c5e2006-12-19 18:02:03 -0700698 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700699 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700700 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600701 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700702
Brian Paul530df582008-07-03 16:21:11 -0600703 /* release */
Brian3c008a02007-04-12 15:22:32 -0600704 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700705
Brian5b01c5e2006-12-19 18:02:03 -0700706 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700707 newList = (struct gl_shader **)
708 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700709 if (!newList) {
710 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
711 return;
712 }
713 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700714 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700715 }
716 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700717 newList[j++] = shProg->Shaders[i];
718 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700719
Brian65a18442006-12-19 18:46:56 -0700720 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600721 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600722
723#ifdef DEBUG
724 /* sanity check */
725 {
726 for (j = 0; j < shProg->NumShaders; j++) {
727 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
728 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
729 assert(shProg->Shaders[j]->RefCount > 0);
730 }
731 }
732#endif
733
Brian5b01c5e2006-12-19 18:02:03 -0700734 return;
735 }
736 }
737
738 /* not found */
Brian Paul530df582008-07-03 16:21:11 -0600739 {
740 GLenum err;
741 if (_mesa_is_shader(ctx, shader))
742 err = GL_INVALID_OPERATION;
743 else if (_mesa_is_program(ctx, shader))
744 err = GL_INVALID_OPERATION;
745 else
746 err = GL_INVALID_VALUE;
747 _mesa_error(ctx, err, "glDetachProgram(shader)");
748 return;
749 }
Brian5b01c5e2006-12-19 18:02:03 -0700750}
751
752
Brian Paulffbc66b2008-07-21 13:58:50 -0600753static GLint
754sizeof_glsl_type(GLenum type)
755{
756 switch (type) {
757 case GL_FLOAT:
758 case GL_INT:
759 case GL_BOOL:
Brian Paul8c51e002008-08-11 15:09:47 -0600760 case GL_SAMPLER_1D:
761 case GL_SAMPLER_2D:
762 case GL_SAMPLER_3D:
763 case GL_SAMPLER_CUBE:
764 case GL_SAMPLER_1D_SHADOW:
765 case GL_SAMPLER_2D_SHADOW:
766 case GL_SAMPLER_2D_RECT_ARB:
767 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
768 case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
769 case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
770 case GL_SAMPLER_CUBE_SHADOW_EXT:
Brian Paulffbc66b2008-07-21 13:58:50 -0600771 return 1;
772 case GL_FLOAT_VEC2:
773 case GL_INT_VEC2:
774 case GL_BOOL_VEC2:
775 return 2;
776 case GL_FLOAT_VEC3:
777 case GL_INT_VEC3:
778 case GL_BOOL_VEC3:
779 return 3;
780 case GL_FLOAT_VEC4:
781 case GL_INT_VEC4:
782 case GL_BOOL_VEC4:
783 return 4;
784 case GL_FLOAT_MAT2:
785 case GL_FLOAT_MAT2x3:
786 case GL_FLOAT_MAT2x4:
787 return 8; /* two float[4] vectors */
788 case GL_FLOAT_MAT3:
789 case GL_FLOAT_MAT3x2:
790 case GL_FLOAT_MAT3x4:
791 return 12; /* three float[4] vectors */
792 case GL_FLOAT_MAT4:
793 case GL_FLOAT_MAT4x2:
794 case GL_FLOAT_MAT4x3:
795 return 16; /* four float[4] vectors */
796 default:
797 _mesa_problem(NULL, "Invalid type in sizeof_glsl_type()");
798 return 1;
799 }
800}
801
802
Brian Pauleda291e2008-08-06 16:26:47 -0600803static GLboolean
804is_boolean_type(GLenum type)
805{
806 switch (type) {
807 case GL_BOOL:
808 case GL_BOOL_VEC2:
809 case GL_BOOL_VEC3:
810 case GL_BOOL_VEC4:
811 return GL_TRUE;
812 default:
813 return GL_FALSE;
814 }
815}
816
817
818static GLboolean
819is_integer_type(GLenum type)
820{
821 switch (type) {
822 case GL_INT:
823 case GL_INT_VEC2:
824 case GL_INT_VEC3:
825 case GL_INT_VEC4:
826 return GL_TRUE;
827 default:
828 return GL_FALSE;
829 }
830}
831
832
Brian Paulc4ffbf02009-02-18 17:46:00 -0700833static GLboolean
834is_sampler_type(GLenum type)
835{
836 switch (type) {
837 case GL_SAMPLER_1D:
838 case GL_SAMPLER_2D:
839 case GL_SAMPLER_3D:
840 case GL_SAMPLER_CUBE:
841 case GL_SAMPLER_1D_SHADOW:
842 case GL_SAMPLER_2D_SHADOW:
843 case GL_SAMPLER_2D_RECT_ARB:
844 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
845 case GL_SAMPLER_1D_ARRAY_EXT:
846 case GL_SAMPLER_2D_ARRAY_EXT:
847 return GL_TRUE;
848 default:
849 return GL_FALSE;
850 }
851}
852
853
Brian Paulfd59f192008-05-18 16:04:55 -0600854static void
Brian5b01c5e2006-12-19 18:02:03 -0700855_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
856 GLsizei maxLength, GLsizei *length, GLint *size,
857 GLenum *type, GLchar *nameOut)
858{
Brian Paul27341a92008-09-16 16:28:36 -0600859 const struct gl_program_parameter_list *attribs = NULL;
Brian Paul530df582008-07-03 16:21:11 -0600860 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700861
Brian Paul530df582008-07-03 16:21:11 -0600862 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
863 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700864 return;
Brian5b01c5e2006-12-19 18:02:03 -0700865
Brian Paul27341a92008-09-16 16:28:36 -0600866 if (shProg->VertexProgram)
867 attribs = shProg->VertexProgram->Base.Attributes;
868
869 if (!attribs || index >= attribs->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600870 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700871 return;
872 }
873
Brian Paul27341a92008-09-16 16:28:36 -0600874 copy_string(nameOut, maxLength, length, attribs->Parameters[index].Name);
875
Brian5b01c5e2006-12-19 18:02:03 -0700876 if (size)
Brian Paul27341a92008-09-16 16:28:36 -0600877 *size = attribs->Parameters[index].Size
878 / sizeof_glsl_type(attribs->Parameters[index].DataType);
879
Brian Paulade50832008-05-14 16:09:46 -0600880 if (type)
Brian Paul27341a92008-09-16 16:28:36 -0600881 *type = attribs->Parameters[index].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700882}
883
884
Brian Pauleda291e2008-08-06 16:26:47 -0600885static struct gl_program_parameter *
886get_uniform_parameter(const struct gl_shader_program *shProg, GLuint index)
887{
Brian Paula531a5c2009-08-13 13:44:01 -0600888 const struct gl_program *prog = NULL;
Brian Pauleda291e2008-08-06 16:26:47 -0600889 GLint progPos;
890
891 progPos = shProg->Uniforms->Uniforms[index].VertPos;
892 if (progPos >= 0) {
893 prog = &shProg->VertexProgram->Base;
894 }
895 else {
896 progPos = shProg->Uniforms->Uniforms[index].FragPos;
897 if (progPos >= 0) {
898 prog = &shProg->FragmentProgram->Base;
899 }
900 }
901
902 if (!prog || progPos < 0)
903 return NULL; /* should never happen */
904
905 return &prog->Parameters->Parameters[progPos];
906}
907
908
Brian5b01c5e2006-12-19 18:02:03 -0700909/**
910 * Called via ctx->Driver.GetActiveUniform().
911 */
Brian Paulfd59f192008-05-18 16:04:55 -0600912static void
Brian5b01c5e2006-12-19 18:02:03 -0700913_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
914 GLsizei maxLength, GLsizei *length, GLint *size,
915 GLenum *type, GLchar *nameOut)
916{
Brian Paul530df582008-07-03 16:21:11 -0600917 const struct gl_shader_program *shProg;
Brian Paula531a5c2009-08-13 13:44:01 -0600918 const struct gl_program *prog = NULL;
Brian Paul369d1852009-02-11 08:16:14 -0700919 const struct gl_program_parameter *param;
Brian Paulade50832008-05-14 16:09:46 -0600920 GLint progPos;
Brian5b01c5e2006-12-19 18:02:03 -0700921
Brian Paul530df582008-07-03 16:21:11 -0600922 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
923 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700924 return;
Brian5b01c5e2006-12-19 18:02:03 -0700925
Brian Paulade50832008-05-14 16:09:46 -0600926 if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
Brian5b01c5e2006-12-19 18:02:03 -0700927 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
928 return;
929 }
930
Brian Paulade50832008-05-14 16:09:46 -0600931 progPos = shProg->Uniforms->Uniforms[index].VertPos;
932 if (progPos >= 0) {
933 prog = &shProg->VertexProgram->Base;
934 }
935 else {
936 progPos = shProg->Uniforms->Uniforms[index].FragPos;
937 if (progPos >= 0) {
938 prog = &shProg->FragmentProgram->Base;
Brian274ac7a2007-04-18 16:05:53 -0600939 }
940 }
941
Brian Paulade50832008-05-14 16:09:46 -0600942 if (!prog || progPos < 0)
943 return; /* should never happen */
944
Brian Paul369d1852009-02-11 08:16:14 -0700945 ASSERT(progPos < prog->Parameters->NumParameters);
946 param = &prog->Parameters->Parameters[progPos];
947
948 if (nameOut) {
949 copy_string(nameOut, maxLength, length, param->Name);
950 }
951
952 if (size) {
953 GLint typeSize = sizeof_glsl_type(param->DataType);
954 if (param->Size > typeSize) {
955 /* This is an array.
956 * Array elements are placed on vector[4] boundaries so they're
957 * a multiple of four floats. We round typeSize up to next multiple
958 * of four to get the right size below.
959 */
960 typeSize = (typeSize + 3) & ~3;
961 }
962 /* Note that the returned size is in units of the <type>, not bytes */
963 *size = param->Size / typeSize;
964 }
965
966 if (type) {
967 *type = param->DataType;
968 }
Brian5b01c5e2006-12-19 18:02:03 -0700969}
970
971
972/**
973 * Called via ctx->Driver.GetAttachedShaders().
974 */
Brian Paulfd59f192008-05-18 16:04:55 -0600975static void
Brian5b01c5e2006-12-19 18:02:03 -0700976_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
977 GLsizei *count, GLuint *obj)
978{
Brian Paul530df582008-07-03 16:21:11 -0600979 struct gl_shader_program *shProg =
980 _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders");
Brian65a18442006-12-19 18:46:56 -0700981 if (shProg) {
Brian Paul530df582008-07-03 16:21:11 -0600982 GLuint i;
983 for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) {
Brian65a18442006-12-19 18:46:56 -0700984 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700985 }
986 if (count)
987 *count = i;
988 }
Brian5b01c5e2006-12-19 18:02:03 -0700989}
990
991
Brian Paulfd59f192008-05-18 16:04:55 -0600992static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700993_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700994{
Ian Romanick905d8e02008-09-29 12:27:00 -0700995 GLint handle = 0;
996
997 if (pname == GL_PROGRAM_OBJECT_ARB) {
998 CALL_GetIntegerv(ctx->Exec, (GL_CURRENT_PROGRAM, &handle));
999 } else {
Brian34ae99d2006-12-18 08:28:54 -07001000 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
1001 }
Ian Romanick905d8e02008-09-29 12:27:00 -07001002
1003 return handle;
Brian34ae99d2006-12-18 08:28:54 -07001004}
1005
1006
Brian Paulfd59f192008-05-18 16:04:55 -06001007static void
Brian5b01c5e2006-12-19 18:02:03 -07001008_mesa_get_programiv(GLcontext *ctx, GLuint program,
1009 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -07001010{
Brian Paul27341a92008-09-16 16:28:36 -06001011 const struct gl_program_parameter_list *attribs;
Brian65a18442006-12-19 18:46:56 -07001012 struct gl_shader_program *shProg
1013 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -07001014
Brian65a18442006-12-19 18:46:56 -07001015 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -07001016 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -07001017 return;
1018 }
1019
Brian Paul27341a92008-09-16 16:28:36 -06001020 if (shProg->VertexProgram)
1021 attribs = shProg->VertexProgram->Base.Attributes;
1022 else
1023 attribs = NULL;
1024
Brian5b01c5e2006-12-19 18:02:03 -07001025 switch (pname) {
1026 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -07001027 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -07001028 break;
1029 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -07001030 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -07001031 break;
Brian5b01c5e2006-12-19 18:02:03 -07001032 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -07001033 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -07001034 break;
1035 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001036 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001037 break;
1038 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -07001039 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -07001040 break;
1041 case GL_ACTIVE_ATTRIBUTES:
Brian Paul27341a92008-09-16 16:28:36 -06001042 *params = attribs ? attribs->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001043 break;
1044 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian Paul27341a92008-09-16 16:28:36 -06001045 *params = _mesa_longest_parameter_name(attribs, PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -07001046 break;
1047 case GL_ACTIVE_UNIFORMS:
Brian Paulade50832008-05-14 16:09:46 -06001048 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001049 break;
1050 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian Paulade50832008-05-14 16:09:46 -06001051 *params = _mesa_longest_uniform_name(shProg->Uniforms);
Brian274ac7a2007-04-18 16:05:53 -06001052 if (*params > 0)
1053 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -07001054 break;
Brian Paulbda6ad22008-08-06 12:45:14 -06001055 case GL_PROGRAM_BINARY_LENGTH_OES:
1056 *params = 0;
1057 break;
Brian34ae99d2006-12-18 08:28:54 -07001058 default:
Brian5b01c5e2006-12-19 18:02:03 -07001059 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
1060 return;
Brian34ae99d2006-12-18 08:28:54 -07001061 }
Brian5b01c5e2006-12-19 18:02:03 -07001062}
Brian34ae99d2006-12-18 08:28:54 -07001063
Brian34ae99d2006-12-18 08:28:54 -07001064
Brian Paulfd59f192008-05-18 16:04:55 -06001065static void
Brian5b01c5e2006-12-19 18:02:03 -07001066_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
1067{
Brian Paul530df582008-07-03 16:21:11 -06001068 struct gl_shader *shader = _mesa_lookup_shader_err(ctx, name, "glGetShaderiv");
Brian5b01c5e2006-12-19 18:02:03 -07001069
1070 if (!shader) {
Brian5b01c5e2006-12-19 18:02:03 -07001071 return;
1072 }
Brian65a18442006-12-19 18:46:56 -07001073
Brian5b01c5e2006-12-19 18:02:03 -07001074 switch (pname) {
1075 case GL_SHADER_TYPE:
1076 *params = shader->Type;
1077 break;
1078 case GL_DELETE_STATUS:
1079 *params = shader->DeletePending;
1080 break;
1081 case GL_COMPILE_STATUS:
1082 *params = shader->CompileStatus;
1083 break;
1084 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001085 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001086 break;
1087 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001088 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001089 break;
1090 default:
1091 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
1092 return;
1093 }
1094}
1095
1096
Brian Paulfd59f192008-05-18 16:04:55 -06001097static void
Brian5b01c5e2006-12-19 18:02:03 -07001098_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
1099 GLsizei *length, GLchar *infoLog)
1100{
Brian65a18442006-12-19 18:46:56 -07001101 struct gl_shader_program *shProg
1102 = _mesa_lookup_shader_program(ctx, program);
1103 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -07001104 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
1105 return;
1106 }
Brian65a18442006-12-19 18:46:56 -07001107 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -07001108}
1109
1110
Brian Paulfd59f192008-05-18 16:04:55 -06001111static void
Brian5b01c5e2006-12-19 18:02:03 -07001112_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
1113 GLsizei *length, GLchar *infoLog)
1114{
Brian65a18442006-12-19 18:46:56 -07001115 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
1116 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001117 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
1118 return;
1119 }
Brian65a18442006-12-19 18:46:56 -07001120 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -07001121}
1122
1123
1124/**
1125 * Called via ctx->Driver.GetShaderSource().
1126 */
Brian Paulfd59f192008-05-18 16:04:55 -06001127static void
Brian5b01c5e2006-12-19 18:02:03 -07001128_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
1129 GLsizei *length, GLchar *sourceOut)
1130{
Brian Paul530df582008-07-03 16:21:11 -06001131 struct gl_shader *sh;
1132 sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource");
Brian65a18442006-12-19 18:46:56 -07001133 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001134 return;
1135 }
Brian65a18442006-12-19 18:46:56 -07001136 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -07001137}
1138
1139
Brian Paul5b982362008-08-06 13:07:09 -06001140static void
1141get_matrix_dims(GLenum type, GLint *rows, GLint *cols)
1142{
1143 switch (type) {
1144 case GL_FLOAT_MAT2:
1145 *rows = *cols = 2;
1146 break;
1147 case GL_FLOAT_MAT2x3:
1148 *rows = 3;
1149 *cols = 2;
1150 break;
1151 case GL_FLOAT_MAT2x4:
1152 *rows = 4;
1153 *cols = 2;
1154 break;
1155 case GL_FLOAT_MAT3:
1156 *rows = 3;
1157 *cols = 3;
1158 break;
1159 case GL_FLOAT_MAT3x2:
1160 *rows = 2;
1161 *cols = 3;
1162 break;
1163 case GL_FLOAT_MAT3x4:
1164 *rows = 4;
1165 *cols = 3;
1166 break;
1167 case GL_FLOAT_MAT4:
1168 *rows = 4;
1169 *cols = 4;
1170 break;
1171 case GL_FLOAT_MAT4x2:
1172 *rows = 2;
1173 *cols = 4;
1174 break;
1175 case GL_FLOAT_MAT4x3:
1176 *rows = 3;
1177 *cols = 4;
1178 break;
1179 default:
1180 *rows = *cols = 0;
1181 }
1182}
1183
1184
1185/**
1186 * Determine the number of rows and columns occupied by a uniform
Brian Paulea9568d2008-09-16 08:55:54 -06001187 * according to its datatype. For non-matrix types (such as GL_FLOAT_VEC4),
1188 * the number of rows = 1 and cols = number of elements in the vector.
Brian Paul5b982362008-08-06 13:07:09 -06001189 */
1190static void
1191get_uniform_rows_cols(const struct gl_program_parameter *p,
1192 GLint *rows, GLint *cols)
1193{
1194 get_matrix_dims(p->DataType, rows, cols);
1195 if (*rows == 0 && *cols == 0) {
1196 /* not a matrix type, probably a float or vector */
Brian Paulea9568d2008-09-16 08:55:54 -06001197 if (p->Size <= 4) {
1198 *rows = 1;
1199 *cols = p->Size;
1200 }
1201 else {
1202 *rows = p->Size / 4 + 1;
1203 if (p->Size % 4 == 0)
1204 *cols = 4;
1205 else
1206 *cols = p->Size % 4;
1207 }
Brian Paul5b982362008-08-06 13:07:09 -06001208 }
1209}
1210
1211
Brian5b01c5e2006-12-19 18:02:03 -07001212/**
Brian Paul4ef7a932009-02-11 09:03:16 -07001213 * Helper for get_uniform[fi]v() functions.
1214 * Given a shader program name and uniform location, return a pointer
1215 * to the shader program and return the program parameter position.
Brian5b01c5e2006-12-19 18:02:03 -07001216 */
Brian Paul4ef7a932009-02-11 09:03:16 -07001217static void
1218lookup_uniform_parameter(GLcontext *ctx, GLuint program, GLint location,
1219 struct gl_program **progOut, GLint *paramPosOut)
Brian5b01c5e2006-12-19 18:02:03 -07001220{
Brian65a18442006-12-19 18:46:56 -07001221 struct gl_shader_program *shProg
Brian Paulbda6ad22008-08-06 12:45:14 -06001222 = _mesa_lookup_shader_program_err(ctx, program, "glGetUniform[if]v");
Brian Paul4ef7a932009-02-11 09:03:16 -07001223 struct gl_program *prog = NULL;
1224 GLint progPos = -1;
Brian Paulade50832008-05-14 16:09:46 -06001225
Brian Paul4ef7a932009-02-11 09:03:16 -07001226 /* if shProg is NULL, we'll have already recorded an error */
1227
1228 if (shProg) {
1229 if (!shProg->Uniforms ||
1230 location < 0 ||
1231 location >= (GLint) shProg->Uniforms->NumUniforms) {
1232 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
1233 }
1234 else {
1235 /* OK, find the gl_program and program parameter location */
Brian Paulade50832008-05-14 16:09:46 -06001236 progPos = shProg->Uniforms->Uniforms[location].VertPos;
1237 if (progPos >= 0) {
1238 prog = &shProg->VertexProgram->Base;
Brian5b01c5e2006-12-19 18:02:03 -07001239 }
Brian Paulade50832008-05-14 16:09:46 -06001240 else {
1241 progPos = shProg->Uniforms->Uniforms[location].FragPos;
1242 if (progPos >= 0) {
1243 prog = &shProg->FragmentProgram->Base;
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001244 }
Brian Paulade50832008-05-14 16:09:46 -06001245 }
Brian5b01c5e2006-12-19 18:02:03 -07001246 }
1247 }
Brian Paul4ef7a932009-02-11 09:03:16 -07001248
1249 *progOut = prog;
1250 *paramPosOut = progPos;
Brian Paul2be54a82008-07-08 16:17:04 -06001251}
1252
1253
1254/**
1255 * Called via ctx->Driver.GetUniformfv().
1256 */
1257static void
1258_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1259 GLfloat *params)
1260{
Brian Paul4ef7a932009-02-11 09:03:16 -07001261 struct gl_program *prog;
1262 GLint paramPos;
1263
1264 lookup_uniform_parameter(ctx, program, location, &prog, &paramPos);
1265
1266 if (prog) {
1267 const struct gl_program_parameter *p =
1268 &prog->Parameters->Parameters[paramPos];
1269 GLint rows, cols, i, j, k;
1270
1271 get_uniform_rows_cols(p, &rows, &cols);
1272
1273 k = 0;
1274 for (i = 0; i < rows; i++) {
1275 for (j = 0; j < cols; j++ ) {
1276 params[k++] = prog->Parameters->ParameterValues[paramPos+i][j];
1277 }
1278 }
1279 }
Brian Paul2be54a82008-07-08 16:17:04 -06001280}
1281
1282
1283/**
1284 * Called via ctx->Driver.GetUniformiv().
Brian Paul4ef7a932009-02-11 09:03:16 -07001285 * \sa _mesa_get_uniformfv, only difference is a cast.
Brian Paul2be54a82008-07-08 16:17:04 -06001286 */
1287static void
1288_mesa_get_uniformiv(GLcontext *ctx, GLuint program, GLint location,
1289 GLint *params)
1290{
Brian Paul4ef7a932009-02-11 09:03:16 -07001291 struct gl_program *prog;
1292 GLint paramPos;
1293
1294 lookup_uniform_parameter(ctx, program, location, &prog, &paramPos);
1295
1296 if (prog) {
1297 const struct gl_program_parameter *p =
1298 &prog->Parameters->Parameters[paramPos];
1299 GLint rows, cols, i, j, k;
1300
1301 get_uniform_rows_cols(p, &rows, &cols);
1302
1303 k = 0;
1304 for (i = 0; i < rows; i++) {
1305 for (j = 0; j < cols; j++ ) {
1306 params[k++] = (GLint) prog->Parameters->ParameterValues[paramPos+i][j];
1307 }
1308 }
Brian Paul2be54a82008-07-08 16:17:04 -06001309 }
Brian5b01c5e2006-12-19 18:02:03 -07001310}
1311
1312
1313/**
Brian Pauleda291e2008-08-06 16:26:47 -06001314 * The value returned by GetUniformLocation actually encodes two things:
1315 * 1. the index into the prog->Uniforms[] array for the uniform
1316 * 2. an offset in the prog->ParameterValues[] array for specifying array
1317 * elements or structure fields.
1318 * This function merges those two values.
1319 */
1320static void
1321merge_location_offset(GLint *location, GLint offset)
1322{
1323 *location = *location | (offset << 16);
1324}
1325
1326
1327/**
1328 * Seperate the uniform location and parameter offset. See above.
1329 */
1330static void
1331split_location_offset(GLint *location, GLint *offset)
1332{
1333 *offset = (*location >> 16);
1334 *location = *location & 0xffff;
1335}
1336
1337
1338/**
Brian5b01c5e2006-12-19 18:02:03 -07001339 * Called via ctx->Driver.GetUniformLocation().
Brian Pauleda291e2008-08-06 16:26:47 -06001340 *
1341 * The return value will encode two values, the uniform location and an
1342 * offset (used for arrays, structs).
Brian5b01c5e2006-12-19 18:02:03 -07001343 */
Brian Paulfd59f192008-05-18 16:04:55 -06001344static GLint
Brian5b01c5e2006-12-19 18:02:03 -07001345_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
1346{
Brian Pauleda291e2008-08-06 16:26:47 -06001347 GLint offset = 0, location = -1;
1348
Brian Paul530df582008-07-03 16:21:11 -06001349 struct gl_shader_program *shProg =
1350 _mesa_lookup_shader_program_err(ctx, program, "glGetUniformLocation");
1351
Brian Paulade50832008-05-14 16:09:46 -06001352 if (!shProg)
1353 return -1;
Brian5b01c5e2006-12-19 18:02:03 -07001354
Brian Paule06565b2008-07-04 09:58:55 -06001355 if (shProg->LinkStatus == GL_FALSE) {
1356 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
1357 return -1;
1358 }
1359
Brian Paul530df582008-07-03 16:21:11 -06001360 /* XXX we should return -1 if the uniform was declared, but not
1361 * actually used.
1362 */
1363
Brian Pauleda291e2008-08-06 16:26:47 -06001364 /* XXX we need to be able to parse uniform names for structs and arrays
1365 * such as:
1366 * mymatrix[1]
1367 * mystruct.field1
1368 */
1369
1370 {
1371 /* handle 1-dimension arrays here... */
1372 char *c = strchr(name, '[');
1373 if (c) {
1374 /* truncate name at [ */
1375 const GLint len = c - name;
1376 GLchar *newName = _mesa_malloc(len + 1);
1377 if (!newName)
1378 return -1; /* out of mem */
1379 _mesa_memcpy(newName, name, len);
1380 newName[len] = 0;
1381
1382 location = _mesa_lookup_uniform(shProg->Uniforms, newName);
1383 if (location >= 0) {
1384 const GLint element = _mesa_atoi(c + 1);
1385 if (element > 0) {
1386 /* get type of the uniform array element */
1387 struct gl_program_parameter *p;
1388 p = get_uniform_parameter(shProg, location);
1389 if (p) {
1390 GLint rows, cols;
1391 get_matrix_dims(p->DataType, &rows, &cols);
1392 if (rows < 1)
1393 rows = 1;
1394 offset = element * rows;
1395 }
1396 }
1397 }
1398
1399 _mesa_free(newName);
1400 }
1401 }
1402
1403 if (location < 0) {
1404 location = _mesa_lookup_uniform(shProg->Uniforms, name);
1405 }
1406
1407 if (location >= 0) {
1408 merge_location_offset(&location, offset);
1409 }
1410
1411 return location;
Brian5b01c5e2006-12-19 18:02:03 -07001412}
1413
1414
Brian34ae99d2006-12-18 08:28:54 -07001415
Brian5b01c5e2006-12-19 18:02:03 -07001416/**
1417 * Called via ctx->Driver.ShaderSource()
1418 */
Brian Paulfd59f192008-05-18 16:04:55 -06001419static void
Brian5b01c5e2006-12-19 18:02:03 -07001420_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -07001421{
Brian Paul530df582008-07-03 16:21:11 -06001422 struct gl_shader *sh;
1423
1424 sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource");
1425 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001426 return;
Brian34ae99d2006-12-18 08:28:54 -07001427
Brian34ae99d2006-12-18 08:28:54 -07001428 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -07001429 if (sh->Source) {
1430 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -07001431 }
Brian65a18442006-12-19 18:46:56 -07001432 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -07001433 sh->CompileStatus = GL_FALSE;
Brian Paulf7783ba2009-08-04 15:35:48 -06001434#ifdef DEBUG
1435 sh->SourceChecksum = _mesa_str_checksum(sh->Source);
1436#endif
Brian34ae99d2006-12-18 08:28:54 -07001437}
1438
1439
Brian5b01c5e2006-12-19 18:02:03 -07001440/**
1441 * Called via ctx->Driver.CompileShader()
1442 */
Brian Paulfd59f192008-05-18 16:04:55 -06001443static void
Brian5b01c5e2006-12-19 18:02:03 -07001444_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -07001445{
Brian Paul530df582008-07-03 16:21:11 -06001446 struct gl_shader *sh;
Brian34ae99d2006-12-18 08:28:54 -07001447
Brian Paul530df582008-07-03 16:21:11 -06001448 sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader");
1449 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001450 return;
Brian34ae99d2006-12-18 08:28:54 -07001451
Brian Paul65fc2ca2009-03-19 10:25:24 -06001452 /* set default pragma state for shader */
1453 sh->Pragmas = ctx->Shader.DefaultPragmas;
1454
Brian Paulcb136e02009-01-22 10:34:15 -07001455 /* this call will set the sh->CompileStatus field to indicate if
1456 * compilation was successful.
1457 */
1458 (void) _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -07001459}
1460
1461
Brian5b01c5e2006-12-19 18:02:03 -07001462/**
1463 * Called via ctx->Driver.LinkProgram()
1464 */
Brian Paulfd59f192008-05-18 16:04:55 -06001465static void
Brian5b01c5e2006-12-19 18:02:03 -07001466_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001467{
Brian65a18442006-12-19 18:46:56 -07001468 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001469
Brian Paul530df582008-07-03 16:21:11 -06001470 shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
1471 if (!shProg)
Brian34ae99d2006-12-18 08:28:54 -07001472 return;
Brian34ae99d2006-12-18 08:28:54 -07001473
Briandf43fb62008-05-06 23:08:51 -06001474 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1475
Brianc1771912007-02-16 09:56:19 -07001476 _slang_link(ctx, program, shProg);
Brian Paulac3c8e32009-09-14 17:32:03 -06001477
1478 /* debug code */
1479 if (0) {
1480 GLuint i;
1481
1482 _mesa_printf("Link %u shaders in program %u: %s\n",
1483 shProg->NumShaders, shProg->Name,
1484 shProg->LinkStatus ? "Success" : "Failed");
1485
1486 for (i = 0; i < shProg->NumShaders; i++) {
1487 _mesa_printf(" shader %u, type 0x%x\n",
1488 shProg->Shaders[i]->Name,
1489 shProg->Shaders[i]->Type);
1490 }
1491 }
Brian34ae99d2006-12-18 08:28:54 -07001492}
1493
1494
1495/**
Brian5b01c5e2006-12-19 18:02:03 -07001496 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001497 */
Brian5b01c5e2006-12-19 18:02:03 -07001498void
1499_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001500{
Brian3c008a02007-04-12 15:22:32 -06001501 struct gl_shader_program *shProg;
1502
Brian00d63aa2007-02-03 11:35:02 -07001503 if (ctx->Shader.CurrentProgram &&
1504 ctx->Shader.CurrentProgram->Name == program) {
1505 /* no-op */
1506 return;
1507 }
1508
Brian Paul027ed1b2009-04-24 09:43:44 -06001509 FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
Brian00d63aa2007-02-03 11:35:02 -07001510
Brian5b01c5e2006-12-19 18:02:03 -07001511 if (program) {
Brian Paul530df582008-07-03 16:21:11 -06001512 shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
Brian65a18442006-12-19 18:46:56 -07001513 if (!shProg) {
Brian Paul530df582008-07-03 16:21:11 -06001514 return;
1515 }
1516 if (!shProg->LinkStatus) {
Brian Paul621c9992009-02-18 13:28:12 -07001517 _mesa_error(ctx, GL_INVALID_OPERATION,
1518 "glUseProgram(program %u not linked)", program);
Brian5b01c5e2006-12-19 18:02:03 -07001519 return;
1520 }
Brian Paul4eda17d2009-03-13 09:11:42 -06001521
1522 /* debug code */
1523 if (0) {
1524 GLuint i;
1525 _mesa_printf("Use Shader %u\n", shProg->Name);
1526 for (i = 0; i < shProg->NumShaders; i++) {
Brian Paulf7783ba2009-08-04 15:35:48 -06001527 _mesa_printf(" shader %u, type 0x%x, checksum %u\n",
Brian Paul4eda17d2009-03-13 09:11:42 -06001528 shProg->Shaders[i]->Name,
Brian Paulf7783ba2009-08-04 15:35:48 -06001529 shProg->Shaders[i]->Type,
1530 shProg->Shaders[i]->SourceChecksum);
Brian Paul4eda17d2009-03-13 09:11:42 -06001531 }
Brian Paulccaa6462009-05-08 12:17:11 -06001532 if (shProg->VertexProgram)
1533 printf(" vert prog %u\n", shProg->VertexProgram->Base.Id);
1534 if (shProg->FragmentProgram)
1535 printf(" frag prog %u\n", shProg->FragmentProgram->Base.Id);
Brian Paul4eda17d2009-03-13 09:11:42 -06001536 }
Brian5b01c5e2006-12-19 18:02:03 -07001537 }
1538 else {
Brian3c008a02007-04-12 15:22:32 -06001539 shProg = NULL;
1540 }
1541
1542 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001543}
Brian34ae99d2006-12-18 08:28:54 -07001544
Brian5b01c5e2006-12-19 18:02:03 -07001545
Brian Paulade50832008-05-14 16:09:46 -06001546
1547/**
Brian Paul517401a2008-11-06 15:04:11 -07001548 * Update the vertex/fragment program's TexturesUsed array.
1549 *
1550 * This needs to be called after glUniform(set sampler var) is called.
1551 * A call to glUniform(samplerVar, value) causes a sampler to point to a
1552 * particular texture unit. We know the sampler's texture target
1553 * (1D/2D/3D/etc) from compile time but the sampler's texture unit is
1554 * set by glUniform() calls.
1555 *
1556 * So, scan the program->SamplerUnits[] and program->SamplerTargets[]
1557 * information to update the prog->TexturesUsed[] values.
1558 * Each value of TexturesUsed[unit] is one of zero, TEXTURE_1D_INDEX,
1559 * TEXTURE_2D_INDEX, TEXTURE_3D_INDEX, etc.
1560 * We'll use that info for state validation before rendering.
Brian Paulade50832008-05-14 16:09:46 -06001561 */
Brian Paul517401a2008-11-06 15:04:11 -07001562void
1563_mesa_update_shader_textures_used(struct gl_program *prog)
Brian Paulade50832008-05-14 16:09:46 -06001564{
1565 GLuint s;
1566
1567 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1568
1569 for (s = 0; s < MAX_SAMPLERS; s++) {
1570 if (prog->SamplersUsed & (1 << s)) {
Brian Paulf05344f2009-08-26 10:58:06 -06001571 GLuint unit = prog->SamplerUnits[s];
1572 GLuint tgt = prog->SamplerTargets[s];
1573 assert(unit < MAX_TEXTURE_IMAGE_UNITS);
1574 assert(tgt < NUM_TEXTURE_TARGETS);
1575 prog->TexturesUsed[unit] |= (1 << tgt);
Brian Paulade50832008-05-14 16:09:46 -06001576 }
1577 }
1578}
1579
1580
1581/**
Brian Paulffbc66b2008-07-21 13:58:50 -06001582 * Check if the type given by userType is allowed to set a uniform of the
1583 * target type. Generally, equivalence is required, but setting Boolean
1584 * uniforms can be done with glUniformiv or glUniformfv.
1585 */
1586static GLboolean
1587compatible_types(GLenum userType, GLenum targetType)
1588{
1589 if (userType == targetType)
1590 return GL_TRUE;
1591
1592 if (targetType == GL_BOOL && (userType == GL_FLOAT || userType == GL_INT))
1593 return GL_TRUE;
1594
1595 if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 ||
1596 userType == GL_INT_VEC2))
1597 return GL_TRUE;
1598
1599 if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 ||
1600 userType == GL_INT_VEC3))
1601 return GL_TRUE;
1602
1603 if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 ||
1604 userType == GL_INT_VEC4))
1605 return GL_TRUE;
1606
Brianb36749d2008-07-21 20:42:05 -06001607 if (is_sampler_type(targetType) && userType == GL_INT)
1608 return GL_TRUE;
1609
Brian Paulffbc66b2008-07-21 13:58:50 -06001610 return GL_FALSE;
1611}
1612
1613
1614/**
Brian Paulade50832008-05-14 16:09:46 -06001615 * Set the value of a program's uniform variable.
1616 * \param program the program whose uniform to update
Brian Pauleda291e2008-08-06 16:26:47 -06001617 * \param index the index of the program parameter for the uniform
1618 * \param offset additional parameter slot offset (for arrays)
Brian Paulc4ffbf02009-02-18 17:46:00 -07001619 * \param type the incoming datatype of 'values'
Brian Paulade50832008-05-14 16:09:46 -06001620 * \param count the number of uniforms to set
Brian Paulc4ffbf02009-02-18 17:46:00 -07001621 * \param elems number of elements per uniform (1, 2, 3 or 4)
1622 * \param values the new values, of datatype 'type'
Brian Paulade50832008-05-14 16:09:46 -06001623 */
1624static void
Brian Pauleda291e2008-08-06 16:26:47 -06001625set_program_uniform(GLcontext *ctx, struct gl_program *program,
1626 GLint index, GLint offset,
1627 GLenum type, GLsizei count, GLint elems,
1628 const void *values)
Brian Paulade50832008-05-14 16:09:46 -06001629{
Brian Paul6df38e62009-08-26 14:35:45 -06001630 const struct gl_program_parameter *param =
Brian Paul949e7382008-11-05 09:17:55 -07001631 &program->Parameters->Parameters[index];
1632
Brian Pauleda291e2008-08-06 16:26:47 -06001633 assert(offset >= 0);
Brian Paulc4ffbf02009-02-18 17:46:00 -07001634 assert(elems >= 1);
1635 assert(elems <= 4);
Brian Pauleda291e2008-08-06 16:26:47 -06001636
Brian Paul949e7382008-11-05 09:17:55 -07001637 if (!compatible_types(type, param->DataType)) {
Brian Paulffbc66b2008-07-21 13:58:50 -06001638 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
1639 return;
1640 }
1641
Michal Krolc5c71302008-08-07 16:23:15 +02001642 if (index + offset > (GLint) program->Parameters->Size) {
Brian Pauleda291e2008-08-06 16:26:47 -06001643 /* out of bounds! */
1644 return;
1645 }
1646
Brian Paul949e7382008-11-05 09:17:55 -07001647 if (param->Type == PROGRAM_SAMPLER) {
Brian Paulade50832008-05-14 16:09:46 -06001648 /* This controls which texture unit which is used by a sampler */
Brian Paulbabb5ba2009-08-26 14:29:50 -06001649 GLboolean changed = GL_FALSE;
Brian Paul2b4f0212009-02-11 09:12:34 -07001650 GLint i;
Brian Paulade50832008-05-14 16:09:46 -06001651
Brian Paul6df38e62009-08-26 14:35:45 -06001652 /* this should have been caught by the compatible_types() check */
1653 ASSERT(type == GL_INT);
Brian Paulade50832008-05-14 16:09:46 -06001654
Brian Paul6df38e62009-08-26 14:35:45 -06001655 /* loop over number of samplers to change */
Brian Paul2b4f0212009-02-11 09:12:34 -07001656 for (i = 0; i < count; i++) {
Brian Paul04d17072009-08-26 11:39:24 -06001657 GLuint sampler =
1658 (GLuint) program->Parameters->ParameterValues[index + offset + i][0];
1659 GLuint texUnit = ((GLuint *) values)[i];
Brian Paulade50832008-05-14 16:09:46 -06001660
Brian Paul2b4f0212009-02-11 09:12:34 -07001661 /* check that the sampler (tex unit index) is legal */
1662 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1663 _mesa_error(ctx, GL_INVALID_VALUE,
1664 "glUniform1(invalid sampler/tex unit index)");
1665 return;
1666 }
1667
1668 /* This maps a sampler to a texture unit: */
1669 if (sampler < MAX_SAMPLERS) {
Brian Paul04d17072009-08-26 11:39:24 -06001670#if 0
1671 _mesa_printf("Set program %p sampler %d '%s' to unit %u\n",
1672 program, sampler, param->Name, texUnit);
1673#endif
Brian Paulbabb5ba2009-08-26 14:29:50 -06001674 if (program->SamplerUnits[sampler] != texUnit) {
1675 program->SamplerUnits[sampler] = texUnit;
1676 changed = GL_TRUE;
1677 }
Brian Paul2b4f0212009-02-11 09:12:34 -07001678 }
Brian Paulade50832008-05-14 16:09:46 -06001679 }
1680
Brian Paulbabb5ba2009-08-26 14:29:50 -06001681 if (changed) {
1682 /* When a sampler's value changes it usually requires rewriting
1683 * a GPU program's TEX instructions since there may not be a
1684 * sampler->texture lookup table. We signal this with the
1685 * ProgramStringNotify() callback.
1686 */
1687 FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM);
1688 _mesa_update_shader_textures_used(program);
1689 ctx->Driver.ProgramStringNotify(ctx, program->Target, program);
1690 }
Brian Paulade50832008-05-14 16:09:46 -06001691 }
1692 else {
1693 /* ordinary uniform variable */
Brian Paul6df38e62009-08-26 14:35:45 -06001694 const GLboolean isUniformBool = is_boolean_type(param->DataType);
1695 const GLboolean areIntValues = is_integer_type(type);
Brian Paul2c1ea072009-02-11 08:46:21 -07001696 const GLint slots = (param->Size + 3) / 4;
1697 const GLint typeSize = sizeof_glsl_type(param->DataType);
Brian Paul6df38e62009-08-26 14:35:45 -06001698 GLsizei k, i;
Brian Paulade50832008-05-14 16:09:46 -06001699
Brian Paul2c1ea072009-02-11 08:46:21 -07001700 if (param->Size > typeSize) {
1701 /* an array */
1702 /* we'll ignore extra data below */
1703 }
1704 else {
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001705 /* non-array: count must be at most one; count == 0 is handled by the loop below */
1706 if (count > 1) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001707 _mesa_error(ctx, GL_INVALID_OPERATION,
1708 "glUniform(uniform is not an array)");
1709 return;
1710 }
Brian Paulade50832008-05-14 16:09:46 -06001711 }
1712
Brian Paulc4ffbf02009-02-18 17:46:00 -07001713 /* loop over number of array elements */
Brian Paulade50832008-05-14 16:09:46 -06001714 for (k = 0; k < count; k++) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001715 GLfloat *uniformVal;
1716
Brian Paulb9d8f712009-02-18 17:40:44 -07001717 if (offset + k >= slots) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001718 /* Extra array data is ignored */
1719 break;
1720 }
1721
Brian Paulc4ffbf02009-02-18 17:46:00 -07001722 /* uniformVal (the destination) is always float[4] */
Brian Paul2c1ea072009-02-11 08:46:21 -07001723 uniformVal = program->Parameters->ParameterValues[index + offset + k];
Brian Paulc4ffbf02009-02-18 17:46:00 -07001724
1725 if (areIntValues) {
1726 /* convert user's ints to floats */
Brian Paulade50832008-05-14 16:09:46 -06001727 const GLint *iValues = ((const GLint *) values) + k * elems;
1728 for (i = 0; i < elems; i++) {
1729 uniformVal[i] = (GLfloat) iValues[i];
1730 }
1731 }
1732 else {
1733 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1734 for (i = 0; i < elems; i++) {
1735 uniformVal[i] = fValues[i];
1736 }
1737 }
Brian Pauleda291e2008-08-06 16:26:47 -06001738
1739 /* if the uniform is bool-valued, convert to 1.0 or 0.0 */
Brian Paulc4ffbf02009-02-18 17:46:00 -07001740 if (isUniformBool) {
Brian Pauleda291e2008-08-06 16:26:47 -06001741 for (i = 0; i < elems; i++) {
Michal Krolc5c71302008-08-07 16:23:15 +02001742 uniformVal[i] = uniformVal[i] ? 1.0f : 0.0f;
Brian Pauleda291e2008-08-06 16:26:47 -06001743 }
1744 }
Brian Paulade50832008-05-14 16:09:46 -06001745 }
1746 }
1747}
1748
1749
Brian5b01c5e2006-12-19 18:02:03 -07001750/**
1751 * Called via ctx->Driver.Uniform().
1752 */
Brian Paulfd59f192008-05-18 16:04:55 -06001753static void
Brian5b01c5e2006-12-19 18:02:03 -07001754_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1755 const GLvoid *values, GLenum type)
1756{
Brian3a8e2772006-12-20 17:19:16 -07001757 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paul2d76a0d2008-11-10 12:33:17 -07001758 struct gl_uniform *uniform;
Brian Pauleda291e2008-08-06 16:26:47 -06001759 GLint elems, offset;
Brian Paule01a03d2009-02-06 10:21:36 -07001760 GLenum basicType;
Brian3a8e2772006-12-20 17:19:16 -07001761
1762 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001763 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001764 return;
1765 }
1766
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001767 if (location == -1)
1768 return; /* The standard specifies this as a no-op */
1769
Brian Paul234f03e2009-02-11 09:05:08 -07001770 if (location < -1) {
1771 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(location)");
1772 return;
1773 }
1774
Brian Pauleda291e2008-08-06 16:26:47 -06001775 split_location_offset(&location, &offset);
1776
Brian Paulade50832008-05-14 16:09:46 -06001777 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
1778 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
Brian3a8e2772006-12-20 17:19:16 -07001779 return;
1780 }
1781
Brian52363952007-03-13 16:50:24 -06001782 if (count < 0) {
1783 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1784 return;
1785 }
1786
Brian98650bd2007-03-13 16:32:48 -06001787 switch (type) {
1788 case GL_FLOAT:
Brian Paule01a03d2009-02-06 10:21:36 -07001789 basicType = GL_FLOAT;
1790 elems = 1;
1791 break;
Brian98650bd2007-03-13 16:32:48 -06001792 case GL_INT:
Brian Paule01a03d2009-02-06 10:21:36 -07001793 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001794 elems = 1;
1795 break;
1796 case GL_FLOAT_VEC2:
Brian Paule01a03d2009-02-06 10:21:36 -07001797 basicType = GL_FLOAT;
1798 elems = 2;
1799 break;
Brian98650bd2007-03-13 16:32:48 -06001800 case GL_INT_VEC2:
Brian Paule01a03d2009-02-06 10:21:36 -07001801 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001802 elems = 2;
1803 break;
1804 case GL_FLOAT_VEC3:
Brian Paule01a03d2009-02-06 10:21:36 -07001805 basicType = GL_FLOAT;
1806 elems = 3;
1807 break;
Brian98650bd2007-03-13 16:32:48 -06001808 case GL_INT_VEC3:
Brian Paule01a03d2009-02-06 10:21:36 -07001809 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001810 elems = 3;
1811 break;
1812 case GL_FLOAT_VEC4:
Brian Paule01a03d2009-02-06 10:21:36 -07001813 basicType = GL_FLOAT;
1814 elems = 4;
1815 break;
Brian98650bd2007-03-13 16:32:48 -06001816 case GL_INT_VEC4:
Brian Paule01a03d2009-02-06 10:21:36 -07001817 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001818 elems = 4;
1819 break;
1820 default:
1821 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1822 return;
Brian89dc4852007-01-04 14:35:44 -07001823 }
Brian98650bd2007-03-13 16:32:48 -06001824
Brian Paul027ed1b2009-04-24 09:43:44 -06001825 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
Brian98650bd2007-03-13 16:32:48 -06001826
Brian Paul2d76a0d2008-11-10 12:33:17 -07001827 uniform = &shProg->Uniforms->Uniforms[location];
1828
Brian Paule01a03d2009-02-06 10:21:36 -07001829 if (ctx->Shader.Flags & GLSL_UNIFORMS) {
1830 GLint i;
1831 _mesa_printf("Mesa: set program %u uniform %s (loc %d) to: ",
1832 shProg->Name, uniform->Name, location);
1833 if (basicType == GL_INT) {
1834 const GLint *v = (const GLint *) values;
1835 for (i = 0; i < count * elems; i++) {
1836 _mesa_printf("%d ", v[i]);
1837 }
1838 }
1839 else {
1840 const GLfloat *v = (const GLfloat *) values;
1841 for (i = 0; i < count * elems; i++) {
1842 _mesa_printf("%g ", v[i]);
1843 }
1844 }
1845 _mesa_printf("\n");
1846 }
1847
Brian Paulade50832008-05-14 16:09:46 -06001848 /* A uniform var may be used by both a vertex shader and a fragment
1849 * shader. We may need to update one or both shader's uniform here:
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001850 */
Brian Paulade50832008-05-14 16:09:46 -06001851 if (shProg->VertexProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001852 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07001853 GLint index = uniform->VertPos;
Brian Pauleda291e2008-08-06 16:26:47 -06001854 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001855 set_program_uniform(ctx, &shProg->VertexProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001856 index, offset, type, count, elems, values);
Bruce Merry2bf2a8c2007-12-21 23:18:40 +02001857 }
Brian5b01c5e2006-12-19 18:02:03 -07001858 }
Brian5cf73262007-01-05 16:02:45 -07001859
Brian Paulade50832008-05-14 16:09:46 -06001860 if (shProg->FragmentProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001861 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07001862 GLint index = uniform->FragPos;
Brian Pauleda291e2008-08-06 16:26:47 -06001863 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001864 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001865 index, offset, type, count, elems, values);
Brian Paulade50832008-05-14 16:09:46 -06001866 }
1867 }
Brian Paul949e7382008-11-05 09:17:55 -07001868
Brian Paul2d76a0d2008-11-10 12:33:17 -07001869 uniform->Initialized = GL_TRUE;
Brian Paulade50832008-05-14 16:09:46 -06001870}
1871
1872
Brian Pauleda291e2008-08-06 16:26:47 -06001873/**
1874 * Set a matrix-valued program parameter.
1875 */
Brian Paulade50832008-05-14 16:09:46 -06001876static void
1877set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
Brian Pauleda291e2008-08-06 16:26:47 -06001878 GLuint index, GLuint offset,
1879 GLuint count, GLuint rows, GLuint cols,
Brian Paulade50832008-05-14 16:09:46 -06001880 GLboolean transpose, const GLfloat *values)
1881{
Brian Paulffbc66b2008-07-21 13:58:50 -06001882 GLuint mat, row, col;
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001883 GLuint src = 0;
1884 const struct gl_program_parameter * param = &program->Parameters->Parameters[index];
1885 const GLint slots = (param->Size + 3) / 4;
1886 const GLint typeSize = sizeof_glsl_type(param->DataType);
Brian Paulffbc66b2008-07-21 13:58:50 -06001887 GLint nr, nc;
1888
1889 /* check that the number of rows, columns is correct */
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001890 get_matrix_dims(param->DataType, &nr, &nc);
Brian Paulffbc66b2008-07-21 13:58:50 -06001891 if (rows != nr || cols != nc) {
1892 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Pauleda291e2008-08-06 16:26:47 -06001893 "glUniformMatrix(matrix size mismatch)");
1894 return;
1895 }
1896
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001897 if (param->Size <= typeSize) {
1898 /* non-array: count must be at most one; count == 0 is handled by the loop below */
1899 if (count > 1) {
1900 _mesa_error(ctx, GL_INVALID_OPERATION,
1901 "glUniformMatrix(uniform is not an array)");
1902 return;
1903 }
Brian Paulffbc66b2008-07-21 13:58:50 -06001904 }
1905
Brian Paulade50832008-05-14 16:09:46 -06001906 /*
1907 * Note: the _columns_ of a matrix are stored in program registers, not
Brian Paulf45ed0e2008-07-18 12:51:39 -06001908 * the rows. So, the loops below look a little funny.
1909 * XXX could optimize this a bit...
Brian Paulade50832008-05-14 16:09:46 -06001910 */
Brian Paulf45ed0e2008-07-18 12:51:39 -06001911
1912 /* loop over matrices */
1913 for (mat = 0; mat < count; mat++) {
1914
1915 /* each matrix: */
Brian Paulade50832008-05-14 16:09:46 -06001916 for (col = 0; col < cols; col++) {
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001917 GLfloat *v;
1918 if (offset >= slots) {
1919 /* Ignore writes beyond the end of (the used part of) an array */
1920 return;
1921 }
1922 v = program->Parameters->ParameterValues[index + offset];
Brian Paulade50832008-05-14 16:09:46 -06001923 for (row = 0; row < rows; row++) {
Brian Paulf45ed0e2008-07-18 12:51:39 -06001924 if (transpose) {
1925 v[row] = values[src + row * cols + col];
1926 }
1927 else {
1928 v[row] = values[src + col * rows + row];
1929 }
Brian Paulade50832008-05-14 16:09:46 -06001930 }
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001931
1932 offset++;
Brian Paulade50832008-05-14 16:09:46 -06001933 }
Brian Paulf45ed0e2008-07-18 12:51:39 -06001934
1935 src += rows * cols; /* next matrix */
Brian5cf73262007-01-05 16:02:45 -07001936 }
Brian34ae99d2006-12-18 08:28:54 -07001937}
1938
1939
1940/**
Brian5b01c5e2006-12-19 18:02:03 -07001941 * Called by ctx->Driver.UniformMatrix().
Brian Paulf45ed0e2008-07-18 12:51:39 -06001942 * Note: cols=2, rows=4 ==> array[2] of vec4
Brian34ae99d2006-12-18 08:28:54 -07001943 */
Brian Paulfd59f192008-05-18 16:04:55 -06001944static void
Brian5b01c5e2006-12-19 18:02:03 -07001945_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
Brian Paul0115a4f2009-04-14 20:00:28 -06001946 GLint location, GLsizei count,
Brian5b01c5e2006-12-19 18:02:03 -07001947 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001948{
Brian3a8e2772006-12-20 17:19:16 -07001949 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paul2d76a0d2008-11-10 12:33:17 -07001950 struct gl_uniform *uniform;
1951 GLint offset;
Brian Paulade50832008-05-14 16:09:46 -06001952
Brian3a8e2772006-12-20 17:19:16 -07001953 if (!shProg || !shProg->LinkStatus) {
1954 _mesa_error(ctx, GL_INVALID_OPERATION,
1955 "glUniformMatrix(program not linked)");
1956 return;
1957 }
Brian Paulade50832008-05-14 16:09:46 -06001958
Bruce Merry89b80322007-12-21 15:20:17 +02001959 if (location == -1)
1960 return; /* The standard specifies this as a no-op */
Brian Paulade50832008-05-14 16:09:46 -06001961
Brian Paul234f03e2009-02-11 09:05:08 -07001962 if (location < -1) {
1963 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(location)");
1964 return;
1965 }
1966
Brian Pauleda291e2008-08-06 16:26:47 -06001967 split_location_offset(&location, &offset);
1968
Brian Paul016701f2008-07-29 17:43:35 -06001969 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian Paulade50832008-05-14 16:09:46 -06001970 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
Brian3a8e2772006-12-20 17:19:16 -07001971 return;
1972 }
Brian34ae99d2006-12-18 08:28:54 -07001973 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001974 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001975 return;
1976 }
1977
Brian Paul027ed1b2009-04-24 09:43:44 -06001978 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
Brian34ae99d2006-12-18 08:28:54 -07001979
Brian Paul2d76a0d2008-11-10 12:33:17 -07001980 uniform = &shProg->Uniforms->Uniforms[location];
1981
Brian Paulade50832008-05-14 16:09:46 -06001982 if (shProg->VertexProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001983 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07001984 GLint index = uniform->VertPos;
Brian Pauleda291e2008-08-06 16:26:47 -06001985 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001986 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001987 index, offset,
1988 count, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07001989 }
Brian Paulade50832008-05-14 16:09:46 -06001990 }
1991
1992 if (shProg->FragmentProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001993 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07001994 GLint index = uniform->FragPos;
Brian Pauleda291e2008-08-06 16:26:47 -06001995 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001996 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001997 index, offset,
1998 count, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07001999 }
Brian34ae99d2006-12-18 08:28:54 -07002000 }
Brian Paul949e7382008-11-05 09:17:55 -07002001
Brian Paul2d76a0d2008-11-10 12:33:17 -07002002 uniform->Initialized = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07002003}
2004
2005
Brian Paulc90fca32009-08-25 17:42:47 -06002006/**
2007 * Validate a program's samplers.
2008 * Specifically, check that there aren't two samplers of different types
2009 * pointing to the same texture unit.
2010 * \return GL_TRUE if valid, GL_FALSE if invalid
2011 */
2012static GLboolean
2013validate_samplers(GLcontext *ctx, const struct gl_program *prog, char *errMsg)
Brian34ae99d2006-12-18 08:28:54 -07002014{
Brian Paulc90fca32009-08-25 17:42:47 -06002015 static const char *targetName[] = {
2016 "TEXTURE_2D_ARRAY",
2017 "TEXTURE_1D_ARRAY",
2018 "TEXTURE_CUBE",
2019 "TEXTURE_3D",
2020 "TEXTURE_RECT",
2021 "TEXTURE_2D",
2022 "TEXTURE_1D",
2023 };
2024 GLint targetUsed[MAX_TEXTURE_IMAGE_UNITS];
2025 GLbitfield samplersUsed = prog->SamplersUsed;
2026 GLuint i;
Brian Paulbc985b52008-07-21 14:16:07 -06002027
Brian Paulc90fca32009-08-25 17:42:47 -06002028 assert(Elements(targetName) == NUM_TEXTURE_TARGETS);
2029
2030 if (samplersUsed == 0x0)
2031 return GL_TRUE;
2032
2033 for (i = 0; i < Elements(targetUsed); i++)
2034 targetUsed[i] = -1;
2035
2036 /* walk over bits which are set in 'samplers' */
2037 while (samplersUsed) {
2038 GLuint unit;
2039 gl_texture_index target;
2040 GLint sampler = _mesa_ffs(samplersUsed) - 1;
2041 assert(sampler >= 0);
2042 assert(sampler < MAX_TEXTURE_IMAGE_UNITS);
2043 unit = prog->SamplerUnits[sampler];
2044 target = prog->SamplerTargets[sampler];
2045 if (targetUsed[unit] != -1 && targetUsed[unit] != target) {
2046 _mesa_snprintf(errMsg, 100,
2047 "Texture unit %d is accessed both as %s and %s",
2048 unit, targetName[targetUsed[unit]], targetName[target]);
2049 return GL_FALSE;
2050 }
2051 targetUsed[unit] = target;
2052 samplersUsed ^= (1 << sampler);
Brian34ae99d2006-12-18 08:28:54 -07002053 }
2054
Brian Paulc90fca32009-08-25 17:42:47 -06002055 return GL_TRUE;
2056}
2057
2058
2059/**
2060 * Do validation of the given shader program.
2061 * \param errMsg returns error message if validation fails.
2062 * \return GL_TRUE if valid, GL_FALSE if invalid (and set errMsg)
2063 */
2064GLboolean
2065_mesa_validate_shader_program(GLcontext *ctx,
2066 const struct gl_shader_program *shProg,
2067 char *errMsg)
2068{
2069 const struct gl_vertex_program *vp = shProg->VertexProgram;
2070 const struct gl_fragment_program *fp = shProg->FragmentProgram;
2071
Brian Paulbc985b52008-07-21 14:16:07 -06002072 if (!shProg->LinkStatus) {
Brian Paulc90fca32009-08-25 17:42:47 -06002073 return GL_FALSE;
Brian Paulbc985b52008-07-21 14:16:07 -06002074 }
2075
2076 /* From the GL spec, a program is invalid if any of these are true:
2077
Brian5b01c5e2006-12-19 18:02:03 -07002078 any two active samplers in the current program object are of
2079 different types, but refer to the same texture image unit,
2080
2081 any active sampler in the current program object refers to a texture
2082 image unit where fixed-function fragment processing accesses a
2083 texture target that does not match the sampler type, or
2084
2085 the sum of the number of active samplers in the program and the
2086 number of texture image units enabled for fixed-function fragment
2087 processing exceeds the combined limit on the total number of texture
2088 image units allowed.
2089 */
Brian Paulbc985b52008-07-21 14:16:07 -06002090
Brian Paulc90fca32009-08-25 17:42:47 -06002091
2092 /*
2093 * Check: any two active samplers in the current program object are of
2094 * different types, but refer to the same texture image unit,
2095 */
2096 if (vp && !validate_samplers(ctx, &vp->Base, errMsg)) {
2097 return GL_FALSE;
2098 }
2099 if (fp && !validate_samplers(ctx, &fp->Base, errMsg)) {
2100 return GL_FALSE;
2101 }
2102
2103 return GL_TRUE;
2104}
2105
2106
2107/**
2108 * Called via glValidateProgram()
2109 */
2110static void
2111_mesa_validate_program(GLcontext *ctx, GLuint program)
2112{
2113 struct gl_shader_program *shProg;
2114 char errMsg[100];
2115
2116 shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram");
2117 if (!shProg) {
2118 return;
2119 }
2120
2121 shProg->Validated = _mesa_validate_shader_program(ctx, shProg, errMsg);
2122 if (!shProg->Validated) {
2123 /* update info log */
2124 if (shProg->InfoLog) {
2125 _mesa_free(shProg->InfoLog);
2126 }
2127 shProg->InfoLog = _mesa_strdup(errMsg);
2128 }
Brian34ae99d2006-12-18 08:28:54 -07002129}
Brian Paulfd59f192008-05-18 16:04:55 -06002130
2131
2132/**
2133 * Plug in Mesa's GLSL functions into the device driver function table.
2134 */
2135void
2136_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
2137{
2138 driver->AttachShader = _mesa_attach_shader;
2139 driver->BindAttribLocation = _mesa_bind_attrib_location;
2140 driver->CompileShader = _mesa_compile_shader;
2141 driver->CreateProgram = _mesa_create_program;
2142 driver->CreateShader = _mesa_create_shader;
2143 driver->DeleteProgram2 = _mesa_delete_program2;
2144 driver->DeleteShader = _mesa_delete_shader;
2145 driver->DetachShader = _mesa_detach_shader;
2146 driver->GetActiveAttrib = _mesa_get_active_attrib;
2147 driver->GetActiveUniform = _mesa_get_active_uniform;
2148 driver->GetAttachedShaders = _mesa_get_attached_shaders;
2149 driver->GetAttribLocation = _mesa_get_attrib_location;
2150 driver->GetHandle = _mesa_get_handle;
2151 driver->GetProgramiv = _mesa_get_programiv;
2152 driver->GetProgramInfoLog = _mesa_get_program_info_log;
2153 driver->GetShaderiv = _mesa_get_shaderiv;
2154 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
2155 driver->GetShaderSource = _mesa_get_shader_source;
2156 driver->GetUniformfv = _mesa_get_uniformfv;
Brian Paul2be54a82008-07-08 16:17:04 -06002157 driver->GetUniformiv = _mesa_get_uniformiv;
Brian Paulfd59f192008-05-18 16:04:55 -06002158 driver->GetUniformLocation = _mesa_get_uniform_location;
2159 driver->IsProgram = _mesa_is_program;
2160 driver->IsShader = _mesa_is_shader;
2161 driver->LinkProgram = _mesa_link_program;
2162 driver->ShaderSource = _mesa_shader_source;
2163 driver->Uniform = _mesa_uniform;
2164 driver->UniformMatrix = _mesa_uniform_matrix;
2165 driver->UseProgram = _mesa_use_program;
2166 driver->ValidateProgram = _mesa_validate_program;
2167}