blob: f47f213ac8467a72c6ee338dfe8b80009f6eb031 [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:
811 case GL_BOOL_VEC2:
812 return 2;
813 case GL_FLOAT_VEC3:
814 case GL_INT_VEC3:
815 case GL_BOOL_VEC3:
816 return 3;
817 case GL_FLOAT_VEC4:
818 case GL_INT_VEC4:
819 case GL_BOOL_VEC4:
820 return 4;
821 case GL_FLOAT_MAT2:
822 case GL_FLOAT_MAT2x3:
823 case GL_FLOAT_MAT2x4:
824 return 8; /* two float[4] vectors */
825 case GL_FLOAT_MAT3:
826 case GL_FLOAT_MAT3x2:
827 case GL_FLOAT_MAT3x4:
828 return 12; /* three float[4] vectors */
829 case GL_FLOAT_MAT4:
830 case GL_FLOAT_MAT4x2:
831 case GL_FLOAT_MAT4x3:
832 return 16; /* four float[4] vectors */
833 default:
Brian Paul1a148662010-04-01 22:15:16 -0600834 _mesa_problem(NULL, "Invalid type in _mesa_sizeof_glsl_type()");
Brian Paulffbc66b2008-07-21 13:58:50 -0600835 return 1;
836 }
837}
838
839
Brian Pauleda291e2008-08-06 16:26:47 -0600840static GLboolean
841is_boolean_type(GLenum type)
842{
843 switch (type) {
844 case GL_BOOL:
845 case GL_BOOL_VEC2:
846 case GL_BOOL_VEC3:
847 case GL_BOOL_VEC4:
848 return GL_TRUE;
849 default:
850 return GL_FALSE;
851 }
852}
853
854
855static GLboolean
856is_integer_type(GLenum type)
857{
858 switch (type) {
859 case GL_INT:
860 case GL_INT_VEC2:
861 case GL_INT_VEC3:
862 case GL_INT_VEC4:
863 return GL_TRUE;
864 default:
865 return GL_FALSE;
866 }
867}
868
869
Brian Paulc4ffbf02009-02-18 17:46:00 -0700870static GLboolean
871is_sampler_type(GLenum type)
872{
873 switch (type) {
874 case GL_SAMPLER_1D:
875 case GL_SAMPLER_2D:
876 case GL_SAMPLER_3D:
877 case GL_SAMPLER_CUBE:
878 case GL_SAMPLER_1D_SHADOW:
879 case GL_SAMPLER_2D_SHADOW:
880 case GL_SAMPLER_2D_RECT_ARB:
881 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
882 case GL_SAMPLER_1D_ARRAY_EXT:
883 case GL_SAMPLER_2D_ARRAY_EXT:
Brian Paulac498f22010-02-25 19:05:11 -0700884 case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
885 case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
Brian Paulc4ffbf02009-02-18 17:46:00 -0700886 return GL_TRUE;
887 default:
888 return GL_FALSE;
889 }
890}
891
892
Brian Paulfd59f192008-05-18 16:04:55 -0600893static void
Brian5b01c5e2006-12-19 18:02:03 -0700894_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
895 GLsizei maxLength, GLsizei *length, GLint *size,
896 GLenum *type, GLchar *nameOut)
897{
Brian Paul27341a92008-09-16 16:28:36 -0600898 const struct gl_program_parameter_list *attribs = NULL;
Brian Paul530df582008-07-03 16:21:11 -0600899 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700900
Brian Paul530df582008-07-03 16:21:11 -0600901 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
902 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700903 return;
Brian5b01c5e2006-12-19 18:02:03 -0700904
Brian Paul27341a92008-09-16 16:28:36 -0600905 if (shProg->VertexProgram)
906 attribs = shProg->VertexProgram->Base.Attributes;
907
908 if (!attribs || index >= attribs->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600909 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700910 return;
911 }
912
Brian Paule5c69642010-03-30 19:54:02 -0600913 _mesa_copy_string(nameOut, maxLength, length,
914 attribs->Parameters[index].Name);
Brian Paul27341a92008-09-16 16:28:36 -0600915
Brian5b01c5e2006-12-19 18:02:03 -0700916 if (size)
Brian Paul27341a92008-09-16 16:28:36 -0600917 *size = attribs->Parameters[index].Size
Brian Paul1a148662010-04-01 22:15:16 -0600918 / _mesa_sizeof_glsl_type(attribs->Parameters[index].DataType);
Brian Paul27341a92008-09-16 16:28:36 -0600919
Brian Paulade50832008-05-14 16:09:46 -0600920 if (type)
Brian Paul27341a92008-09-16 16:28:36 -0600921 *type = attribs->Parameters[index].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700922}
923
924
Brian Pauleda291e2008-08-06 16:26:47 -0600925static struct gl_program_parameter *
926get_uniform_parameter(const struct gl_shader_program *shProg, GLuint index)
927{
Brian Paula531a5c2009-08-13 13:44:01 -0600928 const struct gl_program *prog = NULL;
Brian Pauleda291e2008-08-06 16:26:47 -0600929 GLint progPos;
930
931 progPos = shProg->Uniforms->Uniforms[index].VertPos;
932 if (progPos >= 0) {
933 prog = &shProg->VertexProgram->Base;
934 }
935 else {
936 progPos = shProg->Uniforms->Uniforms[index].FragPos;
937 if (progPos >= 0) {
938 prog = &shProg->FragmentProgram->Base;
939 }
940 }
941
942 if (!prog || progPos < 0)
943 return NULL; /* should never happen */
944
945 return &prog->Parameters->Parameters[progPos];
946}
947
948
Brian5b01c5e2006-12-19 18:02:03 -0700949/**
950 * Called via ctx->Driver.GetActiveUniform().
951 */
Brian Paulfd59f192008-05-18 16:04:55 -0600952static void
Brian5b01c5e2006-12-19 18:02:03 -0700953_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
954 GLsizei maxLength, GLsizei *length, GLint *size,
955 GLenum *type, GLchar *nameOut)
956{
Brian Paul530df582008-07-03 16:21:11 -0600957 const struct gl_shader_program *shProg;
Brian Paula531a5c2009-08-13 13:44:01 -0600958 const struct gl_program *prog = NULL;
Brian Paul369d1852009-02-11 08:16:14 -0700959 const struct gl_program_parameter *param;
Brian Paulade50832008-05-14 16:09:46 -0600960 GLint progPos;
Brian5b01c5e2006-12-19 18:02:03 -0700961
Brian Paul530df582008-07-03 16:21:11 -0600962 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
963 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700964 return;
Brian5b01c5e2006-12-19 18:02:03 -0700965
Brian Paulade50832008-05-14 16:09:46 -0600966 if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
Brian5b01c5e2006-12-19 18:02:03 -0700967 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
968 return;
969 }
970
Brian Paulade50832008-05-14 16:09:46 -0600971 progPos = shProg->Uniforms->Uniforms[index].VertPos;
972 if (progPos >= 0) {
973 prog = &shProg->VertexProgram->Base;
974 }
975 else {
976 progPos = shProg->Uniforms->Uniforms[index].FragPos;
977 if (progPos >= 0) {
978 prog = &shProg->FragmentProgram->Base;
Brian274ac7a2007-04-18 16:05:53 -0600979 }
980 }
981
Brian Paulade50832008-05-14 16:09:46 -0600982 if (!prog || progPos < 0)
983 return; /* should never happen */
984
Brian Paul369d1852009-02-11 08:16:14 -0700985 ASSERT(progPos < prog->Parameters->NumParameters);
986 param = &prog->Parameters->Parameters[progPos];
987
988 if (nameOut) {
Brian Paule5c69642010-03-30 19:54:02 -0600989 _mesa_copy_string(nameOut, maxLength, length, param->Name);
Brian Paul369d1852009-02-11 08:16:14 -0700990 }
991
992 if (size) {
Brian Paul1a148662010-04-01 22:15:16 -0600993 GLint typeSize = _mesa_sizeof_glsl_type(param->DataType);
Brian Paul20fbb242010-01-27 17:03:04 -0700994 if ((GLint) param->Size > typeSize) {
Brian Paul369d1852009-02-11 08:16:14 -0700995 /* This is an array.
996 * Array elements are placed on vector[4] boundaries so they're
997 * a multiple of four floats. We round typeSize up to next multiple
998 * of four to get the right size below.
999 */
1000 typeSize = (typeSize + 3) & ~3;
1001 }
1002 /* Note that the returned size is in units of the <type>, not bytes */
1003 *size = param->Size / typeSize;
1004 }
1005
1006 if (type) {
1007 *type = param->DataType;
1008 }
Brian5b01c5e2006-12-19 18:02:03 -07001009}
1010
1011
1012/**
1013 * Called via ctx->Driver.GetAttachedShaders().
1014 */
Brian Paulfd59f192008-05-18 16:04:55 -06001015static void
Brian5b01c5e2006-12-19 18:02:03 -07001016_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
1017 GLsizei *count, GLuint *obj)
1018{
Brian Paul530df582008-07-03 16:21:11 -06001019 struct gl_shader_program *shProg =
1020 _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders");
Brian65a18442006-12-19 18:46:56 -07001021 if (shProg) {
Brian Paul530df582008-07-03 16:21:11 -06001022 GLuint i;
1023 for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) {
Brian65a18442006-12-19 18:46:56 -07001024 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -07001025 }
1026 if (count)
1027 *count = i;
1028 }
Brian5b01c5e2006-12-19 18:02:03 -07001029}
1030
1031
Brian Paulfd59f192008-05-18 16:04:55 -06001032static GLuint
Brian5b01c5e2006-12-19 18:02:03 -07001033_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -07001034{
Ian Romanick905d8e02008-09-29 12:27:00 -07001035 GLint handle = 0;
1036
1037 if (pname == GL_PROGRAM_OBJECT_ARB) {
1038 CALL_GetIntegerv(ctx->Exec, (GL_CURRENT_PROGRAM, &handle));
1039 } else {
Brian34ae99d2006-12-18 08:28:54 -07001040 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
1041 }
Ian Romanick905d8e02008-09-29 12:27:00 -07001042
1043 return handle;
Brian34ae99d2006-12-18 08:28:54 -07001044}
1045
1046
Brian Paulfd59f192008-05-18 16:04:55 -06001047static void
Brian5b01c5e2006-12-19 18:02:03 -07001048_mesa_get_programiv(GLcontext *ctx, GLuint program,
1049 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -07001050{
Brian Paul27341a92008-09-16 16:28:36 -06001051 const struct gl_program_parameter_list *attribs;
Brian65a18442006-12-19 18:46:56 -07001052 struct gl_shader_program *shProg
1053 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -07001054
Brian65a18442006-12-19 18:46:56 -07001055 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -07001056 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -07001057 return;
1058 }
1059
Brian Paul27341a92008-09-16 16:28:36 -06001060 if (shProg->VertexProgram)
1061 attribs = shProg->VertexProgram->Base.Attributes;
1062 else
1063 attribs = NULL;
1064
Brian5b01c5e2006-12-19 18:02:03 -07001065 switch (pname) {
1066 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -07001067 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -07001068 break;
1069 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -07001070 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -07001071 break;
Brian5b01c5e2006-12-19 18:02:03 -07001072 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -07001073 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -07001074 break;
1075 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001076 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001077 break;
1078 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -07001079 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -07001080 break;
1081 case GL_ACTIVE_ATTRIBUTES:
Brian Paul27341a92008-09-16 16:28:36 -06001082 *params = attribs ? attribs->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001083 break;
1084 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian Paul27341a92008-09-16 16:28:36 -06001085 *params = _mesa_longest_parameter_name(attribs, PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -07001086 break;
1087 case GL_ACTIVE_UNIFORMS:
Brian Paulade50832008-05-14 16:09:46 -06001088 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001089 break;
1090 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian Paulade50832008-05-14 16:09:46 -06001091 *params = _mesa_longest_uniform_name(shProg->Uniforms);
Brian274ac7a2007-04-18 16:05:53 -06001092 if (*params > 0)
1093 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -07001094 break;
Brian Paulbda6ad22008-08-06 12:45:14 -06001095 case GL_PROGRAM_BINARY_LENGTH_OES:
1096 *params = 0;
1097 break;
Brian Paule5c69642010-03-30 19:54:02 -06001098#if FEATURE_EXT_transform_feedback
1099 case GL_TRANSFORM_FEEDBACK_VARYINGS:
1100 *params = shProg->TransformFeedback.NumVarying;
1101 break;
1102 case GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH:
1103 *params = longest_feedback_varying_name(shProg) + 1;
1104 break;
1105 case GL_TRANSFORM_FEEDBACK_BUFFER_MODE:
1106 *params = shProg->TransformFeedback.BufferMode;
1107 break;
1108#endif
Brian34ae99d2006-12-18 08:28:54 -07001109 default:
Brian5b01c5e2006-12-19 18:02:03 -07001110 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
1111 return;
Brian34ae99d2006-12-18 08:28:54 -07001112 }
Brian5b01c5e2006-12-19 18:02:03 -07001113}
Brian34ae99d2006-12-18 08:28:54 -07001114
Brian34ae99d2006-12-18 08:28:54 -07001115
Brian Paulfd59f192008-05-18 16:04:55 -06001116static void
Brian5b01c5e2006-12-19 18:02:03 -07001117_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
1118{
Brian Paul530df582008-07-03 16:21:11 -06001119 struct gl_shader *shader = _mesa_lookup_shader_err(ctx, name, "glGetShaderiv");
Brian5b01c5e2006-12-19 18:02:03 -07001120
1121 if (!shader) {
Brian5b01c5e2006-12-19 18:02:03 -07001122 return;
1123 }
Brian65a18442006-12-19 18:46:56 -07001124
Brian5b01c5e2006-12-19 18:02:03 -07001125 switch (pname) {
1126 case GL_SHADER_TYPE:
1127 *params = shader->Type;
1128 break;
1129 case GL_DELETE_STATUS:
1130 *params = shader->DeletePending;
1131 break;
1132 case GL_COMPILE_STATUS:
1133 *params = shader->CompileStatus;
1134 break;
1135 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001136 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001137 break;
1138 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001139 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001140 break;
1141 default:
1142 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
1143 return;
1144 }
1145}
1146
1147
Brian Paulfd59f192008-05-18 16:04:55 -06001148static void
Brian5b01c5e2006-12-19 18:02:03 -07001149_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
1150 GLsizei *length, GLchar *infoLog)
1151{
Brian65a18442006-12-19 18:46:56 -07001152 struct gl_shader_program *shProg
1153 = _mesa_lookup_shader_program(ctx, program);
1154 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -07001155 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
1156 return;
1157 }
Brian Paule5c69642010-03-30 19:54:02 -06001158 _mesa_copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -07001159}
1160
1161
Brian Paulfd59f192008-05-18 16:04:55 -06001162static void
Brian5b01c5e2006-12-19 18:02:03 -07001163_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
1164 GLsizei *length, GLchar *infoLog)
1165{
Brian65a18442006-12-19 18:46:56 -07001166 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
1167 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001168 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
1169 return;
1170 }
Brian Paule5c69642010-03-30 19:54:02 -06001171 _mesa_copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -07001172}
1173
1174
1175/**
1176 * Called via ctx->Driver.GetShaderSource().
1177 */
Brian Paulfd59f192008-05-18 16:04:55 -06001178static void
Brian5b01c5e2006-12-19 18:02:03 -07001179_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
1180 GLsizei *length, GLchar *sourceOut)
1181{
Brian Paul530df582008-07-03 16:21:11 -06001182 struct gl_shader *sh;
1183 sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource");
Brian65a18442006-12-19 18:46:56 -07001184 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001185 return;
1186 }
Brian Paule5c69642010-03-30 19:54:02 -06001187 _mesa_copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -07001188}
1189
1190
Brian Paul5b982362008-08-06 13:07:09 -06001191static void
1192get_matrix_dims(GLenum type, GLint *rows, GLint *cols)
1193{
1194 switch (type) {
1195 case GL_FLOAT_MAT2:
1196 *rows = *cols = 2;
1197 break;
1198 case GL_FLOAT_MAT2x3:
1199 *rows = 3;
1200 *cols = 2;
1201 break;
1202 case GL_FLOAT_MAT2x4:
1203 *rows = 4;
1204 *cols = 2;
1205 break;
1206 case GL_FLOAT_MAT3:
1207 *rows = 3;
1208 *cols = 3;
1209 break;
1210 case GL_FLOAT_MAT3x2:
1211 *rows = 2;
1212 *cols = 3;
1213 break;
1214 case GL_FLOAT_MAT3x4:
1215 *rows = 4;
1216 *cols = 3;
1217 break;
1218 case GL_FLOAT_MAT4:
1219 *rows = 4;
1220 *cols = 4;
1221 break;
1222 case GL_FLOAT_MAT4x2:
1223 *rows = 2;
1224 *cols = 4;
1225 break;
1226 case GL_FLOAT_MAT4x3:
1227 *rows = 3;
1228 *cols = 4;
1229 break;
1230 default:
1231 *rows = *cols = 0;
1232 }
1233}
1234
1235
1236/**
1237 * Determine the number of rows and columns occupied by a uniform
Brian Paulea9568d2008-09-16 08:55:54 -06001238 * according to its datatype. For non-matrix types (such as GL_FLOAT_VEC4),
1239 * the number of rows = 1 and cols = number of elements in the vector.
Brian Paul5b982362008-08-06 13:07:09 -06001240 */
1241static void
1242get_uniform_rows_cols(const struct gl_program_parameter *p,
1243 GLint *rows, GLint *cols)
1244{
1245 get_matrix_dims(p->DataType, rows, cols);
1246 if (*rows == 0 && *cols == 0) {
1247 /* not a matrix type, probably a float or vector */
Brian Paulea9568d2008-09-16 08:55:54 -06001248 if (p->Size <= 4) {
1249 *rows = 1;
1250 *cols = p->Size;
1251 }
1252 else {
1253 *rows = p->Size / 4 + 1;
1254 if (p->Size % 4 == 0)
1255 *cols = 4;
1256 else
1257 *cols = p->Size % 4;
1258 }
Brian Paul5b982362008-08-06 13:07:09 -06001259 }
1260}
1261
1262
Brian5b01c5e2006-12-19 18:02:03 -07001263/**
Brian Paul4ef7a932009-02-11 09:03:16 -07001264 * Helper for get_uniform[fi]v() functions.
1265 * Given a shader program name and uniform location, return a pointer
1266 * to the shader program and return the program parameter position.
Brian5b01c5e2006-12-19 18:02:03 -07001267 */
Brian Paul4ef7a932009-02-11 09:03:16 -07001268static void
1269lookup_uniform_parameter(GLcontext *ctx, GLuint program, GLint location,
1270 struct gl_program **progOut, GLint *paramPosOut)
Brian5b01c5e2006-12-19 18:02:03 -07001271{
Brian65a18442006-12-19 18:46:56 -07001272 struct gl_shader_program *shProg
Brian Paulbda6ad22008-08-06 12:45:14 -06001273 = _mesa_lookup_shader_program_err(ctx, program, "glGetUniform[if]v");
Brian Paul4ef7a932009-02-11 09:03:16 -07001274 struct gl_program *prog = NULL;
1275 GLint progPos = -1;
Brian Paulade50832008-05-14 16:09:46 -06001276
Brian Paul4ef7a932009-02-11 09:03:16 -07001277 /* if shProg is NULL, we'll have already recorded an error */
1278
1279 if (shProg) {
1280 if (!shProg->Uniforms ||
1281 location < 0 ||
1282 location >= (GLint) shProg->Uniforms->NumUniforms) {
1283 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
1284 }
1285 else {
1286 /* OK, find the gl_program and program parameter location */
Brian Paulade50832008-05-14 16:09:46 -06001287 progPos = shProg->Uniforms->Uniforms[location].VertPos;
1288 if (progPos >= 0) {
1289 prog = &shProg->VertexProgram->Base;
Brian5b01c5e2006-12-19 18:02:03 -07001290 }
Brian Paulade50832008-05-14 16:09:46 -06001291 else {
1292 progPos = shProg->Uniforms->Uniforms[location].FragPos;
1293 if (progPos >= 0) {
1294 prog = &shProg->FragmentProgram->Base;
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001295 }
Brian Paulade50832008-05-14 16:09:46 -06001296 }
Brian5b01c5e2006-12-19 18:02:03 -07001297 }
1298 }
Brian Paul4ef7a932009-02-11 09:03:16 -07001299
1300 *progOut = prog;
1301 *paramPosOut = progPos;
Brian Paul2be54a82008-07-08 16:17:04 -06001302}
1303
1304
1305/**
1306 * Called via ctx->Driver.GetUniformfv().
1307 */
1308static void
1309_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1310 GLfloat *params)
1311{
Brian Paul4ef7a932009-02-11 09:03:16 -07001312 struct gl_program *prog;
1313 GLint paramPos;
1314
1315 lookup_uniform_parameter(ctx, program, location, &prog, &paramPos);
1316
1317 if (prog) {
1318 const struct gl_program_parameter *p =
1319 &prog->Parameters->Parameters[paramPos];
1320 GLint rows, cols, i, j, k;
1321
1322 get_uniform_rows_cols(p, &rows, &cols);
1323
1324 k = 0;
1325 for (i = 0; i < rows; i++) {
1326 for (j = 0; j < cols; j++ ) {
1327 params[k++] = prog->Parameters->ParameterValues[paramPos+i][j];
1328 }
1329 }
1330 }
Brian Paul2be54a82008-07-08 16:17:04 -06001331}
1332
1333
1334/**
1335 * Called via ctx->Driver.GetUniformiv().
Brian Paul4ef7a932009-02-11 09:03:16 -07001336 * \sa _mesa_get_uniformfv, only difference is a cast.
Brian Paul2be54a82008-07-08 16:17:04 -06001337 */
1338static void
1339_mesa_get_uniformiv(GLcontext *ctx, GLuint program, GLint location,
1340 GLint *params)
1341{
Brian Paul4ef7a932009-02-11 09:03:16 -07001342 struct gl_program *prog;
1343 GLint paramPos;
1344
1345 lookup_uniform_parameter(ctx, program, location, &prog, &paramPos);
1346
1347 if (prog) {
1348 const struct gl_program_parameter *p =
1349 &prog->Parameters->Parameters[paramPos];
1350 GLint rows, cols, i, j, k;
1351
1352 get_uniform_rows_cols(p, &rows, &cols);
1353
1354 k = 0;
1355 for (i = 0; i < rows; i++) {
1356 for (j = 0; j < cols; j++ ) {
1357 params[k++] = (GLint) prog->Parameters->ParameterValues[paramPos+i][j];
1358 }
1359 }
Brian Paul2be54a82008-07-08 16:17:04 -06001360 }
Brian5b01c5e2006-12-19 18:02:03 -07001361}
1362
1363
1364/**
Brian Pauleda291e2008-08-06 16:26:47 -06001365 * The value returned by GetUniformLocation actually encodes two things:
1366 * 1. the index into the prog->Uniforms[] array for the uniform
1367 * 2. an offset in the prog->ParameterValues[] array for specifying array
1368 * elements or structure fields.
1369 * This function merges those two values.
1370 */
1371static void
1372merge_location_offset(GLint *location, GLint offset)
1373{
1374 *location = *location | (offset << 16);
1375}
1376
1377
1378/**
1379 * Seperate the uniform location and parameter offset. See above.
1380 */
1381static void
1382split_location_offset(GLint *location, GLint *offset)
1383{
1384 *offset = (*location >> 16);
1385 *location = *location & 0xffff;
1386}
1387
1388
1389/**
Brian5b01c5e2006-12-19 18:02:03 -07001390 * Called via ctx->Driver.GetUniformLocation().
Brian Pauleda291e2008-08-06 16:26:47 -06001391 *
1392 * The return value will encode two values, the uniform location and an
1393 * offset (used for arrays, structs).
Brian5b01c5e2006-12-19 18:02:03 -07001394 */
Brian Paulfd59f192008-05-18 16:04:55 -06001395static GLint
Brian5b01c5e2006-12-19 18:02:03 -07001396_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
1397{
Brian Pauleda291e2008-08-06 16:26:47 -06001398 GLint offset = 0, location = -1;
1399
Brian Paul530df582008-07-03 16:21:11 -06001400 struct gl_shader_program *shProg =
1401 _mesa_lookup_shader_program_err(ctx, program, "glGetUniformLocation");
1402
Brian Paulade50832008-05-14 16:09:46 -06001403 if (!shProg)
1404 return -1;
Brian5b01c5e2006-12-19 18:02:03 -07001405
Brian Paule06565b2008-07-04 09:58:55 -06001406 if (shProg->LinkStatus == GL_FALSE) {
1407 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
1408 return -1;
1409 }
1410
Brian Paul530df582008-07-03 16:21:11 -06001411 /* XXX we should return -1 if the uniform was declared, but not
1412 * actually used.
1413 */
1414
Brian Pauleda291e2008-08-06 16:26:47 -06001415 /* XXX we need to be able to parse uniform names for structs and arrays
1416 * such as:
1417 * mymatrix[1]
1418 * mystruct.field1
1419 */
1420
1421 {
1422 /* handle 1-dimension arrays here... */
1423 char *c = strchr(name, '[');
1424 if (c) {
1425 /* truncate name at [ */
1426 const GLint len = c - name;
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -05001427 GLchar *newName = malloc(len + 1);
Brian Pauleda291e2008-08-06 16:26:47 -06001428 if (!newName)
1429 return -1; /* out of mem */
Kenneth Graunkec7ac48622010-02-18 23:50:59 -08001430 memcpy(newName, name, len);
Brian Pauleda291e2008-08-06 16:26:47 -06001431 newName[len] = 0;
1432
1433 location = _mesa_lookup_uniform(shProg->Uniforms, newName);
1434 if (location >= 0) {
Kenneth Graunke60b0cae2010-02-18 23:50:58 -08001435 const GLint element = atoi(c + 1);
Brian Pauleda291e2008-08-06 16:26:47 -06001436 if (element > 0) {
1437 /* get type of the uniform array element */
1438 struct gl_program_parameter *p;
1439 p = get_uniform_parameter(shProg, location);
1440 if (p) {
1441 GLint rows, cols;
1442 get_matrix_dims(p->DataType, &rows, &cols);
1443 if (rows < 1)
1444 rows = 1;
1445 offset = element * rows;
1446 }
1447 }
1448 }
1449
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -05001450 free(newName);
Brian Pauleda291e2008-08-06 16:26:47 -06001451 }
1452 }
1453
1454 if (location < 0) {
1455 location = _mesa_lookup_uniform(shProg->Uniforms, name);
1456 }
1457
1458 if (location >= 0) {
1459 merge_location_offset(&location, offset);
1460 }
1461
1462 return location;
Brian5b01c5e2006-12-19 18:02:03 -07001463}
1464
1465
Brian34ae99d2006-12-18 08:28:54 -07001466
Brian5b01c5e2006-12-19 18:02:03 -07001467/**
1468 * Called via ctx->Driver.ShaderSource()
1469 */
Brian Paulfd59f192008-05-18 16:04:55 -06001470static void
Brian5b01c5e2006-12-19 18:02:03 -07001471_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -07001472{
Brian Paul530df582008-07-03 16:21:11 -06001473 struct gl_shader *sh;
1474
1475 sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource");
1476 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001477 return;
Brian34ae99d2006-12-18 08:28:54 -07001478
Brian34ae99d2006-12-18 08:28:54 -07001479 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -07001480 if (sh->Source) {
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -05001481 free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -07001482 }
Brian65a18442006-12-19 18:46:56 -07001483 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -07001484 sh->CompileStatus = GL_FALSE;
Brian Paulf7783ba2009-08-04 15:35:48 -06001485#ifdef DEBUG
1486 sh->SourceChecksum = _mesa_str_checksum(sh->Source);
1487#endif
Brian34ae99d2006-12-18 08:28:54 -07001488}
1489
1490
Brian5b01c5e2006-12-19 18:02:03 -07001491/**
1492 * Called via ctx->Driver.CompileShader()
1493 */
Brian Paulfd59f192008-05-18 16:04:55 -06001494static void
Brian5b01c5e2006-12-19 18:02:03 -07001495_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -07001496{
Brian Paul530df582008-07-03 16:21:11 -06001497 struct gl_shader *sh;
Brian34ae99d2006-12-18 08:28:54 -07001498
Brian Paul530df582008-07-03 16:21:11 -06001499 sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader");
1500 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001501 return;
Brian34ae99d2006-12-18 08:28:54 -07001502
Brian Paul65fc2ca2009-03-19 10:25:24 -06001503 /* set default pragma state for shader */
1504 sh->Pragmas = ctx->Shader.DefaultPragmas;
1505
Brian Paulcb136e02009-01-22 10:34:15 -07001506 /* this call will set the sh->CompileStatus field to indicate if
1507 * compilation was successful.
1508 */
1509 (void) _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -07001510}
1511
1512
Brian5b01c5e2006-12-19 18:02:03 -07001513/**
1514 * Called via ctx->Driver.LinkProgram()
1515 */
Brian Paulfd59f192008-05-18 16:04:55 -06001516static void
Brian5b01c5e2006-12-19 18:02:03 -07001517_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001518{
Brian65a18442006-12-19 18:46:56 -07001519 struct gl_shader_program *shProg;
Brian Paulfef6e362010-05-10 21:11:21 -06001520 struct gl_transform_feedback_object *obj =
1521 ctx->TransformFeedback.CurrentObject;
Brian34ae99d2006-12-18 08:28:54 -07001522
Brian Paul530df582008-07-03 16:21:11 -06001523 shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
1524 if (!shProg)
Brian34ae99d2006-12-18 08:28:54 -07001525 return;
Brian34ae99d2006-12-18 08:28:54 -07001526
Brian Paulfef6e362010-05-10 21:11:21 -06001527 if (obj->Active && shProg == ctx->Shader.CurrentProgram) {
Brian Paul1a148662010-04-01 22:15:16 -06001528 _mesa_error(ctx, GL_INVALID_OPERATION,
1529 "glLinkProgram(transform feedback active");
1530 return;
1531 }
1532
Briandf43fb62008-05-06 23:08:51 -06001533 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1534
Brianc1771912007-02-16 09:56:19 -07001535 _slang_link(ctx, program, shProg);
Brian Paulac3c8e32009-09-14 17:32:03 -06001536
1537 /* debug code */
1538 if (0) {
1539 GLuint i;
1540
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001541 printf("Link %u shaders in program %u: %s\n",
Brian Paulac3c8e32009-09-14 17:32:03 -06001542 shProg->NumShaders, shProg->Name,
1543 shProg->LinkStatus ? "Success" : "Failed");
1544
1545 for (i = 0; i < shProg->NumShaders; i++) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001546 printf(" shader %u, type 0x%x\n",
Brian Paulac3c8e32009-09-14 17:32:03 -06001547 shProg->Shaders[i]->Name,
1548 shProg->Shaders[i]->Type);
1549 }
1550 }
Brian34ae99d2006-12-18 08:28:54 -07001551}
1552
1553
1554/**
Brian Paul346250b2009-10-23 16:31:48 -06001555 * Print basic shader info (for debug).
1556 */
1557static void
1558print_shader_info(const struct gl_shader_program *shProg)
1559{
1560 GLuint i;
1561
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001562 printf("Mesa: glUseProgram(%u)\n", shProg->Name);
Brian Paul346250b2009-10-23 16:31:48 -06001563 for (i = 0; i < shProg->NumShaders; i++) {
1564 const char *s;
1565 switch (shProg->Shaders[i]->Type) {
1566 case GL_VERTEX_SHADER:
1567 s = "vertex";
1568 break;
1569 case GL_FRAGMENT_SHADER:
1570 s = "fragment";
1571 break;
1572 case GL_GEOMETRY_SHADER:
1573 s = "geometry";
1574 break;
1575 default:
1576 s = "";
1577 }
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001578 printf(" %s shader %u, checksum %u\n", s,
1579 shProg->Shaders[i]->Name,
1580 shProg->Shaders[i]->SourceChecksum);
Brian Paul346250b2009-10-23 16:31:48 -06001581 }
1582 if (shProg->VertexProgram)
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001583 printf(" vert prog %u\n", shProg->VertexProgram->Base.Id);
Brian Paul346250b2009-10-23 16:31:48 -06001584 if (shProg->FragmentProgram)
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001585 printf(" frag prog %u\n", shProg->FragmentProgram->Base.Id);
Brian Paul346250b2009-10-23 16:31:48 -06001586}
1587
1588
1589/**
Brian5b01c5e2006-12-19 18:02:03 -07001590 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001591 */
Brian5b01c5e2006-12-19 18:02:03 -07001592void
1593_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001594{
Brian3c008a02007-04-12 15:22:32 -06001595 struct gl_shader_program *shProg;
Brian Paulfef6e362010-05-10 21:11:21 -06001596 struct gl_transform_feedback_object *obj =
1597 ctx->TransformFeedback.CurrentObject;
Brian3c008a02007-04-12 15:22:32 -06001598
Brian Paulfef6e362010-05-10 21:11:21 -06001599 if (obj->Active) {
Brian Paul1a148662010-04-01 22:15:16 -06001600 _mesa_error(ctx, GL_INVALID_OPERATION,
1601 "glUseProgram(transform feedback active)");
1602 return;
1603 }
1604
Brian00d63aa2007-02-03 11:35:02 -07001605 if (ctx->Shader.CurrentProgram &&
1606 ctx->Shader.CurrentProgram->Name == program) {
1607 /* no-op */
1608 return;
1609 }
1610
Brian5b01c5e2006-12-19 18:02:03 -07001611 if (program) {
Brian Paul530df582008-07-03 16:21:11 -06001612 shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
Brian65a18442006-12-19 18:46:56 -07001613 if (!shProg) {
Brian Paul530df582008-07-03 16:21:11 -06001614 return;
1615 }
1616 if (!shProg->LinkStatus) {
Brian Paul621c9992009-02-18 13:28:12 -07001617 _mesa_error(ctx, GL_INVALID_OPERATION,
1618 "glUseProgram(program %u not linked)", program);
Brian5b01c5e2006-12-19 18:02:03 -07001619 return;
1620 }
Brian Paul4eda17d2009-03-13 09:11:42 -06001621
1622 /* debug code */
Brian Paul2ee7fd82009-10-15 15:25:52 -06001623 if (ctx->Shader.Flags & GLSL_USE_PROG) {
Brian Paul346250b2009-10-23 16:31:48 -06001624 print_shader_info(shProg);
Brian Paul4eda17d2009-03-13 09:11:42 -06001625 }
Brian5b01c5e2006-12-19 18:02:03 -07001626 }
1627 else {
Brian3c008a02007-04-12 15:22:32 -06001628 shProg = NULL;
1629 }
1630
Brian Paulb44304e2009-10-27 20:09:33 -06001631 if (ctx->Shader.CurrentProgram != shProg) {
1632 FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
1633 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
1634 }
Brian5b01c5e2006-12-19 18:02:03 -07001635}
Brian34ae99d2006-12-18 08:28:54 -07001636
Brian5b01c5e2006-12-19 18:02:03 -07001637
Brian Paulade50832008-05-14 16:09:46 -06001638
1639/**
Brian Paul517401a2008-11-06 15:04:11 -07001640 * Update the vertex/fragment program's TexturesUsed array.
1641 *
1642 * This needs to be called after glUniform(set sampler var) is called.
1643 * A call to glUniform(samplerVar, value) causes a sampler to point to a
1644 * particular texture unit. We know the sampler's texture target
1645 * (1D/2D/3D/etc) from compile time but the sampler's texture unit is
1646 * set by glUniform() calls.
1647 *
1648 * So, scan the program->SamplerUnits[] and program->SamplerTargets[]
1649 * information to update the prog->TexturesUsed[] values.
1650 * Each value of TexturesUsed[unit] is one of zero, TEXTURE_1D_INDEX,
1651 * TEXTURE_2D_INDEX, TEXTURE_3D_INDEX, etc.
1652 * We'll use that info for state validation before rendering.
Brian Paulade50832008-05-14 16:09:46 -06001653 */
Brian Paul517401a2008-11-06 15:04:11 -07001654void
1655_mesa_update_shader_textures_used(struct gl_program *prog)
Brian Paulade50832008-05-14 16:09:46 -06001656{
1657 GLuint s;
1658
1659 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1660
1661 for (s = 0; s < MAX_SAMPLERS; s++) {
1662 if (prog->SamplersUsed & (1 << s)) {
Brian Paulf05344f2009-08-26 10:58:06 -06001663 GLuint unit = prog->SamplerUnits[s];
1664 GLuint tgt = prog->SamplerTargets[s];
1665 assert(unit < MAX_TEXTURE_IMAGE_UNITS);
1666 assert(tgt < NUM_TEXTURE_TARGETS);
1667 prog->TexturesUsed[unit] |= (1 << tgt);
Brian Paulade50832008-05-14 16:09:46 -06001668 }
1669 }
1670}
1671
1672
1673/**
Brian Paulffbc66b2008-07-21 13:58:50 -06001674 * Check if the type given by userType is allowed to set a uniform of the
1675 * target type. Generally, equivalence is required, but setting Boolean
1676 * uniforms can be done with glUniformiv or glUniformfv.
1677 */
1678static GLboolean
1679compatible_types(GLenum userType, GLenum targetType)
1680{
1681 if (userType == targetType)
1682 return GL_TRUE;
1683
1684 if (targetType == GL_BOOL && (userType == GL_FLOAT || userType == GL_INT))
1685 return GL_TRUE;
1686
1687 if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 ||
1688 userType == GL_INT_VEC2))
1689 return GL_TRUE;
1690
1691 if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 ||
1692 userType == GL_INT_VEC3))
1693 return GL_TRUE;
1694
1695 if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 ||
1696 userType == GL_INT_VEC4))
1697 return GL_TRUE;
1698
Brianb36749d2008-07-21 20:42:05 -06001699 if (is_sampler_type(targetType) && userType == GL_INT)
1700 return GL_TRUE;
1701
Brian Paulffbc66b2008-07-21 13:58:50 -06001702 return GL_FALSE;
1703}
1704
1705
1706/**
Brian Paulade50832008-05-14 16:09:46 -06001707 * Set the value of a program's uniform variable.
1708 * \param program the program whose uniform to update
Brian Pauleda291e2008-08-06 16:26:47 -06001709 * \param index the index of the program parameter for the uniform
1710 * \param offset additional parameter slot offset (for arrays)
Brian Paulc4ffbf02009-02-18 17:46:00 -07001711 * \param type the incoming datatype of 'values'
Brian Paulade50832008-05-14 16:09:46 -06001712 * \param count the number of uniforms to set
Brian Paulc4ffbf02009-02-18 17:46:00 -07001713 * \param elems number of elements per uniform (1, 2, 3 or 4)
1714 * \param values the new values, of datatype 'type'
Brian Paulade50832008-05-14 16:09:46 -06001715 */
1716static void
Brian Pauleda291e2008-08-06 16:26:47 -06001717set_program_uniform(GLcontext *ctx, struct gl_program *program,
1718 GLint index, GLint offset,
1719 GLenum type, GLsizei count, GLint elems,
1720 const void *values)
Brian Paulade50832008-05-14 16:09:46 -06001721{
Brian Paul6df38e62009-08-26 14:35:45 -06001722 const struct gl_program_parameter *param =
Brian Paul949e7382008-11-05 09:17:55 -07001723 &program->Parameters->Parameters[index];
1724
Brian Pauleda291e2008-08-06 16:26:47 -06001725 assert(offset >= 0);
Brian Paulc4ffbf02009-02-18 17:46:00 -07001726 assert(elems >= 1);
1727 assert(elems <= 4);
Brian Pauleda291e2008-08-06 16:26:47 -06001728
Brian Paul949e7382008-11-05 09:17:55 -07001729 if (!compatible_types(type, param->DataType)) {
Brian Paulffbc66b2008-07-21 13:58:50 -06001730 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
1731 return;
1732 }
1733
Michal Krolc5c71302008-08-07 16:23:15 +02001734 if (index + offset > (GLint) program->Parameters->Size) {
Brian Pauleda291e2008-08-06 16:26:47 -06001735 /* out of bounds! */
1736 return;
1737 }
1738
Brian Paul949e7382008-11-05 09:17:55 -07001739 if (param->Type == PROGRAM_SAMPLER) {
Brian Paulade50832008-05-14 16:09:46 -06001740 /* This controls which texture unit which is used by a sampler */
Brian Paulbabb5ba2009-08-26 14:29:50 -06001741 GLboolean changed = GL_FALSE;
Brian Paul2b4f0212009-02-11 09:12:34 -07001742 GLint i;
Brian Paulade50832008-05-14 16:09:46 -06001743
Brian Paul6df38e62009-08-26 14:35:45 -06001744 /* this should have been caught by the compatible_types() check */
1745 ASSERT(type == GL_INT);
Brian Paulade50832008-05-14 16:09:46 -06001746
Brian Paul6df38e62009-08-26 14:35:45 -06001747 /* loop over number of samplers to change */
Brian Paul2b4f0212009-02-11 09:12:34 -07001748 for (i = 0; i < count; i++) {
Brian Paul04d17072009-08-26 11:39:24 -06001749 GLuint sampler =
1750 (GLuint) program->Parameters->ParameterValues[index + offset + i][0];
1751 GLuint texUnit = ((GLuint *) values)[i];
Brian Paulade50832008-05-14 16:09:46 -06001752
Brian Paul2b4f0212009-02-11 09:12:34 -07001753 /* check that the sampler (tex unit index) is legal */
1754 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1755 _mesa_error(ctx, GL_INVALID_VALUE,
Brian Paul16f8df892010-05-13 16:52:06 -06001756 "glUniform1(invalid sampler/tex unit index for '%s')",
1757 param->Name);
Brian Paul2b4f0212009-02-11 09:12:34 -07001758 return;
1759 }
1760
1761 /* This maps a sampler to a texture unit: */
1762 if (sampler < MAX_SAMPLERS) {
Brian Paul04d17072009-08-26 11:39:24 -06001763#if 0
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001764 printf("Set program %p sampler %d '%s' to unit %u\n",
1765 program, sampler, param->Name, texUnit);
Brian Paul04d17072009-08-26 11:39:24 -06001766#endif
Brian Paulbabb5ba2009-08-26 14:29:50 -06001767 if (program->SamplerUnits[sampler] != texUnit) {
1768 program->SamplerUnits[sampler] = texUnit;
1769 changed = GL_TRUE;
1770 }
Brian Paul2b4f0212009-02-11 09:12:34 -07001771 }
Brian Paulade50832008-05-14 16:09:46 -06001772 }
1773
Brian Paulbabb5ba2009-08-26 14:29:50 -06001774 if (changed) {
1775 /* When a sampler's value changes it usually requires rewriting
1776 * a GPU program's TEX instructions since there may not be a
1777 * sampler->texture lookup table. We signal this with the
1778 * ProgramStringNotify() callback.
1779 */
1780 FLUSH_VERTICES(ctx, _NEW_TEXTURE | _NEW_PROGRAM);
1781 _mesa_update_shader_textures_used(program);
Brian Paul4ac9c802010-02-04 16:49:35 -07001782 /* Do we need to care about the return value here?
1783 * This should not be the first time the driver was notified of
1784 * this program.
1785 */
1786 (void) ctx->Driver.ProgramStringNotify(ctx, program->Target, program);
Brian Paulbabb5ba2009-08-26 14:29:50 -06001787 }
Brian Paulade50832008-05-14 16:09:46 -06001788 }
1789 else {
1790 /* ordinary uniform variable */
Brian Paul6df38e62009-08-26 14:35:45 -06001791 const GLboolean isUniformBool = is_boolean_type(param->DataType);
1792 const GLboolean areIntValues = is_integer_type(type);
Brian Paul2c1ea072009-02-11 08:46:21 -07001793 const GLint slots = (param->Size + 3) / 4;
Brian Paul1a148662010-04-01 22:15:16 -06001794 const GLint typeSize = _mesa_sizeof_glsl_type(param->DataType);
Brian Paul6df38e62009-08-26 14:35:45 -06001795 GLsizei k, i;
Brian Paulade50832008-05-14 16:09:46 -06001796
Brian Paul20fbb242010-01-27 17:03:04 -07001797 if ((GLint) param->Size > typeSize) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001798 /* an array */
1799 /* we'll ignore extra data below */
1800 }
1801 else {
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001802 /* non-array: count must be at most one; count == 0 is handled by the loop below */
1803 if (count > 1) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001804 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Paul16f8df892010-05-13 16:52:06 -06001805 "glUniform(uniform '%s' is not an array)",
1806 param->Name);
Brian Paul2c1ea072009-02-11 08:46:21 -07001807 return;
1808 }
Brian Paulade50832008-05-14 16:09:46 -06001809 }
1810
Brian Paulc4ffbf02009-02-18 17:46:00 -07001811 /* loop over number of array elements */
Brian Paulade50832008-05-14 16:09:46 -06001812 for (k = 0; k < count; k++) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001813 GLfloat *uniformVal;
1814
Brian Paulb9d8f712009-02-18 17:40:44 -07001815 if (offset + k >= slots) {
Brian Paul2c1ea072009-02-11 08:46:21 -07001816 /* Extra array data is ignored */
1817 break;
1818 }
1819
Brian Paulc4ffbf02009-02-18 17:46:00 -07001820 /* uniformVal (the destination) is always float[4] */
Brian Paul2c1ea072009-02-11 08:46:21 -07001821 uniformVal = program->Parameters->ParameterValues[index + offset + k];
Brian Paulc4ffbf02009-02-18 17:46:00 -07001822
1823 if (areIntValues) {
1824 /* convert user's ints to floats */
Brian Paulade50832008-05-14 16:09:46 -06001825 const GLint *iValues = ((const GLint *) values) + k * elems;
1826 for (i = 0; i < elems; i++) {
1827 uniformVal[i] = (GLfloat) iValues[i];
1828 }
1829 }
1830 else {
1831 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1832 for (i = 0; i < elems; i++) {
1833 uniformVal[i] = fValues[i];
1834 }
1835 }
Brian Pauleda291e2008-08-06 16:26:47 -06001836
1837 /* if the uniform is bool-valued, convert to 1.0 or 0.0 */
Brian Paulc4ffbf02009-02-18 17:46:00 -07001838 if (isUniformBool) {
Brian Pauleda291e2008-08-06 16:26:47 -06001839 for (i = 0; i < elems; i++) {
Michal Krolc5c71302008-08-07 16:23:15 +02001840 uniformVal[i] = uniformVal[i] ? 1.0f : 0.0f;
Brian Pauleda291e2008-08-06 16:26:47 -06001841 }
1842 }
Brian Paulade50832008-05-14 16:09:46 -06001843 }
1844 }
1845}
1846
1847
Brian5b01c5e2006-12-19 18:02:03 -07001848/**
1849 * Called via ctx->Driver.Uniform().
1850 */
Brian Paulfd59f192008-05-18 16:04:55 -06001851static void
Brian5b01c5e2006-12-19 18:02:03 -07001852_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1853 const GLvoid *values, GLenum type)
1854{
Brian3a8e2772006-12-20 17:19:16 -07001855 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paul2d76a0d2008-11-10 12:33:17 -07001856 struct gl_uniform *uniform;
Brian Pauleda291e2008-08-06 16:26:47 -06001857 GLint elems, offset;
Brian Paule01a03d2009-02-06 10:21:36 -07001858 GLenum basicType;
Brian3a8e2772006-12-20 17:19:16 -07001859
1860 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001861 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001862 return;
1863 }
1864
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001865 if (location == -1)
1866 return; /* The standard specifies this as a no-op */
1867
Brian Paul234f03e2009-02-11 09:05:08 -07001868 if (location < -1) {
Brian Paul16f8df892010-05-13 16:52:06 -06001869 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(location=%d)",
1870 location);
Brian Paul234f03e2009-02-11 09:05:08 -07001871 return;
1872 }
1873
Brian Pauleda291e2008-08-06 16:26:47 -06001874 split_location_offset(&location, &offset);
1875
Brian Paulade50832008-05-14 16:09:46 -06001876 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian Paul16f8df892010-05-13 16:52:06 -06001877 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location=%d)", location);
Brian3a8e2772006-12-20 17:19:16 -07001878 return;
1879 }
1880
Brian52363952007-03-13 16:50:24 -06001881 if (count < 0) {
1882 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1883 return;
1884 }
1885
Brian98650bd2007-03-13 16:32:48 -06001886 switch (type) {
1887 case GL_FLOAT:
Brian Paule01a03d2009-02-06 10:21:36 -07001888 basicType = GL_FLOAT;
1889 elems = 1;
1890 break;
Brian98650bd2007-03-13 16:32:48 -06001891 case GL_INT:
Brian Paule01a03d2009-02-06 10:21:36 -07001892 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001893 elems = 1;
1894 break;
1895 case GL_FLOAT_VEC2:
Brian Paule01a03d2009-02-06 10:21:36 -07001896 basicType = GL_FLOAT;
1897 elems = 2;
1898 break;
Brian98650bd2007-03-13 16:32:48 -06001899 case GL_INT_VEC2:
Brian Paule01a03d2009-02-06 10:21:36 -07001900 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001901 elems = 2;
1902 break;
1903 case GL_FLOAT_VEC3:
Brian Paule01a03d2009-02-06 10:21:36 -07001904 basicType = GL_FLOAT;
1905 elems = 3;
1906 break;
Brian98650bd2007-03-13 16:32:48 -06001907 case GL_INT_VEC3:
Brian Paule01a03d2009-02-06 10:21:36 -07001908 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001909 elems = 3;
1910 break;
1911 case GL_FLOAT_VEC4:
Brian Paule01a03d2009-02-06 10:21:36 -07001912 basicType = GL_FLOAT;
1913 elems = 4;
1914 break;
Brian98650bd2007-03-13 16:32:48 -06001915 case GL_INT_VEC4:
Brian Paule01a03d2009-02-06 10:21:36 -07001916 basicType = GL_INT;
Brian98650bd2007-03-13 16:32:48 -06001917 elems = 4;
1918 break;
1919 default:
1920 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1921 return;
Brian89dc4852007-01-04 14:35:44 -07001922 }
Brian98650bd2007-03-13 16:32:48 -06001923
Brian Paul027ed1b2009-04-24 09:43:44 -06001924 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
Brian98650bd2007-03-13 16:32:48 -06001925
Brian Paul2d76a0d2008-11-10 12:33:17 -07001926 uniform = &shProg->Uniforms->Uniforms[location];
1927
Brian Paule01a03d2009-02-06 10:21:36 -07001928 if (ctx->Shader.Flags & GLSL_UNIFORMS) {
1929 GLint i;
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001930 printf("Mesa: set program %u uniform %s (loc %d) to: ",
1931 shProg->Name, uniform->Name, location);
Brian Paule01a03d2009-02-06 10:21:36 -07001932 if (basicType == GL_INT) {
1933 const GLint *v = (const GLint *) values;
1934 for (i = 0; i < count * elems; i++) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001935 printf("%d ", v[i]);
Brian Paule01a03d2009-02-06 10:21:36 -07001936 }
1937 }
1938 else {
1939 const GLfloat *v = (const GLfloat *) values;
1940 for (i = 0; i < count * elems; i++) {
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001941 printf("%g ", v[i]);
Brian Paule01a03d2009-02-06 10:21:36 -07001942 }
1943 }
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05001944 printf("\n");
Brian Paule01a03d2009-02-06 10:21:36 -07001945 }
1946
Brian Paulade50832008-05-14 16:09:46 -06001947 /* A uniform var may be used by both a vertex shader and a fragment
1948 * shader. We may need to update one or both shader's uniform here:
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001949 */
Brian Paulade50832008-05-14 16:09:46 -06001950 if (shProg->VertexProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001951 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07001952 GLint index = uniform->VertPos;
Brian Pauleda291e2008-08-06 16:26:47 -06001953 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001954 set_program_uniform(ctx, &shProg->VertexProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001955 index, offset, type, count, elems, values);
Bruce Merry2bf2a8c2007-12-21 23:18:40 +02001956 }
Brian5b01c5e2006-12-19 18:02:03 -07001957 }
Brian5cf73262007-01-05 16:02:45 -07001958
Brian Paulade50832008-05-14 16:09:46 -06001959 if (shProg->FragmentProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06001960 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07001961 GLint index = uniform->FragPos;
Brian Pauleda291e2008-08-06 16:26:47 -06001962 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06001963 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06001964 index, offset, type, count, elems, values);
Brian Paulade50832008-05-14 16:09:46 -06001965 }
1966 }
Brian Paul949e7382008-11-05 09:17:55 -07001967
Brian Paul2d76a0d2008-11-10 12:33:17 -07001968 uniform->Initialized = GL_TRUE;
Brian Paulade50832008-05-14 16:09:46 -06001969}
1970
1971
Brian Pauleda291e2008-08-06 16:26:47 -06001972/**
1973 * Set a matrix-valued program parameter.
1974 */
Brian Paulade50832008-05-14 16:09:46 -06001975static void
1976set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
Brian Pauleda291e2008-08-06 16:26:47 -06001977 GLuint index, GLuint offset,
1978 GLuint count, GLuint rows, GLuint cols,
Brian Paulade50832008-05-14 16:09:46 -06001979 GLboolean transpose, const GLfloat *values)
1980{
Brian Paulffbc66b2008-07-21 13:58:50 -06001981 GLuint mat, row, col;
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001982 GLuint src = 0;
1983 const struct gl_program_parameter * param = &program->Parameters->Parameters[index];
Brian Paul20fbb242010-01-27 17:03:04 -07001984 const GLuint slots = (param->Size + 3) / 4;
Brian Paul1a148662010-04-01 22:15:16 -06001985 const GLint typeSize = _mesa_sizeof_glsl_type(param->DataType);
Brian Paulffbc66b2008-07-21 13:58:50 -06001986 GLint nr, nc;
1987
1988 /* check that the number of rows, columns is correct */
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001989 get_matrix_dims(param->DataType, &nr, &nc);
Brian Paulffbc66b2008-07-21 13:58:50 -06001990 if (rows != nr || cols != nc) {
1991 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Pauleda291e2008-08-06 16:26:47 -06001992 "glUniformMatrix(matrix size mismatch)");
1993 return;
1994 }
1995
Brian Paul20fbb242010-01-27 17:03:04 -07001996 if ((GLint) param->Size <= typeSize) {
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02001997 /* non-array: count must be at most one; count == 0 is handled by the loop below */
1998 if (count > 1) {
1999 _mesa_error(ctx, GL_INVALID_OPERATION,
2000 "glUniformMatrix(uniform is not an array)");
2001 return;
2002 }
Brian Paulffbc66b2008-07-21 13:58:50 -06002003 }
2004
Brian Paulade50832008-05-14 16:09:46 -06002005 /*
2006 * Note: the _columns_ of a matrix are stored in program registers, not
Brian Paulf45ed0e2008-07-18 12:51:39 -06002007 * the rows. So, the loops below look a little funny.
2008 * XXX could optimize this a bit...
Brian Paulade50832008-05-14 16:09:46 -06002009 */
Brian Paulf45ed0e2008-07-18 12:51:39 -06002010
2011 /* loop over matrices */
2012 for (mat = 0; mat < count; mat++) {
2013
2014 /* each matrix: */
Brian Paulade50832008-05-14 16:09:46 -06002015 for (col = 0; col < cols; col++) {
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02002016 GLfloat *v;
2017 if (offset >= slots) {
2018 /* Ignore writes beyond the end of (the used part of) an array */
2019 return;
2020 }
2021 v = program->Parameters->ParameterValues[index + offset];
Brian Paulade50832008-05-14 16:09:46 -06002022 for (row = 0; row < rows; row++) {
Brian Paulf45ed0e2008-07-18 12:51:39 -06002023 if (transpose) {
2024 v[row] = values[src + row * cols + col];
2025 }
2026 else {
2027 v[row] = values[src + col * rows + row];
2028 }
Brian Paulade50832008-05-14 16:09:46 -06002029 }
Nicolai Hähnle9fde81b2009-10-03 16:30:16 +02002030
2031 offset++;
Brian Paulade50832008-05-14 16:09:46 -06002032 }
Brian Paulf45ed0e2008-07-18 12:51:39 -06002033
2034 src += rows * cols; /* next matrix */
Brian5cf73262007-01-05 16:02:45 -07002035 }
Brian34ae99d2006-12-18 08:28:54 -07002036}
2037
2038
2039/**
Brian5b01c5e2006-12-19 18:02:03 -07002040 * Called by ctx->Driver.UniformMatrix().
Brian Paulf45ed0e2008-07-18 12:51:39 -06002041 * Note: cols=2, rows=4 ==> array[2] of vec4
Brian34ae99d2006-12-18 08:28:54 -07002042 */
Brian Paulfd59f192008-05-18 16:04:55 -06002043static void
Brian5b01c5e2006-12-19 18:02:03 -07002044_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
Brian Paul0115a4f2009-04-14 20:00:28 -06002045 GLint location, GLsizei count,
Brian5b01c5e2006-12-19 18:02:03 -07002046 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07002047{
Brian3a8e2772006-12-20 17:19:16 -07002048 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paul2d76a0d2008-11-10 12:33:17 -07002049 struct gl_uniform *uniform;
2050 GLint offset;
Brian Paulade50832008-05-14 16:09:46 -06002051
Brian3a8e2772006-12-20 17:19:16 -07002052 if (!shProg || !shProg->LinkStatus) {
2053 _mesa_error(ctx, GL_INVALID_OPERATION,
2054 "glUniformMatrix(program not linked)");
2055 return;
2056 }
Brian Paulade50832008-05-14 16:09:46 -06002057
Bruce Merry89b80322007-12-21 15:20:17 +02002058 if (location == -1)
2059 return; /* The standard specifies this as a no-op */
Brian Paulade50832008-05-14 16:09:46 -06002060
Brian Paul234f03e2009-02-11 09:05:08 -07002061 if (location < -1) {
2062 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(location)");
2063 return;
2064 }
2065
Brian Pauleda291e2008-08-06 16:26:47 -06002066 split_location_offset(&location, &offset);
2067
Brian Paul016701f2008-07-29 17:43:35 -06002068 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian Paulade50832008-05-14 16:09:46 -06002069 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
Brian3a8e2772006-12-20 17:19:16 -07002070 return;
2071 }
Brian34ae99d2006-12-18 08:28:54 -07002072 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07002073 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07002074 return;
2075 }
2076
Brian Paul027ed1b2009-04-24 09:43:44 -06002077 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
Brian34ae99d2006-12-18 08:28:54 -07002078
Brian Paul2d76a0d2008-11-10 12:33:17 -07002079 uniform = &shProg->Uniforms->Uniforms[location];
2080
Brian Paulade50832008-05-14 16:09:46 -06002081 if (shProg->VertexProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06002082 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07002083 GLint index = uniform->VertPos;
Brian Pauleda291e2008-08-06 16:26:47 -06002084 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06002085 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06002086 index, offset,
2087 count, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07002088 }
Brian Paulade50832008-05-14 16:09:46 -06002089 }
2090
2091 if (shProg->FragmentProgram) {
Brian Pauleda291e2008-08-06 16:26:47 -06002092 /* convert uniform location to program parameter index */
Brian Paul2d76a0d2008-11-10 12:33:17 -07002093 GLint index = uniform->FragPos;
Brian Pauleda291e2008-08-06 16:26:47 -06002094 if (index >= 0) {
Brian Paulade50832008-05-14 16:09:46 -06002095 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
Brian Pauleda291e2008-08-06 16:26:47 -06002096 index, offset,
2097 count, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07002098 }
Brian34ae99d2006-12-18 08:28:54 -07002099 }
Brian Paul949e7382008-11-05 09:17:55 -07002100
Brian Paul2d76a0d2008-11-10 12:33:17 -07002101 uniform->Initialized = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07002102}
2103
2104
Brian Paulc90fca32009-08-25 17:42:47 -06002105/**
2106 * Validate a program's samplers.
2107 * Specifically, check that there aren't two samplers of different types
2108 * pointing to the same texture unit.
2109 * \return GL_TRUE if valid, GL_FALSE if invalid
2110 */
2111static GLboolean
2112validate_samplers(GLcontext *ctx, const struct gl_program *prog, char *errMsg)
Brian34ae99d2006-12-18 08:28:54 -07002113{
Brian Paulc90fca32009-08-25 17:42:47 -06002114 static const char *targetName[] = {
2115 "TEXTURE_2D_ARRAY",
2116 "TEXTURE_1D_ARRAY",
2117 "TEXTURE_CUBE",
2118 "TEXTURE_3D",
2119 "TEXTURE_RECT",
2120 "TEXTURE_2D",
2121 "TEXTURE_1D",
2122 };
2123 GLint targetUsed[MAX_TEXTURE_IMAGE_UNITS];
2124 GLbitfield samplersUsed = prog->SamplersUsed;
2125 GLuint i;
Brian Paulbc985b52008-07-21 14:16:07 -06002126
Brian Paulc90fca32009-08-25 17:42:47 -06002127 assert(Elements(targetName) == NUM_TEXTURE_TARGETS);
2128
2129 if (samplersUsed == 0x0)
2130 return GL_TRUE;
2131
2132 for (i = 0; i < Elements(targetUsed); i++)
2133 targetUsed[i] = -1;
2134
2135 /* walk over bits which are set in 'samplers' */
2136 while (samplersUsed) {
2137 GLuint unit;
2138 gl_texture_index target;
2139 GLint sampler = _mesa_ffs(samplersUsed) - 1;
2140 assert(sampler >= 0);
2141 assert(sampler < MAX_TEXTURE_IMAGE_UNITS);
2142 unit = prog->SamplerUnits[sampler];
2143 target = prog->SamplerTargets[sampler];
2144 if (targetUsed[unit] != -1 && targetUsed[unit] != target) {
Brian Paul78a0c352010-02-19 12:56:49 -07002145 _mesa_snprintf(errMsg, 100,
Kristian Høgsberg298be2b2010-02-19 12:32:24 -05002146 "Texture unit %d is accessed both as %s and %s",
2147 unit, targetName[targetUsed[unit]], targetName[target]);
Brian Paulc90fca32009-08-25 17:42:47 -06002148 return GL_FALSE;
2149 }
2150 targetUsed[unit] = target;
2151 samplersUsed ^= (1 << sampler);
Brian34ae99d2006-12-18 08:28:54 -07002152 }
2153
Brian Paulc90fca32009-08-25 17:42:47 -06002154 return GL_TRUE;
2155}
2156
2157
2158/**
2159 * Do validation of the given shader program.
2160 * \param errMsg returns error message if validation fails.
2161 * \return GL_TRUE if valid, GL_FALSE if invalid (and set errMsg)
2162 */
2163GLboolean
2164_mesa_validate_shader_program(GLcontext *ctx,
2165 const struct gl_shader_program *shProg,
2166 char *errMsg)
2167{
2168 const struct gl_vertex_program *vp = shProg->VertexProgram;
2169 const struct gl_fragment_program *fp = shProg->FragmentProgram;
2170
Brian Paulbc985b52008-07-21 14:16:07 -06002171 if (!shProg->LinkStatus) {
Brian Paulc90fca32009-08-25 17:42:47 -06002172 return GL_FALSE;
Brian Paulbc985b52008-07-21 14:16:07 -06002173 }
2174
2175 /* From the GL spec, a program is invalid if any of these are true:
2176
Brian5b01c5e2006-12-19 18:02:03 -07002177 any two active samplers in the current program object are of
2178 different types, but refer to the same texture image unit,
2179
2180 any active sampler in the current program object refers to a texture
2181 image unit where fixed-function fragment processing accesses a
2182 texture target that does not match the sampler type, or
2183
2184 the sum of the number of active samplers in the program and the
2185 number of texture image units enabled for fixed-function fragment
2186 processing exceeds the combined limit on the total number of texture
2187 image units allowed.
2188 */
Brian Paulbc985b52008-07-21 14:16:07 -06002189
Brian Paulc90fca32009-08-25 17:42:47 -06002190
2191 /*
2192 * Check: any two active samplers in the current program object are of
2193 * different types, but refer to the same texture image unit,
2194 */
2195 if (vp && !validate_samplers(ctx, &vp->Base, errMsg)) {
2196 return GL_FALSE;
2197 }
2198 if (fp && !validate_samplers(ctx, &fp->Base, errMsg)) {
2199 return GL_FALSE;
2200 }
2201
2202 return GL_TRUE;
2203}
2204
2205
2206/**
2207 * Called via glValidateProgram()
2208 */
2209static void
2210_mesa_validate_program(GLcontext *ctx, GLuint program)
2211{
2212 struct gl_shader_program *shProg;
2213 char errMsg[100];
2214
2215 shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram");
2216 if (!shProg) {
2217 return;
2218 }
2219
2220 shProg->Validated = _mesa_validate_shader_program(ctx, shProg, errMsg);
2221 if (!shProg->Validated) {
2222 /* update info log */
2223 if (shProg->InfoLog) {
Kristian Høgsberg32f2fd12010-02-19 11:58:49 -05002224 free(shProg->InfoLog);
Brian Paulc90fca32009-08-25 17:42:47 -06002225 }
2226 shProg->InfoLog = _mesa_strdup(errMsg);
2227 }
Brian34ae99d2006-12-18 08:28:54 -07002228}
Brian Paulfd59f192008-05-18 16:04:55 -06002229
2230
2231/**
2232 * Plug in Mesa's GLSL functions into the device driver function table.
2233 */
2234void
2235_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
2236{
2237 driver->AttachShader = _mesa_attach_shader;
2238 driver->BindAttribLocation = _mesa_bind_attrib_location;
2239 driver->CompileShader = _mesa_compile_shader;
2240 driver->CreateProgram = _mesa_create_program;
2241 driver->CreateShader = _mesa_create_shader;
2242 driver->DeleteProgram2 = _mesa_delete_program2;
2243 driver->DeleteShader = _mesa_delete_shader;
2244 driver->DetachShader = _mesa_detach_shader;
2245 driver->GetActiveAttrib = _mesa_get_active_attrib;
2246 driver->GetActiveUniform = _mesa_get_active_uniform;
2247 driver->GetAttachedShaders = _mesa_get_attached_shaders;
2248 driver->GetAttribLocation = _mesa_get_attrib_location;
2249 driver->GetHandle = _mesa_get_handle;
2250 driver->GetProgramiv = _mesa_get_programiv;
2251 driver->GetProgramInfoLog = _mesa_get_program_info_log;
2252 driver->GetShaderiv = _mesa_get_shaderiv;
2253 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
2254 driver->GetShaderSource = _mesa_get_shader_source;
2255 driver->GetUniformfv = _mesa_get_uniformfv;
Brian Paul2be54a82008-07-08 16:17:04 -06002256 driver->GetUniformiv = _mesa_get_uniformiv;
Brian Paulfd59f192008-05-18 16:04:55 -06002257 driver->GetUniformLocation = _mesa_get_uniform_location;
2258 driver->IsProgram = _mesa_is_program;
2259 driver->IsShader = _mesa_is_shader;
2260 driver->LinkProgram = _mesa_link_program;
2261 driver->ShaderSource = _mesa_shader_source;
2262 driver->Uniform = _mesa_uniform;
2263 driver->UniformMatrix = _mesa_uniform_matrix;
2264 driver->UseProgram = _mesa_use_program;
2265 driver->ValidateProgram = _mesa_validate_program;
2266}