blob: 6de97984e6d8d827e7ecde265efdffcad2a47478 [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;
Brian Paulcb0de062009-09-29 10:22:32 -0600383 if (_mesa_strstr(env, "nopvert"))
384 flags |= GLSL_NOP_VERT;
385 if (_mesa_strstr(env, "nopfrag"))
386 flags |= GLSL_NOP_FRAG;
Brian Paule01a03d2009-02-06 10:21:36 -0700387 if (_mesa_strstr(env, "nopt"))
388 flags |= GLSL_NO_OPT;
389 else if (_mesa_strstr(env, "opt"))
390 flags |= GLSL_OPT;
391 if (_mesa_strstr(env, "uniform"))
392 flags |= GLSL_UNIFORMS;
393 }
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);
958 if (param->Size > typeSize) {
959 /* 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/**
Brian5b01c5e2006-12-19 18:02:03 -07001500 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001501 */
Brian5b01c5e2006-12-19 18:02:03 -07001502void
1503_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001504{
Brian3c008a02007-04-12 15:22:32 -06001505 struct gl_shader_program *shProg;
1506
Brian00d63aa2007-02-03 11:35:02 -07001507 if (ctx->Shader.CurrentProgram &&
1508 ctx->Shader.CurrentProgram->Name == program) {
1509 /* no-op */
1510 return;
1511 }
1512
Brian Paul027ed1b2009-04-24 09:43:44 -06001513 FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
Brian00d63aa2007-02-03 11:35:02 -07001514
Brian5b01c5e2006-12-19 18:02:03 -07001515 if (program) {
Brian Paul530df582008-07-03 16:21:11 -06001516 shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
Brian65a18442006-12-19 18:46:56 -07001517 if (!shProg) {
Brian Paul530df582008-07-03 16:21:11 -06001518 return;
1519 }
1520 if (!shProg->LinkStatus) {
Brian Paul621c9992009-02-18 13:28:12 -07001521 _mesa_error(ctx, GL_INVALID_OPERATION,
1522 "glUseProgram(program %u not linked)", program);
Brian5b01c5e2006-12-19 18:02:03 -07001523 return;
1524 }
Brian Paul4eda17d2009-03-13 09:11:42 -06001525
1526 /* debug code */
1527 if (0) {
1528 GLuint i;
Brian Paul220f72a2009-10-13 16:33:17 -06001529 _mesa_printf("Use Shader Program %u\n", shProg->Name);
Brian Paul4eda17d2009-03-13 09:11:42 -06001530 for (i = 0; i < shProg->NumShaders; i++) {
Brian Paulf7783ba2009-08-04 15:35:48 -06001531 _mesa_printf(" shader %u, type 0x%x, checksum %u\n",
Brian Paul4eda17d2009-03-13 09:11:42 -06001532 shProg->Shaders[i]->Name,
Brian Paulf7783ba2009-08-04 15:35:48 -06001533 shProg->Shaders[i]->Type,
1534 shProg->Shaders[i]->SourceChecksum);
Brian Paul4eda17d2009-03-13 09:11:42 -06001535 }
Brian Paulccaa6462009-05-08 12:17:11 -06001536 if (shProg->VertexProgram)
1537 printf(" vert prog %u\n", shProg->VertexProgram->Base.Id);
1538 if (shProg->FragmentProgram)
1539 printf(" frag prog %u\n", shProg->FragmentProgram->Base.Id);
Brian Paul4eda17d2009-03-13 09:11:42 -06001540 }
Brian5b01c5e2006-12-19 18:02:03 -07001541 }
1542 else {
Brian3c008a02007-04-12 15:22:32 -06001543 shProg = NULL;
1544 }
1545
1546 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001547}
Brian34ae99d2006-12-18 08:28:54 -07001548
Brian5b01c5e2006-12-19 18:02:03 -07001549
Brian Paulade50832008-05-14 16:09:46 -06001550
1551/**
Brian Paul517401a2008-11-06 15:04:11 -07001552 * Update the vertex/fragment program's TexturesUsed array.
1553 *
1554 * This needs to be called after glUniform(set sampler var) is called.
1555 * A call to glUniform(samplerVar, value) causes a sampler to point to a
1556 * particular texture unit. We know the sampler's texture target
1557 * (1D/2D/3D/etc) from compile time but the sampler's texture unit is
1558 * set by glUniform() calls.
1559 *
1560 * So, scan the program->SamplerUnits[] and program->SamplerTargets[]
1561 * information to update the prog->TexturesUsed[] values.
1562 * Each value of TexturesUsed[unit] is one of zero, TEXTURE_1D_INDEX,
1563 * TEXTURE_2D_INDEX, TEXTURE_3D_INDEX, etc.
1564 * We'll use that info for state validation before rendering.
Brian Paulade50832008-05-14 16:09:46 -06001565 */
Brian Paul517401a2008-11-06 15:04:11 -07001566void
1567_mesa_update_shader_textures_used(struct gl_program *prog)
Brian Paulade50832008-05-14 16:09:46 -06001568{
1569 GLuint s;
1570
1571 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1572
1573 for (s = 0; s < MAX_SAMPLERS; s++) {
1574 if (prog->SamplersUsed & (1 << s)) {
Brian Paulf05344f2009-08-26 10:58:06 -06001575 GLuint unit = prog->SamplerUnits[s];
1576 GLuint tgt = prog->SamplerTargets[s];
1577 assert(unit < MAX_TEXTURE_IMAGE_UNITS);
1578 assert(tgt < NUM_TEXTURE_TARGETS);
1579 prog->TexturesUsed[unit] |= (1 << tgt);
Brian Paulade50832008-05-14 16:09:46 -06001580 }
1581 }
1582}
1583
1584
1585/**
Brian Paulffbc66b2008-07-21 13:58:50 -06001586 * Check if the type given by userType is allowed to set a uniform of the
1587 * target type. Generally, equivalence is required, but setting Boolean
1588 * uniforms can be done with glUniformiv or glUniformfv.
1589 */
1590static GLboolean
1591compatible_types(GLenum userType, GLenum targetType)
1592{
1593 if (userType == targetType)
1594 return GL_TRUE;
1595
1596 if (targetType == GL_BOOL && (userType == GL_FLOAT || userType == GL_INT))
1597 return GL_TRUE;
1598
1599 if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 ||
1600 userType == GL_INT_VEC2))
1601 return GL_TRUE;
1602
1603 if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 ||
1604 userType == GL_INT_VEC3))
1605 return GL_TRUE;
1606
1607 if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 ||
1608 userType == GL_INT_VEC4))
1609 return GL_TRUE;
1610
Brianb36749d2008-07-21 20:42:05 -06001611 if (is_sampler_type(targetType) && userType == GL_INT)
1612 return GL_TRUE;
1613
Brian Paulffbc66b2008-07-21 13:58:50 -06001614 return GL_FALSE;
1615}
1616
1617
1618/**
Brian Paulade50832008-05-14 16:09:46 -06001619 * Set the value of a program's uniform variable.
1620 * \param program the program whose uniform to update
Brian Pauleda291e2008-08-06 16:26:47 -06001621 * \param index the index of the program parameter for the uniform
1622 * \param offset additional parameter slot offset (for arrays)
Brian Paulc4ffbf02009-02-18 17:46:00 -07001623 * \param type the incoming datatype of 'values'
Brian Paulade50832008-05-14 16:09:46 -06001624 * \param count the number of uniforms to set
Brian Paulc4ffbf02009-02-18 17:46:00 -07001625 * \param elems number of elements per uniform (1, 2, 3 or 4)
1626 * \param values the new values, of datatype 'type'
Brian Paulade50832008-05-14 16:09:46 -06001627 */
1628static void
Brian Pauleda291e2008-08-06 16:26:47 -06001629set_program_uniform(GLcontext *ctx, struct gl_program *program,
1630 GLint index, GLint offset,
1631 GLenum type, GLsizei count, GLint elems,
1632 const void *values)
Brian Paulade50832008-05-14 16:09:46 -06001633{
Brian Paul6df38e62009-08-26 14:35:45 -06001634 const struct gl_program_parameter *param =
Brian Paul949e7382008-11-05 09:17:55 -07001635 &program->Parameters->Parameters[index];
1636
Brian Pauleda291e2008-08-06 16:26:47 -06001637 assert(offset >= 0);
Brian Paulc4ffbf02009-02-18 17:46:00 -07001638 assert(elems >= 1);
1639 assert(elems <= 4);
Brian Pauleda291e2008-08-06 16:26:47 -06001640
Brian Paul949e7382008-11-05 09:17:55 -07001641 if (!compatible_types(type, param->DataType)) {
Brian Paulffbc66b2008-07-21 13:58:50 -06001642 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
1643 return;
1644 }
1645
Michal Krolc5c71302008-08-07 16:23:15 +02001646 if (index + offset > (GLint) program->Parameters->Size) {
Brian Pauleda291e2008-08-06 16:26:47 -06001647 /* out of bounds! */
1648 return;
1649 }
1650
Brian Paul949e7382008-11-05 09:17:55 -07001651 if (param->Type == PROGRAM_SAMPLER) {
Brian Paulade50832008-05-14 16:09:46 -06001652 /* This controls which texture unit which is used by a sampler */
Brian Paulbabb5ba2009-08-26 14:29:50 -06001653 GLboolean changed = GL_FALSE;
Brian Paul2b4f0212009-02-11 09:12:34 -07001654 GLint i;
Brian Paulade50832008-05-14 16:09:46 -06001655
Brian Paul6df38e62009-08-26 14:35:45 -06001656 /* this should have been caught by the compatible_types() check */
1657 ASSERT(type == GL_INT);
Brian Paulade50832008-05-14 16:09:46 -06001658
Brian Paul6df38e62009-08-26 14:35:45 -06001659 /* loop over number of samplers to change */
Brian Paul2b4f0212009-02-11 09:12:34 -07001660 for (i = 0; i < count; i++) {
Brian Paul04d17072009-08-26 11:39:24 -06001661 GLuint sampler =
1662 (GLuint) program->Parameters->ParameterValues[index + offset + i][0];
1663 GLuint texUnit = ((GLuint *) values)[i];
Brian Paulade50832008-05-14 16:09:46 -06001664
Brian Paul2b4f0212009-02-11 09:12:34 -07001665 /* check that the sampler (tex unit index) is legal */
1666 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1667 _mesa_error(ctx, GL_INVALID_VALUE,
1668 "glUniform1(invalid sampler/tex unit index)");
1669 return;
1670 }
1671
1672 /* This maps a sampler to a texture unit: */
1673 if (sampler < MAX_SAMPLERS) {
Brian Paul04d17072009-08-26 11:39:24 -06001674#if 0
1675 _mesa_printf("Set program %p sampler %d '%s' to unit %u\n",
1676 program, sampler, param->Name, texUnit);
1677#endif
Brian Paulbabb5ba2009-08-26 14:29:50 -06001678 if (program->SamplerUnits[sampler] != texUnit) {
1679 program->SamplerUnits[sampler] = texUnit;
1680 changed = GL_TRUE;
1681 }
Brian Paul2b4f0212009-02-11 09:12:34 -07001682 }
Brian Paulade50832008-05-14 16:09:46 -06001683 }
1684
Brian Paulbabb5ba2009-08-26 14:29:50 -06001685 if (changed) {
1686 /* When a sampler's value changes it usually requires rewriting
1687 * a GPU program's TEX instructions since there may not be a
1688 * sampler->texture lookup table. We signal this with the
1689 * ProgramStringNotify() callback.
1690 */
1691 FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM);
1692 _mesa_update_shader_textures_used(program);
1693 ctx->Driver.ProgramStringNotify(ctx, program->Target, program);
1694 }
Brian Paulade50832008-05-14 16:09:46 -06001695 }
1696 else {
1697 /* ordinary uniform variable */
Brian Paul6df38e62009-08-26 14:35:45 -06001698 const GLboolean isUniformBool = is_boolean_type(param->DataType);
1699 const GLboolean areIntValues = is_integer_type(type);
Brian Paul2c1ea072009-02-11 08:46:21 -07001700 const GLint slots = (param->Size + 3) / 4;
1701 const GLint typeSize = sizeof_glsl_type(param->DataType);
Brian Paul6df38e62009-08-26 14:35:45 -06001702 GLsizei k, i;
Brian Paulade50832008-05-14 16:09:46 -06001703
Brian Paul2c1ea072009-02-11 08:46:21 -07001704 if (param->Size > typeSize) {
1705 /* an array */
1706 /* we'll ignore extra data below */
1707 }
1708 else {
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001709 /* non-array: count must be at most one; count == 0 is handled by the loop below */
1710 if (count > 1) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001711 _mesa_error(ctx, GL_INVALID_OPERATION,
1712 "glUniform(uniform is not an array)");
1713 return;
1714 }
Brian Paulade50832008-05-14 16:09:46 -06001715 }
1716
Brian Paulc4ffbf02009-02-18 17:46:00 -07001717 /* loop over number of array elements */
Brian Paulade50832008-05-14 16:09:46 -06001718 for (k = 0; k < count; k++) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001719 GLfloat *uniformVal;
1720
Brian Paulb9d8f712009-02-18 17:40:44 -07001721 if (offset + k >= slots) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001722 /* Extra array data is ignored */
1723 break;
1724 }
1725
Brian Paulc4ffbf02009-02-18 17:46:00 -07001726 /* uniformVal (the destination) is always float[4] */
Brian Paul2c1ea072009-02-11 08:46:21 -07001727 uniformVal = program->Parameters->ParameterValues[index + offset + k];
Brian Paulc4ffbf02009-02-18 17:46:00 -07001728
1729 if (areIntValues) {
1730 /* convert user's ints to floats */
Brian Paulade50832008-05-14 16:09:46 -06001731 const GLint *iValues = ((const GLint *) values) + k * elems;
1732 for (i = 0; i < elems; i++) {
1733 uniformVal[i] = (GLfloat) iValues[i];
1734 }
1735 }
1736 else {
1737 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1738 for (i = 0; i < elems; i++) {
1739 uniformVal[i] = fValues[i];
1740 }
1741 }
Brian Pauleda291e2008-08-06 16:26:47 -06001742
1743 /* if the uniform is bool-valued, convert to 1.0 or 0.0 */
Brian Paulc4ffbf02009-02-18 17:46:00 -07001744 if (isUniformBool) {
Brian Pauleda291e2008-08-06 16:26:47 -06001745 for (i = 0; i < elems; i++) {
Michal Krolc5c71302008-08-07 16:23:15 +02001746 uniformVal[i] = uniformVal[i] ? 1.0f : 0.0f;
Brian Pauleda291e2008-08-06 16:26:47 -06001747 }
1748 }
Brian Paulade50832008-05-14 16:09:46 -06001749 }
1750 }
1751}
1752
1753
Brian5b01c5e2006-12-19 18:02:03 -07001754/**
1755 * Called via ctx->Driver.Uniform().
1756 */
Brian Paulfd59f192008-05-18 16:04:55 -06001757static void
Brian5b01c5e2006-12-19 18:02:03 -07001758_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1759 const GLvoid *values, GLenum type)
1760{
Brian3a8e2772006-12-20 17:19:16 -07001761 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paul2d76a0d2008-11-10 12:33:17 -07001762 struct gl_uniform *uniform;
Brian Pauleda291e2008-08-06 16:26:47 -06001763 GLint elems, offset;
Brian Paule01a03d2009-02-06 10:21:36 -07001764 GLenum basicType;
Brian3a8e2772006-12-20 17:19:16 -07001765
1766 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001767 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001768 return;
1769 }
1770
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001771 if (location == -1)
1772 return; /* The standard specifies this as a no-op */
1773
Brian Paul234f03e2009-02-11 09:05:08 -07001774 if (location < -1) {
1775 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(location)");
1776 return;
1777 }
1778
Brian Pauleda291e2008-08-06 16:26:47 -06001779 split_location_offset(&location, &offset);
1780
Brian Paulade50832008-05-14 16:09:46 -06001781 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
1782 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
Brian3a8e2772006-12-20 17:19:16 -07001783 return;
1784 }
1785
Brian52363952007-03-13 16:50:24 -06001786 if (count < 0) {
1787 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1788 return;
1789 }
1790
Brian98650bd2007-03-13 16:32:48 -06001791 switch (type) {
1792 case GL_FLOAT:
Brian Paule01a03d2009-02-06 10:21:36 -07001793 basicType = GL_FLOAT;
1794 elems = 1;
1795 break;
Brian98650bd2007-03-13 16:32:48 -06001796 case GL_INT:
Brian Paule01a03d2009-02-06 10:21:36 -07001797 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001798 elems = 1;
1799 break;
1800 case GL_FLOAT_VEC2:
Brian Paule01a03d2009-02-06 10:21:36 -07001801 basicType = GL_FLOAT;
1802 elems = 2;
1803 break;
Brian98650bd2007-03-13 16:32:48 -06001804 case GL_INT_VEC2:
Brian Paule01a03d2009-02-06 10:21:36 -07001805 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001806 elems = 2;
1807 break;
1808 case GL_FLOAT_VEC3:
Brian Paule01a03d2009-02-06 10:21:36 -07001809 basicType = GL_FLOAT;
1810 elems = 3;
1811 break;
Brian98650bd2007-03-13 16:32:48 -06001812 case GL_INT_VEC3:
Brian Paule01a03d2009-02-06 10:21:36 -07001813 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001814 elems = 3;
1815 break;
1816 case GL_FLOAT_VEC4:
Brian Paule01a03d2009-02-06 10:21:36 -07001817 basicType = GL_FLOAT;
1818 elems = 4;
1819 break;
Brian98650bd2007-03-13 16:32:48 -06001820 case GL_INT_VEC4:
Brian Paule01a03d2009-02-06 10:21:36 -07001821 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001822 elems = 4;
1823 break;
1824 default:
1825 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1826 return;
Brian89dc4852007-01-04 14:35:44 -07001827 }
Brian98650bd2007-03-13 16:32:48 -06001828
Brian Paul027ed1b2009-04-24 09:43:44 -06001829 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
Brian98650bd2007-03-13 16:32:48 -06001830
Brian Paul2d76a0d2008-11-10 12:33:17 -07001831 uniform = &shProg->Uniforms->Uniforms[location];
1832
Brian Paule01a03d2009-02-06 10:21:36 -07001833 if (ctx->Shader.Flags & GLSL_UNIFORMS) {
1834 GLint i;
1835 _mesa_printf("Mesa: set program %u uniform %s (loc %d) to: ",
1836 shProg->Name, uniform->Name, location);
1837 if (basicType == GL_INT) {
1838 const GLint *v = (const GLint *) values;
1839 for (i = 0; i < count * elems; i++) {
1840 _mesa_printf("%d ", v[i]);
1841 }
1842 }
1843 else {
1844 const GLfloat *v = (const GLfloat *) values;
1845 for (i = 0; i < count * elems; i++) {
1846 _mesa_printf("%g ", v[i]);
1847 }
1848 }
1849 _mesa_printf("\n");
1850 }
1851
Brian Paulade50832008-05-14 16:09:46 -06001852 /* A uniform var may be used by both a vertex shader and a fragment
1853 * shader. We may need to update one or both shader's uniform here:
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001854 */
Brian Paulade50832008-05-14 16:09:46 -06001855 if (shProg->VertexProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001856 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07001857 GLint index = uniform->VertPos;
Brian Pauleda291e2008-08-06 16:26:47 -06001858 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001859 set_program_uniform(ctx, &shProg->VertexProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001860 index, offset, type, count, elems, values);
Bruce Merry2bf2a8c2007-12-21 23:18:40 +02001861 }
Brian5b01c5e2006-12-19 18:02:03 -07001862 }
Brian5cf73262007-01-05 16:02:45 -07001863
Brian Paulade50832008-05-14 16:09:46 -06001864 if (shProg->FragmentProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001865 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07001866 GLint index = uniform->FragPos;
Brian Pauleda291e2008-08-06 16:26:47 -06001867 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001868 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001869 index, offset, type, count, elems, values);
Brian Paulade50832008-05-14 16:09:46 -06001870 }
1871 }
Brian Paul949e7382008-11-05 09:17:55 -07001872
Brian Paul2d76a0d2008-11-10 12:33:17 -07001873 uniform->Initialized = GL_TRUE;
Brian Paulade50832008-05-14 16:09:46 -06001874}
1875
1876
Brian Pauleda291e2008-08-06 16:26:47 -06001877/**
1878 * Set a matrix-valued program parameter.
1879 */
Brian Paulade50832008-05-14 16:09:46 -06001880static void
1881set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
Brian Pauleda291e2008-08-06 16:26:47 -06001882 GLuint index, GLuint offset,
1883 GLuint count, GLuint rows, GLuint cols,
Brian Paulade50832008-05-14 16:09:46 -06001884 GLboolean transpose, const GLfloat *values)
1885{
Brian Paulffbc66b2008-07-21 13:58:50 -06001886 GLuint mat, row, col;
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001887 GLuint src = 0;
1888 const struct gl_program_parameter * param = &program->Parameters->Parameters[index];
1889 const GLint slots = (param->Size + 3) / 4;
1890 const GLint typeSize = sizeof_glsl_type(param->DataType);
Brian Paulffbc66b2008-07-21 13:58:50 -06001891 GLint nr, nc;
1892
1893 /* check that the number of rows, columns is correct */
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001894 get_matrix_dims(param->DataType, &nr, &nc);
Brian Paulffbc66b2008-07-21 13:58:50 -06001895 if (rows != nr || cols != nc) {
1896 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Pauleda291e2008-08-06 16:26:47 -06001897 "glUniformMatrix(matrix size mismatch)");
1898 return;
1899 }
1900
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001901 if (param->Size <= typeSize) {
1902 /* non-array: count must be at most one; count == 0 is handled by the loop below */
1903 if (count > 1) {
1904 _mesa_error(ctx, GL_INVALID_OPERATION,
1905 "glUniformMatrix(uniform is not an array)");
1906 return;
1907 }
Brian Paulffbc66b2008-07-21 13:58:50 -06001908 }
1909
Brian Paulade50832008-05-14 16:09:46 -06001910 /*
1911 * Note: the _columns_ of a matrix are stored in program registers, not
Brian Paulf45ed0e2008-07-18 12:51:39 -06001912 * the rows. So, the loops below look a little funny.
1913 * XXX could optimize this a bit...
Brian Paulade50832008-05-14 16:09:46 -06001914 */
Brian Paulf45ed0e2008-07-18 12:51:39 -06001915
1916 /* loop over matrices */
1917 for (mat = 0; mat < count; mat++) {
1918
1919 /* each matrix: */
Brian Paulade50832008-05-14 16:09:46 -06001920 for (col = 0; col < cols; col++) {
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001921 GLfloat *v;
1922 if (offset >= slots) {
1923 /* Ignore writes beyond the end of (the used part of) an array */
1924 return;
1925 }
1926 v = program->Parameters->ParameterValues[index + offset];
Brian Paulade50832008-05-14 16:09:46 -06001927 for (row = 0; row < rows; row++) {
Brian Paulf45ed0e2008-07-18 12:51:39 -06001928 if (transpose) {
1929 v[row] = values[src + row * cols + col];
1930 }
1931 else {
1932 v[row] = values[src + col * rows + row];
1933 }
Brian Paulade50832008-05-14 16:09:46 -06001934 }
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001935
1936 offset++;
Brian Paulade50832008-05-14 16:09:46 -06001937 }
Brian Paulf45ed0e2008-07-18 12:51:39 -06001938
1939 src += rows * cols; /* next matrix */
Brian5cf73262007-01-05 16:02:45 -07001940 }
Brian34ae99d2006-12-18 08:28:54 -07001941}
1942
1943
1944/**
Brian5b01c5e2006-12-19 18:02:03 -07001945 * Called by ctx->Driver.UniformMatrix().
Brian Paulf45ed0e2008-07-18 12:51:39 -06001946 * Note: cols=2, rows=4 ==> array[2] of vec4
Brian34ae99d2006-12-18 08:28:54 -07001947 */
Brian Paulfd59f192008-05-18 16:04:55 -06001948static void
Brian5b01c5e2006-12-19 18:02:03 -07001949_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
Brian Paul0115a4f2009-04-14 20:00:28 -06001950 GLint location, GLsizei count,
Brian5b01c5e2006-12-19 18:02:03 -07001951 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001952{
Brian3a8e2772006-12-20 17:19:16 -07001953 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paul2d76a0d2008-11-10 12:33:17 -07001954 struct gl_uniform *uniform;
1955 GLint offset;
Brian Paulade50832008-05-14 16:09:46 -06001956
Brian3a8e2772006-12-20 17:19:16 -07001957 if (!shProg || !shProg->LinkStatus) {
1958 _mesa_error(ctx, GL_INVALID_OPERATION,
1959 "glUniformMatrix(program not linked)");
1960 return;
1961 }
Brian Paulade50832008-05-14 16:09:46 -06001962
Bruce Merry89b80322007-12-21 15:20:17 +02001963 if (location == -1)
1964 return; /* The standard specifies this as a no-op */
Brian Paulade50832008-05-14 16:09:46 -06001965
Brian Paul234f03e2009-02-11 09:05:08 -07001966 if (location < -1) {
1967 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(location)");
1968 return;
1969 }
1970
Brian Pauleda291e2008-08-06 16:26:47 -06001971 split_location_offset(&location, &offset);
1972
Brian Paul016701f2008-07-29 17:43:35 -06001973 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian Paulade50832008-05-14 16:09:46 -06001974 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
Brian3a8e2772006-12-20 17:19:16 -07001975 return;
1976 }
Brian34ae99d2006-12-18 08:28:54 -07001977 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001978 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001979 return;
1980 }
1981
Brian Paul027ed1b2009-04-24 09:43:44 -06001982 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
Brian34ae99d2006-12-18 08:28:54 -07001983
Brian Paul2d76a0d2008-11-10 12:33:17 -07001984 uniform = &shProg->Uniforms->Uniforms[location];
1985
Brian Paulade50832008-05-14 16:09:46 -06001986 if (shProg->VertexProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001987 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07001988 GLint index = uniform->VertPos;
Brian Pauleda291e2008-08-06 16:26:47 -06001989 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001990 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001991 index, offset,
1992 count, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07001993 }
Brian Paulade50832008-05-14 16:09:46 -06001994 }
1995
1996 if (shProg->FragmentProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001997 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07001998 GLint index = uniform->FragPos;
Brian Pauleda291e2008-08-06 16:26:47 -06001999 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06002000 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06002001 index, offset,
2002 count, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07002003 }
Brian34ae99d2006-12-18 08:28:54 -07002004 }
Brian Paul949e7382008-11-05 09:17:55 -07002005
Brian Paul2d76a0d2008-11-10 12:33:17 -07002006 uniform->Initialized = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07002007}
2008
2009
Brian Paulc90fca32009-08-25 17:42:47 -06002010/**
2011 * Validate a program's samplers.
2012 * Specifically, check that there aren't two samplers of different types
2013 * pointing to the same texture unit.
2014 * \return GL_TRUE if valid, GL_FALSE if invalid
2015 */
2016static GLboolean
2017validate_samplers(GLcontext *ctx, const struct gl_program *prog, char *errMsg)
Brian34ae99d2006-12-18 08:28:54 -07002018{
Brian Paulc90fca32009-08-25 17:42:47 -06002019 static const char *targetName[] = {
2020 "TEXTURE_2D_ARRAY",
2021 "TEXTURE_1D_ARRAY",
2022 "TEXTURE_CUBE",
2023 "TEXTURE_3D",
2024 "TEXTURE_RECT",
2025 "TEXTURE_2D",
2026 "TEXTURE_1D",
2027 };
2028 GLint targetUsed[MAX_TEXTURE_IMAGE_UNITS];
2029 GLbitfield samplersUsed = prog->SamplersUsed;
2030 GLuint i;
Brian Paulbc985b52008-07-21 14:16:07 -06002031
Brian Paulc90fca32009-08-25 17:42:47 -06002032 assert(Elements(targetName) == NUM_TEXTURE_TARGETS);
2033
2034 if (samplersUsed == 0x0)
2035 return GL_TRUE;
2036
2037 for (i = 0; i < Elements(targetUsed); i++)
2038 targetUsed[i] = -1;
2039
2040 /* walk over bits which are set in 'samplers' */
2041 while (samplersUsed) {
2042 GLuint unit;
2043 gl_texture_index target;
2044 GLint sampler = _mesa_ffs(samplersUsed) - 1;
2045 assert(sampler >= 0);
2046 assert(sampler < MAX_TEXTURE_IMAGE_UNITS);
2047 unit = prog->SamplerUnits[sampler];
2048 target = prog->SamplerTargets[sampler];
2049 if (targetUsed[unit] != -1 && targetUsed[unit] != target) {
2050 _mesa_snprintf(errMsg, 100,
2051 "Texture unit %d is accessed both as %s and %s",
2052 unit, targetName[targetUsed[unit]], targetName[target]);
2053 return GL_FALSE;
2054 }
2055 targetUsed[unit] = target;
2056 samplersUsed ^= (1 << sampler);
Brian34ae99d2006-12-18 08:28:54 -07002057 }
2058
Brian Paulc90fca32009-08-25 17:42:47 -06002059 return GL_TRUE;
2060}
2061
2062
2063/**
2064 * Do validation of the given shader program.
2065 * \param errMsg returns error message if validation fails.
2066 * \return GL_TRUE if valid, GL_FALSE if invalid (and set errMsg)
2067 */
2068GLboolean
2069_mesa_validate_shader_program(GLcontext *ctx,
2070 const struct gl_shader_program *shProg,
2071 char *errMsg)
2072{
2073 const struct gl_vertex_program *vp = shProg->VertexProgram;
2074 const struct gl_fragment_program *fp = shProg->FragmentProgram;
2075
Brian Paulbc985b52008-07-21 14:16:07 -06002076 if (!shProg->LinkStatus) {
Brian Paulc90fca32009-08-25 17:42:47 -06002077 return GL_FALSE;
Brian Paulbc985b52008-07-21 14:16:07 -06002078 }
2079
2080 /* From the GL spec, a program is invalid if any of these are true:
2081
Brian5b01c5e2006-12-19 18:02:03 -07002082 any two active samplers in the current program object are of
2083 different types, but refer to the same texture image unit,
2084
2085 any active sampler in the current program object refers to a texture
2086 image unit where fixed-function fragment processing accesses a
2087 texture target that does not match the sampler type, or
2088
2089 the sum of the number of active samplers in the program and the
2090 number of texture image units enabled for fixed-function fragment
2091 processing exceeds the combined limit on the total number of texture
2092 image units allowed.
2093 */
Brian Paulbc985b52008-07-21 14:16:07 -06002094
Brian Paulc90fca32009-08-25 17:42:47 -06002095
2096 /*
2097 * Check: any two active samplers in the current program object are of
2098 * different types, but refer to the same texture image unit,
2099 */
2100 if (vp && !validate_samplers(ctx, &vp->Base, errMsg)) {
2101 return GL_FALSE;
2102 }
2103 if (fp && !validate_samplers(ctx, &fp->Base, errMsg)) {
2104 return GL_FALSE;
2105 }
2106
2107 return GL_TRUE;
2108}
2109
2110
2111/**
2112 * Called via glValidateProgram()
2113 */
2114static void
2115_mesa_validate_program(GLcontext *ctx, GLuint program)
2116{
2117 struct gl_shader_program *shProg;
2118 char errMsg[100];
2119
2120 shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram");
2121 if (!shProg) {
2122 return;
2123 }
2124
2125 shProg->Validated = _mesa_validate_shader_program(ctx, shProg, errMsg);
2126 if (!shProg->Validated) {
2127 /* update info log */
2128 if (shProg->InfoLog) {
2129 _mesa_free(shProg->InfoLog);
2130 }
2131 shProg->InfoLog = _mesa_strdup(errMsg);
2132 }
Brian34ae99d2006-12-18 08:28:54 -07002133}
Brian Paulfd59f192008-05-18 16:04:55 -06002134
2135
2136/**
2137 * Plug in Mesa's GLSL functions into the device driver function table.
2138 */
2139void
2140_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
2141{
2142 driver->AttachShader = _mesa_attach_shader;
2143 driver->BindAttribLocation = _mesa_bind_attrib_location;
2144 driver->CompileShader = _mesa_compile_shader;
2145 driver->CreateProgram = _mesa_create_program;
2146 driver->CreateShader = _mesa_create_shader;
2147 driver->DeleteProgram2 = _mesa_delete_program2;
2148 driver->DeleteShader = _mesa_delete_shader;
2149 driver->DetachShader = _mesa_detach_shader;
2150 driver->GetActiveAttrib = _mesa_get_active_attrib;
2151 driver->GetActiveUniform = _mesa_get_active_uniform;
2152 driver->GetAttachedShaders = _mesa_get_attached_shaders;
2153 driver->GetAttribLocation = _mesa_get_attrib_location;
2154 driver->GetHandle = _mesa_get_handle;
2155 driver->GetProgramiv = _mesa_get_programiv;
2156 driver->GetProgramInfoLog = _mesa_get_program_info_log;
2157 driver->GetShaderiv = _mesa_get_shaderiv;
2158 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
2159 driver->GetShaderSource = _mesa_get_shader_source;
2160 driver->GetUniformfv = _mesa_get_uniformfv;
Brian Paul2be54a82008-07-08 16:17:04 -06002161 driver->GetUniformiv = _mesa_get_uniformiv;
Brian Paulfd59f192008-05-18 16:04:55 -06002162 driver->GetUniformLocation = _mesa_get_uniform_location;
2163 driver->IsProgram = _mesa_is_program;
2164 driver->IsShader = _mesa_is_shader;
2165 driver->LinkProgram = _mesa_link_program;
2166 driver->ShaderSource = _mesa_shader_source;
2167 driver->Uniform = _mesa_uniform;
2168 driver->UniformMatrix = _mesa_uniform_matrix;
2169 driver->UseProgram = _mesa_use_program;
2170 driver->ValidateProgram = _mesa_validate_program;
2171}