blob: cebe899265b86db6ee1147d0cabf81ba5e05beea [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 }
Brian Paule5c69642010-03-30 19:54:02 -0600126
127 /* Transform feedback varying vars */
128 for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) {
129 free(shProg->TransformFeedback.VaryingNames[i]);
130 }
131 free(shProg->TransformFeedback.VaryingNames);
132 shProg->TransformFeedback.VaryingNames = NULL;
133 shProg->TransformFeedback.NumVarying = 0;
Brian3c008a02007-04-12 15:22:32 -0600134}
135
136
137/**
Brianb9fbedd2007-03-26 09:23:44 -0600138 * Free/delete a shader program object.
139 */
Brianf2923612006-12-20 09:56:44 -0700140void
141_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg)
142{
143 _mesa_free_shader_program_data(ctx, shProg);
Alan Hourihaneeec20c32008-04-22 20:29:42 +0100144
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -0500145 free(shProg);
Brianf2923612006-12-20 09:56:44 -0700146}
147
148
149/**
Brian3c008a02007-04-12 15:22:32 -0600150 * Set ptr to point to shProg.
151 * If ptr is pointing to another object, decrement its refcount (and delete
152 * if refcount hits zero).
153 * Then set ptr to point to shProg, incrementing its refcount.
154 */
155/* XXX this could be static */
156void
157_mesa_reference_shader_program(GLcontext *ctx,
158 struct gl_shader_program **ptr,
159 struct gl_shader_program *shProg)
160{
161 assert(ptr);
162 if (*ptr == shProg) {
163 /* no-op */
164 return;
165 }
166 if (*ptr) {
167 /* Unreference the old shader program */
168 GLboolean deleteFlag = GL_FALSE;
169 struct gl_shader_program *old = *ptr;
170
171 ASSERT(old->RefCount > 0);
172 old->RefCount--;
Brian Paul8bdf5b62008-05-16 09:56:59 -0600173#if 0
174 printf("ShaderProgram %p ID=%u RefCount-- to %d\n",
175 (void *) old, old->Name, old->RefCount);
176#endif
Brian3c008a02007-04-12 15:22:32 -0600177 deleteFlag = (old->RefCount == 0);
178
179 if (deleteFlag) {
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800180 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
Brian3c008a02007-04-12 15:22:32 -0600181 _mesa_free_shader_program(ctx, old);
182 }
183
184 *ptr = NULL;
185 }
186 assert(!*ptr);
187
188 if (shProg) {
189 shProg->RefCount++;
Brian Paul8bdf5b62008-05-16 09:56:59 -0600190#if 0
191 printf("ShaderProgram %p ID=%u RefCount++ to %d\n",
192 (void *) shProg, shProg->Name, shProg->RefCount);
193#endif
Brian3c008a02007-04-12 15:22:32 -0600194 *ptr = shProg;
195 }
196}
197
198
199/**
Brianf2923612006-12-20 09:56:44 -0700200 * Lookup a GLSL program object.
201 */
202struct gl_shader_program *
203_mesa_lookup_shader_program(GLcontext *ctx, GLuint name)
204{
205 struct gl_shader_program *shProg;
206 if (name) {
207 shProg = (struct gl_shader_program *)
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800208 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
Brianf2923612006-12-20 09:56:44 -0700209 /* Note that both gl_shader and gl_shader_program objects are kept
210 * in the same hash table. Check the object's type to be sure it's
211 * what we're expecting.
212 */
Brianf3e8c322007-04-18 14:53:23 -0600213 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700214 return NULL;
215 }
216 return shProg;
217 }
218 return NULL;
219}
220
221
222/**
Brian Paul530df582008-07-03 16:21:11 -0600223 * As above, but record an error if program is not found.
224 */
225static struct gl_shader_program *
226_mesa_lookup_shader_program_err(GLcontext *ctx, GLuint name,
227 const char *caller)
228{
229 if (!name) {
230 _mesa_error(ctx, GL_INVALID_VALUE, caller);
231 return NULL;
232 }
233 else {
234 struct gl_shader_program *shProg = (struct gl_shader_program *)
235 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
236 if (!shProg) {
237 _mesa_error(ctx, GL_INVALID_VALUE, caller);
238 return NULL;
239 }
240 if (shProg->Type != GL_SHADER_PROGRAM_MESA) {
241 _mesa_error(ctx, GL_INVALID_OPERATION, caller);
242 return NULL;
243 }
244 return shProg;
245 }
246}
247
248
249
250
251/**
Brianf2923612006-12-20 09:56:44 -0700252 * Allocate a new gl_shader object, initialize it.
253 */
254struct gl_shader *
255_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
256{
257 struct gl_shader *shader;
258 assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
259 shader = CALLOC_STRUCT(gl_shader);
260 if (shader) {
261 shader->Type = type;
262 shader->Name = name;
263 shader->RefCount = 1;
264 }
265 return shader;
266}
267
268
269void
270_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh)
271{
Brianf2923612006-12-20 09:56:44 -0700272 if (sh->Source)
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -0500273 free((void *) sh->Source);
Brianf2923612006-12-20 09:56:44 -0700274 if (sh->InfoLog)
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -0500275 free(sh->InfoLog);
Brian Paul3d500f02008-07-24 14:56:54 -0600276 _mesa_reference_program(ctx, &sh->Program, NULL);
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -0500277 free(sh);
Brianf2923612006-12-20 09:56:44 -0700278}
279
280
281/**
Brian3c008a02007-04-12 15:22:32 -0600282 * Set ptr to point to sh.
283 * If ptr is pointing to another shader, decrement its refcount (and delete
284 * if refcount hits zero).
285 * Then set ptr to point to sh, incrementing its refcount.
286 */
287/* XXX this could be static */
288void
289_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr,
290 struct gl_shader *sh)
291{
292 assert(ptr);
293 if (*ptr == sh) {
294 /* no-op */
295 return;
296 }
297 if (*ptr) {
298 /* Unreference the old shader */
299 GLboolean deleteFlag = GL_FALSE;
300 struct gl_shader *old = *ptr;
301
302 ASSERT(old->RefCount > 0);
303 old->RefCount--;
Brian99193e42007-04-12 15:45:02 -0600304 /*printf("SHADER DECR %p (%d) to %d\n",
305 (void*) old, old->Name, old->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600306 deleteFlag = (old->RefCount == 0);
307
308 if (deleteFlag) {
309 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
310 _mesa_free_shader(ctx, old);
311 }
312
313 *ptr = NULL;
314 }
315 assert(!*ptr);
316
317 if (sh) {
318 /* reference new */
319 sh->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600320 /*printf("SHADER INCR %p (%d) to %d\n",
321 (void*) sh, sh->Name, sh->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600322 *ptr = sh;
323 }
324}
325
326
327/**
Brianf2923612006-12-20 09:56:44 -0700328 * Lookup a GLSL shader object.
329 */
330struct gl_shader *
331_mesa_lookup_shader(GLcontext *ctx, GLuint name)
332{
333 if (name) {
334 struct gl_shader *sh = (struct gl_shader *)
335 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
336 /* Note that both gl_shader and gl_shader_program objects are kept
337 * in the same hash table. Check the object's type to be sure it's
338 * what we're expecting.
339 */
Brianf3e8c322007-04-18 14:53:23 -0600340 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700341 return NULL;
342 }
343 return sh;
344 }
345 return NULL;
346}
347
348
Brianfa4d0362007-02-26 18:33:50 -0700349/**
Brian Paul530df582008-07-03 16:21:11 -0600350 * As above, but record an error if shader is not found.
351 */
352static struct gl_shader *
353_mesa_lookup_shader_err(GLcontext *ctx, GLuint name, const char *caller)
354{
355 if (!name) {
356 _mesa_error(ctx, GL_INVALID_VALUE, caller);
357 return NULL;
358 }
359 else {
360 struct gl_shader *sh = (struct gl_shader *)
361 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
362 if (!sh) {
363 _mesa_error(ctx, GL_INVALID_VALUE, caller);
364 return NULL;
365 }
366 if (sh->Type == GL_SHADER_PROGRAM_MESA) {
367 _mesa_error(ctx, GL_INVALID_OPERATION, caller);
368 return NULL;
369 }
370 return sh;
371 }
372}
373
374
Brian Paule01a03d2009-02-06 10:21:36 -0700375/**
376 * Return mask of GLSL_x flags by examining the MESA_GLSL env var.
377 */
378static GLbitfield
379get_shader_flags(void)
380{
381 GLbitfield flags = 0x0;
382 const char *env = _mesa_getenv("MESA_GLSL");
383
384 if (env) {
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800385 if (strstr(env, "dump"))
Brian Paule01a03d2009-02-06 10:21:36 -0700386 flags |= GLSL_DUMP;
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800387 if (strstr(env, "log"))
Brian Paule01a03d2009-02-06 10:21:36 -0700388 flags |= GLSL_LOG;
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800389 if (strstr(env, "nopvert"))
Brian Paulcb0de062009-09-29 10:22:32 -0600390 flags |= GLSL_NOP_VERT;
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800391 if (strstr(env, "nopfrag"))
Brian Paulcb0de062009-09-29 10:22:32 -0600392 flags |= GLSL_NOP_FRAG;
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800393 if (strstr(env, "nopt"))
Brian Paule01a03d2009-02-06 10:21:36 -0700394 flags |= GLSL_NO_OPT;
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800395 else if (strstr(env, "opt"))
Brian Paule01a03d2009-02-06 10:21:36 -0700396 flags |= GLSL_OPT;
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800397 if (strstr(env, "uniform"))
Brian Paule01a03d2009-02-06 10:21:36 -0700398 flags |= GLSL_UNIFORMS;
Kenneth Graunke0aecdb62010-02-18 23:50:51 -0800399 if (strstr(env, "useprog"))
Brian Paul2ee7fd82009-10-15 15:25:52 -0600400 flags |= GLSL_USE_PROG;
Brian Paule01a03d2009-02-06 10:21:36 -0700401 }
402
403 return flags;
404}
405
Brian Paul530df582008-07-03 16:21:11 -0600406
407/**
Brian Paule5c69642010-03-30 19:54:02 -0600408 * Find the length of the longest transform feedback varying name
409 * which was specified with glTransformFeedbackVaryings().
410 */
411static GLint
412longest_feedback_varying_name(const struct gl_shader_program *shProg)
413{
414 GLuint i;
415 GLint max = 0;
416 for (i = 0; i < shProg->TransformFeedback.NumVarying; i++) {
417 GLint len = strlen(shProg->TransformFeedback.VaryingNames[i]);
418 if (len > max)
419 max = len;
420 }
421 return max;
422}
423
424
425
426/**
Brianfa4d0362007-02-26 18:33:50 -0700427 * Initialize context's shader state.
428 */
Brianf2923612006-12-20 09:56:44 -0700429void
430_mesa_init_shader_state(GLcontext * ctx)
431{
Brianfa4d0362007-02-26 18:33:50 -0700432 /* Device drivers may override these to control what kind of instructions
433 * are generated by the GLSL compiler.
434 */
435 ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
Brian Paul4031ea12009-06-17 11:57:39 -0600436 ctx->Shader.EmitContReturn = GL_TRUE;
Brian Paulc5c38352009-02-16 11:50:05 -0700437 ctx->Shader.EmitCondCodes = GL_FALSE;
Brianfa4d0362007-02-26 18:33:50 -0700438 ctx->Shader.EmitComments = GL_FALSE;
Brian Paule01a03d2009-02-06 10:21:36 -0700439 ctx->Shader.Flags = get_shader_flags();
Brian Paul65fc2ca2009-03-19 10:25:24 -0600440
441 /* Default pragma settings */
442 ctx->Shader.DefaultPragmas.IgnoreOptimize = GL_FALSE;
443 ctx->Shader.DefaultPragmas.IgnoreDebug = GL_FALSE;
444 ctx->Shader.DefaultPragmas.Optimize = GL_TRUE;
445 ctx->Shader.DefaultPragmas.Debug = GL_FALSE;
Brianf2923612006-12-20 09:56:44 -0700446}
447
448
Brian5b01c5e2006-12-19 18:02:03 -0700449/**
Brian935f93f2007-03-24 16:20:02 -0600450 * Free the per-context shader-related state.
451 */
452void
453_mesa_free_shader_state(GLcontext *ctx)
454{
Brian3c008a02007-04-12 15:22:32 -0600455 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
Brian935f93f2007-03-24 16:20:02 -0600456}
457
458
459/**
Brian5b01c5e2006-12-19 18:02:03 -0700460 * Copy string from <src> to <dst>, up to maxLength characters, returning
461 * length of <dst> in <length>.
462 * \param src the strings source
463 * \param maxLength max chars to copy
464 * \param length returns number of chars copied
465 * \param dst the string destination
466 */
Brian Paule5c69642010-03-30 19:54:02 -0600467void
468_mesa_copy_string(GLchar *dst, GLsizei maxLength,
469 GLsizei *length, const GLchar *src)
Brian5b01c5e2006-12-19 18:02:03 -0700470{
471 GLsizei len;
472 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
473 dst[len] = src[len];
474 if (maxLength > 0)
475 dst[len] = 0;
476 if (length)
477 *length = len;
478}
479
480
Brian Paul7acb7c12008-07-03 13:49:48 -0600481static GLboolean
482_mesa_is_program(GLcontext *ctx, GLuint name)
483{
484 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
485 return shProg ? GL_TRUE : GL_FALSE;
486}
487
488
489static GLboolean
490_mesa_is_shader(GLcontext *ctx, GLuint name)
491{
492 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
493 return shader ? GL_TRUE : GL_FALSE;
494}
495
496
Brian5b01c5e2006-12-19 18:02:03 -0700497/**
498 * Called via ctx->Driver.AttachShader()
499 */
Brian Paulfd59f192008-05-18 16:04:55 -0600500static void
Brian5b01c5e2006-12-19 18:02:03 -0700501_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
502{
Brian Paul530df582008-07-03 16:21:11 -0600503 struct gl_shader_program *shProg;
504 struct gl_shader *sh;
505 GLuint i, n;
Brian5b01c5e2006-12-19 18:02:03 -0700506
Brian Paul530df582008-07-03 16:21:11 -0600507 shProg = _mesa_lookup_shader_program_err(ctx, program, "glAttachShader");
508 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700509 return;
Brian5b01c5e2006-12-19 18:02:03 -0700510
Brian Paul530df582008-07-03 16:21:11 -0600511 sh = _mesa_lookup_shader_err(ctx, shader, "glAttachShader");
Brian Paul7acb7c12008-07-03 13:49:48 -0600512 if (!sh) {
Brian Paul7acb7c12008-07-03 13:49:48 -0600513 return;
514 }
515
Brian237b9852007-08-07 21:48:31 +0100516 n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700517 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700518 if (shProg->Shaders[i] == sh) {
Ian Romanickd806d452008-09-29 12:18:06 -0700519 /* The shader is already attched to this program. The
520 * GL_ARB_shader_objects spec says:
521 *
522 * "The error INVALID_OPERATION is generated by AttachObjectARB
523 * if <obj> is already attached to <containerObj>."
524 */
525 _mesa_error(ctx, GL_INVALID_OPERATION, "glAttachShader");
Brian5b01c5e2006-12-19 18:02:03 -0700526 return;
Brian34ae99d2006-12-18 08:28:54 -0700527 }
528 }
Brian5b01c5e2006-12-19 18:02:03 -0700529
530 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700531 shProg->Shaders = (struct gl_shader **)
532 _mesa_realloc(shProg->Shaders,
533 n * sizeof(struct gl_shader *),
534 (n + 1) * sizeof(struct gl_shader *));
535 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700536 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
537 return;
538 }
539
540 /* append */
Brian3c008a02007-04-12 15:22:32 -0600541 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
542 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700543 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700544}
545
546
Brian Paulfd59f192008-05-18 16:04:55 -0600547static GLint
Brian Paul896c0cc2008-05-16 15:47:55 -0600548_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
549 const GLchar *name)
550{
551 struct gl_shader_program *shProg
Brian Paul530df582008-07-03 16:21:11 -0600552 = _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
Brian Paul896c0cc2008-05-16 15:47:55 -0600553
554 if (!shProg) {
Brian Paul896c0cc2008-05-16 15:47:55 -0600555 return -1;
556 }
557
558 if (!shProg->LinkStatus) {
559 _mesa_error(ctx, GL_INVALID_OPERATION,
560 "glGetAttribLocation(program not linked)");
561 return -1;
562 }
563
564 if (!name)
565 return -1;
566
Brian Paul27341a92008-09-16 16:28:36 -0600567 if (shProg->VertexProgram) {
568 const struct gl_program_parameter_list *attribs =
569 shProg->VertexProgram->Base.Attributes;
570 if (attribs) {
571 GLint i = _mesa_lookup_parameter_index(attribs, -1, name);
572 if (i >= 0) {
573 return attribs->Parameters[i].StateIndexes[0];
574 }
Brian Paul896c0cc2008-05-16 15:47:55 -0600575 }
576 }
577 return -1;
578}
579
580
Brian Paulfd59f192008-05-18 16:04:55 -0600581static void
Brian5b01c5e2006-12-19 18:02:03 -0700582_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
583 const GLchar *name)
584{
Brian Paul530df582008-07-03 16:21:11 -0600585 struct gl_shader_program *shProg;
Brianb7978af2007-01-09 19:17:17 -0700586 const GLint size = -1; /* unknown size */
Brian Paul6bc87492008-07-25 08:34:54 -0600587 GLint i, oldIndex;
Brian Paul6f1abb92008-07-29 17:27:22 -0600588 GLenum datatype = GL_FLOAT_VEC4;
Brian5b01c5e2006-12-19 18:02:03 -0700589
Brian Paul530df582008-07-03 16:21:11 -0600590 shProg = _mesa_lookup_shader_program_err(ctx, program,
591 "glBindAttribLocation");
Brian65a18442006-12-19 18:46:56 -0700592 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700593 return;
594 }
595
Brian9e4bae92006-12-20 09:27:42 -0700596 if (!name)
597 return;
598
599 if (strncmp(name, "gl_", 3) == 0) {
600 _mesa_error(ctx, GL_INVALID_OPERATION,
601 "glBindAttribLocation(illegal name)");
602 return;
603 }
604
Brian Paul7acb7c12008-07-03 13:49:48 -0600605 if (index >= ctx->Const.VertexProgram.MaxAttribs) {
606 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
607 return;
608 }
609
Brian Paul6bc87492008-07-25 08:34:54 -0600610 if (shProg->LinkStatus) {
611 /* get current index/location for the attribute */
612 oldIndex = _mesa_get_attrib_location(ctx, program, name);
613 }
614 else {
615 oldIndex = -1;
616 }
617
Brian3209c3e2007-01-09 17:49:24 -0700618 /* this will replace the current value if it's already in the list */
Brian Paulffbc66b2008-07-21 13:58:50 -0600619 i = _mesa_add_attribute(shProg->Attributes, name, size, datatype, index);
Brian3209c3e2007-01-09 17:49:24 -0700620 if (i < 0) {
621 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
Brian Paul6f1abb92008-07-29 17:27:22 -0600622 return;
Brian3209c3e2007-01-09 17:49:24 -0700623 }
624
Brian Paul27341a92008-09-16 16:28:36 -0600625 /*
626 * Note that this attribute binding won't go into effect until
627 * glLinkProgram is called again.
628 */
Brian34ae99d2006-12-18 08:28:54 -0700629}
630
631
Brian Paulfd59f192008-05-18 16:04:55 -0600632static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700633_mesa_create_shader(GLcontext *ctx, GLenum type)
634{
Brian65a18442006-12-19 18:46:56 -0700635 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700636 GLuint name;
637
638 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
639
640 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700641 case GL_FRAGMENT_SHADER:
642 case GL_VERTEX_SHADER:
643 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700644 break;
645 default:
646 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
647 return 0;
648 }
649
Brian65a18442006-12-19 18:46:56 -0700650 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700651
652 return name;
653}
654
655
Brian Paulfd59f192008-05-18 16:04:55 -0600656static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700657_mesa_create_program(GLcontext *ctx)
658{
659 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700660 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700661
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800662 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
Brian65a18442006-12-19 18:46:56 -0700663 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700664
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800665 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700666
Brian3c008a02007-04-12 15:22:32 -0600667 assert(shProg->RefCount == 1);
668
Brian5b01c5e2006-12-19 18:02:03 -0700669 return name;
670}
671
672
Brian3c008a02007-04-12 15:22:32 -0600673/**
674 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
675 * DeleteProgramARB.
676 */
Brian Paulfd59f192008-05-18 16:04:55 -0600677static void
Brian5b01c5e2006-12-19 18:02:03 -0700678_mesa_delete_program2(GLcontext *ctx, GLuint name)
679{
Brian3c008a02007-04-12 15:22:32 -0600680 /*
681 * NOTE: deleting shaders/programs works a bit differently than
682 * texture objects (and buffer objects, etc). Shader/program
683 * handles/IDs exist in the hash table until the object is really
684 * deleted (refcount==0). With texture objects, the handle/ID is
685 * removed from the hash table in glDeleteTextures() while the tex
686 * object itself might linger until its refcount goes to zero.
687 */
Brian65a18442006-12-19 18:46:56 -0700688 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700689
Brian Paul530df582008-07-03 16:21:11 -0600690 shProg = _mesa_lookup_shader_program_err(ctx, name, "glDeleteProgram");
691 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700692 return;
Brian5b01c5e2006-12-19 18:02:03 -0700693
Brian9e4bae92006-12-20 09:27:42 -0700694 shProg->DeletePending = GL_TRUE;
695
Brian3c008a02007-04-12 15:22:32 -0600696 /* effectively, decr shProg's refcount */
697 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700698}
699
700
Brian Paulfd59f192008-05-18 16:04:55 -0600701static void
Brian5b01c5e2006-12-19 18:02:03 -0700702_mesa_delete_shader(GLcontext *ctx, GLuint shader)
703{
Brian Paul530df582008-07-03 16:21:11 -0600704 struct gl_shader *sh;
705
706 sh = _mesa_lookup_shader_err(ctx, shader, "glDeleteShader");
707 if (!sh)
Brian9e4bae92006-12-20 09:27:42 -0700708 return;
Brian5b01c5e2006-12-19 18:02:03 -0700709
Brian9e4bae92006-12-20 09:27:42 -0700710 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600711
712 /* effectively, decr sh's refcount */
713 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700714}
715
716
Brian Paulfd59f192008-05-18 16:04:55 -0600717static void
Brian5b01c5e2006-12-19 18:02:03 -0700718_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
719{
Brian Paul530df582008-07-03 16:21:11 -0600720 struct gl_shader_program *shProg;
Brian237b9852007-08-07 21:48:31 +0100721 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700722 GLuint i, j;
723
Brian Paul530df582008-07-03 16:21:11 -0600724 shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader");
725 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700726 return;
Brian5b01c5e2006-12-19 18:02:03 -0700727
Brian237b9852007-08-07 21:48:31 +0100728 n = shProg->NumShaders;
729
Brian5b01c5e2006-12-19 18:02:03 -0700730 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700731 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700732 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600733 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700734
Brian Paul530df582008-07-03 16:21:11 -0600735 /* release */
Brian3c008a02007-04-12 15:22:32 -0600736 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700737
Brian5b01c5e2006-12-19 18:02:03 -0700738 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700739 newList = (struct gl_shader **)
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -0500740 malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700741 if (!newList) {
742 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
743 return;
744 }
745 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700746 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700747 }
748 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700749 newList[j++] = shProg->Shaders[i];
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -0500750 free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700751
Brian65a18442006-12-19 18:46:56 -0700752 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600753 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600754
755#ifdef DEBUG
756 /* sanity check */
757 {
758 for (j = 0; j < shProg->NumShaders; j++) {
759 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
760 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
761 assert(shProg->Shaders[j]->RefCount > 0);
762 }
763 }
764#endif
765
Brian5b01c5e2006-12-19 18:02:03 -0700766 return;
767 }
768 }
769
770 /* not found */
Brian Paul530df582008-07-03 16:21:11 -0600771 {
772 GLenum err;
773 if (_mesa_is_shader(ctx, shader))
774 err = GL_INVALID_OPERATION;
775 else if (_mesa_is_program(ctx, shader))
776 err = GL_INVALID_OPERATION;
777 else
778 err = GL_INVALID_VALUE;
779 _mesa_error(ctx, err, "glDetachProgram(shader)");
780 return;
781 }
Brian5b01c5e2006-12-19 18:02:03 -0700782}
783
784
Brian Paul1a148662010-04-01 22:15:16 -0600785/**
786 * Return the size of the given GLSL datatype, in floats (components).
787 */
788GLint
789_mesa_sizeof_glsl_type(GLenum type)
Brian Paulffbc66b2008-07-21 13:58:50 -0600790{
791 switch (type) {
792 case GL_FLOAT:
793 case GL_INT:
794 case GL_BOOL:
Brian Paul8c51e002008-08-11 15:09:47 -0600795 case GL_SAMPLER_1D:
796 case GL_SAMPLER_2D:
797 case GL_SAMPLER_3D:
798 case GL_SAMPLER_CUBE:
799 case GL_SAMPLER_1D_SHADOW:
800 case GL_SAMPLER_2D_SHADOW:
801 case GL_SAMPLER_2D_RECT_ARB:
802 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
Brian Paulac498f22010-02-25 19:05:11 -0700803 case GL_SAMPLER_1D_ARRAY_EXT:
804 case GL_SAMPLER_2D_ARRAY_EXT:
Brian Paul8c51e002008-08-11 15:09:47 -0600805 case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
806 case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
807 case GL_SAMPLER_CUBE_SHADOW_EXT:
Brian Paulffbc66b2008-07-21 13:58:50 -0600808 return 1;
809 case GL_FLOAT_VEC2:
810 case GL_INT_VEC2:
Brian Paul91f841a2010-05-25 18:39:47 -0600811 case GL_UNSIGNED_INT_VEC2:
Brian Paulffbc66b2008-07-21 13:58:50 -0600812 case GL_BOOL_VEC2:
813 return 2;
814 case GL_FLOAT_VEC3:
815 case GL_INT_VEC3:
Brian Paul91f841a2010-05-25 18:39:47 -0600816 case GL_UNSIGNED_INT_VEC3:
Brian Paulffbc66b2008-07-21 13:58:50 -0600817 case GL_BOOL_VEC3:
818 return 3;
819 case GL_FLOAT_VEC4:
820 case GL_INT_VEC4:
Brian Paul91f841a2010-05-25 18:39:47 -0600821 case GL_UNSIGNED_INT_VEC4:
Brian Paulffbc66b2008-07-21 13:58:50 -0600822 case GL_BOOL_VEC4:
823 return 4;
824 case GL_FLOAT_MAT2:
825 case GL_FLOAT_MAT2x3:
826 case GL_FLOAT_MAT2x4:
827 return 8; /* two float[4] vectors */
828 case GL_FLOAT_MAT3:
829 case GL_FLOAT_MAT3x2:
830 case GL_FLOAT_MAT3x4:
831 return 12; /* three float[4] vectors */
832 case GL_FLOAT_MAT4:
833 case GL_FLOAT_MAT4x2:
834 case GL_FLOAT_MAT4x3:
835 return 16; /* four float[4] vectors */
836 default:
Brian Paul1a148662010-04-01 22:15:16 -0600837 _mesa_problem(NULL, "Invalid type in _mesa_sizeof_glsl_type()");
Brian Paulffbc66b2008-07-21 13:58:50 -0600838 return 1;
839 }
840}
841
842
Brian Paul09c7d7b2010-05-25 18:51:45 -0600843static GLenum
844base_uniform_type(GLenum type)
845{
846 switch (type) {
847#if 0 /* not needed, for now */
848 case GL_BOOL:
849 case GL_BOOL_VEC2:
850 case GL_BOOL_VEC3:
851 case GL_BOOL_VEC4:
852 return GL_BOOL;
853#endif
854 case GL_FLOAT:
855 case GL_FLOAT_VEC2:
856 case GL_FLOAT_VEC3:
857 case GL_FLOAT_VEC4:
858 return GL_FLOAT;
859 case GL_UNSIGNED_INT:
860 case GL_UNSIGNED_INT_VEC2:
861 case GL_UNSIGNED_INT_VEC3:
862 case GL_UNSIGNED_INT_VEC4:
863 return GL_UNSIGNED_INT;
864 case GL_INT:
865 case GL_INT_VEC2:
866 case GL_INT_VEC3:
867 case GL_INT_VEC4:
868 return GL_INT;
869 default:
870 _mesa_problem(NULL, "Invalid type in base_uniform_type()");
871 return GL_FLOAT;
872 }
873}
874
875
Brian Pauleda291e2008-08-06 16:26:47 -0600876static GLboolean
877is_boolean_type(GLenum type)
878{
879 switch (type) {
880 case GL_BOOL:
881 case GL_BOOL_VEC2:
882 case GL_BOOL_VEC3:
883 case GL_BOOL_VEC4:
884 return GL_TRUE;
885 default:
886 return GL_FALSE;
887 }
888}
889
890
891static GLboolean
Brian Paulc4ffbf02009-02-18 17:46:00 -0700892is_sampler_type(GLenum type)
893{
894 switch (type) {
895 case GL_SAMPLER_1D:
896 case GL_SAMPLER_2D:
897 case GL_SAMPLER_3D:
898 case GL_SAMPLER_CUBE:
899 case GL_SAMPLER_1D_SHADOW:
900 case GL_SAMPLER_2D_SHADOW:
901 case GL_SAMPLER_2D_RECT_ARB:
902 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
903 case GL_SAMPLER_1D_ARRAY_EXT:
904 case GL_SAMPLER_2D_ARRAY_EXT:
Brian Paulac498f22010-02-25 19:05:11 -0700905 case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
906 case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
Brian Paulc4ffbf02009-02-18 17:46:00 -0700907 return GL_TRUE;
908 default:
909 return GL_FALSE;
910 }
911}
912
913
Brian Paulfd59f192008-05-18 16:04:55 -0600914static void
Brian5b01c5e2006-12-19 18:02:03 -0700915_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
916 GLsizei maxLength, GLsizei *length, GLint *size,
917 GLenum *type, GLchar *nameOut)
918{
Brian Paul27341a92008-09-16 16:28:36 -0600919 const struct gl_program_parameter_list *attribs = NULL;
Brian Paul530df582008-07-03 16:21:11 -0600920 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700921
Brian Paul530df582008-07-03 16:21:11 -0600922 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
923 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700924 return;
Brian5b01c5e2006-12-19 18:02:03 -0700925
Brian Paul27341a92008-09-16 16:28:36 -0600926 if (shProg->VertexProgram)
927 attribs = shProg->VertexProgram->Base.Attributes;
928
929 if (!attribs || index >= attribs->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600930 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700931 return;
932 }
933
Brian Paule5c69642010-03-30 19:54:02 -0600934 _mesa_copy_string(nameOut, maxLength, length,
935 attribs->Parameters[index].Name);
Brian Paul27341a92008-09-16 16:28:36 -0600936
Brian5b01c5e2006-12-19 18:02:03 -0700937 if (size)
Brian Paul27341a92008-09-16 16:28:36 -0600938 *size = attribs->Parameters[index].Size
Brian Paul1a148662010-04-01 22:15:16 -0600939 / _mesa_sizeof_glsl_type(attribs->Parameters[index].DataType);
Brian Paul27341a92008-09-16 16:28:36 -0600940
Brian Paulade50832008-05-14 16:09:46 -0600941 if (type)
Brian Paul27341a92008-09-16 16:28:36 -0600942 *type = attribs->Parameters[index].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700943}
944
945
Brian Pauleda291e2008-08-06 16:26:47 -0600946static struct gl_program_parameter *
947get_uniform_parameter(const struct gl_shader_program *shProg, GLuint index)
948{
Brian Paula531a5c2009-08-13 13:44:01 -0600949 const struct gl_program *prog = NULL;
Brian Pauleda291e2008-08-06 16:26:47 -0600950 GLint progPos;
951
952 progPos = shProg->Uniforms->Uniforms[index].VertPos;
953 if (progPos >= 0) {
954 prog = &shProg->VertexProgram->Base;
955 }
956 else {
957 progPos = shProg->Uniforms->Uniforms[index].FragPos;
958 if (progPos >= 0) {
959 prog = &shProg->FragmentProgram->Base;
960 }
961 }
962
963 if (!prog || progPos < 0)
964 return NULL; /* should never happen */
965
966 return &prog->Parameters->Parameters[progPos];
967}
968
969
Brian5b01c5e2006-12-19 18:02:03 -0700970/**
971 * Called via ctx->Driver.GetActiveUniform().
972 */
Brian Paulfd59f192008-05-18 16:04:55 -0600973static void
Brian5b01c5e2006-12-19 18:02:03 -0700974_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
975 GLsizei maxLength, GLsizei *length, GLint *size,
976 GLenum *type, GLchar *nameOut)
977{
Brian Paul530df582008-07-03 16:21:11 -0600978 const struct gl_shader_program *shProg;
Brian Paula531a5c2009-08-13 13:44:01 -0600979 const struct gl_program *prog = NULL;
Brian Paul369d1852009-02-11 08:16:14 -0700980 const struct gl_program_parameter *param;
Brian Paulade50832008-05-14 16:09:46 -0600981 GLint progPos;
Brian5b01c5e2006-12-19 18:02:03 -0700982
Brian Paul530df582008-07-03 16:21:11 -0600983 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
984 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700985 return;
Brian5b01c5e2006-12-19 18:02:03 -0700986
Brian Paulade50832008-05-14 16:09:46 -0600987 if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
Brian5b01c5e2006-12-19 18:02:03 -0700988 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
989 return;
990 }
991
Brian Paulade50832008-05-14 16:09:46 -0600992 progPos = shProg->Uniforms->Uniforms[index].VertPos;
993 if (progPos >= 0) {
994 prog = &shProg->VertexProgram->Base;
995 }
996 else {
997 progPos = shProg->Uniforms->Uniforms[index].FragPos;
998 if (progPos >= 0) {
999 prog = &shProg->FragmentProgram->Base;
Brian274ac7a2007-04-18 16:05:53 -06001000 }
1001 }
1002
Brian Paulade50832008-05-14 16:09:46 -06001003 if (!prog || progPos < 0)
1004 return; /* should never happen */
1005
Brian Paul369d1852009-02-11 08:16:14 -07001006 ASSERT(progPos < prog->Parameters->NumParameters);
1007 param = &prog->Parameters->Parameters[progPos];
1008
1009 if (nameOut) {
Brian Paule5c69642010-03-30 19:54:02 -06001010 _mesa_copy_string(nameOut, maxLength, length, param->Name);
Brian Paul369d1852009-02-11 08:16:14 -07001011 }
1012
1013 if (size) {
Brian Paul1a148662010-04-01 22:15:16 -06001014 GLint typeSize = _mesa_sizeof_glsl_type(param->DataType);
Brian Paul20fbb242010-01-27 17:03:04 -07001015 if ((GLint) param->Size > typeSize) {
Brian Paul369d1852009-02-11 08:16:14 -07001016 /* This is an array.
1017 * Array elements are placed on vector[4] boundaries so they're
1018 * a multiple of four floats. We round typeSize up to next multiple
1019 * of four to get the right size below.
1020 */
1021 typeSize = (typeSize + 3) & ~3;
1022 }
1023 /* Note that the returned size is in units of the <type>, not bytes */
1024 *size = param->Size / typeSize;
1025 }
1026
1027 if (type) {
1028 *type = param->DataType;
1029 }
Brian5b01c5e2006-12-19 18:02:03 -07001030}
1031
1032
1033/**
1034 * Called via ctx->Driver.GetAttachedShaders().
1035 */
Brian Paulfd59f192008-05-18 16:04:55 -06001036static void
Brian5b01c5e2006-12-19 18:02:03 -07001037_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
1038 GLsizei *count, GLuint *obj)
1039{
Brian Paul530df582008-07-03 16:21:11 -06001040 struct gl_shader_program *shProg =
1041 _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders");
Brian65a18442006-12-19 18:46:56 -07001042 if (shProg) {
Brian Paul530df582008-07-03 16:21:11 -06001043 GLuint i;
1044 for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) {
Brian65a18442006-12-19 18:46:56 -07001045 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -07001046 }
1047 if (count)
1048 *count = i;
1049 }
Brian5b01c5e2006-12-19 18:02:03 -07001050}
1051
1052
Brian Paulfd59f192008-05-18 16:04:55 -06001053static GLuint
Brian5b01c5e2006-12-19 18:02:03 -07001054_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -07001055{
Ian Romanick905d8e02008-09-29 12:27:00 -07001056 GLint handle = 0;
1057
1058 if (pname == GL_PROGRAM_OBJECT_ARB) {
1059 CALL_GetIntegerv(ctx->Exec, (GL_CURRENT_PROGRAM, &handle));
1060 } else {
Brian34ae99d2006-12-18 08:28:54 -07001061 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
1062 }
Ian Romanick905d8e02008-09-29 12:27:00 -07001063
1064 return handle;
Brian34ae99d2006-12-18 08:28:54 -07001065}
1066
1067
Brian Paulfd59f192008-05-18 16:04:55 -06001068static void
Brian5b01c5e2006-12-19 18:02:03 -07001069_mesa_get_programiv(GLcontext *ctx, GLuint program,
1070 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -07001071{
Brian Paul27341a92008-09-16 16:28:36 -06001072 const struct gl_program_parameter_list *attribs;
Brian65a18442006-12-19 18:46:56 -07001073 struct gl_shader_program *shProg
1074 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -07001075
Brian65a18442006-12-19 18:46:56 -07001076 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -07001077 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -07001078 return;
1079 }
1080
Brian Paul27341a92008-09-16 16:28:36 -06001081 if (shProg->VertexProgram)
1082 attribs = shProg->VertexProgram->Base.Attributes;
1083 else
1084 attribs = NULL;
1085
Brian5b01c5e2006-12-19 18:02:03 -07001086 switch (pname) {
1087 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -07001088 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -07001089 break;
1090 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -07001091 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -07001092 break;
Brian5b01c5e2006-12-19 18:02:03 -07001093 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -07001094 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -07001095 break;
1096 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001097 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001098 break;
1099 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -07001100 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -07001101 break;
1102 case GL_ACTIVE_ATTRIBUTES:
Brian Paul27341a92008-09-16 16:28:36 -06001103 *params = attribs ? attribs->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001104 break;
1105 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian Paul27341a92008-09-16 16:28:36 -06001106 *params = _mesa_longest_parameter_name(attribs, PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -07001107 break;
1108 case GL_ACTIVE_UNIFORMS:
Brian Paulade50832008-05-14 16:09:46 -06001109 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001110 break;
1111 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian Paulade50832008-05-14 16:09:46 -06001112 *params = _mesa_longest_uniform_name(shProg->Uniforms);
Brian274ac7a2007-04-18 16:05:53 -06001113 if (*params > 0)
1114 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -07001115 break;
Brian Paulbda6ad22008-08-06 12:45:14 -06001116 case GL_PROGRAM_BINARY_LENGTH_OES:
1117 *params = 0;
1118 break;
Brian Paule5c69642010-03-30 19:54:02 -06001119#if FEATURE_EXT_transform_feedback
1120 case GL_TRANSFORM_FEEDBACK_VARYINGS:
1121 *params = shProg->TransformFeedback.NumVarying;
1122 break;
1123 case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
1124 *params = longest_feedback_varying_name(shProg) + 1;
1125 break;
1126 case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
1127 *params = shProg->TransformFeedback.BufferMode;
1128 break;
1129#endif
Brian34ae99d2006-12-18 08:28:54 -07001130 default:
Brian5b01c5e2006-12-19 18:02:03 -07001131 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
1132 return;
Brian34ae99d2006-12-18 08:28:54 -07001133 }
Brian5b01c5e2006-12-19 18:02:03 -07001134}
Brian34ae99d2006-12-18 08:28:54 -07001135
Brian34ae99d2006-12-18 08:28:54 -07001136
Brian Paulfd59f192008-05-18 16:04:55 -06001137static void
Brian5b01c5e2006-12-19 18:02:03 -07001138_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
1139{
Brian Paul530df582008-07-03 16:21:11 -06001140 struct gl_shader *shader = _mesa_lookup_shader_err(ctx, name, "glGetShaderiv");
Brian5b01c5e2006-12-19 18:02:03 -07001141
1142 if (!shader) {
Brian5b01c5e2006-12-19 18:02:03 -07001143 return;
1144 }
Brian65a18442006-12-19 18:46:56 -07001145
Brian5b01c5e2006-12-19 18:02:03 -07001146 switch (pname) {
1147 case GL_SHADER_TYPE:
1148 *params = shader->Type;
1149 break;
1150 case GL_DELETE_STATUS:
1151 *params = shader->DeletePending;
1152 break;
1153 case GL_COMPILE_STATUS:
1154 *params = shader->CompileStatus;
1155 break;
1156 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001157 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001158 break;
1159 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001160 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001161 break;
1162 default:
1163 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
1164 return;
1165 }
1166}
1167
1168
Brian Paulfd59f192008-05-18 16:04:55 -06001169static void
Brian5b01c5e2006-12-19 18:02:03 -07001170_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
1171 GLsizei *length, GLchar *infoLog)
1172{
Brian65a18442006-12-19 18:46:56 -07001173 struct gl_shader_program *shProg
1174 = _mesa_lookup_shader_program(ctx, program);
1175 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -07001176 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
1177 return;
1178 }
Brian Paule5c69642010-03-30 19:54:02 -06001179 _mesa_copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -07001180}
1181
1182
Brian Paulfd59f192008-05-18 16:04:55 -06001183static void
Brian5b01c5e2006-12-19 18:02:03 -07001184_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
1185 GLsizei *length, GLchar *infoLog)
1186{
Brian65a18442006-12-19 18:46:56 -07001187 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
1188 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001189 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
1190 return;
1191 }
Brian Paule5c69642010-03-30 19:54:02 -06001192 _mesa_copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -07001193}
1194
1195
1196/**
1197 * Called via ctx->Driver.GetShaderSource().
1198 */
Brian Paulfd59f192008-05-18 16:04:55 -06001199static void
Brian5b01c5e2006-12-19 18:02:03 -07001200_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
1201 GLsizei *length, GLchar *sourceOut)
1202{
Brian Paul530df582008-07-03 16:21:11 -06001203 struct gl_shader *sh;
1204 sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource");
Brian65a18442006-12-19 18:46:56 -07001205 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001206 return;
1207 }
Brian Paule5c69642010-03-30 19:54:02 -06001208 _mesa_copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -07001209}
1210
1211
Brian Paul5b982362008-08-06 13:07:09 -06001212static void
1213get_matrix_dims(GLenum type, GLint *rows, GLint *cols)
1214{
1215 switch (type) {
1216 case GL_FLOAT_MAT2:
1217 *rows = *cols = 2;
1218 break;
1219 case GL_FLOAT_MAT2x3:
1220 *rows = 3;
1221 *cols = 2;
1222 break;
1223 case GL_FLOAT_MAT2x4:
1224 *rows = 4;
1225 *cols = 2;
1226 break;
1227 case GL_FLOAT_MAT3:
1228 *rows = 3;
1229 *cols = 3;
1230 break;
1231 case GL_FLOAT_MAT3x2:
1232 *rows = 2;
1233 *cols = 3;
1234 break;
1235 case GL_FLOAT_MAT3x4:
1236 *rows = 4;
1237 *cols = 3;
1238 break;
1239 case GL_FLOAT_MAT4:
1240 *rows = 4;
1241 *cols = 4;
1242 break;
1243 case GL_FLOAT_MAT4x2:
1244 *rows = 2;
1245 *cols = 4;
1246 break;
1247 case GL_FLOAT_MAT4x3:
1248 *rows = 3;
1249 *cols = 4;
1250 break;
1251 default:
1252 *rows = *cols = 0;
1253 }
1254}
1255
1256
1257/**
1258 * Determine the number of rows and columns occupied by a uniform
Brian Paulea9568d2008-09-16 08:55:54 -06001259 * according to its datatype. For non-matrix types (such as GL_FLOAT_VEC4),
1260 * the number of rows = 1 and cols = number of elements in the vector.
Brian Paul5b982362008-08-06 13:07:09 -06001261 */
1262static void
1263get_uniform_rows_cols(const struct gl_program_parameter *p,
1264 GLint *rows, GLint *cols)
1265{
1266 get_matrix_dims(p->DataType, rows, cols);
1267 if (*rows == 0 && *cols == 0) {
1268 /* not a matrix type, probably a float or vector */
Brian Paulea9568d2008-09-16 08:55:54 -06001269 if (p->Size <= 4) {
1270 *rows = 1;
1271 *cols = p->Size;
1272 }
1273 else {
1274 *rows = p->Size / 4 + 1;
1275 if (p->Size % 4 == 0)
1276 *cols = 4;
1277 else
1278 *cols = p->Size % 4;
1279 }
Brian Paul5b982362008-08-06 13:07:09 -06001280 }
1281}
1282
1283
Brian5b01c5e2006-12-19 18:02:03 -07001284/**
Brian Paul4ef7a932009-02-11 09:03:16 -07001285 * Helper for get_uniform[fi]v() functions.
1286 * Given a shader program name and uniform location, return a pointer
1287 * to the shader program and return the program parameter position.
Brian5b01c5e2006-12-19 18:02:03 -07001288 */
Brian Paul4ef7a932009-02-11 09:03:16 -07001289static void
1290lookup_uniform_parameter(GLcontext *ctx, GLuint program, GLint location,
1291 struct gl_program **progOut, GLint *paramPosOut)
Brian5b01c5e2006-12-19 18:02:03 -07001292{
Brian65a18442006-12-19 18:46:56 -07001293 struct gl_shader_program *shProg
Brian Paulbda6ad22008-08-06 12:45:14 -06001294 = _mesa_lookup_shader_program_err(ctx, program, "glGetUniform[if]v");
Brian Paul4ef7a932009-02-11 09:03:16 -07001295 struct gl_program *prog = NULL;
1296 GLint progPos = -1;
Brian Paulade50832008-05-14 16:09:46 -06001297
Brian Paul4ef7a932009-02-11 09:03:16 -07001298 /* if shProg is NULL, we'll have already recorded an error */
1299
1300 if (shProg) {
1301 if (!shProg->Uniforms ||
1302 location < 0 ||
1303 location >= (GLint) shProg->Uniforms->NumUniforms) {
1304 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
1305 }
1306 else {
1307 /* OK, find the gl_program and program parameter location */
Brian Paulade50832008-05-14 16:09:46 -06001308 progPos = shProg->Uniforms->Uniforms[location].VertPos;
1309 if (progPos >= 0) {
1310 prog = &shProg->VertexProgram->Base;
Brian5b01c5e2006-12-19 18:02:03 -07001311 }
Brian Paulade50832008-05-14 16:09:46 -06001312 else {
1313 progPos = shProg->Uniforms->Uniforms[location].FragPos;
1314 if (progPos >= 0) {
1315 prog = &shProg->FragmentProgram->Base;
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001316 }
Brian Paulade50832008-05-14 16:09:46 -06001317 }
Brian5b01c5e2006-12-19 18:02:03 -07001318 }
1319 }
Brian Paul4ef7a932009-02-11 09:03:16 -07001320
1321 *progOut = prog;
1322 *paramPosOut = progPos;
Brian Paul2be54a82008-07-08 16:17:04 -06001323}
1324
1325
1326/**
1327 * Called via ctx->Driver.GetUniformfv().
1328 */
1329static void
1330_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1331 GLfloat *params)
1332{
Brian Paul4ef7a932009-02-11 09:03:16 -07001333 struct gl_program *prog;
1334 GLint paramPos;
1335
1336 lookup_uniform_parameter(ctx, program, location, &prog, &paramPos);
1337
1338 if (prog) {
1339 const struct gl_program_parameter *p =
1340 &prog->Parameters->Parameters[paramPos];
1341 GLint rows, cols, i, j, k;
1342
1343 get_uniform_rows_cols(p, &rows, &cols);
1344
1345 k = 0;
1346 for (i = 0; i < rows; i++) {
1347 for (j = 0; j < cols; j++ ) {
1348 params[k++] = prog->Parameters->ParameterValues[paramPos+i][j];
1349 }
1350 }
1351 }
Brian Paul2be54a82008-07-08 16:17:04 -06001352}
1353
1354
1355/**
1356 * Called via ctx->Driver.GetUniformiv().
Brian Paul4ef7a932009-02-11 09:03:16 -07001357 * \sa _mesa_get_uniformfv, only difference is a cast.
Brian Paul2be54a82008-07-08 16:17:04 -06001358 */
1359static void
1360_mesa_get_uniformiv(GLcontext *ctx, GLuint program, GLint location,
1361 GLint *params)
1362{
Brian Paul4ef7a932009-02-11 09:03:16 -07001363 struct gl_program *prog;
1364 GLint paramPos;
1365
1366 lookup_uniform_parameter(ctx, program, location, &prog, &paramPos);
1367
1368 if (prog) {
1369 const struct gl_program_parameter *p =
1370 &prog->Parameters->Parameters[paramPos];
1371 GLint rows, cols, i, j, k;
1372
1373 get_uniform_rows_cols(p, &rows, &cols);
1374
1375 k = 0;
1376 for (i = 0; i < rows; i++) {
1377 for (j = 0; j < cols; j++ ) {
1378 params[k++] = (GLint) prog->Parameters->ParameterValues[paramPos+i][j];
1379 }
1380 }
Brian Paul2be54a82008-07-08 16:17:04 -06001381 }
Brian5b01c5e2006-12-19 18:02:03 -07001382}
1383
1384
1385/**
Brian Pauleda291e2008-08-06 16:26:47 -06001386 * The value returned by GetUniformLocation actually encodes two things:
1387 * 1. the index into the prog->Uniforms[] array for the uniform
1388 * 2. an offset in the prog->ParameterValues[] array for specifying array
1389 * elements or structure fields.
1390 * This function merges those two values.
1391 */
1392static void
1393merge_location_offset(GLint *location, GLint offset)
1394{
1395 *location = *location | (offset << 16);
1396}
1397
1398
1399/**
1400 * Seperate the uniform location and parameter offset. See above.
1401 */
1402static void
1403split_location_offset(GLint *location, GLint *offset)
1404{
1405 *offset = (*location >> 16);
1406 *location = *location & 0xffff;
1407}
1408
1409
1410/**
Brian5b01c5e2006-12-19 18:02:03 -07001411 * Called via ctx->Driver.GetUniformLocation().
Brian Pauleda291e2008-08-06 16:26:47 -06001412 *
1413 * The return value will encode two values, the uniform location and an
1414 * offset (used for arrays, structs).
Brian5b01c5e2006-12-19 18:02:03 -07001415 */
Brian Paulfd59f192008-05-18 16:04:55 -06001416static GLint
Brian5b01c5e2006-12-19 18:02:03 -07001417_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
1418{
Brian Pauleda291e2008-08-06 16:26:47 -06001419 GLint offset = 0, location = -1;
1420
Brian Paul530df582008-07-03 16:21:11 -06001421 struct gl_shader_program *shProg =
1422 _mesa_lookup_shader_program_err(ctx, program, "glGetUniformLocation");
1423
Brian Paulade50832008-05-14 16:09:46 -06001424 if (!shProg)
1425 return -1;
Brian5b01c5e2006-12-19 18:02:03 -07001426
Brian Paule06565b2008-07-04 09:58:55 -06001427 if (shProg->LinkStatus == GL_FALSE) {
1428 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
1429 return -1;
1430 }
1431
Brian Paul530df582008-07-03 16:21:11 -06001432 /* XXX we should return -1 if the uniform was declared, but not
1433 * actually used.
1434 */
1435
Brian Pauleda291e2008-08-06 16:26:47 -06001436 /* XXX we need to be able to parse uniform names for structs and arrays
1437 * such as:
1438 * mymatrix[1]
1439 * mystruct.field1
1440 */
1441
1442 {
1443 /* handle 1-dimension arrays here... */
1444 char *c = strchr(name, '[');
1445 if (c) {
1446 /* truncate name at [ */
1447 const GLint len = c - name;
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -05001448 GLchar *newName = malloc(len + 1);
Brian Pauleda291e2008-08-06 16:26:47 -06001449 if (!newName)
1450 return -1; /* out of mem */
Kenneth Graunkec7ac48622010-02-18 23:50:59 -08001451 memcpy(newName, name, len);
Brian Pauleda291e2008-08-06 16:26:47 -06001452 newName[len] = 0;
1453
1454 location = _mesa_lookup_uniform(shProg->Uniforms, newName);
1455 if (location >= 0) {
Kenneth Graunke60b0cae2010-02-18 23:50:58 -08001456 const GLint element = atoi(c + 1);
Brian Pauleda291e2008-08-06 16:26:47 -06001457 if (element > 0) {
1458 /* get type of the uniform array element */
1459 struct gl_program_parameter *p;
1460 p = get_uniform_parameter(shProg, location);
1461 if (p) {
1462 GLint rows, cols;
1463 get_matrix_dims(p->DataType, &rows, &cols);
1464 if (rows < 1)
1465 rows = 1;
1466 offset = element * rows;
1467 }
1468 }
1469 }
1470
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -05001471 free(newName);
Brian Pauleda291e2008-08-06 16:26:47 -06001472 }
1473 }
1474
1475 if (location < 0) {
1476 location = _mesa_lookup_uniform(shProg->Uniforms, name);
1477 }
1478
1479 if (location >= 0) {
1480 merge_location_offset(&location, offset);
1481 }
1482
1483 return location;
Brian5b01c5e2006-12-19 18:02:03 -07001484}
1485
1486
Brian34ae99d2006-12-18 08:28:54 -07001487
Brian5b01c5e2006-12-19 18:02:03 -07001488/**
1489 * Called via ctx->Driver.ShaderSource()
1490 */
Brian Paulfd59f192008-05-18 16:04:55 -06001491static void
Brian5b01c5e2006-12-19 18:02:03 -07001492_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -07001493{
Brian Paul530df582008-07-03 16:21:11 -06001494 struct gl_shader *sh;
1495
1496 sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource");
1497 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001498 return;
Brian34ae99d2006-12-18 08:28:54 -07001499
Brian34ae99d2006-12-18 08:28:54 -07001500 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -07001501 if (sh->Source) {
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -05001502 free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -07001503 }
Brian65a18442006-12-19 18:46:56 -07001504 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -07001505 sh->CompileStatus = GL_FALSE;
Brian Paulf7783ba2009-08-04 15:35:48 -06001506#ifdef DEBUG
1507 sh->SourceChecksum = _mesa_str_checksum(sh->Source);
1508#endif
Brian34ae99d2006-12-18 08:28:54 -07001509}
1510
1511
Brian5b01c5e2006-12-19 18:02:03 -07001512/**
1513 * Called via ctx->Driver.CompileShader()
1514 */
Brian Paulfd59f192008-05-18 16:04:55 -06001515static void
Brian5b01c5e2006-12-19 18:02:03 -07001516_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -07001517{
Brian Paul530df582008-07-03 16:21:11 -06001518 struct gl_shader *sh;
Brian34ae99d2006-12-18 08:28:54 -07001519
Brian Paul530df582008-07-03 16:21:11 -06001520 sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader");
1521 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001522 return;
Brian34ae99d2006-12-18 08:28:54 -07001523
Brian Paul65fc2ca2009-03-19 10:25:24 -06001524 /* set default pragma state for shader */
1525 sh->Pragmas = ctx->Shader.DefaultPragmas;
1526
Brian Paulcb136e02009-01-22 10:34:15 -07001527 /* this call will set the sh->CompileStatus field to indicate if
1528 * compilation was successful.
1529 */
1530 (void) _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -07001531}
1532
1533
Brian5b01c5e2006-12-19 18:02:03 -07001534/**
1535 * Called via ctx->Driver.LinkProgram()
1536 */
Brian Paulfd59f192008-05-18 16:04:55 -06001537static void
Brian5b01c5e2006-12-19 18:02:03 -07001538_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001539{
Brian65a18442006-12-19 18:46:56 -07001540 struct gl_shader_program *shProg;
Brian Paulfef6e362010-05-10 21:11:21 -06001541 struct gl_transform_feedback_object *obj =
1542 ctx->TransformFeedback.CurrentObject;
Brian34ae99d2006-12-18 08:28:54 -07001543
Brian Paul530df582008-07-03 16:21:11 -06001544 shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
1545 if (!shProg)
Brian34ae99d2006-12-18 08:28:54 -07001546 return;
Brian34ae99d2006-12-18 08:28:54 -07001547
Brian Paulfef6e362010-05-10 21:11:21 -06001548 if (obj->Active && shProg == ctx->Shader.CurrentProgram) {
Brian Paul1a148662010-04-01 22:15:16 -06001549 _mesa_error(ctx, GL_INVALID_OPERATION,
1550 "glLinkProgram(transform feedback active");
1551 return;
1552 }
1553
Briandf43fb62008-05-06 23:08:51 -06001554 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1555
Brianc1771912007-02-16 09:56:19 -07001556 _slang_link(ctx, program, shProg);
Brian Paulac3c8e32009-09-14 17:32:03 -06001557
1558 /* debug code */
1559 if (0) {
1560 GLuint i;
1561
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001562 printf("Link %u shaders in program %u: %s\n",
Brian Paulac3c8e32009-09-14 17:32:03 -06001563 shProg->NumShaders, shProg->Name,
1564 shProg->LinkStatus ? "Success" : "Failed");
1565
1566 for (i = 0; i < shProg->NumShaders; i++) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001567 printf(" shader %u, type 0x%x\n",
Brian Paulac3c8e32009-09-14 17:32:03 -06001568 shProg->Shaders[i]->Name,
1569 shProg->Shaders[i]->Type);
1570 }
1571 }
Brian34ae99d2006-12-18 08:28:54 -07001572}
1573
1574
1575/**
Brian Paul346250b2009-10-23 16:31:48 -06001576 * Print basic shader info (for debug).
1577 */
1578static void
1579print_shader_info(const struct gl_shader_program *shProg)
1580{
1581 GLuint i;
1582
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001583 printf("Mesa: glUseProgram(%u)\n", shProg->Name);
Brian Paul346250b2009-10-23 16:31:48 -06001584 for (i = 0; i < shProg->NumShaders; i++) {
1585 const char *s;
1586 switch (shProg->Shaders[i]->Type) {
1587 case GL_VERTEX_SHADER:
1588 s = "vertex";
1589 break;
1590 case GL_FRAGMENT_SHADER:
1591 s = "fragment";
1592 break;
1593 case GL_GEOMETRY_SHADER:
1594 s = "geometry";
1595 break;
1596 default:
1597 s = "";
1598 }
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001599 printf(" %s shader %u, checksum %u\n", s,
1600 shProg->Shaders[i]->Name,
1601 shProg->Shaders[i]->SourceChecksum);
Brian Paul346250b2009-10-23 16:31:48 -06001602 }
1603 if (shProg->VertexProgram)
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001604 printf(" vert prog %u\n", shProg->VertexProgram->Base.Id);
Brian Paul346250b2009-10-23 16:31:48 -06001605 if (shProg->FragmentProgram)
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001606 printf(" frag prog %u\n", shProg->FragmentProgram->Base.Id);
Brian Paul346250b2009-10-23 16:31:48 -06001607}
1608
1609
1610/**
Brian5b01c5e2006-12-19 18:02:03 -07001611 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001612 */
Brian5b01c5e2006-12-19 18:02:03 -07001613void
1614_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001615{
Brian3c008a02007-04-12 15:22:32 -06001616 struct gl_shader_program *shProg;
Brian Paulfef6e362010-05-10 21:11:21 -06001617 struct gl_transform_feedback_object *obj =
1618 ctx->TransformFeedback.CurrentObject;
Brian3c008a02007-04-12 15:22:32 -06001619
Brian Paulfef6e362010-05-10 21:11:21 -06001620 if (obj->Active) {
Brian Paul1a148662010-04-01 22:15:16 -06001621 _mesa_error(ctx, GL_INVALID_OPERATION,
1622 "glUseProgram(transform feedback active)");
1623 return;
1624 }
1625
Brian00d63aa2007-02-03 11:35:02 -07001626 if (ctx->Shader.CurrentProgram &&
1627 ctx->Shader.CurrentProgram->Name == program) {
1628 /* no-op */
1629 return;
1630 }
1631
Brian5b01c5e2006-12-19 18:02:03 -07001632 if (program) {
Brian Paul530df582008-07-03 16:21:11 -06001633 shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
Brian65a18442006-12-19 18:46:56 -07001634 if (!shProg) {
Brian Paul530df582008-07-03 16:21:11 -06001635 return;
1636 }
1637 if (!shProg->LinkStatus) {
Brian Paul621c9992009-02-18 13:28:12 -07001638 _mesa_error(ctx, GL_INVALID_OPERATION,
1639 "glUseProgram(program %u not linked)", program);
Brian5b01c5e2006-12-19 18:02:03 -07001640 return;
1641 }
Brian Paul4eda17d2009-03-13 09:11:42 -06001642
1643 /* debug code */
Brian Paul2ee7fd82009-10-15 15:25:52 -06001644 if (ctx->Shader.Flags & GLSL_USE_PROG) {
Brian Paul346250b2009-10-23 16:31:48 -06001645 print_shader_info(shProg);
Brian Paul4eda17d2009-03-13 09:11:42 -06001646 }
Brian5b01c5e2006-12-19 18:02:03 -07001647 }
1648 else {
Brian3c008a02007-04-12 15:22:32 -06001649 shProg = NULL;
1650 }
1651
Brian Paulb44304e2009-10-27 20:09:33 -06001652 if (ctx->Shader.CurrentProgram != shProg) {
1653 FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
1654 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
1655 }
Brian5b01c5e2006-12-19 18:02:03 -07001656}
Brian34ae99d2006-12-18 08:28:54 -07001657
Brian5b01c5e2006-12-19 18:02:03 -07001658
Brian Paulade50832008-05-14 16:09:46 -06001659
1660/**
Brian Paul517401a2008-11-06 15:04:11 -07001661 * Update the vertex/fragment program's TexturesUsed array.
1662 *
1663 * This needs to be called after glUniform(set sampler var) is called.
1664 * A call to glUniform(samplerVar, value) causes a sampler to point to a
1665 * particular texture unit. We know the sampler's texture target
1666 * (1D/2D/3D/etc) from compile time but the sampler's texture unit is
1667 * set by glUniform() calls.
1668 *
1669 * So, scan the program->SamplerUnits[] and program->SamplerTargets[]
1670 * information to update the prog->TexturesUsed[] values.
1671 * Each value of TexturesUsed[unit] is one of zero, TEXTURE_1D_INDEX,
1672 * TEXTURE_2D_INDEX, TEXTURE_3D_INDEX, etc.
1673 * We'll use that info for state validation before rendering.
Brian Paulade50832008-05-14 16:09:46 -06001674 */
Brian Paul517401a2008-11-06 15:04:11 -07001675void
1676_mesa_update_shader_textures_used(struct gl_program *prog)
Brian Paulade50832008-05-14 16:09:46 -06001677{
1678 GLuint s;
1679
1680 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1681
1682 for (s = 0; s < MAX_SAMPLERS; s++) {
1683 if (prog->SamplersUsed & (1 << s)) {
Brian Paulf05344f2009-08-26 10:58:06 -06001684 GLuint unit = prog->SamplerUnits[s];
1685 GLuint tgt = prog->SamplerTargets[s];
1686 assert(unit < MAX_TEXTURE_IMAGE_UNITS);
1687 assert(tgt < NUM_TEXTURE_TARGETS);
1688 prog->TexturesUsed[unit] |= (1 << tgt);
Brian Paulade50832008-05-14 16:09:46 -06001689 }
1690 }
1691}
1692
1693
1694/**
Brian Paulffbc66b2008-07-21 13:58:50 -06001695 * Check if the type given by userType is allowed to set a uniform of the
1696 * target type. Generally, equivalence is required, but setting Boolean
1697 * uniforms can be done with glUniformiv or glUniformfv.
1698 */
1699static GLboolean
1700compatible_types(GLenum userType, GLenum targetType)
1701{
1702 if (userType == targetType)
1703 return GL_TRUE;
1704
Brian Paul91f841a2010-05-25 18:39:47 -06001705 if (targetType == GL_BOOL && (userType == GL_FLOAT ||
1706 userType == GL_UNSIGNED_INT ||
1707 userType == GL_INT))
Brian Paulffbc66b2008-07-21 13:58:50 -06001708 return GL_TRUE;
1709
1710 if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 ||
Brian Paul91f841a2010-05-25 18:39:47 -06001711 userType == GL_UNSIGNED_INT_VEC2 ||
Brian Paulffbc66b2008-07-21 13:58:50 -06001712 userType == GL_INT_VEC2))
1713 return GL_TRUE;
1714
1715 if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 ||
Brian Paul91f841a2010-05-25 18:39:47 -06001716 userType == GL_UNSIGNED_INT_VEC3 ||
Brian Paulffbc66b2008-07-21 13:58:50 -06001717 userType == GL_INT_VEC3))
1718 return GL_TRUE;
1719
1720 if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 ||
Brian Paul91f841a2010-05-25 18:39:47 -06001721 userType == GL_UNSIGNED_INT_VEC4 ||
Brian Paulffbc66b2008-07-21 13:58:50 -06001722 userType == GL_INT_VEC4))
1723 return GL_TRUE;
1724
Brianb36749d2008-07-21 20:42:05 -06001725 if (is_sampler_type(targetType) && userType == GL_INT)
1726 return GL_TRUE;
1727
Brian Paulffbc66b2008-07-21 13:58:50 -06001728 return GL_FALSE;
1729}
1730
1731
1732/**
Brian Paulade50832008-05-14 16:09:46 -06001733 * Set the value of a program's uniform variable.
1734 * \param program the program whose uniform to update
Brian Pauleda291e2008-08-06 16:26:47 -06001735 * \param index the index of the program parameter for the uniform
1736 * \param offset additional parameter slot offset (for arrays)
Brian Paulc4ffbf02009-02-18 17:46:00 -07001737 * \param type the incoming datatype of 'values'
Brian Paulade50832008-05-14 16:09:46 -06001738 * \param count the number of uniforms to set
Brian Paulc4ffbf02009-02-18 17:46:00 -07001739 * \param elems number of elements per uniform (1, 2, 3 or 4)
1740 * \param values the new values, of datatype 'type'
Brian Paulade50832008-05-14 16:09:46 -06001741 */
1742static void
Brian Pauleda291e2008-08-06 16:26:47 -06001743set_program_uniform(GLcontext *ctx, struct gl_program *program,
1744 GLint index, GLint offset,
1745 GLenum type, GLsizei count, GLint elems,
1746 const void *values)
Brian Paulade50832008-05-14 16:09:46 -06001747{
Brian Paul6df38e62009-08-26 14:35:45 -06001748 const struct gl_program_parameter *param =
Brian Paul949e7382008-11-05 09:17:55 -07001749 &program->Parameters->Parameters[index];
1750
Brian Pauleda291e2008-08-06 16:26:47 -06001751 assert(offset >= 0);
Brian Paulc4ffbf02009-02-18 17:46:00 -07001752 assert(elems >= 1);
1753 assert(elems <= 4);
Brian Pauleda291e2008-08-06 16:26:47 -06001754
Brian Paul949e7382008-11-05 09:17:55 -07001755 if (!compatible_types(type, param->DataType)) {
Brian Paulffbc66b2008-07-21 13:58:50 -06001756 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
1757 return;
1758 }
1759
Michal Krolc5c71302008-08-07 16:23:15 +02001760 if (index + offset > (GLint) program->Parameters->Size) {
Brian Pauleda291e2008-08-06 16:26:47 -06001761 /* out of bounds! */
1762 return;
1763 }
1764
Brian Paul949e7382008-11-05 09:17:55 -07001765 if (param->Type == PROGRAM_SAMPLER) {
Brian Paulade50832008-05-14 16:09:46 -06001766 /* This controls which texture unit which is used by a sampler */
Brian Paulbabb5ba2009-08-26 14:29:50 -06001767 GLboolean changed = GL_FALSE;
Brian Paul2b4f0212009-02-11 09:12:34 -07001768 GLint i;
Brian Paulade50832008-05-14 16:09:46 -06001769
Brian Paul6df38e62009-08-26 14:35:45 -06001770 /* this should have been caught by the compatible_types() check */
1771 ASSERT(type == GL_INT);
Brian Paulade50832008-05-14 16:09:46 -06001772
Brian Paul6df38e62009-08-26 14:35:45 -06001773 /* loop over number of samplers to change */
Brian Paul2b4f0212009-02-11 09:12:34 -07001774 for (i = 0; i < count; i++) {
Brian Paul04d17072009-08-26 11:39:24 -06001775 GLuint sampler =
1776 (GLuint) program->Parameters->ParameterValues[index + offset + i][0];
1777 GLuint texUnit = ((GLuint *) values)[i];
Brian Paulade50832008-05-14 16:09:46 -06001778
Brian Paul2b4f0212009-02-11 09:12:34 -07001779 /* check that the sampler (tex unit index) is legal */
1780 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1781 _mesa_error(ctx, GL_INVALID_VALUE,
Brian Paul16f8df892010-05-13 16:52:06 -06001782 "glUniform1(invalid sampler/tex unit index for '%s')",
1783 param->Name);
Brian Paul2b4f0212009-02-11 09:12:34 -07001784 return;
1785 }
1786
1787 /* This maps a sampler to a texture unit: */
1788 if (sampler < MAX_SAMPLERS) {
Brian Paul04d17072009-08-26 11:39:24 -06001789#if 0
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001790 printf("Set program %p sampler %d '%s' to unit %u\n",
1791 program, sampler, param->Name, texUnit);
Brian Paul04d17072009-08-26 11:39:24 -06001792#endif
Brian Paulbabb5ba2009-08-26 14:29:50 -06001793 if (program->SamplerUnits[sampler] != texUnit) {
1794 program->SamplerUnits[sampler] = texUnit;
1795 changed = GL_TRUE;
1796 }
Brian Paul2b4f0212009-02-11 09:12:34 -07001797 }
Brian Paulade50832008-05-14 16:09:46 -06001798 }
1799
Brian Paulbabb5ba2009-08-26 14:29:50 -06001800 if (changed) {
1801 /* When a sampler's value changes it usually requires rewriting
1802 * a GPU program's TEX instructions since there may not be a
1803 * sampler->texture lookup table. We signal this with the
1804 * ProgramStringNotify() callback.
1805 */
1806 FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM);
1807 _mesa_update_shader_textures_used(program);
Brian Paul4ac9c802010-02-04 16:49:35 -07001808 /* Do we need to care about the return value here?
1809 * This should not be the first time the driver was notified of
1810 * this program.
1811 */
1812 (void) ctx->Driver.ProgramStringNotify(ctx, program->Target, program);
Brian Paulbabb5ba2009-08-26 14:29:50 -06001813 }
Brian Paulade50832008-05-14 16:09:46 -06001814 }
1815 else {
1816 /* ordinary uniform variable */
Brian Paul6df38e62009-08-26 14:35:45 -06001817 const GLboolean isUniformBool = is_boolean_type(param->DataType);
Brian Paul09c7d7b2010-05-25 18:51:45 -06001818 const GLenum basicType = base_uniform_type(type);
Brian Paul2c1ea072009-02-11 08:46:21 -07001819 const GLint slots = (param->Size + 3) / 4;
Brian Paul1a148662010-04-01 22:15:16 -06001820 const GLint typeSize = _mesa_sizeof_glsl_type(param->DataType);
Brian Paul6df38e62009-08-26 14:35:45 -06001821 GLsizei k, i;
Brian Paulade50832008-05-14 16:09:46 -06001822
Brian Paul20fbb242010-01-27 17:03:04 -07001823 if ((GLint) param->Size > typeSize) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001824 /* an array */
1825 /* we'll ignore extra data below */
1826 }
1827 else {
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001828 /* non-array: count must be at most one; count == 0 is handled by the loop below */
1829 if (count > 1) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001830 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Paul16f8df892010-05-13 16:52:06 -06001831 "glUniform(uniform '%s' is not an array)",
1832 param->Name);
Brian Paul2c1ea072009-02-11 08:46:21 -07001833 return;
1834 }
Brian Paulade50832008-05-14 16:09:46 -06001835 }
1836
Brian Paulc4ffbf02009-02-18 17:46:00 -07001837 /* loop over number of array elements */
Brian Paulade50832008-05-14 16:09:46 -06001838 for (k = 0; k < count; k++) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001839 GLfloat *uniformVal;
1840
Brian Paulb9d8f712009-02-18 17:40:44 -07001841 if (offset + k >= slots) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001842 /* Extra array data is ignored */
1843 break;
1844 }
1845
Brian Paulc4ffbf02009-02-18 17:46:00 -07001846 /* uniformVal (the destination) is always float[4] */
Brian Paul2c1ea072009-02-11 08:46:21 -07001847 uniformVal = program->Parameters->ParameterValues[index + offset + k];
Brian Paulc4ffbf02009-02-18 17:46:00 -07001848
Brian Paul09c7d7b2010-05-25 18:51:45 -06001849 if (basicType == GL_INT) {
Brian Paulc4ffbf02009-02-18 17:46:00 -07001850 /* convert user's ints to floats */
Brian Paulade50832008-05-14 16:09:46 -06001851 const GLint *iValues = ((const GLint *) values) + k * elems;
1852 for (i = 0; i < elems; i++) {
1853 uniformVal[i] = (GLfloat) iValues[i];
1854 }
1855 }
Brian Paul09c7d7b2010-05-25 18:51:45 -06001856 else if (basicType == GL_UNSIGNED_INT) {
Brian Paul91f841a2010-05-25 18:39:47 -06001857 /* convert user's uints to floats */
1858 const GLuint *iValues = ((const GLuint *) values) + k * elems;
1859 for (i = 0; i < elems; i++) {
1860 uniformVal[i] = (GLfloat) iValues[i];
1861 }
1862 }
Brian Paulade50832008-05-14 16:09:46 -06001863 else {
1864 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
Brian Paul09c7d7b2010-05-25 18:51:45 -06001865 assert(basicType == GL_FLOAT);
Brian Paulade50832008-05-14 16:09:46 -06001866 for (i = 0; i < elems; i++) {
1867 uniformVal[i] = fValues[i];
1868 }
1869 }
Brian Pauleda291e2008-08-06 16:26:47 -06001870
1871 /* if the uniform is bool-valued, convert to 1.0 or 0.0 */
Brian Paulc4ffbf02009-02-18 17:46:00 -07001872 if (isUniformBool) {
Brian Pauleda291e2008-08-06 16:26:47 -06001873 for (i = 0; i < elems; i++) {
Michal Krolc5c71302008-08-07 16:23:15 +02001874 uniformVal[i] = uniformVal[i] ? 1.0f : 0.0f;
Brian Pauleda291e2008-08-06 16:26:47 -06001875 }
1876 }
Brian Paulade50832008-05-14 16:09:46 -06001877 }
1878 }
1879}
1880
1881
Brian5b01c5e2006-12-19 18:02:03 -07001882/**
1883 * Called via ctx->Driver.Uniform().
1884 */
Brian Paulfd59f192008-05-18 16:04:55 -06001885static void
Brian5b01c5e2006-12-19 18:02:03 -07001886_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1887 const GLvoid *values, GLenum type)
1888{
Brian3a8e2772006-12-20 17:19:16 -07001889 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paul2d76a0d2008-11-10 12:33:17 -07001890 struct gl_uniform *uniform;
Brian Pauleda291e2008-08-06 16:26:47 -06001891 GLint elems, offset;
Brian3a8e2772006-12-20 17:19:16 -07001892
1893 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001894 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001895 return;
1896 }
1897
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001898 if (location == -1)
1899 return; /* The standard specifies this as a no-op */
1900
Brian Paul234f03e2009-02-11 09:05:08 -07001901 if (location < -1) {
Brian Paul16f8df892010-05-13 16:52:06 -06001902 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(location=%d)",
1903 location);
Brian Paul234f03e2009-02-11 09:05:08 -07001904 return;
1905 }
1906
Brian Pauleda291e2008-08-06 16:26:47 -06001907 split_location_offset(&location, &offset);
1908
Brian Paulade50832008-05-14 16:09:46 -06001909 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian Paul16f8df892010-05-13 16:52:06 -06001910 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location=%d)", location);
Brian3a8e2772006-12-20 17:19:16 -07001911 return;
1912 }
1913
Brian52363952007-03-13 16:50:24 -06001914 if (count < 0) {
1915 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1916 return;
1917 }
1918
Brian Paul09c7d7b2010-05-25 18:51:45 -06001919 elems = _mesa_sizeof_glsl_type(type);
Brian98650bd2007-03-13 16:32:48 -06001920
Brian Paul027ed1b2009-04-24 09:43:44 -06001921 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
Brian98650bd2007-03-13 16:32:48 -06001922
Brian Paul2d76a0d2008-11-10 12:33:17 -07001923 uniform = &shProg->Uniforms->Uniforms[location];
1924
Brian Paule01a03d2009-02-06 10:21:36 -07001925 if (ctx->Shader.Flags & GLSL_UNIFORMS) {
Brian Paul09c7d7b2010-05-25 18:51:45 -06001926 const GLenum basicType = base_uniform_type(type);
Brian Paule01a03d2009-02-06 10:21:36 -07001927 GLint i;
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001928 printf("Mesa: set program %u uniform %s (loc %d) to: ",
1929 shProg->Name, uniform->Name, location);
Brian Paule01a03d2009-02-06 10:21:36 -07001930 if (basicType == GL_INT) {
1931 const GLint *v = (const GLint *) values;
1932 for (i = 0; i < count * elems; i++) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001933 printf("%d ", v[i]);
Brian Paule01a03d2009-02-06 10:21:36 -07001934 }
1935 }
Brian Paul91f841a2010-05-25 18:39:47 -06001936 else if (basicType == GL_UNSIGNED_INT) {
1937 const GLuint *v = (const GLuint *) values;
1938 for (i = 0; i < count * elems; i++) {
1939 printf("%u ", v[i]);
1940 }
1941 }
Brian Paule01a03d2009-02-06 10:21:36 -07001942 else {
1943 const GLfloat *v = (const GLfloat *) values;
Brian Paul91f841a2010-05-25 18:39:47 -06001944 assert(basicType == GL_FLOAT);
Brian Paule01a03d2009-02-06 10:21:36 -07001945 for (i = 0; i < count * elems; i++) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001946 printf("%g ", v[i]);
Brian Paule01a03d2009-02-06 10:21:36 -07001947 }
1948 }
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001949 printf("\n");
Brian Paule01a03d2009-02-06 10:21:36 -07001950 }
1951
Brian Paulade50832008-05-14 16:09:46 -06001952 /* A uniform var may be used by both a vertex shader and a fragment
1953 * shader. We may need to update one or both shader's uniform here:
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001954 */
Brian Paulade50832008-05-14 16:09:46 -06001955 if (shProg->VertexProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001956 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07001957 GLint index = uniform->VertPos;
Brian Pauleda291e2008-08-06 16:26:47 -06001958 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001959 set_program_uniform(ctx, &shProg->VertexProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001960 index, offset, type, count, elems, values);
Bruce Merry2bf2a8c2007-12-21 23:18:40 +02001961 }
Brian5b01c5e2006-12-19 18:02:03 -07001962 }
Brian5cf73262007-01-05 16:02:45 -07001963
Brian Paulade50832008-05-14 16:09:46 -06001964 if (shProg->FragmentProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001965 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07001966 GLint index = uniform->FragPos;
Brian Pauleda291e2008-08-06 16:26:47 -06001967 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001968 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001969 index, offset, type, count, elems, values);
Brian Paulade50832008-05-14 16:09:46 -06001970 }
1971 }
Brian Paul949e7382008-11-05 09:17:55 -07001972
Brian Paul2d76a0d2008-11-10 12:33:17 -07001973 uniform->Initialized = GL_TRUE;
Brian Paulade50832008-05-14 16:09:46 -06001974}
1975
1976
Brian Pauleda291e2008-08-06 16:26:47 -06001977/**
1978 * Set a matrix-valued program parameter.
1979 */
Brian Paulade50832008-05-14 16:09:46 -06001980static void
1981set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
Brian Pauleda291e2008-08-06 16:26:47 -06001982 GLuint index, GLuint offset,
1983 GLuint count, GLuint rows, GLuint cols,
Brian Paulade50832008-05-14 16:09:46 -06001984 GLboolean transpose, const GLfloat *values)
1985{
Brian Paulffbc66b2008-07-21 13:58:50 -06001986 GLuint mat, row, col;
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001987 GLuint src = 0;
1988 const struct gl_program_parameter * param = &program->Parameters->Parameters[index];
Brian Paul20fbb242010-01-27 17:03:04 -07001989 const GLuint slots = (param->Size + 3) / 4;
Brian Paul1a148662010-04-01 22:15:16 -06001990 const GLint typeSize = _mesa_sizeof_glsl_type(param->DataType);
Brian Paulffbc66b2008-07-21 13:58:50 -06001991 GLint nr, nc;
1992
1993 /* check that the number of rows, columns is correct */
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001994 get_matrix_dims(param->DataType, &nr, &nc);
Brian Paulffbc66b2008-07-21 13:58:50 -06001995 if (rows != nr || cols != nc) {
1996 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Pauleda291e2008-08-06 16:26:47 -06001997 "glUniformMatrix(matrix size mismatch)");
1998 return;
1999 }
2000
Brian Paul20fbb242010-01-27 17:03:04 -07002001 if ((GLint) param->Size <= typeSize) {
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02002002 /* non-array: count must be at most one; count == 0 is handled by the loop below */
2003 if (count > 1) {
2004 _mesa_error(ctx, GL_INVALID_OPERATION,
2005 "glUniformMatrix(uniform is not an array)");
2006 return;
2007 }
Brian Paulffbc66b2008-07-21 13:58:50 -06002008 }
2009
Brian Paulade50832008-05-14 16:09:46 -06002010 /*
2011 * Note: the _columns_ of a matrix are stored in program registers, not
Brian Paulf45ed0e2008-07-18 12:51:39 -06002012 * the rows. So, the loops below look a little funny.
2013 * XXX could optimize this a bit...
Brian Paulade50832008-05-14 16:09:46 -06002014 */
Brian Paulf45ed0e2008-07-18 12:51:39 -06002015
2016 /* loop over matrices */
2017 for (mat = 0; mat < count; mat++) {
2018
2019 /* each matrix: */
Brian Paulade50832008-05-14 16:09:46 -06002020 for (col = 0; col < cols; col++) {
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02002021 GLfloat *v;
2022 if (offset >= slots) {
2023 /* Ignore writes beyond the end of (the used part of) an array */
2024 return;
2025 }
2026 v = program->Parameters->ParameterValues[index + offset];
Brian Paulade50832008-05-14 16:09:46 -06002027 for (row = 0; row < rows; row++) {
Brian Paulf45ed0e2008-07-18 12:51:39 -06002028 if (transpose) {
2029 v[row] = values[src + row * cols + col];
2030 }
2031 else {
2032 v[row] = values[src + col * rows + row];
2033 }
Brian Paulade50832008-05-14 16:09:46 -06002034 }
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02002035
2036 offset++;
Brian Paulade50832008-05-14 16:09:46 -06002037 }
Brian Paulf45ed0e2008-07-18 12:51:39 -06002038
2039 src += rows * cols; /* next matrix */
Brian5cf73262007-01-05 16:02:45 -07002040 }
Brian34ae99d2006-12-18 08:28:54 -07002041}
2042
2043
2044/**
Brian5b01c5e2006-12-19 18:02:03 -07002045 * Called by ctx->Driver.UniformMatrix().
Brian Paulf45ed0e2008-07-18 12:51:39 -06002046 * Note: cols=2, rows=4 ==> array[2] of vec4
Brian34ae99d2006-12-18 08:28:54 -07002047 */
Brian Paulfd59f192008-05-18 16:04:55 -06002048static void
Brian5b01c5e2006-12-19 18:02:03 -07002049_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
Brian Paul0115a4f2009-04-14 20:00:28 -06002050 GLint location, GLsizei count,
Brian5b01c5e2006-12-19 18:02:03 -07002051 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07002052{
Brian3a8e2772006-12-20 17:19:16 -07002053 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paul2d76a0d2008-11-10 12:33:17 -07002054 struct gl_uniform *uniform;
2055 GLint offset;
Brian Paulade50832008-05-14 16:09:46 -06002056
Brian3a8e2772006-12-20 17:19:16 -07002057 if (!shProg || !shProg->LinkStatus) {
2058 _mesa_error(ctx, GL_INVALID_OPERATION,
2059 "glUniformMatrix(program not linked)");
2060 return;
2061 }
Brian Paulade50832008-05-14 16:09:46 -06002062
Bruce Merry89b80322007-12-21 15:20:17 +02002063 if (location == -1)
2064 return; /* The standard specifies this as a no-op */
Brian Paulade50832008-05-14 16:09:46 -06002065
Brian Paul234f03e2009-02-11 09:05:08 -07002066 if (location < -1) {
2067 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(location)");
2068 return;
2069 }
2070
Brian Pauleda291e2008-08-06 16:26:47 -06002071 split_location_offset(&location, &offset);
2072
Brian Paul016701f2008-07-29 17:43:35 -06002073 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian Paulade50832008-05-14 16:09:46 -06002074 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
Brian3a8e2772006-12-20 17:19:16 -07002075 return;
2076 }
Brian34ae99d2006-12-18 08:28:54 -07002077 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07002078 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07002079 return;
2080 }
2081
Brian Paul027ed1b2009-04-24 09:43:44 -06002082 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
Brian34ae99d2006-12-18 08:28:54 -07002083
Brian Paul2d76a0d2008-11-10 12:33:17 -07002084 uniform = &shProg->Uniforms->Uniforms[location];
2085
Brian Paulade50832008-05-14 16:09:46 -06002086 if (shProg->VertexProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06002087 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07002088 GLint index = uniform->VertPos;
Brian Pauleda291e2008-08-06 16:26:47 -06002089 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06002090 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06002091 index, offset,
2092 count, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07002093 }
Brian Paulade50832008-05-14 16:09:46 -06002094 }
2095
2096 if (shProg->FragmentProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06002097 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07002098 GLint index = uniform->FragPos;
Brian Pauleda291e2008-08-06 16:26:47 -06002099 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06002100 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06002101 index, offset,
2102 count, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07002103 }
Brian34ae99d2006-12-18 08:28:54 -07002104 }
Brian Paul949e7382008-11-05 09:17:55 -07002105
Brian Paul2d76a0d2008-11-10 12:33:17 -07002106 uniform->Initialized = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07002107}
2108
2109
Brian Paulc90fca32009-08-25 17:42:47 -06002110/**
2111 * Validate a program's samplers.
2112 * Specifically, check that there aren't two samplers of different types
2113 * pointing to the same texture unit.
2114 * \return GL_TRUE if valid, GL_FALSE if invalid
2115 */
2116static GLboolean
2117validate_samplers(GLcontext *ctx, const struct gl_program *prog, char *errMsg)
Brian34ae99d2006-12-18 08:28:54 -07002118{
Brian Paulc90fca32009-08-25 17:42:47 -06002119 static const char *targetName[] = {
2120 "TEXTURE_2D_ARRAY",
2121 "TEXTURE_1D_ARRAY",
2122 "TEXTURE_CUBE",
2123 "TEXTURE_3D",
2124 "TEXTURE_RECT",
2125 "TEXTURE_2D",
2126 "TEXTURE_1D",
2127 };
2128 GLint targetUsed[MAX_TEXTURE_IMAGE_UNITS];
2129 GLbitfield samplersUsed = prog->SamplersUsed;
2130 GLuint i;
Brian Paulbc985b52008-07-21 14:16:07 -06002131
Brian Paulc90fca32009-08-25 17:42:47 -06002132 assert(Elements(targetName) == NUM_TEXTURE_TARGETS);
2133
2134 if (samplersUsed == 0x0)
2135 return GL_TRUE;
2136
2137 for (i = 0; i < Elements(targetUsed); i++)
2138 targetUsed[i] = -1;
2139
2140 /* walk over bits which are set in 'samplers' */
2141 while (samplersUsed) {
2142 GLuint unit;
2143 gl_texture_index target;
2144 GLint sampler = _mesa_ffs(samplersUsed) - 1;
2145 assert(sampler >= 0);
2146 assert(sampler < MAX_TEXTURE_IMAGE_UNITS);
2147 unit = prog->SamplerUnits[sampler];
2148 target = prog->SamplerTargets[sampler];
2149 if (targetUsed[unit] != -1 && targetUsed[unit] != target) {
Brian Paul78a0c352010-02-19 12:56:49 -07002150 _mesa_snprintf(errMsg, 100,
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002151 "Texture unit %d is accessed both as %s and %s",
2152 unit, targetName[targetUsed[unit]], targetName[target]);
Brian Paulc90fca32009-08-25 17:42:47 -06002153 return GL_FALSE;
2154 }
2155 targetUsed[unit] = target;
2156 samplersUsed ^= (1 << sampler);
Brian34ae99d2006-12-18 08:28:54 -07002157 }
2158
Brian Paulc90fca32009-08-25 17:42:47 -06002159 return GL_TRUE;
2160}
2161
2162
2163/**
2164 * Do validation of the given shader program.
2165 * \param errMsg returns error message if validation fails.
2166 * \return GL_TRUE if valid, GL_FALSE if invalid (and set errMsg)
2167 */
2168GLboolean
2169_mesa_validate_shader_program(GLcontext *ctx,
2170 const struct gl_shader_program *shProg,
2171 char *errMsg)
2172{
2173 const struct gl_vertex_program *vp = shProg->VertexProgram;
2174 const struct gl_fragment_program *fp = shProg->FragmentProgram;
2175
Brian Paulbc985b52008-07-21 14:16:07 -06002176 if (!shProg->LinkStatus) {
Brian Paulc90fca32009-08-25 17:42:47 -06002177 return GL_FALSE;
Brian Paulbc985b52008-07-21 14:16:07 -06002178 }
2179
2180 /* From the GL spec, a program is invalid if any of these are true:
2181
Brian5b01c5e2006-12-19 18:02:03 -07002182 any two active samplers in the current program object are of
2183 different types, but refer to the same texture image unit,
2184
2185 any active sampler in the current program object refers to a texture
2186 image unit where fixed-function fragment processing accesses a
2187 texture target that does not match the sampler type, or
2188
2189 the sum of the number of active samplers in the program and the
2190 number of texture image units enabled for fixed-function fragment
2191 processing exceeds the combined limit on the total number of texture
2192 image units allowed.
2193 */
Brian Paulbc985b52008-07-21 14:16:07 -06002194
Brian Paulc90fca32009-08-25 17:42:47 -06002195
2196 /*
2197 * Check: any two active samplers in the current program object are of
2198 * different types, but refer to the same texture image unit,
2199 */
2200 if (vp && !validate_samplers(ctx, &vp->Base, errMsg)) {
2201 return GL_FALSE;
2202 }
2203 if (fp && !validate_samplers(ctx, &fp->Base, errMsg)) {
2204 return GL_FALSE;
2205 }
2206
2207 return GL_TRUE;
2208}
2209
2210
2211/**
2212 * Called via glValidateProgram()
2213 */
2214static void
2215_mesa_validate_program(GLcontext *ctx, GLuint program)
2216{
2217 struct gl_shader_program *shProg;
2218 char errMsg[100];
2219
2220 shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram");
2221 if (!shProg) {
2222 return;
2223 }
2224
2225 shProg->Validated = _mesa_validate_shader_program(ctx, shProg, errMsg);
2226 if (!shProg->Validated) {
2227 /* update info log */
2228 if (shProg->InfoLog) {
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -05002229 free(shProg->InfoLog);
Brian Paulc90fca32009-08-25 17:42:47 -06002230 }
2231 shProg->InfoLog = _mesa_strdup(errMsg);
2232 }
Brian34ae99d2006-12-18 08:28:54 -07002233}
Brian Paulfd59f192008-05-18 16:04:55 -06002234
2235
2236/**
2237 * Plug in Mesa's GLSL functions into the device driver function table.
2238 */
2239void
2240_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
2241{
2242 driver->AttachShader = _mesa_attach_shader;
2243 driver->BindAttribLocation = _mesa_bind_attrib_location;
2244 driver->CompileShader = _mesa_compile_shader;
2245 driver->CreateProgram = _mesa_create_program;
2246 driver->CreateShader = _mesa_create_shader;
2247 driver->DeleteProgram2 = _mesa_delete_program2;
2248 driver->DeleteShader = _mesa_delete_shader;
2249 driver->DetachShader = _mesa_detach_shader;
2250 driver->GetActiveAttrib = _mesa_get_active_attrib;
2251 driver->GetActiveUniform = _mesa_get_active_uniform;
2252 driver->GetAttachedShaders = _mesa_get_attached_shaders;
2253 driver->GetAttribLocation = _mesa_get_attrib_location;
2254 driver->GetHandle = _mesa_get_handle;
2255 driver->GetProgramiv = _mesa_get_programiv;
2256 driver->GetProgramInfoLog = _mesa_get_program_info_log;
2257 driver->GetShaderiv = _mesa_get_shaderiv;
2258 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
2259 driver->GetShaderSource = _mesa_get_shader_source;
2260 driver->GetUniformfv = _mesa_get_uniformfv;
Brian Paul2be54a82008-07-08 16:17:04 -06002261 driver->GetUniformiv = _mesa_get_uniformiv;
Brian Paulfd59f192008-05-18 16:04:55 -06002262 driver->GetUniformLocation = _mesa_get_uniform_location;
2263 driver->IsProgram = _mesa_is_program;
2264 driver->IsShader = _mesa_is_shader;
2265 driver->LinkProgram = _mesa_link_program;
2266 driver->ShaderSource = _mesa_shader_source;
2267 driver->Uniform = _mesa_uniform;
2268 driver->UniformMatrix = _mesa_uniform_matrix;
2269 driver->UseProgram = _mesa_use_program;
2270 driver->ValidateProgram = _mesa_validate_program;
2271}