blob: c2c58fffde3527f859f4452812099e1b6640c61e [file] [log] [blame]
Brian34ae99d2006-12-18 08:28:54 -07001/*
2 * Mesa 3-D graphics library
Brian3e4302f2007-05-09 08:04:32 -06003 * Version: 7.0
Brian34ae99d2006-12-18 08:28:54 -07004 *
Brian5b01c5e2006-12-19 18:02:03 -07005 * Copyright (C) 2004-2007 Brian Paul All Rights Reserved.
Brian34ae99d2006-12-18 08:28:54 -07006 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25/**
26 * \file shader_api.c
Brian5b01c5e2006-12-19 18:02:03 -070027 * Implementation of GLSL-related API functions
Brian34ae99d2006-12-18 08:28:54 -070028 * \author Brian Paul
29 */
30
31/**
32 * XXX things to do:
33 * 1. Check that the right error code is generated for all _mesa_error() calls.
Brian5b01c5e2006-12-19 18:02:03 -070034 * 2. Insert FLUSH_VERTICES calls in various places
Brian34ae99d2006-12-18 08:28:54 -070035 */
36
37
José Fonseca101d1a62008-07-23 21:06:01 +090038#include "main/glheader.h"
39#include "main/context.h"
40#include "main/hash.h"
41#include "main/macros.h"
Brian34ae99d2006-12-18 08:28:54 -070042#include "program.h"
43#include "prog_parameter.h"
Brian3209c3e2007-01-09 17:49:24 -070044#include "prog_print.h"
45#include "prog_statevars.h"
Brianbc029242008-04-04 18:59:21 -060046#include "prog_uniform.h"
Brianc223c6b2007-07-04 13:15:20 -060047#include "shader/shader_api.h"
48#include "shader/slang/slang_compile.h"
49#include "shader/slang/slang_link.h"
Brian34ae99d2006-12-18 08:28:54 -070050
51
52
Brian Paul18cd9c22008-08-06 12:45:14 -060053#ifndef GL_PROGRAM_BINARY_LENGTH_OES
54#define GL_PROGRAM_BINARY_LENGTH_OES 0x8741
55#endif
56
57
Brianf2923612006-12-20 09:56:44 -070058/**
59 * Allocate a new gl_shader_program object, initialize it.
60 */
Brian2d2bb352007-12-07 17:11:30 -070061static struct gl_shader_program *
Brianf2923612006-12-20 09:56:44 -070062_mesa_new_shader_program(GLcontext *ctx, GLuint name)
63{
64 struct gl_shader_program *shProg;
65 shProg = CALLOC_STRUCT(gl_shader_program);
66 if (shProg) {
Brianf3e8c322007-04-18 14:53:23 -060067 shProg->Type = GL_SHADER_PROGRAM_MESA;
Brianf2923612006-12-20 09:56:44 -070068 shProg->Name = name;
69 shProg->RefCount = 1;
Brian3209c3e2007-01-09 17:49:24 -070070 shProg->Attributes = _mesa_new_parameter_list();
Brianf2923612006-12-20 09:56:44 -070071 }
72 return shProg;
73}
74
75
Brianb9fbedd2007-03-26 09:23:44 -060076/**
Brian3c008a02007-04-12 15:22:32 -060077 * Clear (free) the shader program state that gets produced by linking.
Brianb9fbedd2007-03-26 09:23:44 -060078 */
Brianf2923612006-12-20 09:56:44 -070079void
Brian3c008a02007-04-12 15:22:32 -060080_mesa_clear_shader_program_data(GLcontext *ctx,
81 struct gl_shader_program *shProg)
Brianf2923612006-12-20 09:56:44 -070082{
Brian Paul470f6992008-05-16 09:56:59 -060083 _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL);
84 _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL);
Brianf2923612006-12-20 09:56:44 -070085
Brianf2923612006-12-20 09:56:44 -070086 if (shProg->Uniforms) {
Brianbc029242008-04-04 18:59:21 -060087 _mesa_free_uniform_list(shProg->Uniforms);
Brianf2923612006-12-20 09:56:44 -070088 shProg->Uniforms = NULL;
89 }
90
91 if (shProg->Varying) {
92 _mesa_free_parameter_list(shProg->Varying);
93 shProg->Varying = NULL;
94 }
95}
96
97
Brianb9fbedd2007-03-26 09:23:44 -060098/**
Brian3c008a02007-04-12 15:22:32 -060099 * Free all the data that hangs off a shader program object, but not the
100 * object itself.
101 */
102void
103_mesa_free_shader_program_data(GLcontext *ctx,
104 struct gl_shader_program *shProg)
105{
106 GLuint i;
107
Brianf3e8c322007-04-18 14:53:23 -0600108 assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
Brian3c008a02007-04-12 15:22:32 -0600109
110 _mesa_clear_shader_program_data(ctx, shProg);
111
Brian4b7c6fc2007-04-19 15:23:34 -0600112 if (shProg->Attributes) {
113 _mesa_free_parameter_list(shProg->Attributes);
114 shProg->Attributes = NULL;
115 }
116
Brian3c008a02007-04-12 15:22:32 -0600117 /* detach shaders */
118 for (i = 0; i < shProg->NumShaders; i++) {
119 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
120 }
Brian Paul887bfee2008-05-14 16:44:08 -0600121 shProg->NumShaders = 0;
122
Brian3c008a02007-04-12 15:22:32 -0600123 if (shProg->Shaders) {
124 _mesa_free(shProg->Shaders);
125 shProg->Shaders = NULL;
126 }
Brian Paul887bfee2008-05-14 16:44:08 -0600127
128 if (shProg->InfoLog) {
129 _mesa_free(shProg->InfoLog);
130 shProg->InfoLog = NULL;
131 }
Brian3c008a02007-04-12 15:22:32 -0600132}
133
134
135/**
Brianb9fbedd2007-03-26 09:23:44 -0600136 * Free/delete a shader program object.
137 */
Brianf2923612006-12-20 09:56:44 -0700138void
139_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg)
140{
141 _mesa_free_shader_program_data(ctx, shProg);
Brian Paul887bfee2008-05-14 16:44:08 -0600142
Brianf2923612006-12-20 09:56:44 -0700143 _mesa_free(shProg);
144}
145
146
147/**
Brian3c008a02007-04-12 15:22:32 -0600148 * Set ptr to point to shProg.
149 * If ptr is pointing to another object, decrement its refcount (and delete
150 * if refcount hits zero).
151 * Then set ptr to point to shProg, incrementing its refcount.
152 */
153/* XXX this could be static */
154void
155_mesa_reference_shader_program(GLcontext *ctx,
156 struct gl_shader_program **ptr,
157 struct gl_shader_program *shProg)
158{
159 assert(ptr);
160 if (*ptr == shProg) {
161 /* no-op */
162 return;
163 }
164 if (*ptr) {
165 /* Unreference the old shader program */
166 GLboolean deleteFlag = GL_FALSE;
167 struct gl_shader_program *old = *ptr;
168
169 ASSERT(old->RefCount > 0);
170 old->RefCount--;
Brian Paul470f6992008-05-16 09:56:59 -0600171#if 0
172 printf("ShaderProgram %p ID=%u RefCount-- to %d\n",
173 (void *) old, old->Name, old->RefCount);
174#endif
Brian3c008a02007-04-12 15:22:32 -0600175 deleteFlag = (old->RefCount == 0);
176
177 if (deleteFlag) {
178 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
179 _mesa_free_shader_program(ctx, old);
180 }
181
182 *ptr = NULL;
183 }
184 assert(!*ptr);
185
186 if (shProg) {
187 shProg->RefCount++;
Brian Paul470f6992008-05-16 09:56:59 -0600188#if 0
189 printf("ShaderProgram %p ID=%u RefCount++ to %d\n",
190 (void *) shProg, shProg->Name, shProg->RefCount);
191#endif
Brian3c008a02007-04-12 15:22:32 -0600192 *ptr = shProg;
193 }
194}
195
196
197/**
Brianf2923612006-12-20 09:56:44 -0700198 * Lookup a GLSL program object.
199 */
200struct gl_shader_program *
201_mesa_lookup_shader_program(GLcontext *ctx, GLuint name)
202{
203 struct gl_shader_program *shProg;
204 if (name) {
205 shProg = (struct gl_shader_program *)
206 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
207 /* Note that both gl_shader and gl_shader_program objects are kept
208 * in the same hash table. Check the object's type to be sure it's
209 * what we're expecting.
210 */
Brianf3e8c322007-04-18 14:53:23 -0600211 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700212 return NULL;
213 }
214 return shProg;
215 }
216 return NULL;
217}
218
219
220/**
Brian Pauld4172262008-07-03 16:21:15 -0600221 * As above, but record an error if program is not found.
222 */
223static struct gl_shader_program *
224_mesa_lookup_shader_program_err(GLcontext *ctx, GLuint name,
225 const char *caller)
226{
227 if (!name) {
228 _mesa_error(ctx, GL_INVALID_VALUE, caller);
229 return NULL;
230 }
231 else {
232 struct gl_shader_program *shProg = (struct gl_shader_program *)
233 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
234 if (!shProg) {
235 _mesa_error(ctx, GL_INVALID_VALUE, caller);
236 return NULL;
237 }
238 if (shProg->Type != GL_SHADER_PROGRAM_MESA) {
239 _mesa_error(ctx, GL_INVALID_OPERATION, caller);
240 return NULL;
241 }
242 return shProg;
243 }
244}
245
246
247
248
249/**
Brianf2923612006-12-20 09:56:44 -0700250 * Allocate a new gl_shader object, initialize it.
251 */
252struct gl_shader *
253_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
254{
255 struct gl_shader *shader;
256 assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
257 shader = CALLOC_STRUCT(gl_shader);
258 if (shader) {
259 shader->Type = type;
260 shader->Name = name;
261 shader->RefCount = 1;
262 }
263 return shader;
264}
265
266
267void
268_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh)
269{
Brianf2923612006-12-20 09:56:44 -0700270 if (sh->Source)
271 _mesa_free((void *) sh->Source);
272 if (sh->InfoLog)
273 _mesa_free(sh->InfoLog);
Brian Paul90a3af72008-07-24 14:56:54 -0600274 _mesa_reference_program(ctx, &sh->Program, NULL);
Brianf2923612006-12-20 09:56:44 -0700275 _mesa_free(sh);
276}
277
278
279/**
Brian3c008a02007-04-12 15:22:32 -0600280 * Set ptr to point to sh.
281 * If ptr is pointing to another shader, decrement its refcount (and delete
282 * if refcount hits zero).
283 * Then set ptr to point to sh, incrementing its refcount.
284 */
285/* XXX this could be static */
286void
287_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr,
288 struct gl_shader *sh)
289{
290 assert(ptr);
291 if (*ptr == sh) {
292 /* no-op */
293 return;
294 }
295 if (*ptr) {
296 /* Unreference the old shader */
297 GLboolean deleteFlag = GL_FALSE;
298 struct gl_shader *old = *ptr;
299
300 ASSERT(old->RefCount > 0);
301 old->RefCount--;
Brian99193e42007-04-12 15:45:02 -0600302 /*printf("SHADER DECR %p (%d) to %d\n",
303 (void*) old, old->Name, old->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600304 deleteFlag = (old->RefCount == 0);
305
306 if (deleteFlag) {
307 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
308 _mesa_free_shader(ctx, old);
309 }
310
311 *ptr = NULL;
312 }
313 assert(!*ptr);
314
315 if (sh) {
316 /* reference new */
317 sh->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600318 /*printf("SHADER INCR %p (%d) to %d\n",
319 (void*) sh, sh->Name, sh->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600320 *ptr = sh;
321 }
322}
323
324
325/**
Brianf2923612006-12-20 09:56:44 -0700326 * Lookup a GLSL shader object.
327 */
328struct gl_shader *
329_mesa_lookup_shader(GLcontext *ctx, GLuint name)
330{
331 if (name) {
332 struct gl_shader *sh = (struct gl_shader *)
333 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
334 /* Note that both gl_shader and gl_shader_program objects are kept
335 * in the same hash table. Check the object's type to be sure it's
336 * what we're expecting.
337 */
Brianf3e8c322007-04-18 14:53:23 -0600338 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700339 return NULL;
340 }
341 return sh;
342 }
343 return NULL;
344}
345
346
Brianfa4d0362007-02-26 18:33:50 -0700347/**
Brian Pauld4172262008-07-03 16:21:15 -0600348 * As above, but record an error if shader is not found.
349 */
350static struct gl_shader *
351_mesa_lookup_shader_err(GLcontext *ctx, GLuint name, const char *caller)
352{
353 if (!name) {
354 _mesa_error(ctx, GL_INVALID_VALUE, caller);
355 return NULL;
356 }
357 else {
358 struct gl_shader *sh = (struct gl_shader *)
359 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
360 if (!sh) {
361 _mesa_error(ctx, GL_INVALID_VALUE, caller);
362 return NULL;
363 }
364 if (sh->Type == GL_SHADER_PROGRAM_MESA) {
365 _mesa_error(ctx, GL_INVALID_OPERATION, caller);
366 return NULL;
367 }
368 return sh;
369 }
370}
371
372
373
374/**
Brianfa4d0362007-02-26 18:33:50 -0700375 * Initialize context's shader state.
376 */
Brianf2923612006-12-20 09:56:44 -0700377void
378_mesa_init_shader_state(GLcontext * ctx)
379{
Brianfa4d0362007-02-26 18:33:50 -0700380 /* Device drivers may override these to control what kind of instructions
381 * are generated by the GLSL compiler.
382 */
383 ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
michal4a470f62007-08-07 15:34:11 +0100384 ctx->Shader.EmitCondCodes = GL_FALSE;/*GL_TRUE;*/ /* XXX probably want GL_FALSE... */
Brianfa4d0362007-02-26 18:33:50 -0700385 ctx->Shader.EmitComments = GL_FALSE;
Brianf2923612006-12-20 09:56:44 -0700386}
387
388
Brian5b01c5e2006-12-19 18:02:03 -0700389/**
Brian935f93f2007-03-24 16:20:02 -0600390 * Free the per-context shader-related state.
391 */
392void
393_mesa_free_shader_state(GLcontext *ctx)
394{
Brian3c008a02007-04-12 15:22:32 -0600395 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
Brian935f93f2007-03-24 16:20:02 -0600396}
397
398
399/**
Brian5b01c5e2006-12-19 18:02:03 -0700400 * Copy string from <src> to <dst>, up to maxLength characters, returning
401 * length of <dst> in <length>.
402 * \param src the strings source
403 * \param maxLength max chars to copy
404 * \param length returns number of chars copied
405 * \param dst the string destination
406 */
407static void
408copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
409{
410 GLsizei len;
411 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
412 dst[len] = src[len];
413 if (maxLength > 0)
414 dst[len] = 0;
415 if (length)
416 *length = len;
417}
418
419
Brian Pauld4172262008-07-03 16:21:15 -0600420static GLboolean
421_mesa_is_program(GLcontext *ctx, GLuint name)
422{
423 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
424 return shProg ? GL_TRUE : GL_FALSE;
425}
426
427
428static GLboolean
429_mesa_is_shader(GLcontext *ctx, GLuint name)
430{
431 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
432 return shader ? GL_TRUE : GL_FALSE;
433}
434
435
Brian5b01c5e2006-12-19 18:02:03 -0700436/**
437 * Called via ctx->Driver.AttachShader()
438 */
Brian2d2bb352007-12-07 17:11:30 -0700439static void
Brian5b01c5e2006-12-19 18:02:03 -0700440_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
441{
Brian Pauld4172262008-07-03 16:21:15 -0600442 struct gl_shader_program *shProg;
443 struct gl_shader *sh;
444 GLuint i, n;
Brian5b01c5e2006-12-19 18:02:03 -0700445
Brian Pauld4172262008-07-03 16:21:15 -0600446 shProg = _mesa_lookup_shader_program_err(ctx, program, "glAttachShader");
447 if (!shProg)
448 return;
449
450 sh = _mesa_lookup_shader_err(ctx, shader, "glAttachShader");
451 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700452 return;
453 }
454
Brian Paulfc0a48d2008-05-16 15:48:11 -0600455 n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700456 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700457 if (shProg->Shaders[i] == sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700458 /* already attached */
459 return;
Brian34ae99d2006-12-18 08:28:54 -0700460 }
461 }
Brian5b01c5e2006-12-19 18:02:03 -0700462
463 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700464 shProg->Shaders = (struct gl_shader **)
465 _mesa_realloc(shProg->Shaders,
466 n * sizeof(struct gl_shader *),
467 (n + 1) * sizeof(struct gl_shader *));
468 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700469 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
470 return;
471 }
472
473 /* append */
Brian3c008a02007-04-12 15:22:32 -0600474 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
475 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700476 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700477}
478
479
Brian2d2bb352007-12-07 17:11:30 -0700480static GLint
481_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
482 const GLchar *name)
483{
484 struct gl_shader_program *shProg
Brian Pauld4172262008-07-03 16:21:15 -0600485 = _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
Brian2d2bb352007-12-07 17:11:30 -0700486
487 if (!shProg) {
Brian2d2bb352007-12-07 17:11:30 -0700488 return -1;
489 }
490
491 if (!shProg->LinkStatus) {
492 _mesa_error(ctx, GL_INVALID_OPERATION,
493 "glGetAttribLocation(program not linked)");
494 return -1;
495 }
496
497 if (!name)
498 return -1;
499
500 if (shProg->Attributes) {
501 GLint i = _mesa_lookup_parameter_index(shProg->Attributes, -1, name);
502 if (i >= 0) {
503 return shProg->Attributes->Parameters[i].StateIndexes[0];
504 }
505 }
506 return -1;
507}
508
509
510static void
Brian5b01c5e2006-12-19 18:02:03 -0700511_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
512 const GLchar *name)
513{
Brian Pauld4172262008-07-03 16:21:15 -0600514 struct gl_shader_program *shProg;
Brianb7978af2007-01-09 19:17:17 -0700515 const GLint size = -1; /* unknown size */
516 GLint i, oldIndex;
Brian Paul72809f32008-07-25 08:34:54 -0600517 GLenum datatype = GL_FLOAT_VEC4;
Brian5b01c5e2006-12-19 18:02:03 -0700518
Brian Pauld4172262008-07-03 16:21:15 -0600519 shProg = _mesa_lookup_shader_program_err(ctx, program,
520 "glBindAttribLocation");
Brian65a18442006-12-19 18:46:56 -0700521 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700522 return;
523 }
524
Brian9e4bae92006-12-20 09:27:42 -0700525 if (!name)
526 return;
527
528 if (strncmp(name, "gl_", 3) == 0) {
529 _mesa_error(ctx, GL_INVALID_OPERATION,
530 "glBindAttribLocation(illegal name)");
531 return;
532 }
533
Brian Pauld4172262008-07-03 16:21:15 -0600534 if (index >= ctx->Const.VertexProgram.MaxAttribs) {
535 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
536 return;
537 }
538
Brian9f660252007-04-11 09:00:56 -0600539 if (shProg->LinkStatus) {
540 /* get current index/location for the attribute */
541 oldIndex = _mesa_get_attrib_location(ctx, program, name);
542 }
543 else {
544 oldIndex = -1;
545 }
Brian3209c3e2007-01-09 17:49:24 -0700546
547 /* this will replace the current value if it's already in the list */
Brian Paulfbf26e12008-07-21 13:58:50 -0600548 i = _mesa_add_attribute(shProg->Attributes, name, size, datatype, index);
Brian3209c3e2007-01-09 17:49:24 -0700549 if (i < 0) {
550 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
Brian Paul72809f32008-07-25 08:34:54 -0600551 return;
Brian3209c3e2007-01-09 17:49:24 -0700552 }
553
Brian9f660252007-04-11 09:00:56 -0600554 if (shProg->VertexProgram && oldIndex >= 0 && oldIndex != index) {
555 /* If the index changed, need to search/replace references to that attribute
556 * in the vertex program.
557 */
Brian3209c3e2007-01-09 17:49:24 -0700558 _slang_remap_attribute(&shProg->VertexProgram->Base, oldIndex, index);
559 }
Brian34ae99d2006-12-18 08:28:54 -0700560}
561
562
Brian2d2bb352007-12-07 17:11:30 -0700563static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700564_mesa_create_shader(GLcontext *ctx, GLenum type)
565{
Brian65a18442006-12-19 18:46:56 -0700566 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700567 GLuint name;
568
569 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
570
571 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700572 case GL_FRAGMENT_SHADER:
573 case GL_VERTEX_SHADER:
574 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700575 break;
576 default:
577 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
578 return 0;
579 }
580
Brian65a18442006-12-19 18:46:56 -0700581 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700582
583 return name;
584}
585
586
Brian2d2bb352007-12-07 17:11:30 -0700587static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700588_mesa_create_program(GLcontext *ctx)
589{
590 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700591 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700592
Brian65a18442006-12-19 18:46:56 -0700593 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
594 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700595
Brian65a18442006-12-19 18:46:56 -0700596 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700597
Brian3c008a02007-04-12 15:22:32 -0600598 assert(shProg->RefCount == 1);
599
Brian5b01c5e2006-12-19 18:02:03 -0700600 return name;
601}
602
603
Brian3c008a02007-04-12 15:22:32 -0600604/**
605 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
606 * DeleteProgramARB.
607 */
Brian2d2bb352007-12-07 17:11:30 -0700608static void
Brian5b01c5e2006-12-19 18:02:03 -0700609_mesa_delete_program2(GLcontext *ctx, GLuint name)
610{
Brian3c008a02007-04-12 15:22:32 -0600611 /*
612 * NOTE: deleting shaders/programs works a bit differently than
613 * texture objects (and buffer objects, etc). Shader/program
614 * handles/IDs exist in the hash table until the object is really
615 * deleted (refcount==0). With texture objects, the handle/ID is
616 * removed from the hash table in glDeleteTextures() while the tex
617 * object itself might linger until its refcount goes to zero.
618 */
Brian65a18442006-12-19 18:46:56 -0700619 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700620
Brian Pauld4172262008-07-03 16:21:15 -0600621 shProg = _mesa_lookup_shader_program_err(ctx, name, "glDeleteProgram");
622 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700623 return;
Brian5b01c5e2006-12-19 18:02:03 -0700624
Brian9e4bae92006-12-20 09:27:42 -0700625 shProg->DeletePending = GL_TRUE;
626
Brian3c008a02007-04-12 15:22:32 -0600627 /* effectively, decr shProg's refcount */
628 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700629}
630
631
Brian2d2bb352007-12-07 17:11:30 -0700632static void
Brian5b01c5e2006-12-19 18:02:03 -0700633_mesa_delete_shader(GLcontext *ctx, GLuint shader)
634{
Brian Pauld4172262008-07-03 16:21:15 -0600635 struct gl_shader *sh;
636
637 sh = _mesa_lookup_shader_err(ctx, shader, "glDeleteShader");
638 if (!sh)
Brian9e4bae92006-12-20 09:27:42 -0700639 return;
Brian5b01c5e2006-12-19 18:02:03 -0700640
Brian9e4bae92006-12-20 09:27:42 -0700641 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600642
643 /* effectively, decr sh's refcount */
644 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700645}
646
647
Brian2d2bb352007-12-07 17:11:30 -0700648static void
Brian5b01c5e2006-12-19 18:02:03 -0700649_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
650{
Brian Pauld4172262008-07-03 16:21:15 -0600651 struct gl_shader_program *shProg;
Brian Paulfc0a48d2008-05-16 15:48:11 -0600652 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700653 GLuint i, j;
654
Brian Pauld4172262008-07-03 16:21:15 -0600655 shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader");
656 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700657 return;
Brian5b01c5e2006-12-19 18:02:03 -0700658
Brian Paulfc0a48d2008-05-16 15:48:11 -0600659 n = shProg->NumShaders;
660
Brian5b01c5e2006-12-19 18:02:03 -0700661 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700662 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700663 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600664 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700665
Brian Pauld4172262008-07-03 16:21:15 -0600666 /* release */
Brian3c008a02007-04-12 15:22:32 -0600667 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700668
Brian5b01c5e2006-12-19 18:02:03 -0700669 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700670 newList = (struct gl_shader **)
671 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700672 if (!newList) {
673 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
674 return;
675 }
676 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700677 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700678 }
679 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700680 newList[j++] = shProg->Shaders[i];
681 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700682
Brian65a18442006-12-19 18:46:56 -0700683 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600684 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600685
686#ifdef DEBUG
687 /* sanity check */
688 {
689 for (j = 0; j < shProg->NumShaders; j++) {
690 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
691 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
692 assert(shProg->Shaders[j]->RefCount > 0);
693 }
694 }
695#endif
696
Brian5b01c5e2006-12-19 18:02:03 -0700697 return;
698 }
699 }
700
701 /* not found */
Brian Pauld4172262008-07-03 16:21:15 -0600702 {
703 GLenum err;
704 if (_mesa_is_shader(ctx, shader))
705 err = GL_INVALID_OPERATION;
706 else if (_mesa_is_program(ctx, shader))
707 err = GL_INVALID_OPERATION;
708 else
709 err = GL_INVALID_VALUE;
710 _mesa_error(ctx, err, "glDetachProgram(shader)");
711 return;
712 }
Brian5b01c5e2006-12-19 18:02:03 -0700713}
714
715
Brian Paulfbf26e12008-07-21 13:58:50 -0600716static GLint
717sizeof_glsl_type(GLenum type)
718{
719 switch (type) {
720 case GL_FLOAT:
721 case GL_INT:
722 case GL_BOOL:
723 return 1;
724 case GL_FLOAT_VEC2:
725 case GL_INT_VEC2:
726 case GL_BOOL_VEC2:
727 return 2;
728 case GL_FLOAT_VEC3:
729 case GL_INT_VEC3:
730 case GL_BOOL_VEC3:
731 return 3;
732 case GL_FLOAT_VEC4:
733 case GL_INT_VEC4:
734 case GL_BOOL_VEC4:
735 return 4;
736 case GL_FLOAT_MAT2:
737 case GL_FLOAT_MAT2x3:
738 case GL_FLOAT_MAT2x4:
739 return 8; /* two float[4] vectors */
740 case GL_FLOAT_MAT3:
741 case GL_FLOAT_MAT3x2:
742 case GL_FLOAT_MAT3x4:
743 return 12; /* three float[4] vectors */
744 case GL_FLOAT_MAT4:
745 case GL_FLOAT_MAT4x2:
746 case GL_FLOAT_MAT4x3:
747 return 16; /* four float[4] vectors */
748 default:
749 _mesa_problem(NULL, "Invalid type in sizeof_glsl_type()");
750 return 1;
751 }
752}
753
754
Brian Paul8a40fe02008-08-06 16:26:47 -0600755static GLboolean
756is_boolean_type(GLenum type)
757{
758 switch (type) {
759 case GL_BOOL:
760 case GL_BOOL_VEC2:
761 case GL_BOOL_VEC3:
762 case GL_BOOL_VEC4:
763 return GL_TRUE;
764 default:
765 return GL_FALSE;
766 }
767}
768
769
770static GLboolean
771is_integer_type(GLenum type)
772{
773 switch (type) {
774 case GL_INT:
775 case GL_INT_VEC2:
776 case GL_INT_VEC3:
777 case GL_INT_VEC4:
778 return GL_TRUE;
779 default:
780 return GL_FALSE;
781 }
782}
783
784
Brian2d2bb352007-12-07 17:11:30 -0700785static void
Brian5b01c5e2006-12-19 18:02:03 -0700786_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
787 GLsizei maxLength, GLsizei *length, GLint *size,
788 GLenum *type, GLchar *nameOut)
789{
Brian Pauld4172262008-07-03 16:21:15 -0600790 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700791
Brian Pauld4172262008-07-03 16:21:15 -0600792 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
793 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700794 return;
Brian5b01c5e2006-12-19 18:02:03 -0700795
Brian65a18442006-12-19 18:46:56 -0700796 if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600797 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700798 return;
799 }
800
801 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700802 shProg->Attributes->Parameters[index].Name);
Brian5b01c5e2006-12-19 18:02:03 -0700803 if (size)
Brian Paulfbf26e12008-07-21 13:58:50 -0600804 *size = shProg->Attributes->Parameters[index].Size
805 / sizeof_glsl_type(shProg->Attributes->Parameters[index].DataType);
Brian5b01c5e2006-12-19 18:02:03 -0700806 if (type)
Brian Paulfbf26e12008-07-21 13:58:50 -0600807 *type = shProg->Attributes->Parameters[index].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700808}
809
810
Brian Paul8a40fe02008-08-06 16:26:47 -0600811static struct gl_program_parameter *
812get_uniform_parameter(const struct gl_shader_program *shProg, GLuint index)
813{
814 const struct gl_program *prog;
815 GLint progPos;
816
817 progPos = shProg->Uniforms->Uniforms[index].VertPos;
818 if (progPos >= 0) {
819 prog = &shProg->VertexProgram->Base;
820 }
821 else {
822 progPos = shProg->Uniforms->Uniforms[index].FragPos;
823 if (progPos >= 0) {
824 prog = &shProg->FragmentProgram->Base;
825 }
826 }
827
828 if (!prog || progPos < 0)
829 return NULL; /* should never happen */
830
831 return &prog->Parameters->Parameters[progPos];
832}
833
834
Brian5b01c5e2006-12-19 18:02:03 -0700835/**
836 * Called via ctx->Driver.GetActiveUniform().
837 */
Brian2d2bb352007-12-07 17:11:30 -0700838static void
Brian5b01c5e2006-12-19 18:02:03 -0700839_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
840 GLsizei maxLength, GLsizei *length, GLint *size,
841 GLenum *type, GLchar *nameOut)
842{
Brian Pauld4172262008-07-03 16:21:15 -0600843 const struct gl_shader_program *shProg;
Brianbc029242008-04-04 18:59:21 -0600844 const struct gl_program *prog;
845 GLint progPos;
Brian5b01c5e2006-12-19 18:02:03 -0700846
Brian Pauld4172262008-07-03 16:21:15 -0600847 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
848 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700849 return;
Brian5b01c5e2006-12-19 18:02:03 -0700850
Brianbc029242008-04-04 18:59:21 -0600851 if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
Brian5b01c5e2006-12-19 18:02:03 -0700852 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
853 return;
854 }
855
Brianbc029242008-04-04 18:59:21 -0600856 progPos = shProg->Uniforms->Uniforms[index].VertPos;
857 if (progPos >= 0) {
858 prog = &shProg->VertexProgram->Base;
859 }
860 else {
861 progPos = shProg->Uniforms->Uniforms[index].FragPos;
862 if (progPos >= 0) {
863 prog = &shProg->FragmentProgram->Base;
Brian274ac7a2007-04-18 16:05:53 -0600864 }
865 }
866
Brianbc029242008-04-04 18:59:21 -0600867 if (!prog || progPos < 0)
868 return; /* should never happen */
869
870 if (nameOut)
871 copy_string(nameOut, maxLength, length,
872 prog->Parameters->Parameters[progPos].Name);
873 if (size)
Brian Paulfbf26e12008-07-21 13:58:50 -0600874 *size = prog->Parameters->Parameters[progPos].Size
875 / sizeof_glsl_type(prog->Parameters->Parameters[progPos].DataType);
Brianbc029242008-04-04 18:59:21 -0600876 if (type)
877 *type = prog->Parameters->Parameters[progPos].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700878}
879
880
881/**
882 * Called via ctx->Driver.GetAttachedShaders().
883 */
Brian2d2bb352007-12-07 17:11:30 -0700884static void
Brian5b01c5e2006-12-19 18:02:03 -0700885_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
886 GLsizei *count, GLuint *obj)
887{
Brian Pauld4172262008-07-03 16:21:15 -0600888 struct gl_shader_program *shProg =
889 _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders");
Brian65a18442006-12-19 18:46:56 -0700890 if (shProg) {
José Fonseca53174af2008-05-31 18:14:09 +0900891 GLuint i;
Brian Pauld4172262008-07-03 16:21:15 -0600892 for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) {
Brian65a18442006-12-19 18:46:56 -0700893 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700894 }
895 if (count)
896 *count = i;
897 }
Brian5b01c5e2006-12-19 18:02:03 -0700898}
899
900
Brian2d2bb352007-12-07 17:11:30 -0700901static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700902_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700903{
904#if 0
905 GET_CURRENT_CONTEXT(ctx);
906
907 switch (pname) {
908 case GL_PROGRAM_OBJECT_ARB:
909 {
Brian5b01c5e2006-12-19 18:02:03 -0700910 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700911
912 if (pro != NULL)
913 return (**pro)._container._generic.
914 GetName((struct gl2_generic_intf **) (pro));
915 }
916 break;
917 default:
918 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
919 }
920#endif
921 return 0;
922}
923
924
Brian2d2bb352007-12-07 17:11:30 -0700925static void
Brian5b01c5e2006-12-19 18:02:03 -0700926_mesa_get_programiv(GLcontext *ctx, GLuint program,
927 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700928{
Brian65a18442006-12-19 18:46:56 -0700929 struct gl_shader_program *shProg
930 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700931
Brian65a18442006-12-19 18:46:56 -0700932 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700933 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700934 return;
935 }
936
Brian5b01c5e2006-12-19 18:02:03 -0700937 switch (pname) {
938 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700939 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700940 break;
941 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700942 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700943 break;
Brian5b01c5e2006-12-19 18:02:03 -0700944 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700945 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700946 break;
947 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600948 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700949 break;
950 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700951 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700952 break;
953 case GL_ACTIVE_ATTRIBUTES:
Brian3209c3e2007-01-09 17:49:24 -0700954 *params = shProg->Attributes ? shProg->Attributes->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700955 break;
956 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600957 *params = _mesa_longest_parameter_name(shProg->Attributes,
958 PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700959 break;
960 case GL_ACTIVE_UNIFORMS:
Brianbc029242008-04-04 18:59:21 -0600961 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700962 break;
963 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brianbc029242008-04-04 18:59:21 -0600964 *params = _mesa_longest_uniform_name(shProg->Uniforms);
Brian274ac7a2007-04-18 16:05:53 -0600965 if (*params > 0)
966 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700967 break;
Brian Paul18cd9c22008-08-06 12:45:14 -0600968 case GL_PROGRAM_BINARY_LENGTH_OES:
969 *params = 0;
970 break;
Brian34ae99d2006-12-18 08:28:54 -0700971 default:
Brian5b01c5e2006-12-19 18:02:03 -0700972 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
973 return;
Brian34ae99d2006-12-18 08:28:54 -0700974 }
Brian5b01c5e2006-12-19 18:02:03 -0700975}
Brian34ae99d2006-12-18 08:28:54 -0700976
Brian34ae99d2006-12-18 08:28:54 -0700977
Brian2d2bb352007-12-07 17:11:30 -0700978static void
Brian5b01c5e2006-12-19 18:02:03 -0700979_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
980{
Brian Pauld4172262008-07-03 16:21:15 -0600981 struct gl_shader *shader = _mesa_lookup_shader_err(ctx, name, "glGetShaderiv");
Brian5b01c5e2006-12-19 18:02:03 -0700982
983 if (!shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700984 return;
985 }
Brian65a18442006-12-19 18:46:56 -0700986
Brian5b01c5e2006-12-19 18:02:03 -0700987 switch (pname) {
988 case GL_SHADER_TYPE:
989 *params = shader->Type;
990 break;
991 case GL_DELETE_STATUS:
992 *params = shader->DeletePending;
993 break;
994 case GL_COMPILE_STATUS:
995 *params = shader->CompileStatus;
996 break;
997 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600998 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700999 break;
1000 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001001 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001002 break;
1003 default:
1004 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
1005 return;
1006 }
1007}
1008
1009
Brian2d2bb352007-12-07 17:11:30 -07001010static void
Brian5b01c5e2006-12-19 18:02:03 -07001011_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
1012 GLsizei *length, GLchar *infoLog)
1013{
Brian65a18442006-12-19 18:46:56 -07001014 struct gl_shader_program *shProg
1015 = _mesa_lookup_shader_program(ctx, program);
1016 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -07001017 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
1018 return;
1019 }
Brian65a18442006-12-19 18:46:56 -07001020 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -07001021}
1022
1023
Brian2d2bb352007-12-07 17:11:30 -07001024static void
Brian5b01c5e2006-12-19 18:02:03 -07001025_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
1026 GLsizei *length, GLchar *infoLog)
1027{
Brian65a18442006-12-19 18:46:56 -07001028 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
1029 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001030 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
1031 return;
1032 }
Brian65a18442006-12-19 18:46:56 -07001033 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -07001034}
1035
1036
1037/**
1038 * Called via ctx->Driver.GetShaderSource().
1039 */
Brian2d2bb352007-12-07 17:11:30 -07001040static void
Brian5b01c5e2006-12-19 18:02:03 -07001041_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
1042 GLsizei *length, GLchar *sourceOut)
1043{
Brian Pauld4172262008-07-03 16:21:15 -06001044 struct gl_shader *sh;
1045 sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource");
Brian65a18442006-12-19 18:46:56 -07001046 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001047 return;
1048 }
Brian65a18442006-12-19 18:46:56 -07001049 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -07001050}
1051
1052
Brian Paul7a6eba52008-08-06 13:07:09 -06001053static void
1054get_matrix_dims(GLenum type, GLint *rows, GLint *cols)
1055{
1056 switch (type) {
1057 case GL_FLOAT_MAT2:
1058 *rows = *cols = 2;
1059 break;
1060 case GL_FLOAT_MAT2x3:
1061 *rows = 3;
1062 *cols = 2;
1063 break;
1064 case GL_FLOAT_MAT2x4:
1065 *rows = 4;
1066 *cols = 2;
1067 break;
1068 case GL_FLOAT_MAT3:
1069 *rows = 3;
1070 *cols = 3;
1071 break;
1072 case GL_FLOAT_MAT3x2:
1073 *rows = 2;
1074 *cols = 3;
1075 break;
1076 case GL_FLOAT_MAT3x4:
1077 *rows = 4;
1078 *cols = 3;
1079 break;
1080 case GL_FLOAT_MAT4:
1081 *rows = 4;
1082 *cols = 4;
1083 break;
1084 case GL_FLOAT_MAT4x2:
1085 *rows = 2;
1086 *cols = 4;
1087 break;
1088 case GL_FLOAT_MAT4x3:
1089 *rows = 3;
1090 *cols = 4;
1091 break;
1092 default:
1093 *rows = *cols = 0;
1094 }
1095}
1096
1097
1098/**
1099 * Determine the number of rows and columns occupied by a uniform
1100 * according to its datatype.
1101 */
1102static void
1103get_uniform_rows_cols(const struct gl_program_parameter *p,
1104 GLint *rows, GLint *cols)
1105{
1106 get_matrix_dims(p->DataType, rows, cols);
1107 if (*rows == 0 && *cols == 0) {
1108 /* not a matrix type, probably a float or vector */
1109 *rows = p->Size / 4 + 1;
1110 if (p->Size % 4 == 0)
1111 *cols = 4;
1112 else
1113 *cols = p->Size % 4;
1114 }
1115}
1116
1117
Brian Paul072c4742008-07-08 16:12:01 -06001118#define MAX_UNIFORM_ELEMENTS 16
1119
Brian5b01c5e2006-12-19 18:02:03 -07001120/**
Brian Paul072c4742008-07-08 16:12:01 -06001121 * Helper for GetUniformfv(), GetUniformiv()
1122 * Returns number of elements written to 'params' output.
Brian5b01c5e2006-12-19 18:02:03 -07001123 */
Brian Paul072c4742008-07-08 16:12:01 -06001124static GLuint
1125get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1126 GLfloat *params)
Brian5b01c5e2006-12-19 18:02:03 -07001127{
Brian65a18442006-12-19 18:46:56 -07001128 struct gl_shader_program *shProg
Brian Paul18cd9c22008-08-06 12:45:14 -06001129 = _mesa_lookup_shader_program_err(ctx, program, "glGetUniform[if]v");
Brian65a18442006-12-19 18:46:56 -07001130 if (shProg) {
Brian Paul22427692008-06-28 16:47:22 -06001131 if (shProg->Uniforms &&
Michal Krolf9c574d2008-07-15 11:44:47 +02001132 location >= 0 && location < (GLint) shProg->Uniforms->NumUniforms) {
Brian Paul22427692008-06-28 16:47:22 -06001133 GLint progPos;
Brian Paulfc0a48d2008-05-16 15:48:11 -06001134 const struct gl_program *prog = NULL;
Brianbc029242008-04-04 18:59:21 -06001135
1136 progPos = shProg->Uniforms->Uniforms[location].VertPos;
1137 if (progPos >= 0) {
1138 prog = &shProg->VertexProgram->Base;
1139 }
1140 else {
1141 progPos = shProg->Uniforms->Uniforms[location].FragPos;
1142 if (progPos >= 0) {
1143 prog = &shProg->FragmentProgram->Base;
1144 }
1145 }
1146
Brian Paulfc0a48d2008-05-16 15:48:11 -06001147 ASSERT(prog);
1148 if (prog) {
Brian Paul7a6eba52008-08-06 13:07:09 -06001149 const struct gl_program_parameter *p =
1150 &prog->Parameters->Parameters[progPos];
1151 GLint rows, cols, i, j, k;
Brian Paul072c4742008-07-08 16:12:01 -06001152
Brian Paul7a6eba52008-08-06 13:07:09 -06001153 /* See uniformiv() below */
1154 assert(p->Size <= MAX_UNIFORM_ELEMENTS);
1155
1156 get_uniform_rows_cols(p, &rows, &cols);
1157
1158 k = 0;
1159 for (i = 0; i < rows; i++) {
1160 for (j = 0; j < cols; j++ ) {
1161 params[k++] = prog->Parameters->ParameterValues[progPos+i][j];
1162 }
Brian Paulfc0a48d2008-05-16 15:48:11 -06001163 }
Brian Paul7a6eba52008-08-06 13:07:09 -06001164
1165 return p->Size;
Brian5b01c5e2006-12-19 18:02:03 -07001166 }
1167 }
1168 else {
Brian Paul22427692008-06-28 16:47:22 -06001169 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
Brian5b01c5e2006-12-19 18:02:03 -07001170 }
1171 }
Brian Paul072c4742008-07-08 16:12:01 -06001172 return 0;
1173}
1174
1175
1176/**
1177 * Called via ctx->Driver.GetUniformfv().
1178 */
1179static void
1180_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1181 GLfloat *params)
1182{
1183 (void) get_uniformfv(ctx, program, location, params);
1184}
1185
1186
1187/**
1188 * Called via ctx->Driver.GetUniformiv().
1189 */
1190static void
1191_mesa_get_uniformiv(GLcontext *ctx, GLuint program, GLint location,
1192 GLint *params)
1193{
1194 GLfloat fparams[MAX_UNIFORM_ELEMENTS];
1195 GLuint n = get_uniformfv(ctx, program, location, fparams);
1196 GLuint i;
1197 assert(n <= MAX_UNIFORM_ELEMENTS);
1198 for (i = 0; i < n; i++) {
1199 params[i] = (GLint) fparams[i];
1200 }
Brian5b01c5e2006-12-19 18:02:03 -07001201}
1202
1203
1204/**
Brian Paul8a40fe02008-08-06 16:26:47 -06001205 * The value returned by GetUniformLocation actually encodes two things:
1206 * 1. the index into the prog->Uniforms[] array for the uniform
1207 * 2. an offset in the prog->ParameterValues[] array for specifying array
1208 * elements or structure fields.
1209 * This function merges those two values.
1210 */
1211static void
1212merge_location_offset(GLint *location, GLint offset)
1213{
1214 *location = *location | (offset << 16);
1215}
1216
1217
1218/**
1219 * Seperate the uniform location and parameter offset. See above.
1220 */
1221static void
1222split_location_offset(GLint *location, GLint *offset)
1223{
1224 *offset = (*location >> 16);
1225 *location = *location & 0xffff;
1226}
1227
1228
1229/**
Brian5b01c5e2006-12-19 18:02:03 -07001230 * Called via ctx->Driver.GetUniformLocation().
Brian Paul8a40fe02008-08-06 16:26:47 -06001231 *
1232 * The return value will encode two values, the uniform location and an
1233 * offset (used for arrays, structs).
Brian5b01c5e2006-12-19 18:02:03 -07001234 */
Brian2d2bb352007-12-07 17:11:30 -07001235static GLint
Brian5b01c5e2006-12-19 18:02:03 -07001236_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
1237{
Brian Paul8a40fe02008-08-06 16:26:47 -06001238 GLint offset = 0, location = -1;
1239
Brian Pauld4172262008-07-03 16:21:15 -06001240 struct gl_shader_program *shProg =
1241 _mesa_lookup_shader_program_err(ctx, program, "glGetUniformLocation");
1242
Brianbc029242008-04-04 18:59:21 -06001243 if (!shProg)
1244 return -1;
Brian5b01c5e2006-12-19 18:02:03 -07001245
Brian Paul294b0612008-07-04 09:58:14 -06001246 if (shProg->LinkStatus == GL_FALSE) {
1247 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
1248 return -1;
1249 }
1250
Brian Pauld4172262008-07-03 16:21:15 -06001251 /* XXX we should return -1 if the uniform was declared, but not
1252 * actually used.
1253 */
1254
Brian Paul8a40fe02008-08-06 16:26:47 -06001255 /* XXX we need to be able to parse uniform names for structs and arrays
1256 * such as:
1257 * mymatrix[1]
1258 * mystruct.field1
1259 */
1260
1261 {
1262 /* handle 1-dimension arrays here... */
1263 char *c = strchr(name, '[');
1264 if (c) {
1265 /* truncate name at [ */
1266 const GLint len = c - name;
1267 GLchar *newName = _mesa_malloc(len + 1);
1268 if (!newName)
1269 return -1; /* out of mem */
1270 _mesa_memcpy(newName, name, len);
1271 newName[len] = 0;
1272
1273 location = _mesa_lookup_uniform(shProg->Uniforms, newName);
1274 if (location >= 0) {
1275 const GLint element = _mesa_atoi(c + 1);
1276 if (element > 0) {
1277 /* get type of the uniform array element */
1278 struct gl_program_parameter *p;
1279 p = get_uniform_parameter(shProg, location);
1280 if (p) {
1281 GLint rows, cols;
1282 get_matrix_dims(p->DataType, &rows, &cols);
1283 if (rows < 1)
1284 rows = 1;
1285 offset = element * rows;
1286 }
1287 }
1288 }
1289
1290 _mesa_free(newName);
1291 }
1292 }
1293
1294 if (location < 0) {
1295 location = _mesa_lookup_uniform(shProg->Uniforms, name);
1296 }
1297
1298 if (location >= 0) {
1299 merge_location_offset(&location, offset);
1300 }
1301
1302 return location;
Brian5b01c5e2006-12-19 18:02:03 -07001303}
1304
1305
Brian34ae99d2006-12-18 08:28:54 -07001306
Brian5b01c5e2006-12-19 18:02:03 -07001307/**
1308 * Called via ctx->Driver.ShaderSource()
1309 */
Brian2d2bb352007-12-07 17:11:30 -07001310static void
Brian5b01c5e2006-12-19 18:02:03 -07001311_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -07001312{
Brian Pauld4172262008-07-03 16:21:15 -06001313 struct gl_shader *sh;
1314
1315 sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource");
1316 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001317 return;
Brian34ae99d2006-12-18 08:28:54 -07001318
Brian34ae99d2006-12-18 08:28:54 -07001319 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -07001320 if (sh->Source) {
1321 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -07001322 }
Brian65a18442006-12-19 18:46:56 -07001323 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -07001324 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -07001325}
1326
1327
Brian5b01c5e2006-12-19 18:02:03 -07001328/**
1329 * Called via ctx->Driver.CompileShader()
1330 */
Brian2d2bb352007-12-07 17:11:30 -07001331static void
Brian5b01c5e2006-12-19 18:02:03 -07001332_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -07001333{
Brian Pauld4172262008-07-03 16:21:15 -06001334 struct gl_shader *sh;
Brian34ae99d2006-12-18 08:28:54 -07001335
Brian Pauld4172262008-07-03 16:21:15 -06001336 sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader");
1337 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001338 return;
Brian34ae99d2006-12-18 08:28:54 -07001339
Brian43975832007-01-04 08:21:09 -07001340 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -07001341}
1342
1343
Brian5b01c5e2006-12-19 18:02:03 -07001344/**
1345 * Called via ctx->Driver.LinkProgram()
1346 */
Brian2d2bb352007-12-07 17:11:30 -07001347static void
Brian5b01c5e2006-12-19 18:02:03 -07001348_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001349{
Brian65a18442006-12-19 18:46:56 -07001350 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001351
Brian Pauld4172262008-07-03 16:21:15 -06001352 shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
1353 if (!shProg)
Brian34ae99d2006-12-18 08:28:54 -07001354 return;
Brian34ae99d2006-12-18 08:28:54 -07001355
Brian Paulfc0a48d2008-05-16 15:48:11 -06001356 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1357
Brianc1771912007-02-16 09:56:19 -07001358 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001359}
1360
1361
1362/**
Brian5b01c5e2006-12-19 18:02:03 -07001363 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001364 */
Brian5b01c5e2006-12-19 18:02:03 -07001365void
1366_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001367{
Brian3c008a02007-04-12 15:22:32 -06001368 struct gl_shader_program *shProg;
1369
Brian00d63aa2007-02-03 11:35:02 -07001370 if (ctx->Shader.CurrentProgram &&
1371 ctx->Shader.CurrentProgram->Name == program) {
1372 /* no-op */
1373 return;
1374 }
1375
1376 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1377
Brian5b01c5e2006-12-19 18:02:03 -07001378 if (program) {
Brian Pauld4172262008-07-03 16:21:15 -06001379 shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
Brian65a18442006-12-19 18:46:56 -07001380 if (!shProg) {
Brian Pauld4172262008-07-03 16:21:15 -06001381 return;
1382 }
1383 if (!shProg->LinkStatus) {
1384 _mesa_error(ctx, GL_INVALID_OPERATION, "glUseProgram");
Brian5b01c5e2006-12-19 18:02:03 -07001385 return;
1386 }
Brian5b01c5e2006-12-19 18:02:03 -07001387 }
1388 else {
Brian3c008a02007-04-12 15:22:32 -06001389 shProg = NULL;
1390 }
1391
1392 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001393}
Brian34ae99d2006-12-18 08:28:54 -07001394
Brian5b01c5e2006-12-19 18:02:03 -07001395
Brian8fed2462007-10-26 19:19:09 -06001396
1397/**
1398 * Update the vertex and fragment program's TexturesUsed arrays.
1399 */
1400static void
1401update_textures_used(struct gl_program *prog)
1402{
1403 GLuint s;
1404
1405 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1406
1407 for (s = 0; s < MAX_SAMPLERS; s++) {
1408 if (prog->SamplersUsed & (1 << s)) {
1409 GLuint u = prog->SamplerUnits[s];
1410 GLuint t = prog->SamplerTargets[s];
1411 assert(u < MAX_TEXTURE_IMAGE_UNITS);
1412 prog->TexturesUsed[u] |= (1 << t);
1413 }
1414 }
1415}
1416
1417
Brian63025ec2008-07-21 20:42:05 -06001418static GLboolean
1419is_sampler_type(GLenum type)
1420{
1421 switch (type) {
1422 case GL_SAMPLER_1D:
1423 case GL_SAMPLER_2D:
1424 case GL_SAMPLER_3D:
1425 case GL_SAMPLER_CUBE:
1426 case GL_SAMPLER_1D_SHADOW:
1427 case GL_SAMPLER_2D_SHADOW:
1428 case GL_SAMPLER_2D_RECT_ARB:
1429 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
1430 case GL_SAMPLER_1D_ARRAY_EXT:
1431 case GL_SAMPLER_2D_ARRAY_EXT:
1432 return GL_TRUE;
1433 default:
1434 return GL_FALSE;
1435 }
1436}
1437
1438
Brian5b01c5e2006-12-19 18:02:03 -07001439/**
Brian Paulfbf26e12008-07-21 13:58:50 -06001440 * Check if the type given by userType is allowed to set a uniform of the
1441 * target type. Generally, equivalence is required, but setting Boolean
1442 * uniforms can be done with glUniformiv or glUniformfv.
1443 */
1444static GLboolean
1445compatible_types(GLenum userType, GLenum targetType)
1446{
1447 if (userType == targetType)
1448 return GL_TRUE;
1449
1450 if (targetType == GL_BOOL && (userType == GL_FLOAT || userType == GL_INT))
1451 return GL_TRUE;
1452
1453 if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 ||
1454 userType == GL_INT_VEC2))
1455 return GL_TRUE;
1456
1457 if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 ||
1458 userType == GL_INT_VEC3))
1459 return GL_TRUE;
1460
1461 if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 ||
1462 userType == GL_INT_VEC4))
1463 return GL_TRUE;
1464
Brian63025ec2008-07-21 20:42:05 -06001465 if (is_sampler_type(targetType) && userType == GL_INT)
1466 return GL_TRUE;
1467
Brian Paulfbf26e12008-07-21 13:58:50 -06001468 return GL_FALSE;
1469}
1470
1471
1472/**
Brianbc029242008-04-04 18:59:21 -06001473 * Set the value of a program's uniform variable.
1474 * \param program the program whose uniform to update
Brian Paul8a40fe02008-08-06 16:26:47 -06001475 * \param index the index of the program parameter for the uniform
1476 * \param offset additional parameter slot offset (for arrays)
Brianbc029242008-04-04 18:59:21 -06001477 * \param type the datatype of the uniform
1478 * \param count the number of uniforms to set
1479 * \param elems number of elements per uniform
1480 * \param values the new values
1481 */
1482static void
Brian Paul8a40fe02008-08-06 16:26:47 -06001483set_program_uniform(GLcontext *ctx, struct gl_program *program,
1484 GLint index, GLint offset,
1485 GLenum type, GLsizei count, GLint elems,
1486 const void *values)
Brianbc029242008-04-04 18:59:21 -06001487{
Brian Paul8a40fe02008-08-06 16:26:47 -06001488 assert(offset >= 0);
1489
Brian Paulfbf26e12008-07-21 13:58:50 -06001490 if (!compatible_types(type,
Brian Paul8a40fe02008-08-06 16:26:47 -06001491 program->Parameters->Parameters[index].DataType)) {
Brian Paulfbf26e12008-07-21 13:58:50 -06001492 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
1493 return;
1494 }
1495
Brian Paul8a40fe02008-08-06 16:26:47 -06001496 if (index + offset > program->Parameters->Size) {
1497 /* out of bounds! */
1498 return;
1499 }
1500
1501 if (program->Parameters->Parameters[index].Type == PROGRAM_SAMPLER) {
Brianbc029242008-04-04 18:59:21 -06001502 /* This controls which texture unit which is used by a sampler */
1503 GLuint texUnit, sampler;
1504
1505 /* data type for setting samplers must be int */
1506 if (type != GL_INT || count != 1) {
1507 _mesa_error(ctx, GL_INVALID_OPERATION,
1508 "glUniform(only glUniform1i can be used "
1509 "to set sampler uniforms)");
1510 return;
1511 }
1512
Brian Paul8a40fe02008-08-06 16:26:47 -06001513 sampler = (GLuint) program->Parameters->ParameterValues[index][0];
Brianbc029242008-04-04 18:59:21 -06001514 texUnit = ((GLuint *) values)[0];
1515
1516 /* check that the sampler (tex unit index) is legal */
1517 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1518 _mesa_error(ctx, GL_INVALID_VALUE,
1519 "glUniform1(invalid sampler/tex unit index)");
1520 return;
1521 }
1522
1523 /* This maps a sampler to a texture unit: */
1524 program->SamplerUnits[sampler] = texUnit;
1525 update_textures_used(program);
1526
1527 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1528 }
1529 else {
1530 /* ordinary uniform variable */
José Fonseca18ec1402008-06-24 11:34:46 +09001531 GLsizei k, i;
Brian Paul8a40fe02008-08-06 16:26:47 -06001532 GLint slots = (program->Parameters->Parameters[index].Size + 3) / 4;
Brianbc029242008-04-04 18:59:21 -06001533
Brian Paul8a40fe02008-08-06 16:26:47 -06001534 if (count * elems > (GLint) program->Parameters->Parameters[index].Size) {
Brianbc029242008-04-04 18:59:21 -06001535 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1536 return;
1537 }
1538
Brian Paul8a40fe02008-08-06 16:26:47 -06001539 if (count > slots)
1540 count = slots;
1541
Brianbc029242008-04-04 18:59:21 -06001542 for (k = 0; k < count; k++) {
Brian Paul8a40fe02008-08-06 16:26:47 -06001543 GLfloat *uniformVal = program->Parameters->ParameterValues[index + offset + k];
1544 if (is_integer_type(type)) {
Brianbc029242008-04-04 18:59:21 -06001545 const GLint *iValues = ((const GLint *) values) + k * elems;
1546 for (i = 0; i < elems; i++) {
1547 uniformVal[i] = (GLfloat) iValues[i];
1548 }
1549 }
1550 else {
1551 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1552 for (i = 0; i < elems; i++) {
1553 uniformVal[i] = fValues[i];
1554 }
1555 }
Brian Paul8a40fe02008-08-06 16:26:47 -06001556
1557 /* if the uniform is bool-valued, convert to 1.0 or 0.0 */
1558 if (is_boolean_type(program->Parameters->Parameters[index].DataType)) {
1559 for (i = 0; i < elems; i++) {
1560 uniformVal[i] = uniformVal[i] ? 1.0 : 0.0;
1561 }
1562 }
Brianbc029242008-04-04 18:59:21 -06001563 }
1564 }
1565}
1566
1567
1568/**
Brian5b01c5e2006-12-19 18:02:03 -07001569 * Called via ctx->Driver.Uniform().
1570 */
Brian2d2bb352007-12-07 17:11:30 -07001571static void
Brian5b01c5e2006-12-19 18:02:03 -07001572_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1573 const GLvoid *values, GLenum type)
1574{
Brian3a8e2772006-12-20 17:19:16 -07001575 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paul8a40fe02008-08-06 16:26:47 -06001576 GLint elems, offset;
Brian3a8e2772006-12-20 17:19:16 -07001577
1578 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001579 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001580 return;
1581 }
1582
Brian Paulf84005c2008-05-14 16:01:31 -06001583 if (location == -1)
1584 return; /* The standard specifies this as a no-op */
1585
Brian Paul8a40fe02008-08-06 16:26:47 -06001586 split_location_offset(&location, &offset);
1587
Brianbc029242008-04-04 18:59:21 -06001588 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian3a8e2772006-12-20 17:19:16 -07001589 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
1590 return;
1591 }
1592
Brian52363952007-03-13 16:50:24 -06001593 if (count < 0) {
1594 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1595 return;
1596 }
1597
Brian98650bd2007-03-13 16:32:48 -06001598 switch (type) {
1599 case GL_FLOAT:
1600 case GL_INT:
1601 elems = 1;
1602 break;
1603 case GL_FLOAT_VEC2:
1604 case GL_INT_VEC2:
1605 elems = 2;
1606 break;
1607 case GL_FLOAT_VEC3:
1608 case GL_INT_VEC3:
1609 elems = 3;
1610 break;
1611 case GL_FLOAT_VEC4:
1612 case GL_INT_VEC4:
1613 elems = 4;
1614 break;
1615 default:
1616 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1617 return;
Brian89dc4852007-01-04 14:35:44 -07001618 }
Brian98650bd2007-03-13 16:32:48 -06001619
Brianbc029242008-04-04 18:59:21 -06001620 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1621
1622 /* A uniform var may be used by both a vertex shader and a fragment
1623 * shader. We may need to update one or both shader's uniform here:
1624 */
1625 if (shProg->VertexProgram) {
Brian Paul8a40fe02008-08-06 16:26:47 -06001626 /* convert uniform location to program parameter index */
1627 GLint index = shProg->Uniforms->Uniforms[location].VertPos;
1628 if (index >= 0) {
Brianbc029242008-04-04 18:59:21 -06001629 set_program_uniform(ctx, &shProg->VertexProgram->Base,
Brian Paul8a40fe02008-08-06 16:26:47 -06001630 index, offset, type, count, elems, values);
Brianbc029242008-04-04 18:59:21 -06001631 }
Brian98650bd2007-03-13 16:32:48 -06001632 }
1633
Brianbc029242008-04-04 18:59:21 -06001634 if (shProg->FragmentProgram) {
Brian Paul8a40fe02008-08-06 16:26:47 -06001635 /* convert uniform location to program parameter index */
1636 GLint index = shProg->Uniforms->Uniforms[location].FragPos;
1637 if (index >= 0) {
Brianbc029242008-04-04 18:59:21 -06001638 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
Brian Paul8a40fe02008-08-06 16:26:47 -06001639 index, offset, type, count, elems, values);
Brian8fed2462007-10-26 19:19:09 -06001640 }
Brianbc029242008-04-04 18:59:21 -06001641 }
1642}
Brian8fed2462007-10-26 19:19:09 -06001643
Brian8fed2462007-10-26 19:19:09 -06001644
Brian Paul8a40fe02008-08-06 16:26:47 -06001645/**
1646 * Set a matrix-valued program parameter.
1647 */
Brianbc029242008-04-04 18:59:21 -06001648static void
1649set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
Brian Paul8a40fe02008-08-06 16:26:47 -06001650 GLuint index, GLuint offset,
1651 GLuint count, GLuint rows, GLuint cols,
Brianbc029242008-04-04 18:59:21 -06001652 GLboolean transpose, const GLfloat *values)
1653{
Brian Paulfbf26e12008-07-21 13:58:50 -06001654 GLuint mat, row, col;
Brian Paul8a40fe02008-08-06 16:26:47 -06001655 GLuint dst = index + offset, src = 0;
Brian Paulfbf26e12008-07-21 13:58:50 -06001656 GLint nr, nc;
1657
1658 /* check that the number of rows, columns is correct */
Brian Paul8a40fe02008-08-06 16:26:47 -06001659 get_matrix_dims(program->Parameters->Parameters[index].DataType, &nr, &nc);
Brian Paulfbf26e12008-07-21 13:58:50 -06001660 if (rows != nr || cols != nc) {
1661 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Paul8a40fe02008-08-06 16:26:47 -06001662 "glUniformMatrix(matrix size mismatch)");
1663 return;
1664 }
1665
1666 if (index + offset > program->Parameters->Size) {
1667 /* out of bounds! */
Brian Paulfbf26e12008-07-21 13:58:50 -06001668 return;
1669 }
1670
Brianbc029242008-04-04 18:59:21 -06001671 /*
1672 * Note: the _columns_ of a matrix are stored in program registers, not
Brian Paulb64882d2008-07-18 12:51:39 -06001673 * the rows. So, the loops below look a little funny.
1674 * XXX could optimize this a bit...
Brianbc029242008-04-04 18:59:21 -06001675 */
Brian Paulb64882d2008-07-18 12:51:39 -06001676
1677 /* loop over matrices */
1678 for (mat = 0; mat < count; mat++) {
1679
1680 /* each matrix: */
Brianbc029242008-04-04 18:59:21 -06001681 for (col = 0; col < cols; col++) {
Brian Paulb64882d2008-07-18 12:51:39 -06001682 GLfloat *v = program->Parameters->ParameterValues[dst];
Brianbc029242008-04-04 18:59:21 -06001683 for (row = 0; row < rows; row++) {
Brian Paulb64882d2008-07-18 12:51:39 -06001684 if (transpose) {
1685 v[row] = values[src + row * cols + col];
1686 }
1687 else {
1688 v[row] = values[src + col * rows + row];
1689 }
Brianbc029242008-04-04 18:59:21 -06001690 }
Brian Paulb64882d2008-07-18 12:51:39 -06001691 dst++;
Brian8fed2462007-10-26 19:19:09 -06001692 }
Brian Paulb64882d2008-07-18 12:51:39 -06001693
1694 src += rows * cols; /* next matrix */
Brian8fed2462007-10-26 19:19:09 -06001695 }
Brian34ae99d2006-12-18 08:28:54 -07001696}
1697
1698
1699/**
Brian5b01c5e2006-12-19 18:02:03 -07001700 * Called by ctx->Driver.UniformMatrix().
Brian Paulb64882d2008-07-18 12:51:39 -06001701 * Note: cols=2, rows=4 ==> array[2] of vec4
Brian34ae99d2006-12-18 08:28:54 -07001702 */
Brian2d2bb352007-12-07 17:11:30 -07001703static void
Brian5b01c5e2006-12-19 18:02:03 -07001704_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1705 GLenum matrixType, GLint location, GLsizei count,
1706 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001707{
Brian Paul8a40fe02008-08-06 16:26:47 -06001708 GLint offset;
Brian3a8e2772006-12-20 17:19:16 -07001709 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paulf84005c2008-05-14 16:01:31 -06001710
Brian3a8e2772006-12-20 17:19:16 -07001711 if (!shProg || !shProg->LinkStatus) {
1712 _mesa_error(ctx, GL_INVALID_OPERATION,
1713 "glUniformMatrix(program not linked)");
1714 return;
1715 }
Brian Paulf84005c2008-05-14 16:01:31 -06001716
1717 if (location == -1)
1718 return; /* The standard specifies this as a no-op */
1719
Brian Paul8a40fe02008-08-06 16:26:47 -06001720 split_location_offset(&location, &offset);
1721
Michal Krolf9c574d2008-07-15 11:44:47 +02001722 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian3a8e2772006-12-20 17:19:16 -07001723 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
1724 return;
1725 }
Brian34ae99d2006-12-18 08:28:54 -07001726 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001727 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001728 return;
1729 }
1730
1731 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1732
Brianbc029242008-04-04 18:59:21 -06001733 if (shProg->VertexProgram) {
Brian Paul8a40fe02008-08-06 16:26:47 -06001734 /* convert uniform location to program parameter index */
1735 GLint index = shProg->Uniforms->Uniforms[location].VertPos;
1736 if (index >= 0) {
Brianbc029242008-04-04 18:59:21 -06001737 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
Brian Paul8a40fe02008-08-06 16:26:47 -06001738 index, offset,
1739 count, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07001740 }
Brian34ae99d2006-12-18 08:28:54 -07001741 }
Brianbc029242008-04-04 18:59:21 -06001742
1743 if (shProg->FragmentProgram) {
Brian Paul8a40fe02008-08-06 16:26:47 -06001744 /* convert uniform location to program parameter index */
1745 GLint index = shProg->Uniforms->Uniforms[location].FragPos;
1746 if (index >= 0) {
Brianbc029242008-04-04 18:59:21 -06001747 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
Brian Paul8a40fe02008-08-06 16:26:47 -06001748 index, offset,
1749 count, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07001750 }
Brian34ae99d2006-12-18 08:28:54 -07001751 }
1752}
1753
1754
Brian2d2bb352007-12-07 17:11:30 -07001755static void
Brian5b01c5e2006-12-19 18:02:03 -07001756_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001757{
Brian65a18442006-12-19 18:46:56 -07001758 struct gl_shader_program *shProg;
Brian Paul70d39282008-07-21 14:16:07 -06001759
1760 shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram");
Brian65a18442006-12-19 18:46:56 -07001761 if (!shProg) {
Brian34ae99d2006-12-18 08:28:54 -07001762 return;
1763 }
1764
Brian Paul70d39282008-07-21 14:16:07 -06001765 if (!shProg->LinkStatus) {
1766 shProg->Validated = GL_FALSE;
1767 return;
1768 }
1769
1770 /* From the GL spec, a program is invalid if any of these are true:
1771
Brian5b01c5e2006-12-19 18:02:03 -07001772 any two active samplers in the current program object are of
1773 different types, but refer to the same texture image unit,
1774
1775 any active sampler in the current program object refers to a texture
1776 image unit where fixed-function fragment processing accesses a
1777 texture target that does not match the sampler type, or
1778
1779 the sum of the number of active samplers in the program and the
1780 number of texture image units enabled for fixed-function fragment
1781 processing exceeds the combined limit on the total number of texture
1782 image units allowed.
1783 */
Brian Paul70d39282008-07-21 14:16:07 -06001784
1785 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001786}
Brian2d2bb352007-12-07 17:11:30 -07001787
1788
1789/**
1790 * Plug in Mesa's GLSL functions into the device driver function table.
1791 */
1792void
1793_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
1794{
1795 driver->AttachShader = _mesa_attach_shader;
1796 driver->BindAttribLocation = _mesa_bind_attrib_location;
1797 driver->CompileShader = _mesa_compile_shader;
1798 driver->CreateProgram = _mesa_create_program;
1799 driver->CreateShader = _mesa_create_shader;
1800 driver->DeleteProgram2 = _mesa_delete_program2;
1801 driver->DeleteShader = _mesa_delete_shader;
1802 driver->DetachShader = _mesa_detach_shader;
1803 driver->GetActiveAttrib = _mesa_get_active_attrib;
1804 driver->GetActiveUniform = _mesa_get_active_uniform;
1805 driver->GetAttachedShaders = _mesa_get_attached_shaders;
1806 driver->GetAttribLocation = _mesa_get_attrib_location;
1807 driver->GetHandle = _mesa_get_handle;
1808 driver->GetProgramiv = _mesa_get_programiv;
1809 driver->GetProgramInfoLog = _mesa_get_program_info_log;
1810 driver->GetShaderiv = _mesa_get_shaderiv;
1811 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
1812 driver->GetShaderSource = _mesa_get_shader_source;
1813 driver->GetUniformfv = _mesa_get_uniformfv;
Brian Paul072c4742008-07-08 16:12:01 -06001814 driver->GetUniformiv = _mesa_get_uniformiv;
Brian2d2bb352007-12-07 17:11:30 -07001815 driver->GetUniformLocation = _mesa_get_uniform_location;
1816 driver->IsProgram = _mesa_is_program;
1817 driver->IsShader = _mesa_is_shader;
1818 driver->LinkProgram = _mesa_link_program;
1819 driver->ShaderSource = _mesa_shader_source;
1820 driver->Uniform = _mesa_uniform;
1821 driver->UniformMatrix = _mesa_uniform_matrix;
1822 driver->UseProgram = _mesa_use_program;
1823 driver->ValidateProgram = _mesa_validate_program;
1824}