blob: 36fe0a1bb7212bb959837f1e710dbcd7843821b3 [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 Paulffbc66b2008-07-21 13:58:50 -0600785static GLint
786sizeof_glsl_type(GLenum type)
787{
788 switch (type) {
789 case GL_FLOAT:
790 case GL_INT:
791 case GL_BOOL:
Brian Paul8c51e002008-08-11 15:09:47 -0600792 case GL_SAMPLER_1D:
793 case GL_SAMPLER_2D:
794 case GL_SAMPLER_3D:
795 case GL_SAMPLER_CUBE:
796 case GL_SAMPLER_1D_SHADOW:
797 case GL_SAMPLER_2D_SHADOW:
798 case GL_SAMPLER_2D_RECT_ARB:
799 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
Brian Paulac498f22010-02-25 19:05:11 -0700800 case GL_SAMPLER_1D_ARRAY_EXT:
801 case GL_SAMPLER_2D_ARRAY_EXT:
Brian Paul8c51e002008-08-11 15:09:47 -0600802 case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
803 case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
804 case GL_SAMPLER_CUBE_SHADOW_EXT:
Brian Paulffbc66b2008-07-21 13:58:50 -0600805 return 1;
806 case GL_FLOAT_VEC2:
807 case GL_INT_VEC2:
808 case GL_BOOL_VEC2:
809 return 2;
810 case GL_FLOAT_VEC3:
811 case GL_INT_VEC3:
812 case GL_BOOL_VEC3:
813 return 3;
814 case GL_FLOAT_VEC4:
815 case GL_INT_VEC4:
816 case GL_BOOL_VEC4:
817 return 4;
818 case GL_FLOAT_MAT2:
819 case GL_FLOAT_MAT2x3:
820 case GL_FLOAT_MAT2x4:
821 return 8; /* two float[4] vectors */
822 case GL_FLOAT_MAT3:
823 case GL_FLOAT_MAT3x2:
824 case GL_FLOAT_MAT3x4:
825 return 12; /* three float[4] vectors */
826 case GL_FLOAT_MAT4:
827 case GL_FLOAT_MAT4x2:
828 case GL_FLOAT_MAT4x3:
829 return 16; /* four float[4] vectors */
830 default:
831 _mesa_problem(NULL, "Invalid type in sizeof_glsl_type()");
832 return 1;
833 }
834}
835
836
Brian Pauleda291e2008-08-06 16:26:47 -0600837static GLboolean
838is_boolean_type(GLenum type)
839{
840 switch (type) {
841 case GL_BOOL:
842 case GL_BOOL_VEC2:
843 case GL_BOOL_VEC3:
844 case GL_BOOL_VEC4:
845 return GL_TRUE;
846 default:
847 return GL_FALSE;
848 }
849}
850
851
852static GLboolean
853is_integer_type(GLenum type)
854{
855 switch (type) {
856 case GL_INT:
857 case GL_INT_VEC2:
858 case GL_INT_VEC3:
859 case GL_INT_VEC4:
860 return GL_TRUE;
861 default:
862 return GL_FALSE;
863 }
864}
865
866
Brian Paulc4ffbf02009-02-18 17:46:00 -0700867static GLboolean
868is_sampler_type(GLenum type)
869{
870 switch (type) {
871 case GL_SAMPLER_1D:
872 case GL_SAMPLER_2D:
873 case GL_SAMPLER_3D:
874 case GL_SAMPLER_CUBE:
875 case GL_SAMPLER_1D_SHADOW:
876 case GL_SAMPLER_2D_SHADOW:
877 case GL_SAMPLER_2D_RECT_ARB:
878 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
879 case GL_SAMPLER_1D_ARRAY_EXT:
880 case GL_SAMPLER_2D_ARRAY_EXT:
Brian Paulac498f22010-02-25 19:05:11 -0700881 case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
882 case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
Brian Paulc4ffbf02009-02-18 17:46:00 -0700883 return GL_TRUE;
884 default:
885 return GL_FALSE;
886 }
887}
888
889
Brian Paulfd59f192008-05-18 16:04:55 -0600890static void
Brian5b01c5e2006-12-19 18:02:03 -0700891_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
892 GLsizei maxLength, GLsizei *length, GLint *size,
893 GLenum *type, GLchar *nameOut)
894{
Brian Paul27341a92008-09-16 16:28:36 -0600895 const struct gl_program_parameter_list *attribs = NULL;
Brian Paul530df582008-07-03 16:21:11 -0600896 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700897
Brian Paul530df582008-07-03 16:21:11 -0600898 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
899 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700900 return;
Brian5b01c5e2006-12-19 18:02:03 -0700901
Brian Paul27341a92008-09-16 16:28:36 -0600902 if (shProg->VertexProgram)
903 attribs = shProg->VertexProgram->Base.Attributes;
904
905 if (!attribs || index >= attribs->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600906 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700907 return;
908 }
909
Brian Paule5c69642010-03-30 19:54:02 -0600910 _mesa_copy_string(nameOut, maxLength, length,
911 attribs->Parameters[index].Name);
Brian Paul27341a92008-09-16 16:28:36 -0600912
Brian5b01c5e2006-12-19 18:02:03 -0700913 if (size)
Brian Paul27341a92008-09-16 16:28:36 -0600914 *size = attribs->Parameters[index].Size
915 / sizeof_glsl_type(attribs->Parameters[index].DataType);
916
Brian Paulade50832008-05-14 16:09:46 -0600917 if (type)
Brian Paul27341a92008-09-16 16:28:36 -0600918 *type = attribs->Parameters[index].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700919}
920
921
Brian Pauleda291e2008-08-06 16:26:47 -0600922static struct gl_program_parameter *
923get_uniform_parameter(const struct gl_shader_program *shProg, GLuint index)
924{
Brian Paula531a5c2009-08-13 13:44:01 -0600925 const struct gl_program *prog = NULL;
Brian Pauleda291e2008-08-06 16:26:47 -0600926 GLint progPos;
927
928 progPos = shProg->Uniforms->Uniforms[index].VertPos;
929 if (progPos >= 0) {
930 prog = &shProg->VertexProgram->Base;
931 }
932 else {
933 progPos = shProg->Uniforms->Uniforms[index].FragPos;
934 if (progPos >= 0) {
935 prog = &shProg->FragmentProgram->Base;
936 }
937 }
938
939 if (!prog || progPos < 0)
940 return NULL; /* should never happen */
941
942 return &prog->Parameters->Parameters[progPos];
943}
944
945
Brian5b01c5e2006-12-19 18:02:03 -0700946/**
947 * Called via ctx->Driver.GetActiveUniform().
948 */
Brian Paulfd59f192008-05-18 16:04:55 -0600949static void
Brian5b01c5e2006-12-19 18:02:03 -0700950_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
951 GLsizei maxLength, GLsizei *length, GLint *size,
952 GLenum *type, GLchar *nameOut)
953{
Brian Paul530df582008-07-03 16:21:11 -0600954 const struct gl_shader_program *shProg;
Brian Paula531a5c2009-08-13 13:44:01 -0600955 const struct gl_program *prog = NULL;
Brian Paul369d1852009-02-11 08:16:14 -0700956 const struct gl_program_parameter *param;
Brian Paulade50832008-05-14 16:09:46 -0600957 GLint progPos;
Brian5b01c5e2006-12-19 18:02:03 -0700958
Brian Paul530df582008-07-03 16:21:11 -0600959 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
960 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700961 return;
Brian5b01c5e2006-12-19 18:02:03 -0700962
Brian Paulade50832008-05-14 16:09:46 -0600963 if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
Brian5b01c5e2006-12-19 18:02:03 -0700964 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
965 return;
966 }
967
Brian Paulade50832008-05-14 16:09:46 -0600968 progPos = shProg->Uniforms->Uniforms[index].VertPos;
969 if (progPos >= 0) {
970 prog = &shProg->VertexProgram->Base;
971 }
972 else {
973 progPos = shProg->Uniforms->Uniforms[index].FragPos;
974 if (progPos >= 0) {
975 prog = &shProg->FragmentProgram->Base;
Brian274ac7a2007-04-18 16:05:53 -0600976 }
977 }
978
Brian Paulade50832008-05-14 16:09:46 -0600979 if (!prog || progPos < 0)
980 return; /* should never happen */
981
Brian Paul369d1852009-02-11 08:16:14 -0700982 ASSERT(progPos < prog->Parameters->NumParameters);
983 param = &prog->Parameters->Parameters[progPos];
984
985 if (nameOut) {
Brian Paule5c69642010-03-30 19:54:02 -0600986 _mesa_copy_string(nameOut, maxLength, length, param->Name);
Brian Paul369d1852009-02-11 08:16:14 -0700987 }
988
989 if (size) {
990 GLint typeSize = sizeof_glsl_type(param->DataType);
Brian Paul20fbb242010-01-27 17:03:04 -0700991 if ((GLint) param->Size > typeSize) {
Brian Paul369d1852009-02-11 08:16:14 -0700992 /* This is an array.
993 * Array elements are placed on vector[4] boundaries so they're
994 * a multiple of four floats. We round typeSize up to next multiple
995 * of four to get the right size below.
996 */
997 typeSize = (typeSize + 3) & ~3;
998 }
999 /* Note that the returned size is in units of the <type>, not bytes */
1000 *size = param->Size / typeSize;
1001 }
1002
1003 if (type) {
1004 *type = param->DataType;
1005 }
Brian5b01c5e2006-12-19 18:02:03 -07001006}
1007
1008
1009/**
1010 * Called via ctx->Driver.GetAttachedShaders().
1011 */
Brian Paulfd59f192008-05-18 16:04:55 -06001012static void
Brian5b01c5e2006-12-19 18:02:03 -07001013_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
1014 GLsizei *count, GLuint *obj)
1015{
Brian Paul530df582008-07-03 16:21:11 -06001016 struct gl_shader_program *shProg =
1017 _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders");
Brian65a18442006-12-19 18:46:56 -07001018 if (shProg) {
Brian Paul530df582008-07-03 16:21:11 -06001019 GLuint i;
1020 for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) {
Brian65a18442006-12-19 18:46:56 -07001021 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -07001022 }
1023 if (count)
1024 *count = i;
1025 }
Brian5b01c5e2006-12-19 18:02:03 -07001026}
1027
1028
Brian Paulfd59f192008-05-18 16:04:55 -06001029static GLuint
Brian5b01c5e2006-12-19 18:02:03 -07001030_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -07001031{
Ian Romanick905d8e02008-09-29 12:27:00 -07001032 GLint handle = 0;
1033
1034 if (pname == GL_PROGRAM_OBJECT_ARB) {
1035 CALL_GetIntegerv(ctx->Exec, (GL_CURRENT_PROGRAM, &handle));
1036 } else {
Brian34ae99d2006-12-18 08:28:54 -07001037 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
1038 }
Ian Romanick905d8e02008-09-29 12:27:00 -07001039
1040 return handle;
Brian34ae99d2006-12-18 08:28:54 -07001041}
1042
1043
Brian Paulfd59f192008-05-18 16:04:55 -06001044static void
Brian5b01c5e2006-12-19 18:02:03 -07001045_mesa_get_programiv(GLcontext *ctx, GLuint program,
1046 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -07001047{
Brian Paul27341a92008-09-16 16:28:36 -06001048 const struct gl_program_parameter_list *attribs;
Brian65a18442006-12-19 18:46:56 -07001049 struct gl_shader_program *shProg
1050 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -07001051
Brian65a18442006-12-19 18:46:56 -07001052 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -07001053 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -07001054 return;
1055 }
1056
Brian Paul27341a92008-09-16 16:28:36 -06001057 if (shProg->VertexProgram)
1058 attribs = shProg->VertexProgram->Base.Attributes;
1059 else
1060 attribs = NULL;
1061
Brian5b01c5e2006-12-19 18:02:03 -07001062 switch (pname) {
1063 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -07001064 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -07001065 break;
1066 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -07001067 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -07001068 break;
Brian5b01c5e2006-12-19 18:02:03 -07001069 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -07001070 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -07001071 break;
1072 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001073 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001074 break;
1075 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -07001076 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -07001077 break;
1078 case GL_ACTIVE_ATTRIBUTES:
Brian Paul27341a92008-09-16 16:28:36 -06001079 *params = attribs ? attribs->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001080 break;
1081 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian Paul27341a92008-09-16 16:28:36 -06001082 *params = _mesa_longest_parameter_name(attribs, PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -07001083 break;
1084 case GL_ACTIVE_UNIFORMS:
Brian Paulade50832008-05-14 16:09:46 -06001085 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001086 break;
1087 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian Paulade50832008-05-14 16:09:46 -06001088 *params = _mesa_longest_uniform_name(shProg->Uniforms);
Brian274ac7a2007-04-18 16:05:53 -06001089 if (*params > 0)
1090 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -07001091 break;
Brian Paulbda6ad22008-08-06 12:45:14 -06001092 case GL_PROGRAM_BINARY_LENGTH_OES:
1093 *params = 0;
1094 break;
Brian Paule5c69642010-03-30 19:54:02 -06001095#if FEATURE_EXT_transform_feedback
1096 case GL_TRANSFORM_FEEDBACK_VARYINGS:
1097 *params = shProg->TransformFeedback.NumVarying;
1098 break;
1099 case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
1100 *params = longest_feedback_varying_name(shProg) + 1;
1101 break;
1102 case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
1103 *params = shProg->TransformFeedback.BufferMode;
1104 break;
1105#endif
Brian34ae99d2006-12-18 08:28:54 -07001106 default:
Brian5b01c5e2006-12-19 18:02:03 -07001107 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
1108 return;
Brian34ae99d2006-12-18 08:28:54 -07001109 }
Brian5b01c5e2006-12-19 18:02:03 -07001110}
Brian34ae99d2006-12-18 08:28:54 -07001111
Brian34ae99d2006-12-18 08:28:54 -07001112
Brian Paulfd59f192008-05-18 16:04:55 -06001113static void
Brian5b01c5e2006-12-19 18:02:03 -07001114_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
1115{
Brian Paul530df582008-07-03 16:21:11 -06001116 struct gl_shader *shader = _mesa_lookup_shader_err(ctx, name, "glGetShaderiv");
Brian5b01c5e2006-12-19 18:02:03 -07001117
1118 if (!shader) {
Brian5b01c5e2006-12-19 18:02:03 -07001119 return;
1120 }
Brian65a18442006-12-19 18:46:56 -07001121
Brian5b01c5e2006-12-19 18:02:03 -07001122 switch (pname) {
1123 case GL_SHADER_TYPE:
1124 *params = shader->Type;
1125 break;
1126 case GL_DELETE_STATUS:
1127 *params = shader->DeletePending;
1128 break;
1129 case GL_COMPILE_STATUS:
1130 *params = shader->CompileStatus;
1131 break;
1132 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001133 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001134 break;
1135 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001136 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001137 break;
1138 default:
1139 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
1140 return;
1141 }
1142}
1143
1144
Brian Paulfd59f192008-05-18 16:04:55 -06001145static void
Brian5b01c5e2006-12-19 18:02:03 -07001146_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
1147 GLsizei *length, GLchar *infoLog)
1148{
Brian65a18442006-12-19 18:46:56 -07001149 struct gl_shader_program *shProg
1150 = _mesa_lookup_shader_program(ctx, program);
1151 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -07001152 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
1153 return;
1154 }
Brian Paule5c69642010-03-30 19:54:02 -06001155 _mesa_copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -07001156}
1157
1158
Brian Paulfd59f192008-05-18 16:04:55 -06001159static void
Brian5b01c5e2006-12-19 18:02:03 -07001160_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
1161 GLsizei *length, GLchar *infoLog)
1162{
Brian65a18442006-12-19 18:46:56 -07001163 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
1164 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001165 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
1166 return;
1167 }
Brian Paule5c69642010-03-30 19:54:02 -06001168 _mesa_copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -07001169}
1170
1171
1172/**
1173 * Called via ctx->Driver.GetShaderSource().
1174 */
Brian Paulfd59f192008-05-18 16:04:55 -06001175static void
Brian5b01c5e2006-12-19 18:02:03 -07001176_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
1177 GLsizei *length, GLchar *sourceOut)
1178{
Brian Paul530df582008-07-03 16:21:11 -06001179 struct gl_shader *sh;
1180 sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource");
Brian65a18442006-12-19 18:46:56 -07001181 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001182 return;
1183 }
Brian Paule5c69642010-03-30 19:54:02 -06001184 _mesa_copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -07001185}
1186
1187
Brian Paul5b982362008-08-06 13:07:09 -06001188static void
1189get_matrix_dims(GLenum type, GLint *rows, GLint *cols)
1190{
1191 switch (type) {
1192 case GL_FLOAT_MAT2:
1193 *rows = *cols = 2;
1194 break;
1195 case GL_FLOAT_MAT2x3:
1196 *rows = 3;
1197 *cols = 2;
1198 break;
1199 case GL_FLOAT_MAT2x4:
1200 *rows = 4;
1201 *cols = 2;
1202 break;
1203 case GL_FLOAT_MAT3:
1204 *rows = 3;
1205 *cols = 3;
1206 break;
1207 case GL_FLOAT_MAT3x2:
1208 *rows = 2;
1209 *cols = 3;
1210 break;
1211 case GL_FLOAT_MAT3x4:
1212 *rows = 4;
1213 *cols = 3;
1214 break;
1215 case GL_FLOAT_MAT4:
1216 *rows = 4;
1217 *cols = 4;
1218 break;
1219 case GL_FLOAT_MAT4x2:
1220 *rows = 2;
1221 *cols = 4;
1222 break;
1223 case GL_FLOAT_MAT4x3:
1224 *rows = 3;
1225 *cols = 4;
1226 break;
1227 default:
1228 *rows = *cols = 0;
1229 }
1230}
1231
1232
1233/**
1234 * Determine the number of rows and columns occupied by a uniform
Brian Paulea9568d2008-09-16 08:55:54 -06001235 * according to its datatype. For non-matrix types (such as GL_FLOAT_VEC4),
1236 * the number of rows = 1 and cols = number of elements in the vector.
Brian Paul5b982362008-08-06 13:07:09 -06001237 */
1238static void
1239get_uniform_rows_cols(const struct gl_program_parameter *p,
1240 GLint *rows, GLint *cols)
1241{
1242 get_matrix_dims(p->DataType, rows, cols);
1243 if (*rows == 0 && *cols == 0) {
1244 /* not a matrix type, probably a float or vector */
Brian Paulea9568d2008-09-16 08:55:54 -06001245 if (p->Size <= 4) {
1246 *rows = 1;
1247 *cols = p->Size;
1248 }
1249 else {
1250 *rows = p->Size / 4 + 1;
1251 if (p->Size % 4 == 0)
1252 *cols = 4;
1253 else
1254 *cols = p->Size % 4;
1255 }
Brian Paul5b982362008-08-06 13:07:09 -06001256 }
1257}
1258
1259
Brian5b01c5e2006-12-19 18:02:03 -07001260/**
Brian Paul4ef7a932009-02-11 09:03:16 -07001261 * Helper for get_uniform[fi]v() functions.
1262 * Given a shader program name and uniform location, return a pointer
1263 * to the shader program and return the program parameter position.
Brian5b01c5e2006-12-19 18:02:03 -07001264 */
Brian Paul4ef7a932009-02-11 09:03:16 -07001265static void
1266lookup_uniform_parameter(GLcontext *ctx, GLuint program, GLint location,
1267 struct gl_program **progOut, GLint *paramPosOut)
Brian5b01c5e2006-12-19 18:02:03 -07001268{
Brian65a18442006-12-19 18:46:56 -07001269 struct gl_shader_program *shProg
Brian Paulbda6ad22008-08-06 12:45:14 -06001270 = _mesa_lookup_shader_program_err(ctx, program, "glGetUniform[if]v");
Brian Paul4ef7a932009-02-11 09:03:16 -07001271 struct gl_program *prog = NULL;
1272 GLint progPos = -1;
Brian Paulade50832008-05-14 16:09:46 -06001273
Brian Paul4ef7a932009-02-11 09:03:16 -07001274 /* if shProg is NULL, we'll have already recorded an error */
1275
1276 if (shProg) {
1277 if (!shProg->Uniforms ||
1278 location < 0 ||
1279 location >= (GLint) shProg->Uniforms->NumUniforms) {
1280 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
1281 }
1282 else {
1283 /* OK, find the gl_program and program parameter location */
Brian Paulade50832008-05-14 16:09:46 -06001284 progPos = shProg->Uniforms->Uniforms[location].VertPos;
1285 if (progPos >= 0) {
1286 prog = &shProg->VertexProgram->Base;
Brian5b01c5e2006-12-19 18:02:03 -07001287 }
Brian Paulade50832008-05-14 16:09:46 -06001288 else {
1289 progPos = shProg->Uniforms->Uniforms[location].FragPos;
1290 if (progPos >= 0) {
1291 prog = &shProg->FragmentProgram->Base;
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001292 }
Brian Paulade50832008-05-14 16:09:46 -06001293 }
Brian5b01c5e2006-12-19 18:02:03 -07001294 }
1295 }
Brian Paul4ef7a932009-02-11 09:03:16 -07001296
1297 *progOut = prog;
1298 *paramPosOut = progPos;
Brian Paul2be54a82008-07-08 16:17:04 -06001299}
1300
1301
1302/**
1303 * Called via ctx->Driver.GetUniformfv().
1304 */
1305static void
1306_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1307 GLfloat *params)
1308{
Brian Paul4ef7a932009-02-11 09:03:16 -07001309 struct gl_program *prog;
1310 GLint paramPos;
1311
1312 lookup_uniform_parameter(ctx, program, location, &prog, &paramPos);
1313
1314 if (prog) {
1315 const struct gl_program_parameter *p =
1316 &prog->Parameters->Parameters[paramPos];
1317 GLint rows, cols, i, j, k;
1318
1319 get_uniform_rows_cols(p, &rows, &cols);
1320
1321 k = 0;
1322 for (i = 0; i < rows; i++) {
1323 for (j = 0; j < cols; j++ ) {
1324 params[k++] = prog->Parameters->ParameterValues[paramPos+i][j];
1325 }
1326 }
1327 }
Brian Paul2be54a82008-07-08 16:17:04 -06001328}
1329
1330
1331/**
1332 * Called via ctx->Driver.GetUniformiv().
Brian Paul4ef7a932009-02-11 09:03:16 -07001333 * \sa _mesa_get_uniformfv, only difference is a cast.
Brian Paul2be54a82008-07-08 16:17:04 -06001334 */
1335static void
1336_mesa_get_uniformiv(GLcontext *ctx, GLuint program, GLint location,
1337 GLint *params)
1338{
Brian Paul4ef7a932009-02-11 09:03:16 -07001339 struct gl_program *prog;
1340 GLint paramPos;
1341
1342 lookup_uniform_parameter(ctx, program, location, &prog, &paramPos);
1343
1344 if (prog) {
1345 const struct gl_program_parameter *p =
1346 &prog->Parameters->Parameters[paramPos];
1347 GLint rows, cols, i, j, k;
1348
1349 get_uniform_rows_cols(p, &rows, &cols);
1350
1351 k = 0;
1352 for (i = 0; i < rows; i++) {
1353 for (j = 0; j < cols; j++ ) {
1354 params[k++] = (GLint) prog->Parameters->ParameterValues[paramPos+i][j];
1355 }
1356 }
Brian Paul2be54a82008-07-08 16:17:04 -06001357 }
Brian5b01c5e2006-12-19 18:02:03 -07001358}
1359
1360
1361/**
Brian Pauleda291e2008-08-06 16:26:47 -06001362 * The value returned by GetUniformLocation actually encodes two things:
1363 * 1. the index into the prog->Uniforms[] array for the uniform
1364 * 2. an offset in the prog->ParameterValues[] array for specifying array
1365 * elements or structure fields.
1366 * This function merges those two values.
1367 */
1368static void
1369merge_location_offset(GLint *location, GLint offset)
1370{
1371 *location = *location | (offset << 16);
1372}
1373
1374
1375/**
1376 * Seperate the uniform location and parameter offset. See above.
1377 */
1378static void
1379split_location_offset(GLint *location, GLint *offset)
1380{
1381 *offset = (*location >> 16);
1382 *location = *location & 0xffff;
1383}
1384
1385
1386/**
Brian5b01c5e2006-12-19 18:02:03 -07001387 * Called via ctx->Driver.GetUniformLocation().
Brian Pauleda291e2008-08-06 16:26:47 -06001388 *
1389 * The return value will encode two values, the uniform location and an
1390 * offset (used for arrays, structs).
Brian5b01c5e2006-12-19 18:02:03 -07001391 */
Brian Paulfd59f192008-05-18 16:04:55 -06001392static GLint
Brian5b01c5e2006-12-19 18:02:03 -07001393_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
1394{
Brian Pauleda291e2008-08-06 16:26:47 -06001395 GLint offset = 0, location = -1;
1396
Brian Paul530df582008-07-03 16:21:11 -06001397 struct gl_shader_program *shProg =
1398 _mesa_lookup_shader_program_err(ctx, program, "glGetUniformLocation");
1399
Brian Paulade50832008-05-14 16:09:46 -06001400 if (!shProg)
1401 return -1;
Brian5b01c5e2006-12-19 18:02:03 -07001402
Brian Paule06565b2008-07-04 09:58:55 -06001403 if (shProg->LinkStatus == GL_FALSE) {
1404 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
1405 return -1;
1406 }
1407
Brian Paul530df582008-07-03 16:21:11 -06001408 /* XXX we should return -1 if the uniform was declared, but not
1409 * actually used.
1410 */
1411
Brian Pauleda291e2008-08-06 16:26:47 -06001412 /* XXX we need to be able to parse uniform names for structs and arrays
1413 * such as:
1414 * mymatrix[1]
1415 * mystruct.field1
1416 */
1417
1418 {
1419 /* handle 1-dimension arrays here... */
1420 char *c = strchr(name, '[');
1421 if (c) {
1422 /* truncate name at [ */
1423 const GLint len = c - name;
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -05001424 GLchar *newName = malloc(len + 1);
Brian Pauleda291e2008-08-06 16:26:47 -06001425 if (!newName)
1426 return -1; /* out of mem */
Kenneth Graunkec7ac48622010-02-18 23:50:59 -08001427 memcpy(newName, name, len);
Brian Pauleda291e2008-08-06 16:26:47 -06001428 newName[len] = 0;
1429
1430 location = _mesa_lookup_uniform(shProg->Uniforms, newName);
1431 if (location >= 0) {
Kenneth Graunke60b0cae2010-02-18 23:50:58 -08001432 const GLint element = atoi(c + 1);
Brian Pauleda291e2008-08-06 16:26:47 -06001433 if (element > 0) {
1434 /* get type of the uniform array element */
1435 struct gl_program_parameter *p;
1436 p = get_uniform_parameter(shProg, location);
1437 if (p) {
1438 GLint rows, cols;
1439 get_matrix_dims(p->DataType, &rows, &cols);
1440 if (rows < 1)
1441 rows = 1;
1442 offset = element * rows;
1443 }
1444 }
1445 }
1446
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -05001447 free(newName);
Brian Pauleda291e2008-08-06 16:26:47 -06001448 }
1449 }
1450
1451 if (location < 0) {
1452 location = _mesa_lookup_uniform(shProg->Uniforms, name);
1453 }
1454
1455 if (location >= 0) {
1456 merge_location_offset(&location, offset);
1457 }
1458
1459 return location;
Brian5b01c5e2006-12-19 18:02:03 -07001460}
1461
1462
Brian34ae99d2006-12-18 08:28:54 -07001463
Brian5b01c5e2006-12-19 18:02:03 -07001464/**
1465 * Called via ctx->Driver.ShaderSource()
1466 */
Brian Paulfd59f192008-05-18 16:04:55 -06001467static void
Brian5b01c5e2006-12-19 18:02:03 -07001468_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -07001469{
Brian Paul530df582008-07-03 16:21:11 -06001470 struct gl_shader *sh;
1471
1472 sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource");
1473 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001474 return;
Brian34ae99d2006-12-18 08:28:54 -07001475
Brian34ae99d2006-12-18 08:28:54 -07001476 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -07001477 if (sh->Source) {
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -05001478 free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -07001479 }
Brian65a18442006-12-19 18:46:56 -07001480 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -07001481 sh->CompileStatus = GL_FALSE;
Brian Paulf7783ba2009-08-04 15:35:48 -06001482#ifdef DEBUG
1483 sh->SourceChecksum = _mesa_str_checksum(sh->Source);
1484#endif
Brian34ae99d2006-12-18 08:28:54 -07001485}
1486
1487
Brian5b01c5e2006-12-19 18:02:03 -07001488/**
1489 * Called via ctx->Driver.CompileShader()
1490 */
Brian Paulfd59f192008-05-18 16:04:55 -06001491static void
Brian5b01c5e2006-12-19 18:02:03 -07001492_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -07001493{
Brian Paul530df582008-07-03 16:21:11 -06001494 struct gl_shader *sh;
Brian34ae99d2006-12-18 08:28:54 -07001495
Brian Paul530df582008-07-03 16:21:11 -06001496 sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader");
1497 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001498 return;
Brian34ae99d2006-12-18 08:28:54 -07001499
Brian Paul65fc2ca2009-03-19 10:25:24 -06001500 /* set default pragma state for shader */
1501 sh->Pragmas = ctx->Shader.DefaultPragmas;
1502
Brian Paulcb136e02009-01-22 10:34:15 -07001503 /* this call will set the sh->CompileStatus field to indicate if
1504 * compilation was successful.
1505 */
1506 (void) _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -07001507}
1508
1509
Brian5b01c5e2006-12-19 18:02:03 -07001510/**
1511 * Called via ctx->Driver.LinkProgram()
1512 */
Brian Paulfd59f192008-05-18 16:04:55 -06001513static void
Brian5b01c5e2006-12-19 18:02:03 -07001514_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001515{
Brian65a18442006-12-19 18:46:56 -07001516 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001517
Brian Paul530df582008-07-03 16:21:11 -06001518 shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
1519 if (!shProg)
Brian34ae99d2006-12-18 08:28:54 -07001520 return;
Brian34ae99d2006-12-18 08:28:54 -07001521
Briandf43fb62008-05-06 23:08:51 -06001522 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1523
Brianc1771912007-02-16 09:56:19 -07001524 _slang_link(ctx, program, shProg);
Brian Paulac3c8e32009-09-14 17:32:03 -06001525
1526 /* debug code */
1527 if (0) {
1528 GLuint i;
1529
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001530 printf("Link %u shaders in program %u: %s\n",
Brian Paulac3c8e32009-09-14 17:32:03 -06001531 shProg->NumShaders, shProg->Name,
1532 shProg->LinkStatus ? "Success" : "Failed");
1533
1534 for (i = 0; i < shProg->NumShaders; i++) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001535 printf(" shader %u, type 0x%x\n",
Brian Paulac3c8e32009-09-14 17:32:03 -06001536 shProg->Shaders[i]->Name,
1537 shProg->Shaders[i]->Type);
1538 }
1539 }
Brian34ae99d2006-12-18 08:28:54 -07001540}
1541
1542
1543/**
Brian Paul346250b2009-10-23 16:31:48 -06001544 * Print basic shader info (for debug).
1545 */
1546static void
1547print_shader_info(const struct gl_shader_program *shProg)
1548{
1549 GLuint i;
1550
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001551 printf("Mesa: glUseProgram(%u)\n", shProg->Name);
Brian Paul346250b2009-10-23 16:31:48 -06001552 for (i = 0; i < shProg->NumShaders; i++) {
1553 const char *s;
1554 switch (shProg->Shaders[i]->Type) {
1555 case GL_VERTEX_SHADER:
1556 s = "vertex";
1557 break;
1558 case GL_FRAGMENT_SHADER:
1559 s = "fragment";
1560 break;
1561 case GL_GEOMETRY_SHADER:
1562 s = "geometry";
1563 break;
1564 default:
1565 s = "";
1566 }
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001567 printf(" %s shader %u, checksum %u\n", s,
1568 shProg->Shaders[i]->Name,
1569 shProg->Shaders[i]->SourceChecksum);
Brian Paul346250b2009-10-23 16:31:48 -06001570 }
1571 if (shProg->VertexProgram)
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001572 printf(" vert prog %u\n", shProg->VertexProgram->Base.Id);
Brian Paul346250b2009-10-23 16:31:48 -06001573 if (shProg->FragmentProgram)
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001574 printf(" frag prog %u\n", shProg->FragmentProgram->Base.Id);
Brian Paul346250b2009-10-23 16:31:48 -06001575}
1576
1577
1578/**
Brian5b01c5e2006-12-19 18:02:03 -07001579 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001580 */
Brian5b01c5e2006-12-19 18:02:03 -07001581void
1582_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001583{
Brian3c008a02007-04-12 15:22:32 -06001584 struct gl_shader_program *shProg;
1585
Brian00d63aa2007-02-03 11:35:02 -07001586 if (ctx->Shader.CurrentProgram &&
1587 ctx->Shader.CurrentProgram->Name == program) {
1588 /* no-op */
1589 return;
1590 }
1591
Brian5b01c5e2006-12-19 18:02:03 -07001592 if (program) {
Brian Paul530df582008-07-03 16:21:11 -06001593 shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
Brian65a18442006-12-19 18:46:56 -07001594 if (!shProg) {
Brian Paul530df582008-07-03 16:21:11 -06001595 return;
1596 }
1597 if (!shProg->LinkStatus) {
Brian Paul621c9992009-02-18 13:28:12 -07001598 _mesa_error(ctx, GL_INVALID_OPERATION,
1599 "glUseProgram(program %u not linked)", program);
Brian5b01c5e2006-12-19 18:02:03 -07001600 return;
1601 }
Brian Paul4eda17d2009-03-13 09:11:42 -06001602
1603 /* debug code */
Brian Paul2ee7fd82009-10-15 15:25:52 -06001604 if (ctx->Shader.Flags & GLSL_USE_PROG) {
Brian Paul346250b2009-10-23 16:31:48 -06001605 print_shader_info(shProg);
Brian Paul4eda17d2009-03-13 09:11:42 -06001606 }
Brian5b01c5e2006-12-19 18:02:03 -07001607 }
1608 else {
Brian3c008a02007-04-12 15:22:32 -06001609 shProg = NULL;
1610 }
1611
Brian Paulb44304e2009-10-27 20:09:33 -06001612 if (ctx->Shader.CurrentProgram != shProg) {
1613 FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
1614 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
1615 }
Brian5b01c5e2006-12-19 18:02:03 -07001616}
Brian34ae99d2006-12-18 08:28:54 -07001617
Brian5b01c5e2006-12-19 18:02:03 -07001618
Brian Paulade50832008-05-14 16:09:46 -06001619
1620/**
Brian Paul517401a2008-11-06 15:04:11 -07001621 * Update the vertex/fragment program's TexturesUsed array.
1622 *
1623 * This needs to be called after glUniform(set sampler var) is called.
1624 * A call to glUniform(samplerVar, value) causes a sampler to point to a
1625 * particular texture unit. We know the sampler's texture target
1626 * (1D/2D/3D/etc) from compile time but the sampler's texture unit is
1627 * set by glUniform() calls.
1628 *
1629 * So, scan the program->SamplerUnits[] and program->SamplerTargets[]
1630 * information to update the prog->TexturesUsed[] values.
1631 * Each value of TexturesUsed[unit] is one of zero, TEXTURE_1D_INDEX,
1632 * TEXTURE_2D_INDEX, TEXTURE_3D_INDEX, etc.
1633 * We'll use that info for state validation before rendering.
Brian Paulade50832008-05-14 16:09:46 -06001634 */
Brian Paul517401a2008-11-06 15:04:11 -07001635void
1636_mesa_update_shader_textures_used(struct gl_program *prog)
Brian Paulade50832008-05-14 16:09:46 -06001637{
1638 GLuint s;
1639
1640 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1641
1642 for (s = 0; s < MAX_SAMPLERS; s++) {
1643 if (prog->SamplersUsed & (1 << s)) {
Brian Paulf05344f2009-08-26 10:58:06 -06001644 GLuint unit = prog->SamplerUnits[s];
1645 GLuint tgt = prog->SamplerTargets[s];
1646 assert(unit < MAX_TEXTURE_IMAGE_UNITS);
1647 assert(tgt < NUM_TEXTURE_TARGETS);
1648 prog->TexturesUsed[unit] |= (1 << tgt);
Brian Paulade50832008-05-14 16:09:46 -06001649 }
1650 }
1651}
1652
1653
1654/**
Brian Paulffbc66b2008-07-21 13:58:50 -06001655 * Check if the type given by userType is allowed to set a uniform of the
1656 * target type. Generally, equivalence is required, but setting Boolean
1657 * uniforms can be done with glUniformiv or glUniformfv.
1658 */
1659static GLboolean
1660compatible_types(GLenum userType, GLenum targetType)
1661{
1662 if (userType == targetType)
1663 return GL_TRUE;
1664
1665 if (targetType == GL_BOOL && (userType == GL_FLOAT || userType == GL_INT))
1666 return GL_TRUE;
1667
1668 if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 ||
1669 userType == GL_INT_VEC2))
1670 return GL_TRUE;
1671
1672 if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 ||
1673 userType == GL_INT_VEC3))
1674 return GL_TRUE;
1675
1676 if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 ||
1677 userType == GL_INT_VEC4))
1678 return GL_TRUE;
1679
Brianb36749d2008-07-21 20:42:05 -06001680 if (is_sampler_type(targetType) && userType == GL_INT)
1681 return GL_TRUE;
1682
Brian Paulffbc66b2008-07-21 13:58:50 -06001683 return GL_FALSE;
1684}
1685
1686
1687/**
Brian Paulade50832008-05-14 16:09:46 -06001688 * Set the value of a program's uniform variable.
1689 * \param program the program whose uniform to update
Brian Pauleda291e2008-08-06 16:26:47 -06001690 * \param index the index of the program parameter for the uniform
1691 * \param offset additional parameter slot offset (for arrays)
Brian Paulc4ffbf02009-02-18 17:46:00 -07001692 * \param type the incoming datatype of 'values'
Brian Paulade50832008-05-14 16:09:46 -06001693 * \param count the number of uniforms to set
Brian Paulc4ffbf02009-02-18 17:46:00 -07001694 * \param elems number of elements per uniform (1, 2, 3 or 4)
1695 * \param values the new values, of datatype 'type'
Brian Paulade50832008-05-14 16:09:46 -06001696 */
1697static void
Brian Pauleda291e2008-08-06 16:26:47 -06001698set_program_uniform(GLcontext *ctx, struct gl_program *program,
1699 GLint index, GLint offset,
1700 GLenum type, GLsizei count, GLint elems,
1701 const void *values)
Brian Paulade50832008-05-14 16:09:46 -06001702{
Brian Paul6df38e62009-08-26 14:35:45 -06001703 const struct gl_program_parameter *param =
Brian Paul949e7382008-11-05 09:17:55 -07001704 &program->Parameters->Parameters[index];
1705
Brian Pauleda291e2008-08-06 16:26:47 -06001706 assert(offset >= 0);
Brian Paulc4ffbf02009-02-18 17:46:00 -07001707 assert(elems >= 1);
1708 assert(elems <= 4);
Brian Pauleda291e2008-08-06 16:26:47 -06001709
Brian Paul949e7382008-11-05 09:17:55 -07001710 if (!compatible_types(type, param->DataType)) {
Brian Paulffbc66b2008-07-21 13:58:50 -06001711 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
1712 return;
1713 }
1714
Michal Krolc5c71302008-08-07 16:23:15 +02001715 if (index + offset > (GLint) program->Parameters->Size) {
Brian Pauleda291e2008-08-06 16:26:47 -06001716 /* out of bounds! */
1717 return;
1718 }
1719
Brian Paul949e7382008-11-05 09:17:55 -07001720 if (param->Type == PROGRAM_SAMPLER) {
Brian Paulade50832008-05-14 16:09:46 -06001721 /* This controls which texture unit which is used by a sampler */
Brian Paulbabb5ba2009-08-26 14:29:50 -06001722 GLboolean changed = GL_FALSE;
Brian Paul2b4f0212009-02-11 09:12:34 -07001723 GLint i;
Brian Paulade50832008-05-14 16:09:46 -06001724
Brian Paul6df38e62009-08-26 14:35:45 -06001725 /* this should have been caught by the compatible_types() check */
1726 ASSERT(type == GL_INT);
Brian Paulade50832008-05-14 16:09:46 -06001727
Brian Paul6df38e62009-08-26 14:35:45 -06001728 /* loop over number of samplers to change */
Brian Paul2b4f0212009-02-11 09:12:34 -07001729 for (i = 0; i < count; i++) {
Brian Paul04d17072009-08-26 11:39:24 -06001730 GLuint sampler =
1731 (GLuint) program->Parameters->ParameterValues[index + offset + i][0];
1732 GLuint texUnit = ((GLuint *) values)[i];
Brian Paulade50832008-05-14 16:09:46 -06001733
Brian Paul2b4f0212009-02-11 09:12:34 -07001734 /* check that the sampler (tex unit index) is legal */
1735 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1736 _mesa_error(ctx, GL_INVALID_VALUE,
1737 "glUniform1(invalid sampler/tex unit index)");
1738 return;
1739 }
1740
1741 /* This maps a sampler to a texture unit: */
1742 if (sampler < MAX_SAMPLERS) {
Brian Paul04d17072009-08-26 11:39:24 -06001743#if 0
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001744 printf("Set program %p sampler %d '%s' to unit %u\n",
1745 program, sampler, param->Name, texUnit);
Brian Paul04d17072009-08-26 11:39:24 -06001746#endif
Brian Paulbabb5ba2009-08-26 14:29:50 -06001747 if (program->SamplerUnits[sampler] != texUnit) {
1748 program->SamplerUnits[sampler] = texUnit;
1749 changed = GL_TRUE;
1750 }
Brian Paul2b4f0212009-02-11 09:12:34 -07001751 }
Brian Paulade50832008-05-14 16:09:46 -06001752 }
1753
Brian Paulbabb5ba2009-08-26 14:29:50 -06001754 if (changed) {
1755 /* When a sampler's value changes it usually requires rewriting
1756 * a GPU program's TEX instructions since there may not be a
1757 * sampler->texture lookup table. We signal this with the
1758 * ProgramStringNotify() callback.
1759 */
1760 FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM);
1761 _mesa_update_shader_textures_used(program);
Brian Paul4ac9c802010-02-04 16:49:35 -07001762 /* Do we need to care about the return value here?
1763 * This should not be the first time the driver was notified of
1764 * this program.
1765 */
1766 (void) ctx->Driver.ProgramStringNotify(ctx, program->Target, program);
Brian Paulbabb5ba2009-08-26 14:29:50 -06001767 }
Brian Paulade50832008-05-14 16:09:46 -06001768 }
1769 else {
1770 /* ordinary uniform variable */
Brian Paul6df38e62009-08-26 14:35:45 -06001771 const GLboolean isUniformBool = is_boolean_type(param->DataType);
1772 const GLboolean areIntValues = is_integer_type(type);
Brian Paul2c1ea072009-02-11 08:46:21 -07001773 const GLint slots = (param->Size + 3) / 4;
1774 const GLint typeSize = sizeof_glsl_type(param->DataType);
Brian Paul6df38e62009-08-26 14:35:45 -06001775 GLsizei k, i;
Brian Paulade50832008-05-14 16:09:46 -06001776
Brian Paul20fbb242010-01-27 17:03:04 -07001777 if ((GLint) param->Size > typeSize) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001778 /* an array */
1779 /* we'll ignore extra data below */
1780 }
1781 else {
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001782 /* non-array: count must be at most one; count == 0 is handled by the loop below */
1783 if (count > 1) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001784 _mesa_error(ctx, GL_INVALID_OPERATION,
1785 "glUniform(uniform is not an array)");
1786 return;
1787 }
Brian Paulade50832008-05-14 16:09:46 -06001788 }
1789
Brian Paulc4ffbf02009-02-18 17:46:00 -07001790 /* loop over number of array elements */
Brian Paulade50832008-05-14 16:09:46 -06001791 for (k = 0; k < count; k++) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001792 GLfloat *uniformVal;
1793
Brian Paulb9d8f712009-02-18 17:40:44 -07001794 if (offset + k >= slots) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001795 /* Extra array data is ignored */
1796 break;
1797 }
1798
Brian Paulc4ffbf02009-02-18 17:46:00 -07001799 /* uniformVal (the destination) is always float[4] */
Brian Paul2c1ea072009-02-11 08:46:21 -07001800 uniformVal = program->Parameters->ParameterValues[index + offset + k];
Brian Paulc4ffbf02009-02-18 17:46:00 -07001801
1802 if (areIntValues) {
1803 /* convert user's ints to floats */
Brian Paulade50832008-05-14 16:09:46 -06001804 const GLint *iValues = ((const GLint *) values) + k * elems;
1805 for (i = 0; i < elems; i++) {
1806 uniformVal[i] = (GLfloat) iValues[i];
1807 }
1808 }
1809 else {
1810 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1811 for (i = 0; i < elems; i++) {
1812 uniformVal[i] = fValues[i];
1813 }
1814 }
Brian Pauleda291e2008-08-06 16:26:47 -06001815
1816 /* if the uniform is bool-valued, convert to 1.0 or 0.0 */
Brian Paulc4ffbf02009-02-18 17:46:00 -07001817 if (isUniformBool) {
Brian Pauleda291e2008-08-06 16:26:47 -06001818 for (i = 0; i < elems; i++) {
Michal Krolc5c71302008-08-07 16:23:15 +02001819 uniformVal[i] = uniformVal[i] ? 1.0f : 0.0f;
Brian Pauleda291e2008-08-06 16:26:47 -06001820 }
1821 }
Brian Paulade50832008-05-14 16:09:46 -06001822 }
1823 }
1824}
1825
1826
Brian5b01c5e2006-12-19 18:02:03 -07001827/**
1828 * Called via ctx->Driver.Uniform().
1829 */
Brian Paulfd59f192008-05-18 16:04:55 -06001830static void
Brian5b01c5e2006-12-19 18:02:03 -07001831_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1832 const GLvoid *values, GLenum type)
1833{
Brian3a8e2772006-12-20 17:19:16 -07001834 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paul2d76a0d2008-11-10 12:33:17 -07001835 struct gl_uniform *uniform;
Brian Pauleda291e2008-08-06 16:26:47 -06001836 GLint elems, offset;
Brian Paule01a03d2009-02-06 10:21:36 -07001837 GLenum basicType;
Brian3a8e2772006-12-20 17:19:16 -07001838
1839 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001840 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001841 return;
1842 }
1843
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001844 if (location == -1)
1845 return; /* The standard specifies this as a no-op */
1846
Brian Paul234f03e2009-02-11 09:05:08 -07001847 if (location < -1) {
1848 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(location)");
1849 return;
1850 }
1851
Brian Pauleda291e2008-08-06 16:26:47 -06001852 split_location_offset(&location, &offset);
1853
Brian Paulade50832008-05-14 16:09:46 -06001854 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
1855 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
Brian3a8e2772006-12-20 17:19:16 -07001856 return;
1857 }
1858
Brian52363952007-03-13 16:50:24 -06001859 if (count < 0) {
1860 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1861 return;
1862 }
1863
Brian98650bd2007-03-13 16:32:48 -06001864 switch (type) {
1865 case GL_FLOAT:
Brian Paule01a03d2009-02-06 10:21:36 -07001866 basicType = GL_FLOAT;
1867 elems = 1;
1868 break;
Brian98650bd2007-03-13 16:32:48 -06001869 case GL_INT:
Brian Paule01a03d2009-02-06 10:21:36 -07001870 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001871 elems = 1;
1872 break;
1873 case GL_FLOAT_VEC2:
Brian Paule01a03d2009-02-06 10:21:36 -07001874 basicType = GL_FLOAT;
1875 elems = 2;
1876 break;
Brian98650bd2007-03-13 16:32:48 -06001877 case GL_INT_VEC2:
Brian Paule01a03d2009-02-06 10:21:36 -07001878 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001879 elems = 2;
1880 break;
1881 case GL_FLOAT_VEC3:
Brian Paule01a03d2009-02-06 10:21:36 -07001882 basicType = GL_FLOAT;
1883 elems = 3;
1884 break;
Brian98650bd2007-03-13 16:32:48 -06001885 case GL_INT_VEC3:
Brian Paule01a03d2009-02-06 10:21:36 -07001886 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001887 elems = 3;
1888 break;
1889 case GL_FLOAT_VEC4:
Brian Paule01a03d2009-02-06 10:21:36 -07001890 basicType = GL_FLOAT;
1891 elems = 4;
1892 break;
Brian98650bd2007-03-13 16:32:48 -06001893 case GL_INT_VEC4:
Brian Paule01a03d2009-02-06 10:21:36 -07001894 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001895 elems = 4;
1896 break;
1897 default:
1898 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1899 return;
Brian89dc4852007-01-04 14:35:44 -07001900 }
Brian98650bd2007-03-13 16:32:48 -06001901
Brian Paul027ed1b2009-04-24 09:43:44 -06001902 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
Brian98650bd2007-03-13 16:32:48 -06001903
Brian Paul2d76a0d2008-11-10 12:33:17 -07001904 uniform = &shProg->Uniforms->Uniforms[location];
1905
Brian Paule01a03d2009-02-06 10:21:36 -07001906 if (ctx->Shader.Flags & GLSL_UNIFORMS) {
1907 GLint i;
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001908 printf("Mesa: set program %u uniform %s (loc %d) to: ",
1909 shProg->Name, uniform->Name, location);
Brian Paule01a03d2009-02-06 10:21:36 -07001910 if (basicType == GL_INT) {
1911 const GLint *v = (const GLint *) values;
1912 for (i = 0; i < count * elems; i++) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001913 printf("%d ", v[i]);
Brian Paule01a03d2009-02-06 10:21:36 -07001914 }
1915 }
1916 else {
1917 const GLfloat *v = (const GLfloat *) values;
1918 for (i = 0; i < count * elems; i++) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001919 printf("%g ", v[i]);
Brian Paule01a03d2009-02-06 10:21:36 -07001920 }
1921 }
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001922 printf("\n");
Brian Paule01a03d2009-02-06 10:21:36 -07001923 }
1924
Brian Paulade50832008-05-14 16:09:46 -06001925 /* A uniform var may be used by both a vertex shader and a fragment
1926 * shader. We may need to update one or both shader's uniform here:
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001927 */
Brian Paulade50832008-05-14 16:09:46 -06001928 if (shProg->VertexProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001929 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07001930 GLint index = uniform->VertPos;
Brian Pauleda291e2008-08-06 16:26:47 -06001931 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001932 set_program_uniform(ctx, &shProg->VertexProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001933 index, offset, type, count, elems, values);
Bruce Merry2bf2a8c2007-12-21 23:18:40 +02001934 }
Brian5b01c5e2006-12-19 18:02:03 -07001935 }
Brian5cf73262007-01-05 16:02:45 -07001936
Brian Paulade50832008-05-14 16:09:46 -06001937 if (shProg->FragmentProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001938 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07001939 GLint index = uniform->FragPos;
Brian Pauleda291e2008-08-06 16:26:47 -06001940 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001941 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001942 index, offset, type, count, elems, values);
Brian Paulade50832008-05-14 16:09:46 -06001943 }
1944 }
Brian Paul949e7382008-11-05 09:17:55 -07001945
Brian Paul2d76a0d2008-11-10 12:33:17 -07001946 uniform->Initialized = GL_TRUE;
Brian Paulade50832008-05-14 16:09:46 -06001947}
1948
1949
Brian Pauleda291e2008-08-06 16:26:47 -06001950/**
1951 * Set a matrix-valued program parameter.
1952 */
Brian Paulade50832008-05-14 16:09:46 -06001953static void
1954set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
Brian Pauleda291e2008-08-06 16:26:47 -06001955 GLuint index, GLuint offset,
1956 GLuint count, GLuint rows, GLuint cols,
Brian Paulade50832008-05-14 16:09:46 -06001957 GLboolean transpose, const GLfloat *values)
1958{
Brian Paulffbc66b2008-07-21 13:58:50 -06001959 GLuint mat, row, col;
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001960 GLuint src = 0;
1961 const struct gl_program_parameter * param = &program->Parameters->Parameters[index];
Brian Paul20fbb242010-01-27 17:03:04 -07001962 const GLuint slots = (param->Size + 3) / 4;
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001963 const GLint typeSize = sizeof_glsl_type(param->DataType);
Brian Paulffbc66b2008-07-21 13:58:50 -06001964 GLint nr, nc;
1965
1966 /* check that the number of rows, columns is correct */
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001967 get_matrix_dims(param->DataType, &nr, &nc);
Brian Paulffbc66b2008-07-21 13:58:50 -06001968 if (rows != nr || cols != nc) {
1969 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Pauleda291e2008-08-06 16:26:47 -06001970 "glUniformMatrix(matrix size mismatch)");
1971 return;
1972 }
1973
Brian Paul20fbb242010-01-27 17:03:04 -07001974 if ((GLint) param->Size <= typeSize) {
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001975 /* non-array: count must be at most one; count == 0 is handled by the loop below */
1976 if (count > 1) {
1977 _mesa_error(ctx, GL_INVALID_OPERATION,
1978 "glUniformMatrix(uniform is not an array)");
1979 return;
1980 }
Brian Paulffbc66b2008-07-21 13:58:50 -06001981 }
1982
Brian Paulade50832008-05-14 16:09:46 -06001983 /*
1984 * Note: the _columns_ of a matrix are stored in program registers, not
Brian Paulf45ed0e2008-07-18 12:51:39 -06001985 * the rows. So, the loops below look a little funny.
1986 * XXX could optimize this a bit...
Brian Paulade50832008-05-14 16:09:46 -06001987 */
Brian Paulf45ed0e2008-07-18 12:51:39 -06001988
1989 /* loop over matrices */
1990 for (mat = 0; mat < count; mat++) {
1991
1992 /* each matrix: */
Brian Paulade50832008-05-14 16:09:46 -06001993 for (col = 0; col < cols; col++) {
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001994 GLfloat *v;
1995 if (offset >= slots) {
1996 /* Ignore writes beyond the end of (the used part of) an array */
1997 return;
1998 }
1999 v = program->Parameters->ParameterValues[index + offset];
Brian Paulade50832008-05-14 16:09:46 -06002000 for (row = 0; row < rows; row++) {
Brian Paulf45ed0e2008-07-18 12:51:39 -06002001 if (transpose) {
2002 v[row] = values[src + row * cols + col];
2003 }
2004 else {
2005 v[row] = values[src + col * rows + row];
2006 }
Brian Paulade50832008-05-14 16:09:46 -06002007 }
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02002008
2009 offset++;
Brian Paulade50832008-05-14 16:09:46 -06002010 }
Brian Paulf45ed0e2008-07-18 12:51:39 -06002011
2012 src += rows * cols; /* next matrix */
Brian5cf73262007-01-05 16:02:45 -07002013 }
Brian34ae99d2006-12-18 08:28:54 -07002014}
2015
2016
2017/**
Brian5b01c5e2006-12-19 18:02:03 -07002018 * Called by ctx->Driver.UniformMatrix().
Brian Paulf45ed0e2008-07-18 12:51:39 -06002019 * Note: cols=2, rows=4 ==> array[2] of vec4
Brian34ae99d2006-12-18 08:28:54 -07002020 */
Brian Paulfd59f192008-05-18 16:04:55 -06002021static void
Brian5b01c5e2006-12-19 18:02:03 -07002022_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
Brian Paul0115a4f2009-04-14 20:00:28 -06002023 GLint location, GLsizei count,
Brian5b01c5e2006-12-19 18:02:03 -07002024 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07002025{
Brian3a8e2772006-12-20 17:19:16 -07002026 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paul2d76a0d2008-11-10 12:33:17 -07002027 struct gl_uniform *uniform;
2028 GLint offset;
Brian Paulade50832008-05-14 16:09:46 -06002029
Brian3a8e2772006-12-20 17:19:16 -07002030 if (!shProg || !shProg->LinkStatus) {
2031 _mesa_error(ctx, GL_INVALID_OPERATION,
2032 "glUniformMatrix(program not linked)");
2033 return;
2034 }
Brian Paulade50832008-05-14 16:09:46 -06002035
Bruce Merry89b80322007-12-21 15:20:17 +02002036 if (location == -1)
2037 return; /* The standard specifies this as a no-op */
Brian Paulade50832008-05-14 16:09:46 -06002038
Brian Paul234f03e2009-02-11 09:05:08 -07002039 if (location < -1) {
2040 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(location)");
2041 return;
2042 }
2043
Brian Pauleda291e2008-08-06 16:26:47 -06002044 split_location_offset(&location, &offset);
2045
Brian Paul016701f2008-07-29 17:43:35 -06002046 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian Paulade50832008-05-14 16:09:46 -06002047 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
Brian3a8e2772006-12-20 17:19:16 -07002048 return;
2049 }
Brian34ae99d2006-12-18 08:28:54 -07002050 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07002051 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07002052 return;
2053 }
2054
Brian Paul027ed1b2009-04-24 09:43:44 -06002055 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
Brian34ae99d2006-12-18 08:28:54 -07002056
Brian Paul2d76a0d2008-11-10 12:33:17 -07002057 uniform = &shProg->Uniforms->Uniforms[location];
2058
Brian Paulade50832008-05-14 16:09:46 -06002059 if (shProg->VertexProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06002060 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07002061 GLint index = uniform->VertPos;
Brian Pauleda291e2008-08-06 16:26:47 -06002062 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06002063 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06002064 index, offset,
2065 count, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07002066 }
Brian Paulade50832008-05-14 16:09:46 -06002067 }
2068
2069 if (shProg->FragmentProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06002070 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07002071 GLint index = uniform->FragPos;
Brian Pauleda291e2008-08-06 16:26:47 -06002072 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06002073 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06002074 index, offset,
2075 count, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07002076 }
Brian34ae99d2006-12-18 08:28:54 -07002077 }
Brian Paul949e7382008-11-05 09:17:55 -07002078
Brian Paul2d76a0d2008-11-10 12:33:17 -07002079 uniform->Initialized = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07002080}
2081
2082
Brian Paulc90fca32009-08-25 17:42:47 -06002083/**
2084 * Validate a program's samplers.
2085 * Specifically, check that there aren't two samplers of different types
2086 * pointing to the same texture unit.
2087 * \return GL_TRUE if valid, GL_FALSE if invalid
2088 */
2089static GLboolean
2090validate_samplers(GLcontext *ctx, const struct gl_program *prog, char *errMsg)
Brian34ae99d2006-12-18 08:28:54 -07002091{
Brian Paulc90fca32009-08-25 17:42:47 -06002092 static const char *targetName[] = {
2093 "TEXTURE_2D_ARRAY",
2094 "TEXTURE_1D_ARRAY",
2095 "TEXTURE_CUBE",
2096 "TEXTURE_3D",
2097 "TEXTURE_RECT",
2098 "TEXTURE_2D",
2099 "TEXTURE_1D",
2100 };
2101 GLint targetUsed[MAX_TEXTURE_IMAGE_UNITS];
2102 GLbitfield samplersUsed = prog->SamplersUsed;
2103 GLuint i;
Brian Paulbc985b52008-07-21 14:16:07 -06002104
Brian Paulc90fca32009-08-25 17:42:47 -06002105 assert(Elements(targetName) == NUM_TEXTURE_TARGETS);
2106
2107 if (samplersUsed == 0x0)
2108 return GL_TRUE;
2109
2110 for (i = 0; i < Elements(targetUsed); i++)
2111 targetUsed[i] = -1;
2112
2113 /* walk over bits which are set in 'samplers' */
2114 while (samplersUsed) {
2115 GLuint unit;
2116 gl_texture_index target;
2117 GLint sampler = _mesa_ffs(samplersUsed) - 1;
2118 assert(sampler >= 0);
2119 assert(sampler < MAX_TEXTURE_IMAGE_UNITS);
2120 unit = prog->SamplerUnits[sampler];
2121 target = prog->SamplerTargets[sampler];
2122 if (targetUsed[unit] != -1 && targetUsed[unit] != target) {
Brian Paul78a0c352010-02-19 12:56:49 -07002123 _mesa_snprintf(errMsg, 100,
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002124 "Texture unit %d is accessed both as %s and %s",
2125 unit, targetName[targetUsed[unit]], targetName[target]);
Brian Paulc90fca32009-08-25 17:42:47 -06002126 return GL_FALSE;
2127 }
2128 targetUsed[unit] = target;
2129 samplersUsed ^= (1 << sampler);
Brian34ae99d2006-12-18 08:28:54 -07002130 }
2131
Brian Paulc90fca32009-08-25 17:42:47 -06002132 return GL_TRUE;
2133}
2134
2135
2136/**
2137 * Do validation of the given shader program.
2138 * \param errMsg returns error message if validation fails.
2139 * \return GL_TRUE if valid, GL_FALSE if invalid (and set errMsg)
2140 */
2141GLboolean
2142_mesa_validate_shader_program(GLcontext *ctx,
2143 const struct gl_shader_program *shProg,
2144 char *errMsg)
2145{
2146 const struct gl_vertex_program *vp = shProg->VertexProgram;
2147 const struct gl_fragment_program *fp = shProg->FragmentProgram;
2148
Brian Paulbc985b52008-07-21 14:16:07 -06002149 if (!shProg->LinkStatus) {
Brian Paulc90fca32009-08-25 17:42:47 -06002150 return GL_FALSE;
Brian Paulbc985b52008-07-21 14:16:07 -06002151 }
2152
2153 /* From the GL spec, a program is invalid if any of these are true:
2154
Brian5b01c5e2006-12-19 18:02:03 -07002155 any two active samplers in the current program object are of
2156 different types, but refer to the same texture image unit,
2157
2158 any active sampler in the current program object refers to a texture
2159 image unit where fixed-function fragment processing accesses a
2160 texture target that does not match the sampler type, or
2161
2162 the sum of the number of active samplers in the program and the
2163 number of texture image units enabled for fixed-function fragment
2164 processing exceeds the combined limit on the total number of texture
2165 image units allowed.
2166 */
Brian Paulbc985b52008-07-21 14:16:07 -06002167
Brian Paulc90fca32009-08-25 17:42:47 -06002168
2169 /*
2170 * Check: any two active samplers in the current program object are of
2171 * different types, but refer to the same texture image unit,
2172 */
2173 if (vp && !validate_samplers(ctx, &vp->Base, errMsg)) {
2174 return GL_FALSE;
2175 }
2176 if (fp && !validate_samplers(ctx, &fp->Base, errMsg)) {
2177 return GL_FALSE;
2178 }
2179
2180 return GL_TRUE;
2181}
2182
2183
2184/**
2185 * Called via glValidateProgram()
2186 */
2187static void
2188_mesa_validate_program(GLcontext *ctx, GLuint program)
2189{
2190 struct gl_shader_program *shProg;
2191 char errMsg[100];
2192
2193 shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram");
2194 if (!shProg) {
2195 return;
2196 }
2197
2198 shProg->Validated = _mesa_validate_shader_program(ctx, shProg, errMsg);
2199 if (!shProg->Validated) {
2200 /* update info log */
2201 if (shProg->InfoLog) {
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -05002202 free(shProg->InfoLog);
Brian Paulc90fca32009-08-25 17:42:47 -06002203 }
2204 shProg->InfoLog = _mesa_strdup(errMsg);
2205 }
Brian34ae99d2006-12-18 08:28:54 -07002206}
Brian Paulfd59f192008-05-18 16:04:55 -06002207
2208
2209/**
2210 * Plug in Mesa's GLSL functions into the device driver function table.
2211 */
2212void
2213_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
2214{
2215 driver->AttachShader = _mesa_attach_shader;
2216 driver->BindAttribLocation = _mesa_bind_attrib_location;
2217 driver->CompileShader = _mesa_compile_shader;
2218 driver->CreateProgram = _mesa_create_program;
2219 driver->CreateShader = _mesa_create_shader;
2220 driver->DeleteProgram2 = _mesa_delete_program2;
2221 driver->DeleteShader = _mesa_delete_shader;
2222 driver->DetachShader = _mesa_detach_shader;
2223 driver->GetActiveAttrib = _mesa_get_active_attrib;
2224 driver->GetActiveUniform = _mesa_get_active_uniform;
2225 driver->GetAttachedShaders = _mesa_get_attached_shaders;
2226 driver->GetAttribLocation = _mesa_get_attrib_location;
2227 driver->GetHandle = _mesa_get_handle;
2228 driver->GetProgramiv = _mesa_get_programiv;
2229 driver->GetProgramInfoLog = _mesa_get_program_info_log;
2230 driver->GetShaderiv = _mesa_get_shaderiv;
2231 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
2232 driver->GetShaderSource = _mesa_get_shader_source;
2233 driver->GetUniformfv = _mesa_get_uniformfv;
Brian Paul2be54a82008-07-08 16:17:04 -06002234 driver->GetUniformiv = _mesa_get_uniformiv;
Brian Paulfd59f192008-05-18 16:04:55 -06002235 driver->GetUniformLocation = _mesa_get_uniform_location;
2236 driver->IsProgram = _mesa_is_program;
2237 driver->IsShader = _mesa_is_shader;
2238 driver->LinkProgram = _mesa_link_program;
2239 driver->ShaderSource = _mesa_shader_source;
2240 driver->Uniform = _mesa_uniform;
2241 driver->UniformMatrix = _mesa_uniform_matrix;
2242 driver->UseProgram = _mesa_use_program;
2243 driver->ValidateProgram = _mesa_validate_program;
2244}