blob: 940fe2d03ced364a542ce5ef7cf36f9bf4765780 [file] [log] [blame]
Brian34ae99d2006-12-18 08:28:54 -07001/*
2 * Mesa 3-D graphics library
Brian Paulc90fca32009-08-25 17:42:47 -06003 * Version: 7.6
Brian34ae99d2006-12-18 08:28:54 -07004 *
Brian Paul8c51e002008-08-11 15:09:47 -06005 * Copyright (C) 2004-2008 Brian Paul All Rights Reserved.
Brian Paulc4ffbf02009-02-18 17:46:00 -07006 * Copyright (C) 2009 VMware, Inc. All Rights Reserved.
Brian34ae99d2006-12-18 08:28:54 -07007 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included
16 * in all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26/**
27 * \file shader_api.c
Brian5b01c5e2006-12-19 18:02:03 -070028 * Implementation of GLSL-related API functions
Brian34ae99d2006-12-18 08:28:54 -070029 * \author Brian Paul
30 */
31
32/**
33 * XXX things to do:
34 * 1. Check that the right error code is generated for all _mesa_error() calls.
Brian5b01c5e2006-12-19 18:02:03 -070035 * 2. Insert FLUSH_VERTICES calls in various places
Brian34ae99d2006-12-18 08:28:54 -070036 */
37
38
Brian Paulbbd28712008-09-18 12:26:54 -060039#include "main/glheader.h"
40#include "main/context.h"
41#include "main/hash.h"
Brian Paulbbd28712008-09-18 12:26:54 -060042#include "shader/program.h"
43#include "shader/prog_parameter.h"
Brian Paulbbd28712008-09-18 12:26:54 -060044#include "shader/prog_statevars.h"
45#include "shader/prog_uniform.h"
Brianc223c6b2007-07-04 13:15:20 -060046#include "shader/shader_api.h"
47#include "shader/slang/slang_compile.h"
48#include "shader/slang/slang_link.h"
Chia-I Wu2cf44392010-02-24 12:01:14 +080049#include "main/dispatch.h"
Brian34ae99d2006-12-18 08:28:54 -070050
51
Brianf2923612006-12-20 09:56:44 -070052/**
53 * Allocate a new gl_shader_program object, initialize it.
54 */
Brian Paulfd59f192008-05-18 16:04:55 -060055static struct gl_shader_program *
Brianf2923612006-12-20 09:56:44 -070056_mesa_new_shader_program(GLcontext *ctx, GLuint name)
57{
58 struct gl_shader_program *shProg;
59 shProg = CALLOC_STRUCT(gl_shader_program);
60 if (shProg) {
Brianf3e8c322007-04-18 14:53:23 -060061 shProg->Type = GL_SHADER_PROGRAM_MESA;
Brianf2923612006-12-20 09:56:44 -070062 shProg->Name = name;
63 shProg->RefCount = 1;
Brian3209c3e2007-01-09 17:49:24 -070064 shProg->Attributes = _mesa_new_parameter_list();
Brianf2923612006-12-20 09:56:44 -070065 }
66 return shProg;
67}
68
69
Brianb9fbedd2007-03-26 09:23:44 -060070/**
Brian3c008a02007-04-12 15:22:32 -060071 * Clear (free) the shader program state that gets produced by linking.
Brianb9fbedd2007-03-26 09:23:44 -060072 */
Brianf2923612006-12-20 09:56:44 -070073void
Brian3c008a02007-04-12 15:22:32 -060074_mesa_clear_shader_program_data(GLcontext *ctx,
75 struct gl_shader_program *shProg)
Brianf2923612006-12-20 09:56:44 -070076{
Brian Paul8bdf5b62008-05-16 09:56:59 -060077 _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL);
78 _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL);
Brianf2923612006-12-20 09:56:44 -070079
Brianf2923612006-12-20 09:56:44 -070080 if (shProg->Uniforms) {
Brian Paulade50832008-05-14 16:09:46 -060081 _mesa_free_uniform_list(shProg->Uniforms);
Brianf2923612006-12-20 09:56:44 -070082 shProg->Uniforms = NULL;
83 }
84
85 if (shProg->Varying) {
86 _mesa_free_parameter_list(shProg->Varying);
87 shProg->Varying = NULL;
88 }
89}
90
91
Brianb9fbedd2007-03-26 09:23:44 -060092/**
Brian3c008a02007-04-12 15:22:32 -060093 * Free all the data that hangs off a shader program object, but not the
94 * object itself.
95 */
96void
97_mesa_free_shader_program_data(GLcontext *ctx,
98 struct gl_shader_program *shProg)
99{
100 GLuint i;
101
Brianf3e8c322007-04-18 14:53:23 -0600102 assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
Brian3c008a02007-04-12 15:22:32 -0600103
104 _mesa_clear_shader_program_data(ctx, shProg);
105
Brian4b7c6fc2007-04-19 15:23:34 -0600106 if (shProg->Attributes) {
107 _mesa_free_parameter_list(shProg->Attributes);
108 shProg->Attributes = NULL;
109 }
110
Brian3c008a02007-04-12 15:22:32 -0600111 /* detach shaders */
112 for (i = 0; i < shProg->NumShaders; i++) {
113 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
114 }
Xiang, Haihao63d8a842008-03-31 17:02:47 +0800115 shProg->NumShaders = 0;
116
Brian3c008a02007-04-12 15:22:32 -0600117 if (shProg->Shaders) {
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -0500118 free(shProg->Shaders);
Brian3c008a02007-04-12 15:22:32 -0600119 shProg->Shaders = NULL;
120 }
Alan Hourihaneeec20c32008-04-22 20:29:42 +0100121
122 if (shProg->InfoLog) {
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -0500123 free(shProg->InfoLog);
Alan Hourihaneeec20c32008-04-22 20:29:42 +0100124 shProg->InfoLog = NULL;
125 }
Brian3c008a02007-04-12 15:22:32 -0600126}
127
128
129/**
Brianb9fbedd2007-03-26 09:23:44 -0600130 * Free/delete a shader program object.
131 */
Brianf2923612006-12-20 09:56:44 -0700132void
133_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg)
134{
135 _mesa_free_shader_program_data(ctx, shProg);
Alan Hourihaneeec20c32008-04-22 20:29:42 +0100136
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -0500137 free(shProg);
Brianf2923612006-12-20 09:56:44 -0700138}
139
140
141/**
Brian3c008a02007-04-12 15:22:32 -0600142 * Set ptr to point to shProg.
143 * If ptr is pointing to another object, decrement its refcount (and delete
144 * if refcount hits zero).
145 * Then set ptr to point to shProg, incrementing its refcount.
146 */
147/* XXX this could be static */
148void
149_mesa_reference_shader_program(GLcontext *ctx,
150 struct gl_shader_program **ptr,
151 struct gl_shader_program *shProg)
152{
153 assert(ptr);
154 if (*ptr == shProg) {
155 /* no-op */
156 return;
157 }
158 if (*ptr) {
159 /* Unreference the old shader program */
160 GLboolean deleteFlag = GL_FALSE;
161 struct gl_shader_program *old = *ptr;
162
163 ASSERT(old->RefCount > 0);
164 old->RefCount--;
Brian Paul8bdf5b62008-05-16 09:56:59 -0600165#if 0
166 printf("ShaderProgram %p ID=%u RefCount-- to %d\n",
167 (void *) old, old->Name, old->RefCount);
168#endif
Brian3c008a02007-04-12 15:22:32 -0600169 deleteFlag = (old->RefCount == 0);
170
171 if (deleteFlag) {
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800172 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
Brian3c008a02007-04-12 15:22:32 -0600173 _mesa_free_shader_program(ctx, old);
174 }
175
176 *ptr = NULL;
177 }
178 assert(!*ptr);
179
180 if (shProg) {
181 shProg->RefCount++;
Brian Paul8bdf5b62008-05-16 09:56:59 -0600182#if 0
183 printf("ShaderProgram %p ID=%u RefCount++ to %d\n",
184 (void *) shProg, shProg->Name, shProg->RefCount);
185#endif
Brian3c008a02007-04-12 15:22:32 -0600186 *ptr = shProg;
187 }
188}
189
190
191/**
Brianf2923612006-12-20 09:56:44 -0700192 * Lookup a GLSL program object.
193 */
194struct gl_shader_program *
195_mesa_lookup_shader_program(GLcontext *ctx, GLuint name)
196{
197 struct gl_shader_program *shProg;
198 if (name) {
199 shProg = (struct gl_shader_program *)
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800200 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
Brianf2923612006-12-20 09:56:44 -0700201 /* Note that both gl_shader and gl_shader_program objects are kept
202 * in the same hash table. Check the object's type to be sure it's
203 * what we're expecting.
204 */
Brianf3e8c322007-04-18 14:53:23 -0600205 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700206 return NULL;
207 }
208 return shProg;
209 }
210 return NULL;
211}
212
213
214/**
Brian Paul530df582008-07-03 16:21:11 -0600215 * As above, but record an error if program is not found.
216 */
217static struct gl_shader_program *
218_mesa_lookup_shader_program_err(GLcontext *ctx, GLuint name,
219 const char *caller)
220{
221 if (!name) {
222 _mesa_error(ctx, GL_INVALID_VALUE, caller);
223 return NULL;
224 }
225 else {
226 struct gl_shader_program *shProg = (struct gl_shader_program *)
227 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
228 if (!shProg) {
229 _mesa_error(ctx, GL_INVALID_VALUE, caller);
230 return NULL;
231 }
232 if (shProg->Type != GL_SHADER_PROGRAM_MESA) {
233 _mesa_error(ctx, GL_INVALID_OPERATION, caller);
234 return NULL;
235 }
236 return shProg;
237 }
238}
239
240
241
242
243/**
Brianf2923612006-12-20 09:56:44 -0700244 * Allocate a new gl_shader object, initialize it.
245 */
246struct gl_shader *
247_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
248{
249 struct gl_shader *shader;
250 assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
251 shader = CALLOC_STRUCT(gl_shader);
252 if (shader) {
253 shader->Type = type;
254 shader->Name = name;
255 shader->RefCount = 1;
256 }
257 return shader;
258}
259
260
261void
262_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh)
263{
Brianf2923612006-12-20 09:56:44 -0700264 if (sh->Source)
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -0500265 free((void *) sh->Source);
Brianf2923612006-12-20 09:56:44 -0700266 if (sh->InfoLog)
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -0500267 free(sh->InfoLog);
Brian Paul3d500f02008-07-24 14:56:54 -0600268 _mesa_reference_program(ctx, &sh->Program, NULL);
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -0500269 free(sh);
Brianf2923612006-12-20 09:56:44 -0700270}
271
272
273/**
Brian3c008a02007-04-12 15:22:32 -0600274 * Set ptr to point to sh.
275 * If ptr is pointing to another shader, decrement its refcount (and delete
276 * if refcount hits zero).
277 * Then set ptr to point to sh, incrementing its refcount.
278 */
279/* XXX this could be static */
280void
281_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr,
282 struct gl_shader *sh)
283{
284 assert(ptr);
285 if (*ptr == sh) {
286 /* no-op */
287 return;
288 }
289 if (*ptr) {
290 /* Unreference the old shader */
291 GLboolean deleteFlag = GL_FALSE;
292 struct gl_shader *old = *ptr;
293
294 ASSERT(old->RefCount > 0);
295 old->RefCount--;
Brian99193e42007-04-12 15:45:02 -0600296 /*printf("SHADER DECR %p (%d) to %d\n",
297 (void*) old, old->Name, old->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600298 deleteFlag = (old->RefCount == 0);
299
300 if (deleteFlag) {
301 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
302 _mesa_free_shader(ctx, old);
303 }
304
305 *ptr = NULL;
306 }
307 assert(!*ptr);
308
309 if (sh) {
310 /* reference new */
311 sh->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600312 /*printf("SHADER INCR %p (%d) to %d\n",
313 (void*) sh, sh->Name, sh->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600314 *ptr = sh;
315 }
316}
317
318
319/**
Brianf2923612006-12-20 09:56:44 -0700320 * Lookup a GLSL shader object.
321 */
322struct gl_shader *
323_mesa_lookup_shader(GLcontext *ctx, GLuint name)
324{
325 if (name) {
326 struct gl_shader *sh = (struct gl_shader *)
327 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
328 /* Note that both gl_shader and gl_shader_program objects are kept
329 * in the same hash table. Check the object's type to be sure it's
330 * what we're expecting.
331 */
Brianf3e8c322007-04-18 14:53:23 -0600332 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700333 return NULL;
334 }
335 return sh;
336 }
337 return NULL;
338}
339
340
Brianfa4d0362007-02-26 18:33:50 -0700341/**
Brian Paul530df582008-07-03 16:21:11 -0600342 * As above, but record an error if shader is not found.
343 */
344static struct gl_shader *
345_mesa_lookup_shader_err(GLcontext *ctx, GLuint name, const char *caller)
346{
347 if (!name) {
348 _mesa_error(ctx, GL_INVALID_VALUE, caller);
349 return NULL;
350 }
351 else {
352 struct gl_shader *sh = (struct gl_shader *)
353 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
354 if (!sh) {
355 _mesa_error(ctx, GL_INVALID_VALUE, caller);
356 return NULL;
357 }
358 if (sh->Type == GL_SHADER_PROGRAM_MESA) {
359 _mesa_error(ctx, GL_INVALID_OPERATION, caller);
360 return NULL;
361 }
362 return sh;
363 }
364}
365
366
Brian Paule01a03d2009-02-06 10:21:36 -0700367/**
368 * Return mask of GLSL_x flags by examining the MESA_GLSL env var.
369 */
370static GLbitfield
371get_shader_flags(void)
372{
373 GLbitfield flags = 0x0;
374 const char *env = _mesa_getenv("MESA_GLSL");
375
376 if (env) {
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800377 if (strstr(env, "dump"))
Brian Paule01a03d2009-02-06 10:21:36 -0700378 flags |= GLSL_DUMP;
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800379 if (strstr(env, "log"))
Brian Paule01a03d2009-02-06 10:21:36 -0700380 flags |= GLSL_LOG;
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800381 if (strstr(env, "nopvert"))
Brian Paulcb0de062009-09-29 10:22:32 -0600382 flags |= GLSL_NOP_VERT;
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800383 if (strstr(env, "nopfrag"))
Brian Paulcb0de062009-09-29 10:22:32 -0600384 flags |= GLSL_NOP_FRAG;
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800385 if (strstr(env, "nopt"))
Brian Paule01a03d2009-02-06 10:21:36 -0700386 flags |= GLSL_NO_OPT;
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800387 else if (strstr(env, "opt"))
Brian Paule01a03d2009-02-06 10:21:36 -0700388 flags |= GLSL_OPT;
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800389 if (strstr(env, "uniform"))
Brian Paule01a03d2009-02-06 10:21:36 -0700390 flags |= GLSL_UNIFORMS;
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800391 if (strstr(env, "useprog"))
Brian Paul2ee7fd82009-10-15 15:25:52 -0600392 flags |= GLSL_USE_PROG;
Brian Paule01a03d2009-02-06 10:21:36 -0700393 }
394
395 return flags;
396}
397
Brian Paul530df582008-07-03 16:21:11 -0600398
399/**
Brianfa4d0362007-02-26 18:33:50 -0700400 * Initialize context's shader state.
401 */
Brianf2923612006-12-20 09:56:44 -0700402void
403_mesa_init_shader_state(GLcontext * ctx)
404{
Brianfa4d0362007-02-26 18:33:50 -0700405 /* Device drivers may override these to control what kind of instructions
406 * are generated by the GLSL compiler.
407 */
408 ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
Brian Paul4031ea12009-06-17 11:57:39 -0600409 ctx->Shader.EmitContReturn = GL_TRUE;
Brian Paulc5c38352009-02-16 11:50:05 -0700410 ctx->Shader.EmitCondCodes = GL_FALSE;
Brianfa4d0362007-02-26 18:33:50 -0700411 ctx->Shader.EmitComments = GL_FALSE;
Brian Paule01a03d2009-02-06 10:21:36 -0700412 ctx->Shader.Flags = get_shader_flags();
Brian Paul65fc2ca2009-03-19 10:25:24 -0600413
414 /* Default pragma settings */
415 ctx->Shader.DefaultPragmas.IgnoreOptimize = GL_FALSE;
416 ctx->Shader.DefaultPragmas.IgnoreDebug = GL_FALSE;
417 ctx->Shader.DefaultPragmas.Optimize = GL_TRUE;
418 ctx->Shader.DefaultPragmas.Debug = GL_FALSE;
Brianf2923612006-12-20 09:56:44 -0700419}
420
421
Brian5b01c5e2006-12-19 18:02:03 -0700422/**
Brian935f93f2007-03-24 16:20:02 -0600423 * Free the per-context shader-related state.
424 */
425void
426_mesa_free_shader_state(GLcontext *ctx)
427{
Brian3c008a02007-04-12 15:22:32 -0600428 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
Brian935f93f2007-03-24 16:20:02 -0600429}
430
431
432/**
Brian5b01c5e2006-12-19 18:02:03 -0700433 * Copy string from <src> to <dst>, up to maxLength characters, returning
434 * length of <dst> in <length>.
435 * \param src the strings source
436 * \param maxLength max chars to copy
437 * \param length returns number of chars copied
438 * \param dst the string destination
439 */
440static void
441copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
442{
443 GLsizei len;
444 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
445 dst[len] = src[len];
446 if (maxLength > 0)
447 dst[len] = 0;
448 if (length)
449 *length = len;
450}
451
452
Brian Paul7acb7c12008-07-03 13:49:48 -0600453static GLboolean
454_mesa_is_program(GLcontext *ctx, GLuint name)
455{
456 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
457 return shProg ? GL_TRUE : GL_FALSE;
458}
459
460
461static GLboolean
462_mesa_is_shader(GLcontext *ctx, GLuint name)
463{
464 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
465 return shader ? GL_TRUE : GL_FALSE;
466}
467
468
Brian5b01c5e2006-12-19 18:02:03 -0700469/**
470 * Called via ctx->Driver.AttachShader()
471 */
Brian Paulfd59f192008-05-18 16:04:55 -0600472static void
Brian5b01c5e2006-12-19 18:02:03 -0700473_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
474{
Brian Paul530df582008-07-03 16:21:11 -0600475 struct gl_shader_program *shProg;
476 struct gl_shader *sh;
477 GLuint i, n;
Brian5b01c5e2006-12-19 18:02:03 -0700478
Brian Paul530df582008-07-03 16:21:11 -0600479 shProg = _mesa_lookup_shader_program_err(ctx, program, "glAttachShader");
480 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700481 return;
Brian5b01c5e2006-12-19 18:02:03 -0700482
Brian Paul530df582008-07-03 16:21:11 -0600483 sh = _mesa_lookup_shader_err(ctx, shader, "glAttachShader");
Brian Paul7acb7c12008-07-03 13:49:48 -0600484 if (!sh) {
Brian Paul7acb7c12008-07-03 13:49:48 -0600485 return;
486 }
487
Brian237b9852007-08-07 21:48:31 +0100488 n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700489 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700490 if (shProg->Shaders[i] == sh) {
Ian Romanickd806d452008-09-29 12:18:06 -0700491 /* The shader is already attched to this program. The
492 * GL_ARB_shader_objects spec says:
493 *
494 * "The error INVALID_OPERATION is generated by AttachObjectARB
495 * if <obj> is already attached to <containerObj>."
496 */
497 _mesa_error(ctx, GL_INVALID_OPERATION, "glAttachShader");
Brian5b01c5e2006-12-19 18:02:03 -0700498 return;
Brian34ae99d2006-12-18 08:28:54 -0700499 }
500 }
Brian5b01c5e2006-12-19 18:02:03 -0700501
502 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700503 shProg->Shaders = (struct gl_shader **)
504 _mesa_realloc(shProg->Shaders,
505 n * sizeof(struct gl_shader *),
506 (n + 1) * sizeof(struct gl_shader *));
507 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700508 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
509 return;
510 }
511
512 /* append */
Brian3c008a02007-04-12 15:22:32 -0600513 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
514 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700515 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700516}
517
518
Brian Paulfd59f192008-05-18 16:04:55 -0600519static GLint
Brian Paul896c0cc2008-05-16 15:47:55 -0600520_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
521 const GLchar *name)
522{
523 struct gl_shader_program *shProg
Brian Paul530df582008-07-03 16:21:11 -0600524 = _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
Brian Paul896c0cc2008-05-16 15:47:55 -0600525
526 if (!shProg) {
Brian Paul896c0cc2008-05-16 15:47:55 -0600527 return -1;
528 }
529
530 if (!shProg->LinkStatus) {
531 _mesa_error(ctx, GL_INVALID_OPERATION,
532 "glGetAttribLocation(program not linked)");
533 return -1;
534 }
535
536 if (!name)
537 return -1;
538
Brian Paul27341a92008-09-16 16:28:36 -0600539 if (shProg->VertexProgram) {
540 const struct gl_program_parameter_list *attribs =
541 shProg->VertexProgram->Base.Attributes;
542 if (attribs) {
543 GLint i = _mesa_lookup_parameter_index(attribs, -1, name);
544 if (i >= 0) {
545 return attribs->Parameters[i].StateIndexes[0];
546 }
Brian Paul896c0cc2008-05-16 15:47:55 -0600547 }
548 }
549 return -1;
550}
551
552
Brian Paulfd59f192008-05-18 16:04:55 -0600553static void
Brian5b01c5e2006-12-19 18:02:03 -0700554_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
555 const GLchar *name)
556{
Brian Paul530df582008-07-03 16:21:11 -0600557 struct gl_shader_program *shProg;
Brianb7978af2007-01-09 19:17:17 -0700558 const GLint size = -1; /* unknown size */
Brian Paul6bc87492008-07-25 08:34:54 -0600559 GLint i, oldIndex;
Brian Paul6f1abb92008-07-29 17:27:22 -0600560 GLenum datatype = GL_FLOAT_VEC4;
Brian5b01c5e2006-12-19 18:02:03 -0700561
Brian Paul530df582008-07-03 16:21:11 -0600562 shProg = _mesa_lookup_shader_program_err(ctx, program,
563 "glBindAttribLocation");
Brian65a18442006-12-19 18:46:56 -0700564 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700565 return;
566 }
567
Brian9e4bae92006-12-20 09:27:42 -0700568 if (!name)
569 return;
570
571 if (strncmp(name, "gl_", 3) == 0) {
572 _mesa_error(ctx, GL_INVALID_OPERATION,
573 "glBindAttribLocation(illegal name)");
574 return;
575 }
576
Brian Paul7acb7c12008-07-03 13:49:48 -0600577 if (index >= ctx->Const.VertexProgram.MaxAttribs) {
578 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
579 return;
580 }
581
Brian Paul6bc87492008-07-25 08:34:54 -0600582 if (shProg->LinkStatus) {
583 /* get current index/location for the attribute */
584 oldIndex = _mesa_get_attrib_location(ctx, program, name);
585 }
586 else {
587 oldIndex = -1;
588 }
589
Brian3209c3e2007-01-09 17:49:24 -0700590 /* this will replace the current value if it's already in the list */
Brian Paulffbc66b2008-07-21 13:58:50 -0600591 i = _mesa_add_attribute(shProg->Attributes, name, size, datatype, index);
Brian3209c3e2007-01-09 17:49:24 -0700592 if (i < 0) {
593 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
Brian Paul6f1abb92008-07-29 17:27:22 -0600594 return;
Brian3209c3e2007-01-09 17:49:24 -0700595 }
596
Brian Paul27341a92008-09-16 16:28:36 -0600597 /*
598 * Note that this attribute binding won't go into effect until
599 * glLinkProgram is called again.
600 */
Brian34ae99d2006-12-18 08:28:54 -0700601}
602
603
Brian Paulfd59f192008-05-18 16:04:55 -0600604static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700605_mesa_create_shader(GLcontext *ctx, GLenum type)
606{
Brian65a18442006-12-19 18:46:56 -0700607 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700608 GLuint name;
609
610 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
611
612 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700613 case GL_FRAGMENT_SHADER:
614 case GL_VERTEX_SHADER:
615 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700616 break;
617 default:
618 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
619 return 0;
620 }
621
Brian65a18442006-12-19 18:46:56 -0700622 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700623
624 return name;
625}
626
627
Brian Paulfd59f192008-05-18 16:04:55 -0600628static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700629_mesa_create_program(GLcontext *ctx)
630{
631 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700632 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700633
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800634 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
Brian65a18442006-12-19 18:46:56 -0700635 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700636
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800637 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700638
Brian3c008a02007-04-12 15:22:32 -0600639 assert(shProg->RefCount == 1);
640
Brian5b01c5e2006-12-19 18:02:03 -0700641 return name;
642}
643
644
Brian3c008a02007-04-12 15:22:32 -0600645/**
646 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
647 * DeleteProgramARB.
648 */
Brian Paulfd59f192008-05-18 16:04:55 -0600649static void
Brian5b01c5e2006-12-19 18:02:03 -0700650_mesa_delete_program2(GLcontext *ctx, GLuint name)
651{
Brian3c008a02007-04-12 15:22:32 -0600652 /*
653 * NOTE: deleting shaders/programs works a bit differently than
654 * texture objects (and buffer objects, etc). Shader/program
655 * handles/IDs exist in the hash table until the object is really
656 * deleted (refcount==0). With texture objects, the handle/ID is
657 * removed from the hash table in glDeleteTextures() while the tex
658 * object itself might linger until its refcount goes to zero.
659 */
Brian65a18442006-12-19 18:46:56 -0700660 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700661
Brian Paul530df582008-07-03 16:21:11 -0600662 shProg = _mesa_lookup_shader_program_err(ctx, name, "glDeleteProgram");
663 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700664 return;
Brian5b01c5e2006-12-19 18:02:03 -0700665
Brian9e4bae92006-12-20 09:27:42 -0700666 shProg->DeletePending = GL_TRUE;
667
Brian3c008a02007-04-12 15:22:32 -0600668 /* effectively, decr shProg's refcount */
669 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700670}
671
672
Brian Paulfd59f192008-05-18 16:04:55 -0600673static void
Brian5b01c5e2006-12-19 18:02:03 -0700674_mesa_delete_shader(GLcontext *ctx, GLuint shader)
675{
Brian Paul530df582008-07-03 16:21:11 -0600676 struct gl_shader *sh;
677
678 sh = _mesa_lookup_shader_err(ctx, shader, "glDeleteShader");
679 if (!sh)
Brian9e4bae92006-12-20 09:27:42 -0700680 return;
Brian5b01c5e2006-12-19 18:02:03 -0700681
Brian9e4bae92006-12-20 09:27:42 -0700682 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600683
684 /* effectively, decr sh's refcount */
685 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700686}
687
688
Brian Paulfd59f192008-05-18 16:04:55 -0600689static void
Brian5b01c5e2006-12-19 18:02:03 -0700690_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
691{
Brian Paul530df582008-07-03 16:21:11 -0600692 struct gl_shader_program *shProg;
Brian237b9852007-08-07 21:48:31 +0100693 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700694 GLuint i, j;
695
Brian Paul530df582008-07-03 16:21:11 -0600696 shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader");
697 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700698 return;
Brian5b01c5e2006-12-19 18:02:03 -0700699
Brian237b9852007-08-07 21:48:31 +0100700 n = shProg->NumShaders;
701
Brian5b01c5e2006-12-19 18:02:03 -0700702 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700703 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700704 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600705 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700706
Brian Paul530df582008-07-03 16:21:11 -0600707 /* release */
Brian3c008a02007-04-12 15:22:32 -0600708 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700709
Brian5b01c5e2006-12-19 18:02:03 -0700710 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700711 newList = (struct gl_shader **)
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -0500712 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];
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -0500722 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:
Brian Paulac498f22010-02-25 19:05:11 -0700772 case GL_SAMPLER_1D_ARRAY_EXT:
773 case GL_SAMPLER_2D_ARRAY_EXT:
Brian Paul8c51e002008-08-11 15:09:47 -0600774 case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
775 case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
776 case GL_SAMPLER_CUBE_SHADOW_EXT:
Brian Paulffbc66b2008-07-21 13:58:50 -0600777 return 1;
778 case GL_FLOAT_VEC2:
779 case GL_INT_VEC2:
780 case GL_BOOL_VEC2:
781 return 2;
782 case GL_FLOAT_VEC3:
783 case GL_INT_VEC3:
784 case GL_BOOL_VEC3:
785 return 3;
786 case GL_FLOAT_VEC4:
787 case GL_INT_VEC4:
788 case GL_BOOL_VEC4:
789 return 4;
790 case GL_FLOAT_MAT2:
791 case GL_FLOAT_MAT2x3:
792 case GL_FLOAT_MAT2x4:
793 return 8; /* two float[4] vectors */
794 case GL_FLOAT_MAT3:
795 case GL_FLOAT_MAT3x2:
796 case GL_FLOAT_MAT3x4:
797 return 12; /* three float[4] vectors */
798 case GL_FLOAT_MAT4:
799 case GL_FLOAT_MAT4x2:
800 case GL_FLOAT_MAT4x3:
801 return 16; /* four float[4] vectors */
802 default:
803 _mesa_problem(NULL, "Invalid type in sizeof_glsl_type()");
804 return 1;
805 }
806}
807
808
Brian Pauleda291e2008-08-06 16:26:47 -0600809static GLboolean
810is_boolean_type(GLenum type)
811{
812 switch (type) {
813 case GL_BOOL:
814 case GL_BOOL_VEC2:
815 case GL_BOOL_VEC3:
816 case GL_BOOL_VEC4:
817 return GL_TRUE;
818 default:
819 return GL_FALSE;
820 }
821}
822
823
824static GLboolean
825is_integer_type(GLenum type)
826{
827 switch (type) {
828 case GL_INT:
829 case GL_INT_VEC2:
830 case GL_INT_VEC3:
831 case GL_INT_VEC4:
832 return GL_TRUE;
833 default:
834 return GL_FALSE;
835 }
836}
837
838
Brian Paulc4ffbf02009-02-18 17:46:00 -0700839static GLboolean
840is_sampler_type(GLenum type)
841{
842 switch (type) {
843 case GL_SAMPLER_1D:
844 case GL_SAMPLER_2D:
845 case GL_SAMPLER_3D:
846 case GL_SAMPLER_CUBE:
847 case GL_SAMPLER_1D_SHADOW:
848 case GL_SAMPLER_2D_SHADOW:
849 case GL_SAMPLER_2D_RECT_ARB:
850 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
851 case GL_SAMPLER_1D_ARRAY_EXT:
852 case GL_SAMPLER_2D_ARRAY_EXT:
Brian Paulac498f22010-02-25 19:05:11 -0700853 case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
854 case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
Brian Paulc4ffbf02009-02-18 17:46:00 -0700855 return GL_TRUE;
856 default:
857 return GL_FALSE;
858 }
859}
860
861
Brian Paulfd59f192008-05-18 16:04:55 -0600862static void
Brian5b01c5e2006-12-19 18:02:03 -0700863_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
864 GLsizei maxLength, GLsizei *length, GLint *size,
865 GLenum *type, GLchar *nameOut)
866{
Brian Paul27341a92008-09-16 16:28:36 -0600867 const struct gl_program_parameter_list *attribs = NULL;
Brian Paul530df582008-07-03 16:21:11 -0600868 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700869
Brian Paul530df582008-07-03 16:21:11 -0600870 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
871 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700872 return;
Brian5b01c5e2006-12-19 18:02:03 -0700873
Brian Paul27341a92008-09-16 16:28:36 -0600874 if (shProg->VertexProgram)
875 attribs = shProg->VertexProgram->Base.Attributes;
876
877 if (!attribs || index >= attribs->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600878 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700879 return;
880 }
881
Brian Paul27341a92008-09-16 16:28:36 -0600882 copy_string(nameOut, maxLength, length, attribs->Parameters[index].Name);
883
Brian5b01c5e2006-12-19 18:02:03 -0700884 if (size)
Brian Paul27341a92008-09-16 16:28:36 -0600885 *size = attribs->Parameters[index].Size
886 / sizeof_glsl_type(attribs->Parameters[index].DataType);
887
Brian Paulade50832008-05-14 16:09:46 -0600888 if (type)
Brian Paul27341a92008-09-16 16:28:36 -0600889 *type = attribs->Parameters[index].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700890}
891
892
Brian Pauleda291e2008-08-06 16:26:47 -0600893static struct gl_program_parameter *
894get_uniform_parameter(const struct gl_shader_program *shProg, GLuint index)
895{
Brian Paula531a5c2009-08-13 13:44:01 -0600896 const struct gl_program *prog = NULL;
Brian Pauleda291e2008-08-06 16:26:47 -0600897 GLint progPos;
898
899 progPos = shProg->Uniforms->Uniforms[index].VertPos;
900 if (progPos >= 0) {
901 prog = &shProg->VertexProgram->Base;
902 }
903 else {
904 progPos = shProg->Uniforms->Uniforms[index].FragPos;
905 if (progPos >= 0) {
906 prog = &shProg->FragmentProgram->Base;
907 }
908 }
909
910 if (!prog || progPos < 0)
911 return NULL; /* should never happen */
912
913 return &prog->Parameters->Parameters[progPos];
914}
915
916
Brian5b01c5e2006-12-19 18:02:03 -0700917/**
918 * Called via ctx->Driver.GetActiveUniform().
919 */
Brian Paulfd59f192008-05-18 16:04:55 -0600920static void
Brian5b01c5e2006-12-19 18:02:03 -0700921_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
922 GLsizei maxLength, GLsizei *length, GLint *size,
923 GLenum *type, GLchar *nameOut)
924{
Brian Paul530df582008-07-03 16:21:11 -0600925 const struct gl_shader_program *shProg;
Brian Paula531a5c2009-08-13 13:44:01 -0600926 const struct gl_program *prog = NULL;
Brian Paul369d1852009-02-11 08:16:14 -0700927 const struct gl_program_parameter *param;
Brian Paulade50832008-05-14 16:09:46 -0600928 GLint progPos;
Brian5b01c5e2006-12-19 18:02:03 -0700929
Brian Paul530df582008-07-03 16:21:11 -0600930 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
931 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700932 return;
Brian5b01c5e2006-12-19 18:02:03 -0700933
Brian Paulade50832008-05-14 16:09:46 -0600934 if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
Brian5b01c5e2006-12-19 18:02:03 -0700935 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
936 return;
937 }
938
Brian Paulade50832008-05-14 16:09:46 -0600939 progPos = shProg->Uniforms->Uniforms[index].VertPos;
940 if (progPos >= 0) {
941 prog = &shProg->VertexProgram->Base;
942 }
943 else {
944 progPos = shProg->Uniforms->Uniforms[index].FragPos;
945 if (progPos >= 0) {
946 prog = &shProg->FragmentProgram->Base;
Brian274ac7a2007-04-18 16:05:53 -0600947 }
948 }
949
Brian Paulade50832008-05-14 16:09:46 -0600950 if (!prog || progPos < 0)
951 return; /* should never happen */
952
Brian Paul369d1852009-02-11 08:16:14 -0700953 ASSERT(progPos < prog->Parameters->NumParameters);
954 param = &prog->Parameters->Parameters[progPos];
955
956 if (nameOut) {
957 copy_string(nameOut, maxLength, length, param->Name);
958 }
959
960 if (size) {
961 GLint typeSize = sizeof_glsl_type(param->DataType);
Brian Paul20fbb242010-01-27 17:03:04 -0700962 if ((GLint) param->Size > typeSize) {
Brian Paul369d1852009-02-11 08:16:14 -0700963 /* This is an array.
964 * Array elements are placed on vector[4] boundaries so they're
965 * a multiple of four floats. We round typeSize up to next multiple
966 * of four to get the right size below.
967 */
968 typeSize = (typeSize + 3) & ~3;
969 }
970 /* Note that the returned size is in units of the <type>, not bytes */
971 *size = param->Size / typeSize;
972 }
973
974 if (type) {
975 *type = param->DataType;
976 }
Brian5b01c5e2006-12-19 18:02:03 -0700977}
978
979
980/**
981 * Called via ctx->Driver.GetAttachedShaders().
982 */
Brian Paulfd59f192008-05-18 16:04:55 -0600983static void
Brian5b01c5e2006-12-19 18:02:03 -0700984_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
985 GLsizei *count, GLuint *obj)
986{
Brian Paul530df582008-07-03 16:21:11 -0600987 struct gl_shader_program *shProg =
988 _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders");
Brian65a18442006-12-19 18:46:56 -0700989 if (shProg) {
Brian Paul530df582008-07-03 16:21:11 -0600990 GLuint i;
991 for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) {
Brian65a18442006-12-19 18:46:56 -0700992 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700993 }
994 if (count)
995 *count = i;
996 }
Brian5b01c5e2006-12-19 18:02:03 -0700997}
998
999
Brian Paulfd59f192008-05-18 16:04:55 -06001000static GLuint
Brian5b01c5e2006-12-19 18:02:03 -07001001_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -07001002{
Ian Romanick905d8e02008-09-29 12:27:00 -07001003 GLint handle = 0;
1004
1005 if (pname == GL_PROGRAM_OBJECT_ARB) {
1006 CALL_GetIntegerv(ctx->Exec, (GL_CURRENT_PROGRAM, &handle));
1007 } else {
Brian34ae99d2006-12-18 08:28:54 -07001008 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
1009 }
Ian Romanick905d8e02008-09-29 12:27:00 -07001010
1011 return handle;
Brian34ae99d2006-12-18 08:28:54 -07001012}
1013
1014
Brian Paulfd59f192008-05-18 16:04:55 -06001015static void
Brian5b01c5e2006-12-19 18:02:03 -07001016_mesa_get_programiv(GLcontext *ctx, GLuint program,
1017 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -07001018{
Brian Paul27341a92008-09-16 16:28:36 -06001019 const struct gl_program_parameter_list *attribs;
Brian65a18442006-12-19 18:46:56 -07001020 struct gl_shader_program *shProg
1021 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -07001022
Brian65a18442006-12-19 18:46:56 -07001023 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -07001024 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -07001025 return;
1026 }
1027
Brian Paul27341a92008-09-16 16:28:36 -06001028 if (shProg->VertexProgram)
1029 attribs = shProg->VertexProgram->Base.Attributes;
1030 else
1031 attribs = NULL;
1032
Brian5b01c5e2006-12-19 18:02:03 -07001033 switch (pname) {
1034 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -07001035 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -07001036 break;
1037 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -07001038 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -07001039 break;
Brian5b01c5e2006-12-19 18:02:03 -07001040 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -07001041 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -07001042 break;
1043 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001044 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001045 break;
1046 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -07001047 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -07001048 break;
1049 case GL_ACTIVE_ATTRIBUTES:
Brian Paul27341a92008-09-16 16:28:36 -06001050 *params = attribs ? attribs->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001051 break;
1052 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian Paul27341a92008-09-16 16:28:36 -06001053 *params = _mesa_longest_parameter_name(attribs, PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -07001054 break;
1055 case GL_ACTIVE_UNIFORMS:
Brian Paulade50832008-05-14 16:09:46 -06001056 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001057 break;
1058 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian Paulade50832008-05-14 16:09:46 -06001059 *params = _mesa_longest_uniform_name(shProg->Uniforms);
Brian274ac7a2007-04-18 16:05:53 -06001060 if (*params > 0)
1061 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -07001062 break;
Brian Paulbda6ad22008-08-06 12:45:14 -06001063 case GL_PROGRAM_BINARY_LENGTH_OES:
1064 *params = 0;
1065 break;
Brian34ae99d2006-12-18 08:28:54 -07001066 default:
Brian5b01c5e2006-12-19 18:02:03 -07001067 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
1068 return;
Brian34ae99d2006-12-18 08:28:54 -07001069 }
Brian5b01c5e2006-12-19 18:02:03 -07001070}
Brian34ae99d2006-12-18 08:28:54 -07001071
Brian34ae99d2006-12-18 08:28:54 -07001072
Brian Paulfd59f192008-05-18 16:04:55 -06001073static void
Brian5b01c5e2006-12-19 18:02:03 -07001074_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
1075{
Brian Paul530df582008-07-03 16:21:11 -06001076 struct gl_shader *shader = _mesa_lookup_shader_err(ctx, name, "glGetShaderiv");
Brian5b01c5e2006-12-19 18:02:03 -07001077
1078 if (!shader) {
Brian5b01c5e2006-12-19 18:02:03 -07001079 return;
1080 }
Brian65a18442006-12-19 18:46:56 -07001081
Brian5b01c5e2006-12-19 18:02:03 -07001082 switch (pname) {
1083 case GL_SHADER_TYPE:
1084 *params = shader->Type;
1085 break;
1086 case GL_DELETE_STATUS:
1087 *params = shader->DeletePending;
1088 break;
1089 case GL_COMPILE_STATUS:
1090 *params = shader->CompileStatus;
1091 break;
1092 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001093 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001094 break;
1095 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001096 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001097 break;
1098 default:
1099 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
1100 return;
1101 }
1102}
1103
1104
Brian Paulfd59f192008-05-18 16:04:55 -06001105static void
Brian5b01c5e2006-12-19 18:02:03 -07001106_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
1107 GLsizei *length, GLchar *infoLog)
1108{
Brian65a18442006-12-19 18:46:56 -07001109 struct gl_shader_program *shProg
1110 = _mesa_lookup_shader_program(ctx, program);
1111 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -07001112 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
1113 return;
1114 }
Brian65a18442006-12-19 18:46:56 -07001115 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -07001116}
1117
1118
Brian Paulfd59f192008-05-18 16:04:55 -06001119static void
Brian5b01c5e2006-12-19 18:02:03 -07001120_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
1121 GLsizei *length, GLchar *infoLog)
1122{
Brian65a18442006-12-19 18:46:56 -07001123 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
1124 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001125 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
1126 return;
1127 }
Brian65a18442006-12-19 18:46:56 -07001128 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -07001129}
1130
1131
1132/**
1133 * Called via ctx->Driver.GetShaderSource().
1134 */
Brian Paulfd59f192008-05-18 16:04:55 -06001135static void
Brian5b01c5e2006-12-19 18:02:03 -07001136_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
1137 GLsizei *length, GLchar *sourceOut)
1138{
Brian Paul530df582008-07-03 16:21:11 -06001139 struct gl_shader *sh;
1140 sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource");
Brian65a18442006-12-19 18:46:56 -07001141 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001142 return;
1143 }
Brian65a18442006-12-19 18:46:56 -07001144 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -07001145}
1146
1147
Brian Paul5b982362008-08-06 13:07:09 -06001148static void
1149get_matrix_dims(GLenum type, GLint *rows, GLint *cols)
1150{
1151 switch (type) {
1152 case GL_FLOAT_MAT2:
1153 *rows = *cols = 2;
1154 break;
1155 case GL_FLOAT_MAT2x3:
1156 *rows = 3;
1157 *cols = 2;
1158 break;
1159 case GL_FLOAT_MAT2x4:
1160 *rows = 4;
1161 *cols = 2;
1162 break;
1163 case GL_FLOAT_MAT3:
1164 *rows = 3;
1165 *cols = 3;
1166 break;
1167 case GL_FLOAT_MAT3x2:
1168 *rows = 2;
1169 *cols = 3;
1170 break;
1171 case GL_FLOAT_MAT3x4:
1172 *rows = 4;
1173 *cols = 3;
1174 break;
1175 case GL_FLOAT_MAT4:
1176 *rows = 4;
1177 *cols = 4;
1178 break;
1179 case GL_FLOAT_MAT4x2:
1180 *rows = 2;
1181 *cols = 4;
1182 break;
1183 case GL_FLOAT_MAT4x3:
1184 *rows = 3;
1185 *cols = 4;
1186 break;
1187 default:
1188 *rows = *cols = 0;
1189 }
1190}
1191
1192
1193/**
1194 * Determine the number of rows and columns occupied by a uniform
Brian Paulea9568d2008-09-16 08:55:54 -06001195 * according to its datatype. For non-matrix types (such as GL_FLOAT_VEC4),
1196 * the number of rows = 1 and cols = number of elements in the vector.
Brian Paul5b982362008-08-06 13:07:09 -06001197 */
1198static void
1199get_uniform_rows_cols(const struct gl_program_parameter *p,
1200 GLint *rows, GLint *cols)
1201{
1202 get_matrix_dims(p->DataType, rows, cols);
1203 if (*rows == 0 && *cols == 0) {
1204 /* not a matrix type, probably a float or vector */
Brian Paulea9568d2008-09-16 08:55:54 -06001205 if (p->Size <= 4) {
1206 *rows = 1;
1207 *cols = p->Size;
1208 }
1209 else {
1210 *rows = p->Size / 4 + 1;
1211 if (p->Size % 4 == 0)
1212 *cols = 4;
1213 else
1214 *cols = p->Size % 4;
1215 }
Brian Paul5b982362008-08-06 13:07:09 -06001216 }
1217}
1218
1219
Brian5b01c5e2006-12-19 18:02:03 -07001220/**
Brian Paul4ef7a932009-02-11 09:03:16 -07001221 * Helper for get_uniform[fi]v() functions.
1222 * Given a shader program name and uniform location, return a pointer
1223 * to the shader program and return the program parameter position.
Brian5b01c5e2006-12-19 18:02:03 -07001224 */
Brian Paul4ef7a932009-02-11 09:03:16 -07001225static void
1226lookup_uniform_parameter(GLcontext *ctx, GLuint program, GLint location,
1227 struct gl_program **progOut, GLint *paramPosOut)
Brian5b01c5e2006-12-19 18:02:03 -07001228{
Brian65a18442006-12-19 18:46:56 -07001229 struct gl_shader_program *shProg
Brian Paulbda6ad22008-08-06 12:45:14 -06001230 = _mesa_lookup_shader_program_err(ctx, program, "glGetUniform[if]v");
Brian Paul4ef7a932009-02-11 09:03:16 -07001231 struct gl_program *prog = NULL;
1232 GLint progPos = -1;
Brian Paulade50832008-05-14 16:09:46 -06001233
Brian Paul4ef7a932009-02-11 09:03:16 -07001234 /* if shProg is NULL, we'll have already recorded an error */
1235
1236 if (shProg) {
1237 if (!shProg->Uniforms ||
1238 location < 0 ||
1239 location >= (GLint) shProg->Uniforms->NumUniforms) {
1240 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
1241 }
1242 else {
1243 /* OK, find the gl_program and program parameter location */
Brian Paulade50832008-05-14 16:09:46 -06001244 progPos = shProg->Uniforms->Uniforms[location].VertPos;
1245 if (progPos >= 0) {
1246 prog = &shProg->VertexProgram->Base;
Brian5b01c5e2006-12-19 18:02:03 -07001247 }
Brian Paulade50832008-05-14 16:09:46 -06001248 else {
1249 progPos = shProg->Uniforms->Uniforms[location].FragPos;
1250 if (progPos >= 0) {
1251 prog = &shProg->FragmentProgram->Base;
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001252 }
Brian Paulade50832008-05-14 16:09:46 -06001253 }
Brian5b01c5e2006-12-19 18:02:03 -07001254 }
1255 }
Brian Paul4ef7a932009-02-11 09:03:16 -07001256
1257 *progOut = prog;
1258 *paramPosOut = progPos;
Brian Paul2be54a82008-07-08 16:17:04 -06001259}
1260
1261
1262/**
1263 * Called via ctx->Driver.GetUniformfv().
1264 */
1265static void
1266_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1267 GLfloat *params)
1268{
Brian Paul4ef7a932009-02-11 09:03:16 -07001269 struct gl_program *prog;
1270 GLint paramPos;
1271
1272 lookup_uniform_parameter(ctx, program, location, &prog, &paramPos);
1273
1274 if (prog) {
1275 const struct gl_program_parameter *p =
1276 &prog->Parameters->Parameters[paramPos];
1277 GLint rows, cols, i, j, k;
1278
1279 get_uniform_rows_cols(p, &rows, &cols);
1280
1281 k = 0;
1282 for (i = 0; i < rows; i++) {
1283 for (j = 0; j < cols; j++ ) {
1284 params[k++] = prog->Parameters->ParameterValues[paramPos+i][j];
1285 }
1286 }
1287 }
Brian Paul2be54a82008-07-08 16:17:04 -06001288}
1289
1290
1291/**
1292 * Called via ctx->Driver.GetUniformiv().
Brian Paul4ef7a932009-02-11 09:03:16 -07001293 * \sa _mesa_get_uniformfv, only difference is a cast.
Brian Paul2be54a82008-07-08 16:17:04 -06001294 */
1295static void
1296_mesa_get_uniformiv(GLcontext *ctx, GLuint program, GLint location,
1297 GLint *params)
1298{
Brian Paul4ef7a932009-02-11 09:03:16 -07001299 struct gl_program *prog;
1300 GLint paramPos;
1301
1302 lookup_uniform_parameter(ctx, program, location, &prog, &paramPos);
1303
1304 if (prog) {
1305 const struct gl_program_parameter *p =
1306 &prog->Parameters->Parameters[paramPos];
1307 GLint rows, cols, i, j, k;
1308
1309 get_uniform_rows_cols(p, &rows, &cols);
1310
1311 k = 0;
1312 for (i = 0; i < rows; i++) {
1313 for (j = 0; j < cols; j++ ) {
1314 params[k++] = (GLint) prog->Parameters->ParameterValues[paramPos+i][j];
1315 }
1316 }
Brian Paul2be54a82008-07-08 16:17:04 -06001317 }
Brian5b01c5e2006-12-19 18:02:03 -07001318}
1319
1320
1321/**
Brian Pauleda291e2008-08-06 16:26:47 -06001322 * The value returned by GetUniformLocation actually encodes two things:
1323 * 1. the index into the prog->Uniforms[] array for the uniform
1324 * 2. an offset in the prog->ParameterValues[] array for specifying array
1325 * elements or structure fields.
1326 * This function merges those two values.
1327 */
1328static void
1329merge_location_offset(GLint *location, GLint offset)
1330{
1331 *location = *location | (offset << 16);
1332}
1333
1334
1335/**
1336 * Seperate the uniform location and parameter offset. See above.
1337 */
1338static void
1339split_location_offset(GLint *location, GLint *offset)
1340{
1341 *offset = (*location >> 16);
1342 *location = *location & 0xffff;
1343}
1344
1345
1346/**
Brian5b01c5e2006-12-19 18:02:03 -07001347 * Called via ctx->Driver.GetUniformLocation().
Brian Pauleda291e2008-08-06 16:26:47 -06001348 *
1349 * The return value will encode two values, the uniform location and an
1350 * offset (used for arrays, structs).
Brian5b01c5e2006-12-19 18:02:03 -07001351 */
Brian Paulfd59f192008-05-18 16:04:55 -06001352static GLint
Brian5b01c5e2006-12-19 18:02:03 -07001353_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
1354{
Brian Pauleda291e2008-08-06 16:26:47 -06001355 GLint offset = 0, location = -1;
1356
Brian Paul530df582008-07-03 16:21:11 -06001357 struct gl_shader_program *shProg =
1358 _mesa_lookup_shader_program_err(ctx, program, "glGetUniformLocation");
1359
Brian Paulade50832008-05-14 16:09:46 -06001360 if (!shProg)
1361 return -1;
Brian5b01c5e2006-12-19 18:02:03 -07001362
Brian Paule06565b2008-07-04 09:58:55 -06001363 if (shProg->LinkStatus == GL_FALSE) {
1364 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
1365 return -1;
1366 }
1367
Brian Paul530df582008-07-03 16:21:11 -06001368 /* XXX we should return -1 if the uniform was declared, but not
1369 * actually used.
1370 */
1371
Brian Pauleda291e2008-08-06 16:26:47 -06001372 /* XXX we need to be able to parse uniform names for structs and arrays
1373 * such as:
1374 * mymatrix[1]
1375 * mystruct.field1
1376 */
1377
1378 {
1379 /* handle 1-dimension arrays here... */
1380 char *c = strchr(name, '[');
1381 if (c) {
1382 /* truncate name at [ */
1383 const GLint len = c - name;
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -05001384 GLchar *newName = malloc(len + 1);
Brian Pauleda291e2008-08-06 16:26:47 -06001385 if (!newName)
1386 return -1; /* out of mem */
Kenneth Graunkec7ac48622010-02-18 23:50:59 -08001387 memcpy(newName, name, len);
Brian Pauleda291e2008-08-06 16:26:47 -06001388 newName[len] = 0;
1389
1390 location = _mesa_lookup_uniform(shProg->Uniforms, newName);
1391 if (location >= 0) {
Kenneth Graunke60b0cae2010-02-18 23:50:58 -08001392 const GLint element = atoi(c + 1);
Brian Pauleda291e2008-08-06 16:26:47 -06001393 if (element > 0) {
1394 /* get type of the uniform array element */
1395 struct gl_program_parameter *p;
1396 p = get_uniform_parameter(shProg, location);
1397 if (p) {
1398 GLint rows, cols;
1399 get_matrix_dims(p->DataType, &rows, &cols);
1400 if (rows < 1)
1401 rows = 1;
1402 offset = element * rows;
1403 }
1404 }
1405 }
1406
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -05001407 free(newName);
Brian Pauleda291e2008-08-06 16:26:47 -06001408 }
1409 }
1410
1411 if (location < 0) {
1412 location = _mesa_lookup_uniform(shProg->Uniforms, name);
1413 }
1414
1415 if (location >= 0) {
1416 merge_location_offset(&location, offset);
1417 }
1418
1419 return location;
Brian5b01c5e2006-12-19 18:02:03 -07001420}
1421
1422
Brian34ae99d2006-12-18 08:28:54 -07001423
Brian5b01c5e2006-12-19 18:02:03 -07001424/**
1425 * Called via ctx->Driver.ShaderSource()
1426 */
Brian Paulfd59f192008-05-18 16:04:55 -06001427static void
Brian5b01c5e2006-12-19 18:02:03 -07001428_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -07001429{
Brian Paul530df582008-07-03 16:21:11 -06001430 struct gl_shader *sh;
1431
1432 sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource");
1433 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001434 return;
Brian34ae99d2006-12-18 08:28:54 -07001435
Brian34ae99d2006-12-18 08:28:54 -07001436 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -07001437 if (sh->Source) {
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -05001438 free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -07001439 }
Brian65a18442006-12-19 18:46:56 -07001440 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -07001441 sh->CompileStatus = GL_FALSE;
Brian Paulf7783ba2009-08-04 15:35:48 -06001442#ifdef DEBUG
1443 sh->SourceChecksum = _mesa_str_checksum(sh->Source);
1444#endif
Brian34ae99d2006-12-18 08:28:54 -07001445}
1446
1447
Brian5b01c5e2006-12-19 18:02:03 -07001448/**
1449 * Called via ctx->Driver.CompileShader()
1450 */
Brian Paulfd59f192008-05-18 16:04:55 -06001451static void
Brian5b01c5e2006-12-19 18:02:03 -07001452_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -07001453{
Brian Paul530df582008-07-03 16:21:11 -06001454 struct gl_shader *sh;
Brian34ae99d2006-12-18 08:28:54 -07001455
Brian Paul530df582008-07-03 16:21:11 -06001456 sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader");
1457 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001458 return;
Brian34ae99d2006-12-18 08:28:54 -07001459
Brian Paul65fc2ca2009-03-19 10:25:24 -06001460 /* set default pragma state for shader */
1461 sh->Pragmas = ctx->Shader.DefaultPragmas;
1462
Brian Paulcb136e02009-01-22 10:34:15 -07001463 /* this call will set the sh->CompileStatus field to indicate if
1464 * compilation was successful.
1465 */
1466 (void) _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -07001467}
1468
1469
Brian5b01c5e2006-12-19 18:02:03 -07001470/**
1471 * Called via ctx->Driver.LinkProgram()
1472 */
Brian Paulfd59f192008-05-18 16:04:55 -06001473static void
Brian5b01c5e2006-12-19 18:02:03 -07001474_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001475{
Brian65a18442006-12-19 18:46:56 -07001476 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001477
Brian Paul530df582008-07-03 16:21:11 -06001478 shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
1479 if (!shProg)
Brian34ae99d2006-12-18 08:28:54 -07001480 return;
Brian34ae99d2006-12-18 08:28:54 -07001481
Briandf43fb62008-05-06 23:08:51 -06001482 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1483
Brianc1771912007-02-16 09:56:19 -07001484 _slang_link(ctx, program, shProg);
Brian Paulac3c8e32009-09-14 17:32:03 -06001485
1486 /* debug code */
1487 if (0) {
1488 GLuint i;
1489
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001490 printf("Link %u shaders in program %u: %s\n",
Brian Paulac3c8e32009-09-14 17:32:03 -06001491 shProg->NumShaders, shProg->Name,
1492 shProg->LinkStatus ? "Success" : "Failed");
1493
1494 for (i = 0; i < shProg->NumShaders; i++) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001495 printf(" shader %u, type 0x%x\n",
Brian Paulac3c8e32009-09-14 17:32:03 -06001496 shProg->Shaders[i]->Name,
1497 shProg->Shaders[i]->Type);
1498 }
1499 }
Brian34ae99d2006-12-18 08:28:54 -07001500}
1501
1502
1503/**
Brian Paul346250b2009-10-23 16:31:48 -06001504 * Print basic shader info (for debug).
1505 */
1506static void
1507print_shader_info(const struct gl_shader_program *shProg)
1508{
1509 GLuint i;
1510
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001511 printf("Mesa: glUseProgram(%u)\n", shProg->Name);
Brian Paul346250b2009-10-23 16:31:48 -06001512 for (i = 0; i < shProg->NumShaders; i++) {
1513 const char *s;
1514 switch (shProg->Shaders[i]->Type) {
1515 case GL_VERTEX_SHADER:
1516 s = "vertex";
1517 break;
1518 case GL_FRAGMENT_SHADER:
1519 s = "fragment";
1520 break;
1521 case GL_GEOMETRY_SHADER:
1522 s = "geometry";
1523 break;
1524 default:
1525 s = "";
1526 }
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001527 printf(" %s shader %u, checksum %u\n", s,
1528 shProg->Shaders[i]->Name,
1529 shProg->Shaders[i]->SourceChecksum);
Brian Paul346250b2009-10-23 16:31:48 -06001530 }
1531 if (shProg->VertexProgram)
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001532 printf(" vert prog %u\n", shProg->VertexProgram->Base.Id);
Brian Paul346250b2009-10-23 16:31:48 -06001533 if (shProg->FragmentProgram)
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001534 printf(" frag prog %u\n", shProg->FragmentProgram->Base.Id);
Brian Paul346250b2009-10-23 16:31:48 -06001535}
1536
1537
1538/**
Brian5b01c5e2006-12-19 18:02:03 -07001539 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001540 */
Brian5b01c5e2006-12-19 18:02:03 -07001541void
1542_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001543{
Brian3c008a02007-04-12 15:22:32 -06001544 struct gl_shader_program *shProg;
1545
Brian00d63aa2007-02-03 11:35:02 -07001546 if (ctx->Shader.CurrentProgram &&
1547 ctx->Shader.CurrentProgram->Name == program) {
1548 /* no-op */
1549 return;
1550 }
1551
Brian5b01c5e2006-12-19 18:02:03 -07001552 if (program) {
Brian Paul530df582008-07-03 16:21:11 -06001553 shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
Brian65a18442006-12-19 18:46:56 -07001554 if (!shProg) {
Brian Paul530df582008-07-03 16:21:11 -06001555 return;
1556 }
1557 if (!shProg->LinkStatus) {
Brian Paul621c9992009-02-18 13:28:12 -07001558 _mesa_error(ctx, GL_INVALID_OPERATION,
1559 "glUseProgram(program %u not linked)", program);
Brian5b01c5e2006-12-19 18:02:03 -07001560 return;
1561 }
Brian Paul4eda17d2009-03-13 09:11:42 -06001562
1563 /* debug code */
Brian Paul2ee7fd82009-10-15 15:25:52 -06001564 if (ctx->Shader.Flags & GLSL_USE_PROG) {
Brian Paul346250b2009-10-23 16:31:48 -06001565 print_shader_info(shProg);
Brian Paul4eda17d2009-03-13 09:11:42 -06001566 }
Brian5b01c5e2006-12-19 18:02:03 -07001567 }
1568 else {
Brian3c008a02007-04-12 15:22:32 -06001569 shProg = NULL;
1570 }
1571
Brian Paulb44304e2009-10-27 20:09:33 -06001572 if (ctx->Shader.CurrentProgram != shProg) {
1573 FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
1574 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
1575 }
Brian5b01c5e2006-12-19 18:02:03 -07001576}
Brian34ae99d2006-12-18 08:28:54 -07001577
Brian5b01c5e2006-12-19 18:02:03 -07001578
Brian Paulade50832008-05-14 16:09:46 -06001579
1580/**
Brian Paul517401a2008-11-06 15:04:11 -07001581 * Update the vertex/fragment program's TexturesUsed array.
1582 *
1583 * This needs to be called after glUniform(set sampler var) is called.
1584 * A call to glUniform(samplerVar, value) causes a sampler to point to a
1585 * particular texture unit. We know the sampler's texture target
1586 * (1D/2D/3D/etc) from compile time but the sampler's texture unit is
1587 * set by glUniform() calls.
1588 *
1589 * So, scan the program->SamplerUnits[] and program->SamplerTargets[]
1590 * information to update the prog->TexturesUsed[] values.
1591 * Each value of TexturesUsed[unit] is one of zero, TEXTURE_1D_INDEX,
1592 * TEXTURE_2D_INDEX, TEXTURE_3D_INDEX, etc.
1593 * We'll use that info for state validation before rendering.
Brian Paulade50832008-05-14 16:09:46 -06001594 */
Brian Paul517401a2008-11-06 15:04:11 -07001595void
1596_mesa_update_shader_textures_used(struct gl_program *prog)
Brian Paulade50832008-05-14 16:09:46 -06001597{
1598 GLuint s;
1599
1600 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1601
1602 for (s = 0; s < MAX_SAMPLERS; s++) {
1603 if (prog->SamplersUsed & (1 << s)) {
Brian Paulf05344f2009-08-26 10:58:06 -06001604 GLuint unit = prog->SamplerUnits[s];
1605 GLuint tgt = prog->SamplerTargets[s];
1606 assert(unit < MAX_TEXTURE_IMAGE_UNITS);
1607 assert(tgt < NUM_TEXTURE_TARGETS);
1608 prog->TexturesUsed[unit] |= (1 << tgt);
Brian Paulade50832008-05-14 16:09:46 -06001609 }
1610 }
1611}
1612
1613
1614/**
Brian Paulffbc66b2008-07-21 13:58:50 -06001615 * Check if the type given by userType is allowed to set a uniform of the
1616 * target type. Generally, equivalence is required, but setting Boolean
1617 * uniforms can be done with glUniformiv or glUniformfv.
1618 */
1619static GLboolean
1620compatible_types(GLenum userType, GLenum targetType)
1621{
1622 if (userType == targetType)
1623 return GL_TRUE;
1624
1625 if (targetType == GL_BOOL && (userType == GL_FLOAT || userType == GL_INT))
1626 return GL_TRUE;
1627
1628 if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 ||
1629 userType == GL_INT_VEC2))
1630 return GL_TRUE;
1631
1632 if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 ||
1633 userType == GL_INT_VEC3))
1634 return GL_TRUE;
1635
1636 if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 ||
1637 userType == GL_INT_VEC4))
1638 return GL_TRUE;
1639
Brianb36749d2008-07-21 20:42:05 -06001640 if (is_sampler_type(targetType) && userType == GL_INT)
1641 return GL_TRUE;
1642
Brian Paulffbc66b2008-07-21 13:58:50 -06001643 return GL_FALSE;
1644}
1645
1646
1647/**
Brian Paulade50832008-05-14 16:09:46 -06001648 * Set the value of a program's uniform variable.
1649 * \param program the program whose uniform to update
Brian Pauleda291e2008-08-06 16:26:47 -06001650 * \param index the index of the program parameter for the uniform
1651 * \param offset additional parameter slot offset (for arrays)
Brian Paulc4ffbf02009-02-18 17:46:00 -07001652 * \param type the incoming datatype of 'values'
Brian Paulade50832008-05-14 16:09:46 -06001653 * \param count the number of uniforms to set
Brian Paulc4ffbf02009-02-18 17:46:00 -07001654 * \param elems number of elements per uniform (1, 2, 3 or 4)
1655 * \param values the new values, of datatype 'type'
Brian Paulade50832008-05-14 16:09:46 -06001656 */
1657static void
Brian Pauleda291e2008-08-06 16:26:47 -06001658set_program_uniform(GLcontext *ctx, struct gl_program *program,
1659 GLint index, GLint offset,
1660 GLenum type, GLsizei count, GLint elems,
1661 const void *values)
Brian Paulade50832008-05-14 16:09:46 -06001662{
Brian Paul6df38e62009-08-26 14:35:45 -06001663 const struct gl_program_parameter *param =
Brian Paul949e7382008-11-05 09:17:55 -07001664 &program->Parameters->Parameters[index];
1665
Brian Pauleda291e2008-08-06 16:26:47 -06001666 assert(offset >= 0);
Brian Paulc4ffbf02009-02-18 17:46:00 -07001667 assert(elems >= 1);
1668 assert(elems <= 4);
Brian Pauleda291e2008-08-06 16:26:47 -06001669
Brian Paul949e7382008-11-05 09:17:55 -07001670 if (!compatible_types(type, param->DataType)) {
Brian Paulffbc66b2008-07-21 13:58:50 -06001671 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
1672 return;
1673 }
1674
Michal Krolc5c71302008-08-07 16:23:15 +02001675 if (index + offset > (GLint) program->Parameters->Size) {
Brian Pauleda291e2008-08-06 16:26:47 -06001676 /* out of bounds! */
1677 return;
1678 }
1679
Brian Paul949e7382008-11-05 09:17:55 -07001680 if (param->Type == PROGRAM_SAMPLER) {
Brian Paulade50832008-05-14 16:09:46 -06001681 /* This controls which texture unit which is used by a sampler */
Brian Paulbabb5ba2009-08-26 14:29:50 -06001682 GLboolean changed = GL_FALSE;
Brian Paul2b4f0212009-02-11 09:12:34 -07001683 GLint i;
Brian Paulade50832008-05-14 16:09:46 -06001684
Brian Paul6df38e62009-08-26 14:35:45 -06001685 /* this should have been caught by the compatible_types() check */
1686 ASSERT(type == GL_INT);
Brian Paulade50832008-05-14 16:09:46 -06001687
Brian Paul6df38e62009-08-26 14:35:45 -06001688 /* loop over number of samplers to change */
Brian Paul2b4f0212009-02-11 09:12:34 -07001689 for (i = 0; i < count; i++) {
Brian Paul04d17072009-08-26 11:39:24 -06001690 GLuint sampler =
1691 (GLuint) program->Parameters->ParameterValues[index + offset + i][0];
1692 GLuint texUnit = ((GLuint *) values)[i];
Brian Paulade50832008-05-14 16:09:46 -06001693
Brian Paul2b4f0212009-02-11 09:12:34 -07001694 /* check that the sampler (tex unit index) is legal */
1695 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1696 _mesa_error(ctx, GL_INVALID_VALUE,
1697 "glUniform1(invalid sampler/tex unit index)");
1698 return;
1699 }
1700
1701 /* This maps a sampler to a texture unit: */
1702 if (sampler < MAX_SAMPLERS) {
Brian Paul04d17072009-08-26 11:39:24 -06001703#if 0
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001704 printf("Set program %p sampler %d '%s' to unit %u\n",
1705 program, sampler, param->Name, texUnit);
Brian Paul04d17072009-08-26 11:39:24 -06001706#endif
Brian Paulbabb5ba2009-08-26 14:29:50 -06001707 if (program->SamplerUnits[sampler] != texUnit) {
1708 program->SamplerUnits[sampler] = texUnit;
1709 changed = GL_TRUE;
1710 }
Brian Paul2b4f0212009-02-11 09:12:34 -07001711 }
Brian Paulade50832008-05-14 16:09:46 -06001712 }
1713
Brian Paulbabb5ba2009-08-26 14:29:50 -06001714 if (changed) {
1715 /* When a sampler's value changes it usually requires rewriting
1716 * a GPU program's TEX instructions since there may not be a
1717 * sampler->texture lookup table. We signal this with the
1718 * ProgramStringNotify() callback.
1719 */
1720 FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM);
1721 _mesa_update_shader_textures_used(program);
Brian Paul4ac9c802010-02-04 16:49:35 -07001722 /* Do we need to care about the return value here?
1723 * This should not be the first time the driver was notified of
1724 * this program.
1725 */
1726 (void) ctx->Driver.ProgramStringNotify(ctx, program->Target, program);
Brian Paulbabb5ba2009-08-26 14:29:50 -06001727 }
Brian Paulade50832008-05-14 16:09:46 -06001728 }
1729 else {
1730 /* ordinary uniform variable */
Brian Paul6df38e62009-08-26 14:35:45 -06001731 const GLboolean isUniformBool = is_boolean_type(param->DataType);
1732 const GLboolean areIntValues = is_integer_type(type);
Brian Paul2c1ea072009-02-11 08:46:21 -07001733 const GLint slots = (param->Size + 3) / 4;
1734 const GLint typeSize = sizeof_glsl_type(param->DataType);
Brian Paul6df38e62009-08-26 14:35:45 -06001735 GLsizei k, i;
Brian Paulade50832008-05-14 16:09:46 -06001736
Brian Paul20fbb242010-01-27 17:03:04 -07001737 if ((GLint) param->Size > typeSize) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001738 /* an array */
1739 /* we'll ignore extra data below */
1740 }
1741 else {
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001742 /* non-array: count must be at most one; count == 0 is handled by the loop below */
1743 if (count > 1) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001744 _mesa_error(ctx, GL_INVALID_OPERATION,
1745 "glUniform(uniform is not an array)");
1746 return;
1747 }
Brian Paulade50832008-05-14 16:09:46 -06001748 }
1749
Brian Paulc4ffbf02009-02-18 17:46:00 -07001750 /* loop over number of array elements */
Brian Paulade50832008-05-14 16:09:46 -06001751 for (k = 0; k < count; k++) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001752 GLfloat *uniformVal;
1753
Brian Paulb9d8f712009-02-18 17:40:44 -07001754 if (offset + k >= slots) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001755 /* Extra array data is ignored */
1756 break;
1757 }
1758
Brian Paulc4ffbf02009-02-18 17:46:00 -07001759 /* uniformVal (the destination) is always float[4] */
Brian Paul2c1ea072009-02-11 08:46:21 -07001760 uniformVal = program->Parameters->ParameterValues[index + offset + k];
Brian Paulc4ffbf02009-02-18 17:46:00 -07001761
1762 if (areIntValues) {
1763 /* convert user's ints to floats */
Brian Paulade50832008-05-14 16:09:46 -06001764 const GLint *iValues = ((const GLint *) values) + k * elems;
1765 for (i = 0; i < elems; i++) {
1766 uniformVal[i] = (GLfloat) iValues[i];
1767 }
1768 }
1769 else {
1770 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1771 for (i = 0; i < elems; i++) {
1772 uniformVal[i] = fValues[i];
1773 }
1774 }
Brian Pauleda291e2008-08-06 16:26:47 -06001775
1776 /* if the uniform is bool-valued, convert to 1.0 or 0.0 */
Brian Paulc4ffbf02009-02-18 17:46:00 -07001777 if (isUniformBool) {
Brian Pauleda291e2008-08-06 16:26:47 -06001778 for (i = 0; i < elems; i++) {
Michal Krolc5c71302008-08-07 16:23:15 +02001779 uniformVal[i] = uniformVal[i] ? 1.0f : 0.0f;
Brian Pauleda291e2008-08-06 16:26:47 -06001780 }
1781 }
Brian Paulade50832008-05-14 16:09:46 -06001782 }
1783 }
1784}
1785
1786
Brian5b01c5e2006-12-19 18:02:03 -07001787/**
1788 * Called via ctx->Driver.Uniform().
1789 */
Brian Paulfd59f192008-05-18 16:04:55 -06001790static void
Brian5b01c5e2006-12-19 18:02:03 -07001791_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1792 const GLvoid *values, GLenum type)
1793{
Brian3a8e2772006-12-20 17:19:16 -07001794 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paul2d76a0d2008-11-10 12:33:17 -07001795 struct gl_uniform *uniform;
Brian Pauleda291e2008-08-06 16:26:47 -06001796 GLint elems, offset;
Brian Paule01a03d2009-02-06 10:21:36 -07001797 GLenum basicType;
Brian3a8e2772006-12-20 17:19:16 -07001798
1799 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001800 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001801 return;
1802 }
1803
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001804 if (location == -1)
1805 return; /* The standard specifies this as a no-op */
1806
Brian Paul234f03e2009-02-11 09:05:08 -07001807 if (location < -1) {
1808 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(location)");
1809 return;
1810 }
1811
Brian Pauleda291e2008-08-06 16:26:47 -06001812 split_location_offset(&location, &offset);
1813
Brian Paulade50832008-05-14 16:09:46 -06001814 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
1815 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
Brian3a8e2772006-12-20 17:19:16 -07001816 return;
1817 }
1818
Brian52363952007-03-13 16:50:24 -06001819 if (count < 0) {
1820 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1821 return;
1822 }
1823
Brian98650bd2007-03-13 16:32:48 -06001824 switch (type) {
1825 case GL_FLOAT:
Brian Paule01a03d2009-02-06 10:21:36 -07001826 basicType = GL_FLOAT;
1827 elems = 1;
1828 break;
Brian98650bd2007-03-13 16:32:48 -06001829 case GL_INT:
Brian Paule01a03d2009-02-06 10:21:36 -07001830 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001831 elems = 1;
1832 break;
1833 case GL_FLOAT_VEC2:
Brian Paule01a03d2009-02-06 10:21:36 -07001834 basicType = GL_FLOAT;
1835 elems = 2;
1836 break;
Brian98650bd2007-03-13 16:32:48 -06001837 case GL_INT_VEC2:
Brian Paule01a03d2009-02-06 10:21:36 -07001838 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001839 elems = 2;
1840 break;
1841 case GL_FLOAT_VEC3:
Brian Paule01a03d2009-02-06 10:21:36 -07001842 basicType = GL_FLOAT;
1843 elems = 3;
1844 break;
Brian98650bd2007-03-13 16:32:48 -06001845 case GL_INT_VEC3:
Brian Paule01a03d2009-02-06 10:21:36 -07001846 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001847 elems = 3;
1848 break;
1849 case GL_FLOAT_VEC4:
Brian Paule01a03d2009-02-06 10:21:36 -07001850 basicType = GL_FLOAT;
1851 elems = 4;
1852 break;
Brian98650bd2007-03-13 16:32:48 -06001853 case GL_INT_VEC4:
Brian Paule01a03d2009-02-06 10:21:36 -07001854 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001855 elems = 4;
1856 break;
1857 default:
1858 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1859 return;
Brian89dc4852007-01-04 14:35:44 -07001860 }
Brian98650bd2007-03-13 16:32:48 -06001861
Brian Paul027ed1b2009-04-24 09:43:44 -06001862 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
Brian98650bd2007-03-13 16:32:48 -06001863
Brian Paul2d76a0d2008-11-10 12:33:17 -07001864 uniform = &shProg->Uniforms->Uniforms[location];
1865
Brian Paule01a03d2009-02-06 10:21:36 -07001866 if (ctx->Shader.Flags & GLSL_UNIFORMS) {
1867 GLint i;
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001868 printf("Mesa: set program %u uniform %s (loc %d) to: ",
1869 shProg->Name, uniform->Name, location);
Brian Paule01a03d2009-02-06 10:21:36 -07001870 if (basicType == GL_INT) {
1871 const GLint *v = (const GLint *) values;
1872 for (i = 0; i < count * elems; i++) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001873 printf("%d ", v[i]);
Brian Paule01a03d2009-02-06 10:21:36 -07001874 }
1875 }
1876 else {
1877 const GLfloat *v = (const GLfloat *) values;
1878 for (i = 0; i < count * elems; i++) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001879 printf("%g ", v[i]);
Brian Paule01a03d2009-02-06 10:21:36 -07001880 }
1881 }
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001882 printf("\n");
Brian Paule01a03d2009-02-06 10:21:36 -07001883 }
1884
Brian Paulade50832008-05-14 16:09:46 -06001885 /* A uniform var may be used by both a vertex shader and a fragment
1886 * shader. We may need to update one or both shader's uniform here:
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001887 */
Brian Paulade50832008-05-14 16:09:46 -06001888 if (shProg->VertexProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001889 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07001890 GLint index = uniform->VertPos;
Brian Pauleda291e2008-08-06 16:26:47 -06001891 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001892 set_program_uniform(ctx, &shProg->VertexProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001893 index, offset, type, count, elems, values);
Bruce Merry2bf2a8c2007-12-21 23:18:40 +02001894 }
Brian5b01c5e2006-12-19 18:02:03 -07001895 }
Brian5cf73262007-01-05 16:02:45 -07001896
Brian Paulade50832008-05-14 16:09:46 -06001897 if (shProg->FragmentProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001898 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07001899 GLint index = uniform->FragPos;
Brian Pauleda291e2008-08-06 16:26:47 -06001900 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001901 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001902 index, offset, type, count, elems, values);
Brian Paulade50832008-05-14 16:09:46 -06001903 }
1904 }
Brian Paul949e7382008-11-05 09:17:55 -07001905
Brian Paul2d76a0d2008-11-10 12:33:17 -07001906 uniform->Initialized = GL_TRUE;
Brian Paulade50832008-05-14 16:09:46 -06001907}
1908
1909
Brian Pauleda291e2008-08-06 16:26:47 -06001910/**
1911 * Set a matrix-valued program parameter.
1912 */
Brian Paulade50832008-05-14 16:09:46 -06001913static void
1914set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
Brian Pauleda291e2008-08-06 16:26:47 -06001915 GLuint index, GLuint offset,
1916 GLuint count, GLuint rows, GLuint cols,
Brian Paulade50832008-05-14 16:09:46 -06001917 GLboolean transpose, const GLfloat *values)
1918{
Brian Paulffbc66b2008-07-21 13:58:50 -06001919 GLuint mat, row, col;
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001920 GLuint src = 0;
1921 const struct gl_program_parameter * param = &program->Parameters->Parameters[index];
Brian Paul20fbb242010-01-27 17:03:04 -07001922 const GLuint slots = (param->Size + 3) / 4;
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001923 const GLint typeSize = sizeof_glsl_type(param->DataType);
Brian Paulffbc66b2008-07-21 13:58:50 -06001924 GLint nr, nc;
1925
1926 /* check that the number of rows, columns is correct */
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001927 get_matrix_dims(param->DataType, &nr, &nc);
Brian Paulffbc66b2008-07-21 13:58:50 -06001928 if (rows != nr || cols != nc) {
1929 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Pauleda291e2008-08-06 16:26:47 -06001930 "glUniformMatrix(matrix size mismatch)");
1931 return;
1932 }
1933
Brian Paul20fbb242010-01-27 17:03:04 -07001934 if ((GLint) param->Size <= typeSize) {
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001935 /* non-array: count must be at most one; count == 0 is handled by the loop below */
1936 if (count > 1) {
1937 _mesa_error(ctx, GL_INVALID_OPERATION,
1938 "glUniformMatrix(uniform is not an array)");
1939 return;
1940 }
Brian Paulffbc66b2008-07-21 13:58:50 -06001941 }
1942
Brian Paulade50832008-05-14 16:09:46 -06001943 /*
1944 * Note: the _columns_ of a matrix are stored in program registers, not
Brian Paulf45ed0e2008-07-18 12:51:39 -06001945 * the rows. So, the loops below look a little funny.
1946 * XXX could optimize this a bit...
Brian Paulade50832008-05-14 16:09:46 -06001947 */
Brian Paulf45ed0e2008-07-18 12:51:39 -06001948
1949 /* loop over matrices */
1950 for (mat = 0; mat < count; mat++) {
1951
1952 /* each matrix: */
Brian Paulade50832008-05-14 16:09:46 -06001953 for (col = 0; col < cols; col++) {
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001954 GLfloat *v;
1955 if (offset >= slots) {
1956 /* Ignore writes beyond the end of (the used part of) an array */
1957 return;
1958 }
1959 v = program->Parameters->ParameterValues[index + offset];
Brian Paulade50832008-05-14 16:09:46 -06001960 for (row = 0; row < rows; row++) {
Brian Paulf45ed0e2008-07-18 12:51:39 -06001961 if (transpose) {
1962 v[row] = values[src + row * cols + col];
1963 }
1964 else {
1965 v[row] = values[src + col * rows + row];
1966 }
Brian Paulade50832008-05-14 16:09:46 -06001967 }
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001968
1969 offset++;
Brian Paulade50832008-05-14 16:09:46 -06001970 }
Brian Paulf45ed0e2008-07-18 12:51:39 -06001971
1972 src += rows * cols; /* next matrix */
Brian5cf73262007-01-05 16:02:45 -07001973 }
Brian34ae99d2006-12-18 08:28:54 -07001974}
1975
1976
1977/**
Brian5b01c5e2006-12-19 18:02:03 -07001978 * Called by ctx->Driver.UniformMatrix().
Brian Paulf45ed0e2008-07-18 12:51:39 -06001979 * Note: cols=2, rows=4 ==> array[2] of vec4
Brian34ae99d2006-12-18 08:28:54 -07001980 */
Brian Paulfd59f192008-05-18 16:04:55 -06001981static void
Brian5b01c5e2006-12-19 18:02:03 -07001982_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
Brian Paul0115a4f2009-04-14 20:00:28 -06001983 GLint location, GLsizei count,
Brian5b01c5e2006-12-19 18:02:03 -07001984 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001985{
Brian3a8e2772006-12-20 17:19:16 -07001986 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paul2d76a0d2008-11-10 12:33:17 -07001987 struct gl_uniform *uniform;
1988 GLint offset;
Brian Paulade50832008-05-14 16:09:46 -06001989
Brian3a8e2772006-12-20 17:19:16 -07001990 if (!shProg || !shProg->LinkStatus) {
1991 _mesa_error(ctx, GL_INVALID_OPERATION,
1992 "glUniformMatrix(program not linked)");
1993 return;
1994 }
Brian Paulade50832008-05-14 16:09:46 -06001995
Bruce Merry89b80322007-12-21 15:20:17 +02001996 if (location == -1)
1997 return; /* The standard specifies this as a no-op */
Brian Paulade50832008-05-14 16:09:46 -06001998
Brian Paul234f03e2009-02-11 09:05:08 -07001999 if (location < -1) {
2000 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(location)");
2001 return;
2002 }
2003
Brian Pauleda291e2008-08-06 16:26:47 -06002004 split_location_offset(&location, &offset);
2005
Brian Paul016701f2008-07-29 17:43:35 -06002006 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian Paulade50832008-05-14 16:09:46 -06002007 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
Brian3a8e2772006-12-20 17:19:16 -07002008 return;
2009 }
Brian34ae99d2006-12-18 08:28:54 -07002010 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07002011 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07002012 return;
2013 }
2014
Brian Paul027ed1b2009-04-24 09:43:44 -06002015 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
Brian34ae99d2006-12-18 08:28:54 -07002016
Brian Paul2d76a0d2008-11-10 12:33:17 -07002017 uniform = &shProg->Uniforms->Uniforms[location];
2018
Brian Paulade50832008-05-14 16:09:46 -06002019 if (shProg->VertexProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06002020 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07002021 GLint index = uniform->VertPos;
Brian Pauleda291e2008-08-06 16:26:47 -06002022 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06002023 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06002024 index, offset,
2025 count, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07002026 }
Brian Paulade50832008-05-14 16:09:46 -06002027 }
2028
2029 if (shProg->FragmentProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06002030 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07002031 GLint index = uniform->FragPos;
Brian Pauleda291e2008-08-06 16:26:47 -06002032 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06002033 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06002034 index, offset,
2035 count, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07002036 }
Brian34ae99d2006-12-18 08:28:54 -07002037 }
Brian Paul949e7382008-11-05 09:17:55 -07002038
Brian Paul2d76a0d2008-11-10 12:33:17 -07002039 uniform->Initialized = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07002040}
2041
2042
Brian Paulc90fca32009-08-25 17:42:47 -06002043/**
2044 * Validate a program's samplers.
2045 * Specifically, check that there aren't two samplers of different types
2046 * pointing to the same texture unit.
2047 * \return GL_TRUE if valid, GL_FALSE if invalid
2048 */
2049static GLboolean
2050validate_samplers(GLcontext *ctx, const struct gl_program *prog, char *errMsg)
Brian34ae99d2006-12-18 08:28:54 -07002051{
Brian Paulc90fca32009-08-25 17:42:47 -06002052 static const char *targetName[] = {
2053 "TEXTURE_2D_ARRAY",
2054 "TEXTURE_1D_ARRAY",
2055 "TEXTURE_CUBE",
2056 "TEXTURE_3D",
2057 "TEXTURE_RECT",
2058 "TEXTURE_2D",
2059 "TEXTURE_1D",
2060 };
2061 GLint targetUsed[MAX_TEXTURE_IMAGE_UNITS];
2062 GLbitfield samplersUsed = prog->SamplersUsed;
2063 GLuint i;
Brian Paulbc985b52008-07-21 14:16:07 -06002064
Brian Paulc90fca32009-08-25 17:42:47 -06002065 assert(Elements(targetName) == NUM_TEXTURE_TARGETS);
2066
2067 if (samplersUsed == 0x0)
2068 return GL_TRUE;
2069
2070 for (i = 0; i < Elements(targetUsed); i++)
2071 targetUsed[i] = -1;
2072
2073 /* walk over bits which are set in 'samplers' */
2074 while (samplersUsed) {
2075 GLuint unit;
2076 gl_texture_index target;
2077 GLint sampler = _mesa_ffs(samplersUsed) - 1;
2078 assert(sampler >= 0);
2079 assert(sampler < MAX_TEXTURE_IMAGE_UNITS);
2080 unit = prog->SamplerUnits[sampler];
2081 target = prog->SamplerTargets[sampler];
2082 if (targetUsed[unit] != -1 && targetUsed[unit] != target) {
Brian Paul78a0c352010-02-19 12:56:49 -07002083 _mesa_snprintf(errMsg, 100,
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002084 "Texture unit %d is accessed both as %s and %s",
2085 unit, targetName[targetUsed[unit]], targetName[target]);
Brian Paulc90fca32009-08-25 17:42:47 -06002086 return GL_FALSE;
2087 }
2088 targetUsed[unit] = target;
2089 samplersUsed ^= (1 << sampler);
Brian34ae99d2006-12-18 08:28:54 -07002090 }
2091
Brian Paulc90fca32009-08-25 17:42:47 -06002092 return GL_TRUE;
2093}
2094
2095
2096/**
2097 * Do validation of the given shader program.
2098 * \param errMsg returns error message if validation fails.
2099 * \return GL_TRUE if valid, GL_FALSE if invalid (and set errMsg)
2100 */
2101GLboolean
2102_mesa_validate_shader_program(GLcontext *ctx,
2103 const struct gl_shader_program *shProg,
2104 char *errMsg)
2105{
2106 const struct gl_vertex_program *vp = shProg->VertexProgram;
2107 const struct gl_fragment_program *fp = shProg->FragmentProgram;
2108
Brian Paulbc985b52008-07-21 14:16:07 -06002109 if (!shProg->LinkStatus) {
Brian Paulc90fca32009-08-25 17:42:47 -06002110 return GL_FALSE;
Brian Paulbc985b52008-07-21 14:16:07 -06002111 }
2112
2113 /* From the GL spec, a program is invalid if any of these are true:
2114
Brian5b01c5e2006-12-19 18:02:03 -07002115 any two active samplers in the current program object are of
2116 different types, but refer to the same texture image unit,
2117
2118 any active sampler in the current program object refers to a texture
2119 image unit where fixed-function fragment processing accesses a
2120 texture target that does not match the sampler type, or
2121
2122 the sum of the number of active samplers in the program and the
2123 number of texture image units enabled for fixed-function fragment
2124 processing exceeds the combined limit on the total number of texture
2125 image units allowed.
2126 */
Brian Paulbc985b52008-07-21 14:16:07 -06002127
Brian Paulc90fca32009-08-25 17:42:47 -06002128
2129 /*
2130 * Check: any two active samplers in the current program object are of
2131 * different types, but refer to the same texture image unit,
2132 */
2133 if (vp && !validate_samplers(ctx, &vp->Base, errMsg)) {
2134 return GL_FALSE;
2135 }
2136 if (fp && !validate_samplers(ctx, &fp->Base, errMsg)) {
2137 return GL_FALSE;
2138 }
2139
2140 return GL_TRUE;
2141}
2142
2143
2144/**
2145 * Called via glValidateProgram()
2146 */
2147static void
2148_mesa_validate_program(GLcontext *ctx, GLuint program)
2149{
2150 struct gl_shader_program *shProg;
2151 char errMsg[100];
2152
2153 shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram");
2154 if (!shProg) {
2155 return;
2156 }
2157
2158 shProg->Validated = _mesa_validate_shader_program(ctx, shProg, errMsg);
2159 if (!shProg->Validated) {
2160 /* update info log */
2161 if (shProg->InfoLog) {
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -05002162 free(shProg->InfoLog);
Brian Paulc90fca32009-08-25 17:42:47 -06002163 }
2164 shProg->InfoLog = _mesa_strdup(errMsg);
2165 }
Brian34ae99d2006-12-18 08:28:54 -07002166}
Brian Paulfd59f192008-05-18 16:04:55 -06002167
2168
2169/**
2170 * Plug in Mesa's GLSL functions into the device driver function table.
2171 */
2172void
2173_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
2174{
2175 driver->AttachShader = _mesa_attach_shader;
2176 driver->BindAttribLocation = _mesa_bind_attrib_location;
2177 driver->CompileShader = _mesa_compile_shader;
2178 driver->CreateProgram = _mesa_create_program;
2179 driver->CreateShader = _mesa_create_shader;
2180 driver->DeleteProgram2 = _mesa_delete_program2;
2181 driver->DeleteShader = _mesa_delete_shader;
2182 driver->DetachShader = _mesa_detach_shader;
2183 driver->GetActiveAttrib = _mesa_get_active_attrib;
2184 driver->GetActiveUniform = _mesa_get_active_uniform;
2185 driver->GetAttachedShaders = _mesa_get_attached_shaders;
2186 driver->GetAttribLocation = _mesa_get_attrib_location;
2187 driver->GetHandle = _mesa_get_handle;
2188 driver->GetProgramiv = _mesa_get_programiv;
2189 driver->GetProgramInfoLog = _mesa_get_program_info_log;
2190 driver->GetShaderiv = _mesa_get_shaderiv;
2191 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
2192 driver->GetShaderSource = _mesa_get_shader_source;
2193 driver->GetUniformfv = _mesa_get_uniformfv;
Brian Paul2be54a82008-07-08 16:17:04 -06002194 driver->GetUniformiv = _mesa_get_uniformiv;
Brian Paulfd59f192008-05-18 16:04:55 -06002195 driver->GetUniformLocation = _mesa_get_uniform_location;
2196 driver->IsProgram = _mesa_is_program;
2197 driver->IsShader = _mesa_is_shader;
2198 driver->LinkProgram = _mesa_link_program;
2199 driver->ShaderSource = _mesa_shader_source;
2200 driver->Uniform = _mesa_uniform;
2201 driver->UniformMatrix = _mesa_uniform_matrix;
2202 driver->UseProgram = _mesa_use_program;
2203 driver->ValidateProgram = _mesa_validate_program;
2204}