blob: a86ef56c654aeaf61276f7b89f2780d84459b8fe [file] [log] [blame]
Brian34ae99d2006-12-18 08:28:54 -07001/*
2 * Mesa 3-D graphics library
Brian Paul6fccd8d2008-08-11 15:10:18 -06003 * Version: 7.1
Brian34ae99d2006-12-18 08:28:54 -07004 *
Brian Paul6fccd8d2008-08-11 15:10:18 -06005 * Copyright (C) 2004-2008 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:
Brian Paul6fccd8d2008-08-11 15:10:18 -0600723 case GL_SAMPLER_1D:
724 case GL_SAMPLER_2D:
725 case GL_SAMPLER_3D:
726 case GL_SAMPLER_CUBE:
727 case GL_SAMPLER_1D_SHADOW:
728 case GL_SAMPLER_2D_SHADOW:
729 case GL_SAMPLER_2D_RECT_ARB:
730 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
731 case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
732 case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
733 case GL_SAMPLER_CUBE_SHADOW_EXT:
Brian Paulfbf26e12008-07-21 13:58:50 -0600734 return 1;
735 case GL_FLOAT_VEC2:
736 case GL_INT_VEC2:
737 case GL_BOOL_VEC2:
738 return 2;
739 case GL_FLOAT_VEC3:
740 case GL_INT_VEC3:
741 case GL_BOOL_VEC3:
742 return 3;
743 case GL_FLOAT_VEC4:
744 case GL_INT_VEC4:
745 case GL_BOOL_VEC4:
746 return 4;
747 case GL_FLOAT_MAT2:
748 case GL_FLOAT_MAT2x3:
749 case GL_FLOAT_MAT2x4:
750 return 8; /* two float[4] vectors */
751 case GL_FLOAT_MAT3:
752 case GL_FLOAT_MAT3x2:
753 case GL_FLOAT_MAT3x4:
754 return 12; /* three float[4] vectors */
755 case GL_FLOAT_MAT4:
756 case GL_FLOAT_MAT4x2:
757 case GL_FLOAT_MAT4x3:
758 return 16; /* four float[4] vectors */
759 default:
760 _mesa_problem(NULL, "Invalid type in sizeof_glsl_type()");
761 return 1;
762 }
763}
764
765
Brian Paul8a40fe02008-08-06 16:26:47 -0600766static GLboolean
767is_boolean_type(GLenum type)
768{
769 switch (type) {
770 case GL_BOOL:
771 case GL_BOOL_VEC2:
772 case GL_BOOL_VEC3:
773 case GL_BOOL_VEC4:
774 return GL_TRUE;
775 default:
776 return GL_FALSE;
777 }
778}
779
780
781static GLboolean
782is_integer_type(GLenum type)
783{
784 switch (type) {
785 case GL_INT:
786 case GL_INT_VEC2:
787 case GL_INT_VEC3:
788 case GL_INT_VEC4:
789 return GL_TRUE;
790 default:
791 return GL_FALSE;
792 }
793}
794
795
Brian2d2bb352007-12-07 17:11:30 -0700796static void
Brian5b01c5e2006-12-19 18:02:03 -0700797_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
798 GLsizei maxLength, GLsizei *length, GLint *size,
799 GLenum *type, GLchar *nameOut)
800{
Brian Pauld4172262008-07-03 16:21:15 -0600801 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700802
Brian Pauld4172262008-07-03 16:21:15 -0600803 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
804 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700805 return;
Brian5b01c5e2006-12-19 18:02:03 -0700806
Brian65a18442006-12-19 18:46:56 -0700807 if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600808 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700809 return;
810 }
811
812 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700813 shProg->Attributes->Parameters[index].Name);
Brian5b01c5e2006-12-19 18:02:03 -0700814 if (size)
Brian Paulfbf26e12008-07-21 13:58:50 -0600815 *size = shProg->Attributes->Parameters[index].Size
816 / sizeof_glsl_type(shProg->Attributes->Parameters[index].DataType);
Brian5b01c5e2006-12-19 18:02:03 -0700817 if (type)
Brian Paulfbf26e12008-07-21 13:58:50 -0600818 *type = shProg->Attributes->Parameters[index].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700819}
820
821
Brian Paul8a40fe02008-08-06 16:26:47 -0600822static struct gl_program_parameter *
823get_uniform_parameter(const struct gl_shader_program *shProg, GLuint index)
824{
825 const struct gl_program *prog;
826 GLint progPos;
827
828 progPos = shProg->Uniforms->Uniforms[index].VertPos;
829 if (progPos >= 0) {
830 prog = &shProg->VertexProgram->Base;
831 }
832 else {
833 progPos = shProg->Uniforms->Uniforms[index].FragPos;
834 if (progPos >= 0) {
835 prog = &shProg->FragmentProgram->Base;
836 }
837 }
838
839 if (!prog || progPos < 0)
840 return NULL; /* should never happen */
841
842 return &prog->Parameters->Parameters[progPos];
843}
844
845
Brian5b01c5e2006-12-19 18:02:03 -0700846/**
847 * Called via ctx->Driver.GetActiveUniform().
848 */
Brian2d2bb352007-12-07 17:11:30 -0700849static void
Brian5b01c5e2006-12-19 18:02:03 -0700850_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
851 GLsizei maxLength, GLsizei *length, GLint *size,
852 GLenum *type, GLchar *nameOut)
853{
Brian Pauld4172262008-07-03 16:21:15 -0600854 const struct gl_shader_program *shProg;
Brianbc029242008-04-04 18:59:21 -0600855 const struct gl_program *prog;
856 GLint progPos;
Brian5b01c5e2006-12-19 18:02:03 -0700857
Brian Pauld4172262008-07-03 16:21:15 -0600858 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
859 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700860 return;
Brian5b01c5e2006-12-19 18:02:03 -0700861
Brianbc029242008-04-04 18:59:21 -0600862 if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
Brian5b01c5e2006-12-19 18:02:03 -0700863 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
864 return;
865 }
866
Brianbc029242008-04-04 18:59:21 -0600867 progPos = shProg->Uniforms->Uniforms[index].VertPos;
868 if (progPos >= 0) {
869 prog = &shProg->VertexProgram->Base;
870 }
871 else {
872 progPos = shProg->Uniforms->Uniforms[index].FragPos;
873 if (progPos >= 0) {
874 prog = &shProg->FragmentProgram->Base;
Brian274ac7a2007-04-18 16:05:53 -0600875 }
876 }
877
Brianbc029242008-04-04 18:59:21 -0600878 if (!prog || progPos < 0)
879 return; /* should never happen */
880
881 if (nameOut)
882 copy_string(nameOut, maxLength, length,
883 prog->Parameters->Parameters[progPos].Name);
884 if (size)
Brian Paulfbf26e12008-07-21 13:58:50 -0600885 *size = prog->Parameters->Parameters[progPos].Size
886 / sizeof_glsl_type(prog->Parameters->Parameters[progPos].DataType);
Brianbc029242008-04-04 18:59:21 -0600887 if (type)
888 *type = prog->Parameters->Parameters[progPos].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700889}
890
891
892/**
893 * Called via ctx->Driver.GetAttachedShaders().
894 */
Brian2d2bb352007-12-07 17:11:30 -0700895static void
Brian5b01c5e2006-12-19 18:02:03 -0700896_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
897 GLsizei *count, GLuint *obj)
898{
Brian Pauld4172262008-07-03 16:21:15 -0600899 struct gl_shader_program *shProg =
900 _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders");
Brian65a18442006-12-19 18:46:56 -0700901 if (shProg) {
José Fonseca53174af2008-05-31 18:14:09 +0900902 GLuint i;
Brian Pauld4172262008-07-03 16:21:15 -0600903 for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) {
Brian65a18442006-12-19 18:46:56 -0700904 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700905 }
906 if (count)
907 *count = i;
908 }
Brian5b01c5e2006-12-19 18:02:03 -0700909}
910
911
Brian2d2bb352007-12-07 17:11:30 -0700912static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700913_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700914{
915#if 0
916 GET_CURRENT_CONTEXT(ctx);
917
918 switch (pname) {
919 case GL_PROGRAM_OBJECT_ARB:
920 {
Brian5b01c5e2006-12-19 18:02:03 -0700921 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700922
923 if (pro != NULL)
924 return (**pro)._container._generic.
925 GetName((struct gl2_generic_intf **) (pro));
926 }
927 break;
928 default:
929 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
930 }
931#endif
932 return 0;
933}
934
935
Brian2d2bb352007-12-07 17:11:30 -0700936static void
Brian5b01c5e2006-12-19 18:02:03 -0700937_mesa_get_programiv(GLcontext *ctx, GLuint program,
938 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700939{
Brian65a18442006-12-19 18:46:56 -0700940 struct gl_shader_program *shProg
941 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700942
Brian65a18442006-12-19 18:46:56 -0700943 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700944 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700945 return;
946 }
947
Brian5b01c5e2006-12-19 18:02:03 -0700948 switch (pname) {
949 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700950 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700951 break;
952 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700953 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700954 break;
Brian5b01c5e2006-12-19 18:02:03 -0700955 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700956 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700957 break;
958 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600959 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700960 break;
961 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700962 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700963 break;
964 case GL_ACTIVE_ATTRIBUTES:
Brian3209c3e2007-01-09 17:49:24 -0700965 *params = shProg->Attributes ? shProg->Attributes->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700966 break;
967 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600968 *params = _mesa_longest_parameter_name(shProg->Attributes,
969 PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700970 break;
971 case GL_ACTIVE_UNIFORMS:
Brianbc029242008-04-04 18:59:21 -0600972 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700973 break;
974 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brianbc029242008-04-04 18:59:21 -0600975 *params = _mesa_longest_uniform_name(shProg->Uniforms);
Brian274ac7a2007-04-18 16:05:53 -0600976 if (*params > 0)
977 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700978 break;
Brian Paul18cd9c22008-08-06 12:45:14 -0600979 case GL_PROGRAM_BINARY_LENGTH_OES:
980 *params = 0;
981 break;
Brian34ae99d2006-12-18 08:28:54 -0700982 default:
Brian5b01c5e2006-12-19 18:02:03 -0700983 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
984 return;
Brian34ae99d2006-12-18 08:28:54 -0700985 }
Brian5b01c5e2006-12-19 18:02:03 -0700986}
Brian34ae99d2006-12-18 08:28:54 -0700987
Brian34ae99d2006-12-18 08:28:54 -0700988
Brian2d2bb352007-12-07 17:11:30 -0700989static void
Brian5b01c5e2006-12-19 18:02:03 -0700990_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
991{
Brian Pauld4172262008-07-03 16:21:15 -0600992 struct gl_shader *shader = _mesa_lookup_shader_err(ctx, name, "glGetShaderiv");
Brian5b01c5e2006-12-19 18:02:03 -0700993
994 if (!shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700995 return;
996 }
Brian65a18442006-12-19 18:46:56 -0700997
Brian5b01c5e2006-12-19 18:02:03 -0700998 switch (pname) {
999 case GL_SHADER_TYPE:
1000 *params = shader->Type;
1001 break;
1002 case GL_DELETE_STATUS:
1003 *params = shader->DeletePending;
1004 break;
1005 case GL_COMPILE_STATUS:
1006 *params = shader->CompileStatus;
1007 break;
1008 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001009 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001010 break;
1011 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -06001012 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -07001013 break;
1014 default:
1015 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
1016 return;
1017 }
1018}
1019
1020
Brian2d2bb352007-12-07 17:11:30 -07001021static void
Brian5b01c5e2006-12-19 18:02:03 -07001022_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
1023 GLsizei *length, GLchar *infoLog)
1024{
Brian65a18442006-12-19 18:46:56 -07001025 struct gl_shader_program *shProg
1026 = _mesa_lookup_shader_program(ctx, program);
1027 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -07001028 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
1029 return;
1030 }
Brian65a18442006-12-19 18:46:56 -07001031 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -07001032}
1033
1034
Brian2d2bb352007-12-07 17:11:30 -07001035static void
Brian5b01c5e2006-12-19 18:02:03 -07001036_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
1037 GLsizei *length, GLchar *infoLog)
1038{
Brian65a18442006-12-19 18:46:56 -07001039 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
1040 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001041 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
1042 return;
1043 }
Brian65a18442006-12-19 18:46:56 -07001044 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -07001045}
1046
1047
1048/**
1049 * Called via ctx->Driver.GetShaderSource().
1050 */
Brian2d2bb352007-12-07 17:11:30 -07001051static void
Brian5b01c5e2006-12-19 18:02:03 -07001052_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
1053 GLsizei *length, GLchar *sourceOut)
1054{
Brian Pauld4172262008-07-03 16:21:15 -06001055 struct gl_shader *sh;
1056 sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource");
Brian65a18442006-12-19 18:46:56 -07001057 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001058 return;
1059 }
Brian65a18442006-12-19 18:46:56 -07001060 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -07001061}
1062
1063
Brian Paul7a6eba52008-08-06 13:07:09 -06001064static void
1065get_matrix_dims(GLenum type, GLint *rows, GLint *cols)
1066{
1067 switch (type) {
1068 case GL_FLOAT_MAT2:
1069 *rows = *cols = 2;
1070 break;
1071 case GL_FLOAT_MAT2x3:
1072 *rows = 3;
1073 *cols = 2;
1074 break;
1075 case GL_FLOAT_MAT2x4:
1076 *rows = 4;
1077 *cols = 2;
1078 break;
1079 case GL_FLOAT_MAT3:
1080 *rows = 3;
1081 *cols = 3;
1082 break;
1083 case GL_FLOAT_MAT3x2:
1084 *rows = 2;
1085 *cols = 3;
1086 break;
1087 case GL_FLOAT_MAT3x4:
1088 *rows = 4;
1089 *cols = 3;
1090 break;
1091 case GL_FLOAT_MAT4:
1092 *rows = 4;
1093 *cols = 4;
1094 break;
1095 case GL_FLOAT_MAT4x2:
1096 *rows = 2;
1097 *cols = 4;
1098 break;
1099 case GL_FLOAT_MAT4x3:
1100 *rows = 3;
1101 *cols = 4;
1102 break;
1103 default:
1104 *rows = *cols = 0;
1105 }
1106}
1107
1108
1109/**
1110 * Determine the number of rows and columns occupied by a uniform
Brian Paulea9568d2008-09-16 08:55:54 -06001111 * according to its datatype. For non-matrix types (such as GL_FLOAT_VEC4),
1112 * the number of rows = 1 and cols = number of elements in the vector.
Brian Paul7a6eba52008-08-06 13:07:09 -06001113 */
1114static void
1115get_uniform_rows_cols(const struct gl_program_parameter *p,
1116 GLint *rows, GLint *cols)
1117{
1118 get_matrix_dims(p->DataType, rows, cols);
1119 if (*rows == 0 && *cols == 0) {
1120 /* not a matrix type, probably a float or vector */
Brian Paulea9568d2008-09-16 08:55:54 -06001121 if (p->Size <= 4) {
1122 *rows = 1;
1123 *cols = p->Size;
1124 }
1125 else {
1126 *rows = p->Size / 4 + 1;
1127 if (p->Size % 4 == 0)
1128 *cols = 4;
1129 else
1130 *cols = p->Size % 4;
1131 }
Brian Paul7a6eba52008-08-06 13:07:09 -06001132 }
1133}
1134
1135
Brian Paul072c4742008-07-08 16:12:01 -06001136#define MAX_UNIFORM_ELEMENTS 16
1137
Brian5b01c5e2006-12-19 18:02:03 -07001138/**
Brian Paul072c4742008-07-08 16:12:01 -06001139 * Helper for GetUniformfv(), GetUniformiv()
1140 * Returns number of elements written to 'params' output.
Brian5b01c5e2006-12-19 18:02:03 -07001141 */
Brian Paul072c4742008-07-08 16:12:01 -06001142static GLuint
1143get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1144 GLfloat *params)
Brian5b01c5e2006-12-19 18:02:03 -07001145{
Brian65a18442006-12-19 18:46:56 -07001146 struct gl_shader_program *shProg
Brian Paul18cd9c22008-08-06 12:45:14 -06001147 = _mesa_lookup_shader_program_err(ctx, program, "glGetUniform[if]v");
Brian65a18442006-12-19 18:46:56 -07001148 if (shProg) {
Brian Paul22427692008-06-28 16:47:22 -06001149 if (shProg->Uniforms &&
Michal Krolf9c574d2008-07-15 11:44:47 +02001150 location >= 0 && location < (GLint) shProg->Uniforms->NumUniforms) {
Brian Paul22427692008-06-28 16:47:22 -06001151 GLint progPos;
Brian Paulfc0a48d2008-05-16 15:48:11 -06001152 const struct gl_program *prog = NULL;
Brianbc029242008-04-04 18:59:21 -06001153
1154 progPos = shProg->Uniforms->Uniforms[location].VertPos;
1155 if (progPos >= 0) {
1156 prog = &shProg->VertexProgram->Base;
1157 }
1158 else {
1159 progPos = shProg->Uniforms->Uniforms[location].FragPos;
1160 if (progPos >= 0) {
1161 prog = &shProg->FragmentProgram->Base;
1162 }
1163 }
1164
Brian Paulfc0a48d2008-05-16 15:48:11 -06001165 ASSERT(prog);
1166 if (prog) {
Brian Paul7a6eba52008-08-06 13:07:09 -06001167 const struct gl_program_parameter *p =
1168 &prog->Parameters->Parameters[progPos];
1169 GLint rows, cols, i, j, k;
Brian Paul072c4742008-07-08 16:12:01 -06001170
Brian Paul7a6eba52008-08-06 13:07:09 -06001171 /* See uniformiv() below */
1172 assert(p->Size <= MAX_UNIFORM_ELEMENTS);
1173
1174 get_uniform_rows_cols(p, &rows, &cols);
1175
1176 k = 0;
1177 for (i = 0; i < rows; i++) {
1178 for (j = 0; j < cols; j++ ) {
1179 params[k++] = prog->Parameters->ParameterValues[progPos+i][j];
1180 }
Brian Paulfc0a48d2008-05-16 15:48:11 -06001181 }
Brian Paul7a6eba52008-08-06 13:07:09 -06001182
1183 return p->Size;
Brian5b01c5e2006-12-19 18:02:03 -07001184 }
1185 }
1186 else {
Brian Paul22427692008-06-28 16:47:22 -06001187 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
Brian5b01c5e2006-12-19 18:02:03 -07001188 }
1189 }
Brian Paul072c4742008-07-08 16:12:01 -06001190 return 0;
1191}
1192
1193
1194/**
1195 * Called via ctx->Driver.GetUniformfv().
1196 */
1197static void
1198_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1199 GLfloat *params)
1200{
1201 (void) get_uniformfv(ctx, program, location, params);
1202}
1203
1204
1205/**
1206 * Called via ctx->Driver.GetUniformiv().
1207 */
1208static void
1209_mesa_get_uniformiv(GLcontext *ctx, GLuint program, GLint location,
1210 GLint *params)
1211{
1212 GLfloat fparams[MAX_UNIFORM_ELEMENTS];
1213 GLuint n = get_uniformfv(ctx, program, location, fparams);
1214 GLuint i;
1215 assert(n <= MAX_UNIFORM_ELEMENTS);
1216 for (i = 0; i < n; i++) {
1217 params[i] = (GLint) fparams[i];
1218 }
Brian5b01c5e2006-12-19 18:02:03 -07001219}
1220
1221
1222/**
Brian Paul8a40fe02008-08-06 16:26:47 -06001223 * The value returned by GetUniformLocation actually encodes two things:
1224 * 1. the index into the prog->Uniforms[] array for the uniform
1225 * 2. an offset in the prog->ParameterValues[] array for specifying array
1226 * elements or structure fields.
1227 * This function merges those two values.
1228 */
1229static void
1230merge_location_offset(GLint *location, GLint offset)
1231{
1232 *location = *location | (offset << 16);
1233}
1234
1235
1236/**
1237 * Seperate the uniform location and parameter offset. See above.
1238 */
1239static void
1240split_location_offset(GLint *location, GLint *offset)
1241{
1242 *offset = (*location >> 16);
1243 *location = *location & 0xffff;
1244}
1245
1246
1247/**
Brian5b01c5e2006-12-19 18:02:03 -07001248 * Called via ctx->Driver.GetUniformLocation().
Brian Paul8a40fe02008-08-06 16:26:47 -06001249 *
1250 * The return value will encode two values, the uniform location and an
1251 * offset (used for arrays, structs).
Brian5b01c5e2006-12-19 18:02:03 -07001252 */
Brian2d2bb352007-12-07 17:11:30 -07001253static GLint
Brian5b01c5e2006-12-19 18:02:03 -07001254_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
1255{
Brian Paul8a40fe02008-08-06 16:26:47 -06001256 GLint offset = 0, location = -1;
1257
Brian Pauld4172262008-07-03 16:21:15 -06001258 struct gl_shader_program *shProg =
1259 _mesa_lookup_shader_program_err(ctx, program, "glGetUniformLocation");
1260
Brianbc029242008-04-04 18:59:21 -06001261 if (!shProg)
1262 return -1;
Brian5b01c5e2006-12-19 18:02:03 -07001263
Brian Paul294b0612008-07-04 09:58:14 -06001264 if (shProg->LinkStatus == GL_FALSE) {
1265 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
1266 return -1;
1267 }
1268
Brian Pauld4172262008-07-03 16:21:15 -06001269 /* XXX we should return -1 if the uniform was declared, but not
1270 * actually used.
1271 */
1272
Brian Paul8a40fe02008-08-06 16:26:47 -06001273 /* XXX we need to be able to parse uniform names for structs and arrays
1274 * such as:
1275 * mymatrix[1]
1276 * mystruct.field1
1277 */
1278
1279 {
1280 /* handle 1-dimension arrays here... */
1281 char *c = strchr(name, '[');
1282 if (c) {
1283 /* truncate name at [ */
1284 const GLint len = c - name;
1285 GLchar *newName = _mesa_malloc(len + 1);
1286 if (!newName)
1287 return -1; /* out of mem */
1288 _mesa_memcpy(newName, name, len);
1289 newName[len] = 0;
1290
1291 location = _mesa_lookup_uniform(shProg->Uniforms, newName);
1292 if (location >= 0) {
1293 const GLint element = _mesa_atoi(c + 1);
1294 if (element > 0) {
1295 /* get type of the uniform array element */
1296 struct gl_program_parameter *p;
1297 p = get_uniform_parameter(shProg, location);
1298 if (p) {
1299 GLint rows, cols;
1300 get_matrix_dims(p->DataType, &rows, &cols);
1301 if (rows < 1)
1302 rows = 1;
1303 offset = element * rows;
1304 }
1305 }
1306 }
1307
1308 _mesa_free(newName);
1309 }
1310 }
1311
1312 if (location < 0) {
1313 location = _mesa_lookup_uniform(shProg->Uniforms, name);
1314 }
1315
1316 if (location >= 0) {
1317 merge_location_offset(&location, offset);
1318 }
1319
1320 return location;
Brian5b01c5e2006-12-19 18:02:03 -07001321}
1322
1323
Brian34ae99d2006-12-18 08:28:54 -07001324
Brian5b01c5e2006-12-19 18:02:03 -07001325/**
1326 * Called via ctx->Driver.ShaderSource()
1327 */
Brian2d2bb352007-12-07 17:11:30 -07001328static void
Brian5b01c5e2006-12-19 18:02:03 -07001329_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -07001330{
Brian Pauld4172262008-07-03 16:21:15 -06001331 struct gl_shader *sh;
1332
1333 sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource");
1334 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001335 return;
Brian34ae99d2006-12-18 08:28:54 -07001336
Brian34ae99d2006-12-18 08:28:54 -07001337 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -07001338 if (sh->Source) {
1339 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -07001340 }
Brian65a18442006-12-19 18:46:56 -07001341 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -07001342 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -07001343}
1344
1345
Brian5b01c5e2006-12-19 18:02:03 -07001346/**
1347 * Called via ctx->Driver.CompileShader()
1348 */
Brian2d2bb352007-12-07 17:11:30 -07001349static void
Brian5b01c5e2006-12-19 18:02:03 -07001350_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -07001351{
Brian Pauld4172262008-07-03 16:21:15 -06001352 struct gl_shader *sh;
Brian34ae99d2006-12-18 08:28:54 -07001353
Brian Pauld4172262008-07-03 16:21:15 -06001354 sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader");
1355 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001356 return;
Brian34ae99d2006-12-18 08:28:54 -07001357
Brian43975832007-01-04 08:21:09 -07001358 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -07001359}
1360
1361
Brian5b01c5e2006-12-19 18:02:03 -07001362/**
1363 * Called via ctx->Driver.LinkProgram()
1364 */
Brian2d2bb352007-12-07 17:11:30 -07001365static void
Brian5b01c5e2006-12-19 18:02:03 -07001366_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001367{
Brian65a18442006-12-19 18:46:56 -07001368 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001369
Brian Pauld4172262008-07-03 16:21:15 -06001370 shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
1371 if (!shProg)
Brian34ae99d2006-12-18 08:28:54 -07001372 return;
Brian34ae99d2006-12-18 08:28:54 -07001373
Brian Paulfc0a48d2008-05-16 15:48:11 -06001374 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1375
Brianc1771912007-02-16 09:56:19 -07001376 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001377}
1378
1379
1380/**
Brian5b01c5e2006-12-19 18:02:03 -07001381 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001382 */
Brian5b01c5e2006-12-19 18:02:03 -07001383void
1384_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001385{
Brian3c008a02007-04-12 15:22:32 -06001386 struct gl_shader_program *shProg;
1387
Brian00d63aa2007-02-03 11:35:02 -07001388 if (ctx->Shader.CurrentProgram &&
1389 ctx->Shader.CurrentProgram->Name == program) {
1390 /* no-op */
1391 return;
1392 }
1393
1394 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1395
Brian5b01c5e2006-12-19 18:02:03 -07001396 if (program) {
Brian Pauld4172262008-07-03 16:21:15 -06001397 shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
Brian65a18442006-12-19 18:46:56 -07001398 if (!shProg) {
Brian Pauld4172262008-07-03 16:21:15 -06001399 return;
1400 }
1401 if (!shProg->LinkStatus) {
1402 _mesa_error(ctx, GL_INVALID_OPERATION, "glUseProgram");
Brian5b01c5e2006-12-19 18:02:03 -07001403 return;
1404 }
Brian5b01c5e2006-12-19 18:02:03 -07001405 }
1406 else {
Brian3c008a02007-04-12 15:22:32 -06001407 shProg = NULL;
1408 }
1409
1410 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001411}
Brian34ae99d2006-12-18 08:28:54 -07001412
Brian5b01c5e2006-12-19 18:02:03 -07001413
Brian8fed2462007-10-26 19:19:09 -06001414
1415/**
1416 * Update the vertex and fragment program's TexturesUsed arrays.
1417 */
1418static void
1419update_textures_used(struct gl_program *prog)
1420{
1421 GLuint s;
1422
1423 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1424
1425 for (s = 0; s < MAX_SAMPLERS; s++) {
1426 if (prog->SamplersUsed & (1 << s)) {
1427 GLuint u = prog->SamplerUnits[s];
1428 GLuint t = prog->SamplerTargets[s];
1429 assert(u < MAX_TEXTURE_IMAGE_UNITS);
1430 prog->TexturesUsed[u] |= (1 << t);
1431 }
1432 }
1433}
1434
1435
Brian63025ec2008-07-21 20:42:05 -06001436static GLboolean
1437is_sampler_type(GLenum type)
1438{
1439 switch (type) {
1440 case GL_SAMPLER_1D:
1441 case GL_SAMPLER_2D:
1442 case GL_SAMPLER_3D:
1443 case GL_SAMPLER_CUBE:
1444 case GL_SAMPLER_1D_SHADOW:
1445 case GL_SAMPLER_2D_SHADOW:
1446 case GL_SAMPLER_2D_RECT_ARB:
1447 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
1448 case GL_SAMPLER_1D_ARRAY_EXT:
1449 case GL_SAMPLER_2D_ARRAY_EXT:
1450 return GL_TRUE;
1451 default:
1452 return GL_FALSE;
1453 }
1454}
1455
1456
Brian5b01c5e2006-12-19 18:02:03 -07001457/**
Brian Paulfbf26e12008-07-21 13:58:50 -06001458 * Check if the type given by userType is allowed to set a uniform of the
1459 * target type. Generally, equivalence is required, but setting Boolean
1460 * uniforms can be done with glUniformiv or glUniformfv.
1461 */
1462static GLboolean
1463compatible_types(GLenum userType, GLenum targetType)
1464{
1465 if (userType == targetType)
1466 return GL_TRUE;
1467
1468 if (targetType == GL_BOOL && (userType == GL_FLOAT || userType == GL_INT))
1469 return GL_TRUE;
1470
1471 if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 ||
1472 userType == GL_INT_VEC2))
1473 return GL_TRUE;
1474
1475 if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 ||
1476 userType == GL_INT_VEC3))
1477 return GL_TRUE;
1478
1479 if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 ||
1480 userType == GL_INT_VEC4))
1481 return GL_TRUE;
1482
Brian63025ec2008-07-21 20:42:05 -06001483 if (is_sampler_type(targetType) && userType == GL_INT)
1484 return GL_TRUE;
1485
Brian Paulfbf26e12008-07-21 13:58:50 -06001486 return GL_FALSE;
1487}
1488
1489
1490/**
Brianbc029242008-04-04 18:59:21 -06001491 * Set the value of a program's uniform variable.
1492 * \param program the program whose uniform to update
Brian Paul8a40fe02008-08-06 16:26:47 -06001493 * \param index the index of the program parameter for the uniform
1494 * \param offset additional parameter slot offset (for arrays)
Brianbc029242008-04-04 18:59:21 -06001495 * \param type the datatype of the uniform
1496 * \param count the number of uniforms to set
1497 * \param elems number of elements per uniform
1498 * \param values the new values
1499 */
1500static void
Brian Paul8a40fe02008-08-06 16:26:47 -06001501set_program_uniform(GLcontext *ctx, struct gl_program *program,
1502 GLint index, GLint offset,
1503 GLenum type, GLsizei count, GLint elems,
1504 const void *values)
Brianbc029242008-04-04 18:59:21 -06001505{
Brian Paul8a40fe02008-08-06 16:26:47 -06001506 assert(offset >= 0);
1507
Brian Paulfbf26e12008-07-21 13:58:50 -06001508 if (!compatible_types(type,
Brian Paul8a40fe02008-08-06 16:26:47 -06001509 program->Parameters->Parameters[index].DataType)) {
Brian Paulfbf26e12008-07-21 13:58:50 -06001510 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
1511 return;
1512 }
1513
Michal Krolc5c71302008-08-07 16:23:15 +02001514 if (index + offset > (GLint) program->Parameters->Size) {
Brian Paul8a40fe02008-08-06 16:26:47 -06001515 /* out of bounds! */
1516 return;
1517 }
1518
1519 if (program->Parameters->Parameters[index].Type == PROGRAM_SAMPLER) {
Brianbc029242008-04-04 18:59:21 -06001520 /* This controls which texture unit which is used by a sampler */
1521 GLuint texUnit, sampler;
1522
1523 /* data type for setting samplers must be int */
1524 if (type != GL_INT || count != 1) {
1525 _mesa_error(ctx, GL_INVALID_OPERATION,
1526 "glUniform(only glUniform1i can be used "
1527 "to set sampler uniforms)");
1528 return;
1529 }
1530
Brian Paul8a40fe02008-08-06 16:26:47 -06001531 sampler = (GLuint) program->Parameters->ParameterValues[index][0];
Brianbc029242008-04-04 18:59:21 -06001532 texUnit = ((GLuint *) values)[0];
1533
1534 /* check that the sampler (tex unit index) is legal */
1535 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1536 _mesa_error(ctx, GL_INVALID_VALUE,
1537 "glUniform1(invalid sampler/tex unit index)");
1538 return;
1539 }
1540
1541 /* This maps a sampler to a texture unit: */
1542 program->SamplerUnits[sampler] = texUnit;
1543 update_textures_used(program);
1544
1545 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1546 }
1547 else {
1548 /* ordinary uniform variable */
José Fonseca18ec1402008-06-24 11:34:46 +09001549 GLsizei k, i;
Brian Paul8a40fe02008-08-06 16:26:47 -06001550 GLint slots = (program->Parameters->Parameters[index].Size + 3) / 4;
Brianbc029242008-04-04 18:59:21 -06001551
Brian Paul8a40fe02008-08-06 16:26:47 -06001552 if (count * elems > (GLint) program->Parameters->Parameters[index].Size) {
Brianbc029242008-04-04 18:59:21 -06001553 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1554 return;
1555 }
1556
Brian Paul8a40fe02008-08-06 16:26:47 -06001557 if (count > slots)
1558 count = slots;
1559
Brianbc029242008-04-04 18:59:21 -06001560 for (k = 0; k < count; k++) {
Brian Paul8a40fe02008-08-06 16:26:47 -06001561 GLfloat *uniformVal = program->Parameters->ParameterValues[index + offset + k];
1562 if (is_integer_type(type)) {
Brianbc029242008-04-04 18:59:21 -06001563 const GLint *iValues = ((const GLint *) values) + k * elems;
1564 for (i = 0; i < elems; i++) {
1565 uniformVal[i] = (GLfloat) iValues[i];
1566 }
1567 }
1568 else {
1569 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1570 for (i = 0; i < elems; i++) {
1571 uniformVal[i] = fValues[i];
1572 }
1573 }
Brian Paul8a40fe02008-08-06 16:26:47 -06001574
1575 /* if the uniform is bool-valued, convert to 1.0 or 0.0 */
1576 if (is_boolean_type(program->Parameters->Parameters[index].DataType)) {
1577 for (i = 0; i < elems; i++) {
Michal Krolc5c71302008-08-07 16:23:15 +02001578 uniformVal[i] = uniformVal[i] ? 1.0f : 0.0f;
Brian Paul8a40fe02008-08-06 16:26:47 -06001579 }
1580 }
Brianbc029242008-04-04 18:59:21 -06001581 }
1582 }
1583}
1584
1585
1586/**
Brian5b01c5e2006-12-19 18:02:03 -07001587 * Called via ctx->Driver.Uniform().
1588 */
Brian2d2bb352007-12-07 17:11:30 -07001589static void
Brian5b01c5e2006-12-19 18:02:03 -07001590_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1591 const GLvoid *values, GLenum type)
1592{
Brian3a8e2772006-12-20 17:19:16 -07001593 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paul8a40fe02008-08-06 16:26:47 -06001594 GLint elems, offset;
Brian3a8e2772006-12-20 17:19:16 -07001595
1596 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001597 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001598 return;
1599 }
1600
Brian Paulf84005c2008-05-14 16:01:31 -06001601 if (location == -1)
1602 return; /* The standard specifies this as a no-op */
1603
Brian Paul8a40fe02008-08-06 16:26:47 -06001604 split_location_offset(&location, &offset);
1605
Brianbc029242008-04-04 18:59:21 -06001606 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian3a8e2772006-12-20 17:19:16 -07001607 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
1608 return;
1609 }
1610
Brian52363952007-03-13 16:50:24 -06001611 if (count < 0) {
1612 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1613 return;
1614 }
1615
Brian98650bd2007-03-13 16:32:48 -06001616 switch (type) {
1617 case GL_FLOAT:
1618 case GL_INT:
1619 elems = 1;
1620 break;
1621 case GL_FLOAT_VEC2:
1622 case GL_INT_VEC2:
1623 elems = 2;
1624 break;
1625 case GL_FLOAT_VEC3:
1626 case GL_INT_VEC3:
1627 elems = 3;
1628 break;
1629 case GL_FLOAT_VEC4:
1630 case GL_INT_VEC4:
1631 elems = 4;
1632 break;
1633 default:
1634 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1635 return;
Brian89dc4852007-01-04 14:35:44 -07001636 }
Brian98650bd2007-03-13 16:32:48 -06001637
Brianbc029242008-04-04 18:59:21 -06001638 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1639
1640 /* A uniform var may be used by both a vertex shader and a fragment
1641 * shader. We may need to update one or both shader's uniform here:
1642 */
1643 if (shProg->VertexProgram) {
Brian Paul8a40fe02008-08-06 16:26:47 -06001644 /* convert uniform location to program parameter index */
1645 GLint index = shProg->Uniforms->Uniforms[location].VertPos;
1646 if (index >= 0) {
Brianbc029242008-04-04 18:59:21 -06001647 set_program_uniform(ctx, &shProg->VertexProgram->Base,
Brian Paul8a40fe02008-08-06 16:26:47 -06001648 index, offset, type, count, elems, values);
Brianbc029242008-04-04 18:59:21 -06001649 }
Brian98650bd2007-03-13 16:32:48 -06001650 }
1651
Brianbc029242008-04-04 18:59:21 -06001652 if (shProg->FragmentProgram) {
Brian Paul8a40fe02008-08-06 16:26:47 -06001653 /* convert uniform location to program parameter index */
1654 GLint index = shProg->Uniforms->Uniforms[location].FragPos;
1655 if (index >= 0) {
Brianbc029242008-04-04 18:59:21 -06001656 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
Brian Paul8a40fe02008-08-06 16:26:47 -06001657 index, offset, type, count, elems, values);
Brian8fed2462007-10-26 19:19:09 -06001658 }
Brianbc029242008-04-04 18:59:21 -06001659 }
1660}
Brian8fed2462007-10-26 19:19:09 -06001661
Brian8fed2462007-10-26 19:19:09 -06001662
Brian Paul8a40fe02008-08-06 16:26:47 -06001663/**
1664 * Set a matrix-valued program parameter.
1665 */
Brianbc029242008-04-04 18:59:21 -06001666static void
1667set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
Brian Paul8a40fe02008-08-06 16:26:47 -06001668 GLuint index, GLuint offset,
1669 GLuint count, GLuint rows, GLuint cols,
Brianbc029242008-04-04 18:59:21 -06001670 GLboolean transpose, const GLfloat *values)
1671{
Brian Paulfbf26e12008-07-21 13:58:50 -06001672 GLuint mat, row, col;
Brian Paul8a40fe02008-08-06 16:26:47 -06001673 GLuint dst = index + offset, src = 0;
Brian Paulfbf26e12008-07-21 13:58:50 -06001674 GLint nr, nc;
1675
1676 /* check that the number of rows, columns is correct */
Brian Paul8a40fe02008-08-06 16:26:47 -06001677 get_matrix_dims(program->Parameters->Parameters[index].DataType, &nr, &nc);
Brian Paulfbf26e12008-07-21 13:58:50 -06001678 if (rows != nr || cols != nc) {
1679 _mesa_error(ctx, GL_INVALID_OPERATION,
Brian Paul8a40fe02008-08-06 16:26:47 -06001680 "glUniformMatrix(matrix size mismatch)");
1681 return;
1682 }
1683
1684 if (index + offset > program->Parameters->Size) {
1685 /* out of bounds! */
Brian Paulfbf26e12008-07-21 13:58:50 -06001686 return;
1687 }
1688
Brianbc029242008-04-04 18:59:21 -06001689 /*
1690 * Note: the _columns_ of a matrix are stored in program registers, not
Brian Paulb64882d2008-07-18 12:51:39 -06001691 * the rows. So, the loops below look a little funny.
1692 * XXX could optimize this a bit...
Brianbc029242008-04-04 18:59:21 -06001693 */
Brian Paulb64882d2008-07-18 12:51:39 -06001694
1695 /* loop over matrices */
1696 for (mat = 0; mat < count; mat++) {
1697
1698 /* each matrix: */
Brianbc029242008-04-04 18:59:21 -06001699 for (col = 0; col < cols; col++) {
Brian Paulb64882d2008-07-18 12:51:39 -06001700 GLfloat *v = program->Parameters->ParameterValues[dst];
Brianbc029242008-04-04 18:59:21 -06001701 for (row = 0; row < rows; row++) {
Brian Paulb64882d2008-07-18 12:51:39 -06001702 if (transpose) {
1703 v[row] = values[src + row * cols + col];
1704 }
1705 else {
1706 v[row] = values[src + col * rows + row];
1707 }
Brianbc029242008-04-04 18:59:21 -06001708 }
Brian Paulb64882d2008-07-18 12:51:39 -06001709 dst++;
Brian8fed2462007-10-26 19:19:09 -06001710 }
Brian Paulb64882d2008-07-18 12:51:39 -06001711
1712 src += rows * cols; /* next matrix */
Brian8fed2462007-10-26 19:19:09 -06001713 }
Brian34ae99d2006-12-18 08:28:54 -07001714}
1715
1716
1717/**
Brian5b01c5e2006-12-19 18:02:03 -07001718 * Called by ctx->Driver.UniformMatrix().
Brian Paulb64882d2008-07-18 12:51:39 -06001719 * Note: cols=2, rows=4 ==> array[2] of vec4
Brian34ae99d2006-12-18 08:28:54 -07001720 */
Brian2d2bb352007-12-07 17:11:30 -07001721static void
Brian5b01c5e2006-12-19 18:02:03 -07001722_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1723 GLenum matrixType, GLint location, GLsizei count,
1724 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001725{
Brian Paul8a40fe02008-08-06 16:26:47 -06001726 GLint offset;
Brian3a8e2772006-12-20 17:19:16 -07001727 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paulf84005c2008-05-14 16:01:31 -06001728
Brian3a8e2772006-12-20 17:19:16 -07001729 if (!shProg || !shProg->LinkStatus) {
1730 _mesa_error(ctx, GL_INVALID_OPERATION,
1731 "glUniformMatrix(program not linked)");
1732 return;
1733 }
Brian Paulf84005c2008-05-14 16:01:31 -06001734
1735 if (location == -1)
1736 return; /* The standard specifies this as a no-op */
1737
Brian Paul8a40fe02008-08-06 16:26:47 -06001738 split_location_offset(&location, &offset);
1739
Michal Krolf9c574d2008-07-15 11:44:47 +02001740 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian3a8e2772006-12-20 17:19:16 -07001741 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
1742 return;
1743 }
Brian34ae99d2006-12-18 08:28:54 -07001744 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001745 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001746 return;
1747 }
1748
1749 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1750
Brianbc029242008-04-04 18:59:21 -06001751 if (shProg->VertexProgram) {
Brian Paul8a40fe02008-08-06 16:26:47 -06001752 /* convert uniform location to program parameter index */
1753 GLint index = shProg->Uniforms->Uniforms[location].VertPos;
1754 if (index >= 0) {
Brianbc029242008-04-04 18:59:21 -06001755 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
Brian Paul8a40fe02008-08-06 16:26:47 -06001756 index, offset,
1757 count, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07001758 }
Brian34ae99d2006-12-18 08:28:54 -07001759 }
Brianbc029242008-04-04 18:59:21 -06001760
1761 if (shProg->FragmentProgram) {
Brian Paul8a40fe02008-08-06 16:26:47 -06001762 /* convert uniform location to program parameter index */
1763 GLint index = shProg->Uniforms->Uniforms[location].FragPos;
1764 if (index >= 0) {
Brianbc029242008-04-04 18:59:21 -06001765 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
Brian Paul8a40fe02008-08-06 16:26:47 -06001766 index, offset,
1767 count, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07001768 }
Brian34ae99d2006-12-18 08:28:54 -07001769 }
1770}
1771
1772
Brian2d2bb352007-12-07 17:11:30 -07001773static void
Brian5b01c5e2006-12-19 18:02:03 -07001774_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001775{
Brian65a18442006-12-19 18:46:56 -07001776 struct gl_shader_program *shProg;
Brian Paul70d39282008-07-21 14:16:07 -06001777
1778 shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram");
Brian65a18442006-12-19 18:46:56 -07001779 if (!shProg) {
Brian34ae99d2006-12-18 08:28:54 -07001780 return;
1781 }
1782
Brian Paul70d39282008-07-21 14:16:07 -06001783 if (!shProg->LinkStatus) {
1784 shProg->Validated = GL_FALSE;
1785 return;
1786 }
1787
1788 /* From the GL spec, a program is invalid if any of these are true:
1789
Brian5b01c5e2006-12-19 18:02:03 -07001790 any two active samplers in the current program object are of
1791 different types, but refer to the same texture image unit,
1792
1793 any active sampler in the current program object refers to a texture
1794 image unit where fixed-function fragment processing accesses a
1795 texture target that does not match the sampler type, or
1796
1797 the sum of the number of active samplers in the program and the
1798 number of texture image units enabled for fixed-function fragment
1799 processing exceeds the combined limit on the total number of texture
1800 image units allowed.
1801 */
Brian Paul70d39282008-07-21 14:16:07 -06001802
1803 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001804}
Brian2d2bb352007-12-07 17:11:30 -07001805
1806
1807/**
1808 * Plug in Mesa's GLSL functions into the device driver function table.
1809 */
1810void
1811_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
1812{
1813 driver->AttachShader = _mesa_attach_shader;
1814 driver->BindAttribLocation = _mesa_bind_attrib_location;
1815 driver->CompileShader = _mesa_compile_shader;
1816 driver->CreateProgram = _mesa_create_program;
1817 driver->CreateShader = _mesa_create_shader;
1818 driver->DeleteProgram2 = _mesa_delete_program2;
1819 driver->DeleteShader = _mesa_delete_shader;
1820 driver->DetachShader = _mesa_detach_shader;
1821 driver->GetActiveAttrib = _mesa_get_active_attrib;
1822 driver->GetActiveUniform = _mesa_get_active_uniform;
1823 driver->GetAttachedShaders = _mesa_get_attached_shaders;
1824 driver->GetAttribLocation = _mesa_get_attrib_location;
1825 driver->GetHandle = _mesa_get_handle;
1826 driver->GetProgramiv = _mesa_get_programiv;
1827 driver->GetProgramInfoLog = _mesa_get_program_info_log;
1828 driver->GetShaderiv = _mesa_get_shaderiv;
1829 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
1830 driver->GetShaderSource = _mesa_get_shader_source;
1831 driver->GetUniformfv = _mesa_get_uniformfv;
Brian Paul072c4742008-07-08 16:12:01 -06001832 driver->GetUniformiv = _mesa_get_uniformiv;
Brian2d2bb352007-12-07 17:11:30 -07001833 driver->GetUniformLocation = _mesa_get_uniform_location;
1834 driver->IsProgram = _mesa_is_program;
1835 driver->IsShader = _mesa_is_shader;
1836 driver->LinkProgram = _mesa_link_program;
1837 driver->ShaderSource = _mesa_shader_source;
1838 driver->Uniform = _mesa_uniform;
1839 driver->UniformMatrix = _mesa_uniform_matrix;
1840 driver->UseProgram = _mesa_use_program;
1841 driver->ValidateProgram = _mesa_validate_program;
1842}