blob: 25c0484feb2cafd27df94dccab78e1707ed7e041 [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
38#include "glheader.h"
39#include "context.h"
40#include "hash.h"
Brian274ac7a2007-04-18 16:05:53 -060041#include "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"
Brian Paulade50832008-05-14 16:09:46 -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
Brianf2923612006-12-20 09:56:44 -070053/**
54 * Allocate a new gl_shader_program object, initialize it.
55 */
Brian Paulfd59f192008-05-18 16:04:55 -060056static struct gl_shader_program *
Brianf2923612006-12-20 09:56:44 -070057_mesa_new_shader_program(GLcontext *ctx, GLuint name)
58{
59 struct gl_shader_program *shProg;
60 shProg = CALLOC_STRUCT(gl_shader_program);
61 if (shProg) {
Brianf3e8c322007-04-18 14:53:23 -060062 shProg->Type = GL_SHADER_PROGRAM_MESA;
Brianf2923612006-12-20 09:56:44 -070063 shProg->Name = name;
64 shProg->RefCount = 1;
Brian3209c3e2007-01-09 17:49:24 -070065 shProg->Attributes = _mesa_new_parameter_list();
Brianf2923612006-12-20 09:56:44 -070066 }
67 return shProg;
68}
69
70
Brianb9fbedd2007-03-26 09:23:44 -060071/**
Brian3c008a02007-04-12 15:22:32 -060072 * Clear (free) the shader program state that gets produced by linking.
Brianb9fbedd2007-03-26 09:23:44 -060073 */
Brianf2923612006-12-20 09:56:44 -070074void
Brian3c008a02007-04-12 15:22:32 -060075_mesa_clear_shader_program_data(GLcontext *ctx,
76 struct gl_shader_program *shProg)
Brianf2923612006-12-20 09:56:44 -070077{
Brian Paul8bdf5b62008-05-16 09:56:59 -060078 _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL);
79 _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL);
Brianf2923612006-12-20 09:56:44 -070080
Brianf2923612006-12-20 09:56:44 -070081 if (shProg->Uniforms) {
Brian Paulade50832008-05-14 16:09:46 -060082 _mesa_free_uniform_list(shProg->Uniforms);
Brianf2923612006-12-20 09:56:44 -070083 shProg->Uniforms = NULL;
84 }
85
86 if (shProg->Varying) {
87 _mesa_free_parameter_list(shProg->Varying);
88 shProg->Varying = NULL;
89 }
90}
91
92
Brianb9fbedd2007-03-26 09:23:44 -060093/**
Brian3c008a02007-04-12 15:22:32 -060094 * Free all the data that hangs off a shader program object, but not the
95 * object itself.
96 */
97void
98_mesa_free_shader_program_data(GLcontext *ctx,
99 struct gl_shader_program *shProg)
100{
101 GLuint i;
102
Brianf3e8c322007-04-18 14:53:23 -0600103 assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
Brian3c008a02007-04-12 15:22:32 -0600104
105 _mesa_clear_shader_program_data(ctx, shProg);
106
Brian4b7c6fc2007-04-19 15:23:34 -0600107 if (shProg->Attributes) {
108 _mesa_free_parameter_list(shProg->Attributes);
109 shProg->Attributes = NULL;
110 }
111
Brian3c008a02007-04-12 15:22:32 -0600112 /* detach shaders */
113 for (i = 0; i < shProg->NumShaders; i++) {
114 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
115 }
Xiang, Haihao63d8a842008-03-31 17:02:47 +0800116 shProg->NumShaders = 0;
117
Brian3c008a02007-04-12 15:22:32 -0600118 if (shProg->Shaders) {
119 _mesa_free(shProg->Shaders);
120 shProg->Shaders = NULL;
121 }
Alan Hourihaneeec20c32008-04-22 20:29:42 +0100122
123 if (shProg->InfoLog) {
124 _mesa_free(shProg->InfoLog);
125 shProg->InfoLog = NULL;
126 }
Brian3c008a02007-04-12 15:22:32 -0600127}
128
129
130/**
Brianb9fbedd2007-03-26 09:23:44 -0600131 * Free/delete a shader program object.
132 */
Brianf2923612006-12-20 09:56:44 -0700133void
134_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg)
135{
136 _mesa_free_shader_program_data(ctx, shProg);
Alan Hourihaneeec20c32008-04-22 20:29:42 +0100137
Brianf2923612006-12-20 09:56:44 -0700138 _mesa_free(shProg);
139}
140
141
142/**
Brian3c008a02007-04-12 15:22:32 -0600143 * Set ptr to point to shProg.
144 * If ptr is pointing to another object, decrement its refcount (and delete
145 * if refcount hits zero).
146 * Then set ptr to point to shProg, incrementing its refcount.
147 */
148/* XXX this could be static */
149void
150_mesa_reference_shader_program(GLcontext *ctx,
151 struct gl_shader_program **ptr,
152 struct gl_shader_program *shProg)
153{
154 assert(ptr);
155 if (*ptr == shProg) {
156 /* no-op */
157 return;
158 }
159 if (*ptr) {
160 /* Unreference the old shader program */
161 GLboolean deleteFlag = GL_FALSE;
162 struct gl_shader_program *old = *ptr;
163
164 ASSERT(old->RefCount > 0);
165 old->RefCount--;
Brian Paul8bdf5b62008-05-16 09:56:59 -0600166#if 0
167 printf("ShaderProgram %p ID=%u RefCount-- to %d\n",
168 (void *) old, old->Name, old->RefCount);
169#endif
Brian3c008a02007-04-12 15:22:32 -0600170 deleteFlag = (old->RefCount == 0);
171
172 if (deleteFlag) {
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800173 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
Brian3c008a02007-04-12 15:22:32 -0600174 _mesa_free_shader_program(ctx, old);
175 }
176
177 *ptr = NULL;
178 }
179 assert(!*ptr);
180
181 if (shProg) {
182 shProg->RefCount++;
Brian Paul8bdf5b62008-05-16 09:56:59 -0600183#if 0
184 printf("ShaderProgram %p ID=%u RefCount++ to %d\n",
185 (void *) shProg, shProg->Name, shProg->RefCount);
186#endif
Brian3c008a02007-04-12 15:22:32 -0600187 *ptr = shProg;
188 }
189}
190
191
192/**
Brianf2923612006-12-20 09:56:44 -0700193 * Lookup a GLSL program object.
194 */
195struct gl_shader_program *
196_mesa_lookup_shader_program(GLcontext *ctx, GLuint name)
197{
198 struct gl_shader_program *shProg;
199 if (name) {
200 shProg = (struct gl_shader_program *)
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800201 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
Brianf2923612006-12-20 09:56:44 -0700202 /* Note that both gl_shader and gl_shader_program objects are kept
203 * in the same hash table. Check the object's type to be sure it's
204 * what we're expecting.
205 */
Brianf3e8c322007-04-18 14:53:23 -0600206 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700207 return NULL;
208 }
209 return shProg;
210 }
211 return NULL;
212}
213
214
215/**
Brian Paul530df582008-07-03 16:21:11 -0600216 * As above, but record an error if program is not found.
217 */
218static struct gl_shader_program *
219_mesa_lookup_shader_program_err(GLcontext *ctx, GLuint name,
220 const char *caller)
221{
222 if (!name) {
223 _mesa_error(ctx, GL_INVALID_VALUE, caller);
224 return NULL;
225 }
226 else {
227 struct gl_shader_program *shProg = (struct gl_shader_program *)
228 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
229 if (!shProg) {
230 _mesa_error(ctx, GL_INVALID_VALUE, caller);
231 return NULL;
232 }
233 if (shProg->Type != GL_SHADER_PROGRAM_MESA) {
234 _mesa_error(ctx, GL_INVALID_OPERATION, caller);
235 return NULL;
236 }
237 return shProg;
238 }
239}
240
241
242
243
244/**
Brianf2923612006-12-20 09:56:44 -0700245 * Allocate a new gl_shader object, initialize it.
246 */
247struct gl_shader *
248_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
249{
250 struct gl_shader *shader;
251 assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
252 shader = CALLOC_STRUCT(gl_shader);
253 if (shader) {
254 shader->Type = type;
255 shader->Name = name;
256 shader->RefCount = 1;
257 }
258 return shader;
259}
260
261
262void
263_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh)
264{
265 GLuint i;
266 if (sh->Source)
267 _mesa_free((void *) sh->Source);
268 if (sh->InfoLog)
269 _mesa_free(sh->InfoLog);
Brian Paul57e222d2008-05-14 12:10:45 -0600270 for (i = 0; i < sh->NumPrograms; i++)
271 _mesa_reference_program(ctx, &sh->Programs[i], NULL);
Brianf2923612006-12-20 09:56:44 -0700272 if (sh->Programs)
273 _mesa_free(sh->Programs);
274 _mesa_free(sh);
275}
276
277
278/**
Brian3c008a02007-04-12 15:22:32 -0600279 * Set ptr to point to sh.
280 * If ptr is pointing to another shader, decrement its refcount (and delete
281 * if refcount hits zero).
282 * Then set ptr to point to sh, incrementing its refcount.
283 */
284/* XXX this could be static */
285void
286_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr,
287 struct gl_shader *sh)
288{
289 assert(ptr);
290 if (*ptr == sh) {
291 /* no-op */
292 return;
293 }
294 if (*ptr) {
295 /* Unreference the old shader */
296 GLboolean deleteFlag = GL_FALSE;
297 struct gl_shader *old = *ptr;
298
299 ASSERT(old->RefCount > 0);
300 old->RefCount--;
Brian99193e42007-04-12 15:45:02 -0600301 /*printf("SHADER DECR %p (%d) to %d\n",
302 (void*) old, old->Name, old->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600303 deleteFlag = (old->RefCount == 0);
304
305 if (deleteFlag) {
306 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
307 _mesa_free_shader(ctx, old);
308 }
309
310 *ptr = NULL;
311 }
312 assert(!*ptr);
313
314 if (sh) {
315 /* reference new */
316 sh->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600317 /*printf("SHADER INCR %p (%d) to %d\n",
318 (void*) sh, sh->Name, sh->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600319 *ptr = sh;
320 }
321}
322
323
324/**
Brianf2923612006-12-20 09:56:44 -0700325 * Lookup a GLSL shader object.
326 */
327struct gl_shader *
328_mesa_lookup_shader(GLcontext *ctx, GLuint name)
329{
330 if (name) {
331 struct gl_shader *sh = (struct gl_shader *)
332 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
333 /* Note that both gl_shader and gl_shader_program objects are kept
334 * in the same hash table. Check the object's type to be sure it's
335 * what we're expecting.
336 */
Brianf3e8c322007-04-18 14:53:23 -0600337 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700338 return NULL;
339 }
340 return sh;
341 }
342 return NULL;
343}
344
345
Brianfa4d0362007-02-26 18:33:50 -0700346/**
Brian Paul530df582008-07-03 16:21:11 -0600347 * As above, but record an error if shader is not found.
348 */
349static struct gl_shader *
350_mesa_lookup_shader_err(GLcontext *ctx, GLuint name, const char *caller)
351{
352 if (!name) {
353 _mesa_error(ctx, GL_INVALID_VALUE, caller);
354 return NULL;
355 }
356 else {
357 struct gl_shader *sh = (struct gl_shader *)
358 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
359 if (!sh) {
360 _mesa_error(ctx, GL_INVALID_VALUE, caller);
361 return NULL;
362 }
363 if (sh->Type == GL_SHADER_PROGRAM_MESA) {
364 _mesa_error(ctx, GL_INVALID_OPERATION, caller);
365 return NULL;
366 }
367 return sh;
368 }
369}
370
371
372
373/**
Brianfa4d0362007-02-26 18:33:50 -0700374 * Initialize context's shader state.
375 */
Brianf2923612006-12-20 09:56:44 -0700376void
377_mesa_init_shader_state(GLcontext * ctx)
378{
Brianfa4d0362007-02-26 18:33:50 -0700379 /* Device drivers may override these to control what kind of instructions
380 * are generated by the GLSL compiler.
381 */
382 ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
Brian63556fa2007-03-23 14:47:46 -0600383 ctx->Shader.EmitCondCodes = GL_TRUE; /* XXX probably want GL_FALSE... */
Brianfa4d0362007-02-26 18:33:50 -0700384 ctx->Shader.EmitComments = GL_FALSE;
Brianf2923612006-12-20 09:56:44 -0700385}
386
387
Brian5b01c5e2006-12-19 18:02:03 -0700388/**
Brian935f93f2007-03-24 16:20:02 -0600389 * Free the per-context shader-related state.
390 */
391void
392_mesa_free_shader_state(GLcontext *ctx)
393{
Brian3c008a02007-04-12 15:22:32 -0600394 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
Brian935f93f2007-03-24 16:20:02 -0600395}
396
397
398/**
Brian5b01c5e2006-12-19 18:02:03 -0700399 * Copy string from <src> to <dst>, up to maxLength characters, returning
400 * length of <dst> in <length>.
401 * \param src the strings source
402 * \param maxLength max chars to copy
403 * \param length returns number of chars copied
404 * \param dst the string destination
405 */
406static void
407copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
408{
409 GLsizei len;
410 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
411 dst[len] = src[len];
412 if (maxLength > 0)
413 dst[len] = 0;
414 if (length)
415 *length = len;
416}
417
418
Brian Paul7acb7c12008-07-03 13:49:48 -0600419static GLboolean
420_mesa_is_program(GLcontext *ctx, GLuint name)
421{
422 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
423 return shProg ? GL_TRUE : GL_FALSE;
424}
425
426
427static GLboolean
428_mesa_is_shader(GLcontext *ctx, GLuint name)
429{
430 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
431 return shader ? GL_TRUE : GL_FALSE;
432}
433
434
Brian5b01c5e2006-12-19 18:02:03 -0700435/**
436 * Called via ctx->Driver.AttachShader()
437 */
Brian Paulfd59f192008-05-18 16:04:55 -0600438static void
Brian5b01c5e2006-12-19 18:02:03 -0700439_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
440{
Brian Paul530df582008-07-03 16:21:11 -0600441 struct gl_shader_program *shProg;
442 struct gl_shader *sh;
443 GLuint i, n;
Brian5b01c5e2006-12-19 18:02:03 -0700444
Brian Paul530df582008-07-03 16:21:11 -0600445 shProg = _mesa_lookup_shader_program_err(ctx, program, "glAttachShader");
446 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700447 return;
Brian5b01c5e2006-12-19 18:02:03 -0700448
Brian Paul530df582008-07-03 16:21:11 -0600449 sh = _mesa_lookup_shader_err(ctx, shader, "glAttachShader");
Brian Paul7acb7c12008-07-03 13:49:48 -0600450 if (!sh) {
Brian Paul7acb7c12008-07-03 13:49:48 -0600451 return;
452 }
453
Brian237b9852007-08-07 21:48:31 +0100454 n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700455 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700456 if (shProg->Shaders[i] == sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700457 /* already attached */
458 return;
Brian34ae99d2006-12-18 08:28:54 -0700459 }
460 }
Brian5b01c5e2006-12-19 18:02:03 -0700461
462 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700463 shProg->Shaders = (struct gl_shader **)
464 _mesa_realloc(shProg->Shaders,
465 n * sizeof(struct gl_shader *),
466 (n + 1) * sizeof(struct gl_shader *));
467 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700468 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
469 return;
470 }
471
472 /* append */
Brian3c008a02007-04-12 15:22:32 -0600473 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
474 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700475 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700476}
477
478
Brian Paulfd59f192008-05-18 16:04:55 -0600479static GLint
Brian Paul896c0cc2008-05-16 15:47:55 -0600480_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
481 const GLchar *name)
482{
483 struct gl_shader_program *shProg
Brian Paul530df582008-07-03 16:21:11 -0600484 = _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
Brian Paul896c0cc2008-05-16 15:47:55 -0600485
486 if (!shProg) {
Brian Paul896c0cc2008-05-16 15:47:55 -0600487 return -1;
488 }
489
490 if (!shProg->LinkStatus) {
491 _mesa_error(ctx, GL_INVALID_OPERATION,
492 "glGetAttribLocation(program not linked)");
493 return -1;
494 }
495
496 if (!name)
497 return -1;
498
499 if (shProg->Attributes) {
500 GLint i = _mesa_lookup_parameter_index(shProg->Attributes, -1, name);
501 if (i >= 0) {
502 return shProg->Attributes->Parameters[i].StateIndexes[0];
503 }
504 }
505 return -1;
506}
507
508
Brian Paulfd59f192008-05-18 16:04:55 -0600509static void
Brian5b01c5e2006-12-19 18:02:03 -0700510_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
511 const GLchar *name)
512{
Brian Paul530df582008-07-03 16:21:11 -0600513 struct gl_shader_program *shProg;
Brianb7978af2007-01-09 19:17:17 -0700514 const GLint size = -1; /* unknown size */
515 GLint i, oldIndex;
Brian Paulffbc66b2008-07-21 13:58:50 -0600516 GLenum datatype;
Brian5b01c5e2006-12-19 18:02:03 -0700517
Brian Paul530df582008-07-03 16:21:11 -0600518 shProg = _mesa_lookup_shader_program_err(ctx, program,
519 "glBindAttribLocation");
Brian65a18442006-12-19 18:46:56 -0700520 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700521 return;
522 }
523
Brian9e4bae92006-12-20 09:27:42 -0700524 if (!name)
525 return;
526
527 if (strncmp(name, "gl_", 3) == 0) {
528 _mesa_error(ctx, GL_INVALID_OPERATION,
529 "glBindAttribLocation(illegal name)");
530 return;
531 }
532
Brian Paul7acb7c12008-07-03 13:49:48 -0600533 if (index >= ctx->Const.VertexProgram.MaxAttribs) {
534 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
535 return;
536 }
537
Brian9f660252007-04-11 09:00:56 -0600538 if (shProg->LinkStatus) {
539 /* get current index/location for the attribute */
540 oldIndex = _mesa_get_attrib_location(ctx, program, name);
Brian Paulffbc66b2008-07-21 13:58:50 -0600541 assert(0);
Brian9f660252007-04-11 09:00:56 -0600542 }
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 Paulffbc66b2008-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");
551 }
552
Brian9f660252007-04-11 09:00:56 -0600553 if (shProg->VertexProgram && oldIndex >= 0 && oldIndex != index) {
554 /* If the index changed, need to search/replace references to that attribute
555 * in the vertex program.
556 */
Brian3209c3e2007-01-09 17:49:24 -0700557 _slang_remap_attribute(&shProg->VertexProgram->Base, oldIndex, index);
558 }
Brian34ae99d2006-12-18 08:28:54 -0700559}
560
561
Brian Paulfd59f192008-05-18 16:04:55 -0600562static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700563_mesa_create_shader(GLcontext *ctx, GLenum type)
564{
Brian65a18442006-12-19 18:46:56 -0700565 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700566 GLuint name;
567
568 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
569
570 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700571 case GL_FRAGMENT_SHADER:
572 case GL_VERTEX_SHADER:
573 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700574 break;
575 default:
576 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
577 return 0;
578 }
579
Brian65a18442006-12-19 18:46:56 -0700580 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700581
582 return name;
583}
584
585
Brian Paulfd59f192008-05-18 16:04:55 -0600586static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700587_mesa_create_program(GLcontext *ctx)
588{
589 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700590 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700591
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800592 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
Brian65a18442006-12-19 18:46:56 -0700593 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700594
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800595 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700596
Brian3c008a02007-04-12 15:22:32 -0600597 assert(shProg->RefCount == 1);
598
Brian5b01c5e2006-12-19 18:02:03 -0700599 return name;
600}
601
602
Brian3c008a02007-04-12 15:22:32 -0600603/**
604 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
605 * DeleteProgramARB.
606 */
Brian Paulfd59f192008-05-18 16:04:55 -0600607static void
Brian5b01c5e2006-12-19 18:02:03 -0700608_mesa_delete_program2(GLcontext *ctx, GLuint name)
609{
Brian3c008a02007-04-12 15:22:32 -0600610 /*
611 * NOTE: deleting shaders/programs works a bit differently than
612 * texture objects (and buffer objects, etc). Shader/program
613 * handles/IDs exist in the hash table until the object is really
614 * deleted (refcount==0). With texture objects, the handle/ID is
615 * removed from the hash table in glDeleteTextures() while the tex
616 * object itself might linger until its refcount goes to zero.
617 */
Brian65a18442006-12-19 18:46:56 -0700618 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700619
Brian Paul530df582008-07-03 16:21:11 -0600620 shProg = _mesa_lookup_shader_program_err(ctx, name, "glDeleteProgram");
621 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700622 return;
Brian5b01c5e2006-12-19 18:02:03 -0700623
Brian9e4bae92006-12-20 09:27:42 -0700624 shProg->DeletePending = GL_TRUE;
625
Brian3c008a02007-04-12 15:22:32 -0600626 /* effectively, decr shProg's refcount */
627 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700628}
629
630
Brian Paulfd59f192008-05-18 16:04:55 -0600631static void
Brian5b01c5e2006-12-19 18:02:03 -0700632_mesa_delete_shader(GLcontext *ctx, GLuint shader)
633{
Brian Paul530df582008-07-03 16:21:11 -0600634 struct gl_shader *sh;
635
636 sh = _mesa_lookup_shader_err(ctx, shader, "glDeleteShader");
637 if (!sh)
Brian9e4bae92006-12-20 09:27:42 -0700638 return;
Brian5b01c5e2006-12-19 18:02:03 -0700639
Brian9e4bae92006-12-20 09:27:42 -0700640 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600641
642 /* effectively, decr sh's refcount */
643 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700644}
645
646
Brian Paulfd59f192008-05-18 16:04:55 -0600647static void
Brian5b01c5e2006-12-19 18:02:03 -0700648_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
649{
Brian Paul530df582008-07-03 16:21:11 -0600650 struct gl_shader_program *shProg;
Brian237b9852007-08-07 21:48:31 +0100651 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700652 GLuint i, j;
653
Brian Paul530df582008-07-03 16:21:11 -0600654 shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader");
655 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700656 return;
Brian5b01c5e2006-12-19 18:02:03 -0700657
Brian237b9852007-08-07 21:48:31 +0100658 n = shProg->NumShaders;
659
Brian5b01c5e2006-12-19 18:02:03 -0700660 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700661 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700662 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600663 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700664
Brian Paul530df582008-07-03 16:21:11 -0600665 /* release */
Brian3c008a02007-04-12 15:22:32 -0600666 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700667
Brian5b01c5e2006-12-19 18:02:03 -0700668 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700669 newList = (struct gl_shader **)
670 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700671 if (!newList) {
672 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
673 return;
674 }
675 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700676 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700677 }
678 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700679 newList[j++] = shProg->Shaders[i];
680 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700681
Brian65a18442006-12-19 18:46:56 -0700682 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600683 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600684
685#ifdef DEBUG
686 /* sanity check */
687 {
688 for (j = 0; j < shProg->NumShaders; j++) {
689 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
690 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
691 assert(shProg->Shaders[j]->RefCount > 0);
692 }
693 }
694#endif
695
Brian5b01c5e2006-12-19 18:02:03 -0700696 return;
697 }
698 }
699
700 /* not found */
Brian Paul530df582008-07-03 16:21:11 -0600701 {
702 GLenum err;
703 if (_mesa_is_shader(ctx, shader))
704 err = GL_INVALID_OPERATION;
705 else if (_mesa_is_program(ctx, shader))
706 err = GL_INVALID_OPERATION;
707 else
708 err = GL_INVALID_VALUE;
709 _mesa_error(ctx, err, "glDetachProgram(shader)");
710 return;
711 }
Brian5b01c5e2006-12-19 18:02:03 -0700712}
713
714
Brian Paulffbc66b2008-07-21 13:58:50 -0600715static GLint
716sizeof_glsl_type(GLenum type)
717{
718 switch (type) {
719 case GL_FLOAT:
720 case GL_INT:
721 case GL_BOOL:
722 return 1;
723 case GL_FLOAT_VEC2:
724 case GL_INT_VEC2:
725 case GL_BOOL_VEC2:
726 return 2;
727 case GL_FLOAT_VEC3:
728 case GL_INT_VEC3:
729 case GL_BOOL_VEC3:
730 return 3;
731 case GL_FLOAT_VEC4:
732 case GL_INT_VEC4:
733 case GL_BOOL_VEC4:
734 return 4;
735 case GL_FLOAT_MAT2:
736 case GL_FLOAT_MAT2x3:
737 case GL_FLOAT_MAT2x4:
738 return 8; /* two float[4] vectors */
739 case GL_FLOAT_MAT3:
740 case GL_FLOAT_MAT3x2:
741 case GL_FLOAT_MAT3x4:
742 return 12; /* three float[4] vectors */
743 case GL_FLOAT_MAT4:
744 case GL_FLOAT_MAT4x2:
745 case GL_FLOAT_MAT4x3:
746 return 16; /* four float[4] vectors */
747 default:
748 _mesa_problem(NULL, "Invalid type in sizeof_glsl_type()");
749 return 1;
750 }
751}
752
753
Brian Paulfd59f192008-05-18 16:04:55 -0600754static void
Brian5b01c5e2006-12-19 18:02:03 -0700755_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
756 GLsizei maxLength, GLsizei *length, GLint *size,
757 GLenum *type, GLchar *nameOut)
758{
Brian Paul530df582008-07-03 16:21:11 -0600759 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700760
Brian Paul530df582008-07-03 16:21:11 -0600761 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
762 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700763 return;
Brian5b01c5e2006-12-19 18:02:03 -0700764
Brian65a18442006-12-19 18:46:56 -0700765 if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600766 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700767 return;
768 }
769
770 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700771 shProg->Attributes->Parameters[index].Name);
Brian5b01c5e2006-12-19 18:02:03 -0700772 if (size)
Brian Paulffbc66b2008-07-21 13:58:50 -0600773 *size = shProg->Attributes->Parameters[index].Size
774 / sizeof_glsl_type(shProg->Attributes->Parameters[index].DataType);
Brian Paulade50832008-05-14 16:09:46 -0600775 if (type)
Brian Paulffbc66b2008-07-21 13:58:50 -0600776 *type = shProg->Attributes->Parameters[index].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700777}
778
779
780/**
781 * Called via ctx->Driver.GetActiveUniform().
782 */
Brian Paulfd59f192008-05-18 16:04:55 -0600783static void
Brian5b01c5e2006-12-19 18:02:03 -0700784_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
785 GLsizei maxLength, GLsizei *length, GLint *size,
786 GLenum *type, GLchar *nameOut)
787{
Brian Paul530df582008-07-03 16:21:11 -0600788 const struct gl_shader_program *shProg;
Brian Paulade50832008-05-14 16:09:46 -0600789 const struct gl_program *prog;
790 GLint progPos;
Brian5b01c5e2006-12-19 18:02:03 -0700791
Brian Paul530df582008-07-03 16:21:11 -0600792 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
793 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700794 return;
Brian5b01c5e2006-12-19 18:02:03 -0700795
Brian Paulade50832008-05-14 16:09:46 -0600796 if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
Brian5b01c5e2006-12-19 18:02:03 -0700797 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
798 return;
799 }
800
Brian Paulade50832008-05-14 16:09:46 -0600801 progPos = shProg->Uniforms->Uniforms[index].VertPos;
802 if (progPos >= 0) {
803 prog = &shProg->VertexProgram->Base;
804 }
805 else {
806 progPos = shProg->Uniforms->Uniforms[index].FragPos;
807 if (progPos >= 0) {
808 prog = &shProg->FragmentProgram->Base;
Brian274ac7a2007-04-18 16:05:53 -0600809 }
810 }
811
Brian Paulade50832008-05-14 16:09:46 -0600812 if (!prog || progPos < 0)
813 return; /* should never happen */
814
815 if (nameOut)
816 copy_string(nameOut, maxLength, length,
817 prog->Parameters->Parameters[progPos].Name);
818 if (size)
Brian Paulffbc66b2008-07-21 13:58:50 -0600819 *size = prog->Parameters->Parameters[progPos].Size
820 / sizeof_glsl_type(prog->Parameters->Parameters[progPos].DataType);
Brian Paulade50832008-05-14 16:09:46 -0600821 if (type)
822 *type = prog->Parameters->Parameters[progPos].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700823}
824
825
826/**
827 * Called via ctx->Driver.GetAttachedShaders().
828 */
Brian Paulfd59f192008-05-18 16:04:55 -0600829static void
Brian5b01c5e2006-12-19 18:02:03 -0700830_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
831 GLsizei *count, GLuint *obj)
832{
Brian Paul530df582008-07-03 16:21:11 -0600833 struct gl_shader_program *shProg =
834 _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders");
Brian65a18442006-12-19 18:46:56 -0700835 if (shProg) {
Brian Paul530df582008-07-03 16:21:11 -0600836 GLuint i;
837 for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) {
Brian65a18442006-12-19 18:46:56 -0700838 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700839 }
840 if (count)
841 *count = i;
842 }
Brian5b01c5e2006-12-19 18:02:03 -0700843}
844
845
Brian Paulfd59f192008-05-18 16:04:55 -0600846static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700847_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700848{
849#if 0
850 GET_CURRENT_CONTEXT(ctx);
851
852 switch (pname) {
853 case GL_PROGRAM_OBJECT_ARB:
854 {
Brian5b01c5e2006-12-19 18:02:03 -0700855 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700856
857 if (pro != NULL)
858 return (**pro)._container._generic.
859 GetName((struct gl2_generic_intf **) (pro));
860 }
861 break;
862 default:
863 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
864 }
865#endif
866 return 0;
867}
868
869
Brian Paulfd59f192008-05-18 16:04:55 -0600870static void
Brian5b01c5e2006-12-19 18:02:03 -0700871_mesa_get_programiv(GLcontext *ctx, GLuint program,
872 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700873{
Brian65a18442006-12-19 18:46:56 -0700874 struct gl_shader_program *shProg
875 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700876
Brian65a18442006-12-19 18:46:56 -0700877 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700878 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700879 return;
880 }
881
Brian5b01c5e2006-12-19 18:02:03 -0700882 switch (pname) {
883 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700884 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700885 break;
886 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700887 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700888 break;
Brian5b01c5e2006-12-19 18:02:03 -0700889 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700890 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700891 break;
892 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600893 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700894 break;
895 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700896 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700897 break;
898 case GL_ACTIVE_ATTRIBUTES:
Brian3209c3e2007-01-09 17:49:24 -0700899 *params = shProg->Attributes ? shProg->Attributes->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700900 break;
901 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600902 *params = _mesa_longest_parameter_name(shProg->Attributes,
903 PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700904 break;
905 case GL_ACTIVE_UNIFORMS:
Brian Paulade50832008-05-14 16:09:46 -0600906 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700907 break;
908 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian Paulade50832008-05-14 16:09:46 -0600909 *params = _mesa_longest_uniform_name(shProg->Uniforms);
Brian274ac7a2007-04-18 16:05:53 -0600910 if (*params > 0)
911 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700912 break;
913 default:
Brian5b01c5e2006-12-19 18:02:03 -0700914 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
915 return;
Brian34ae99d2006-12-18 08:28:54 -0700916 }
Brian5b01c5e2006-12-19 18:02:03 -0700917}
Brian34ae99d2006-12-18 08:28:54 -0700918
Brian34ae99d2006-12-18 08:28:54 -0700919
Brian Paulfd59f192008-05-18 16:04:55 -0600920static void
Brian5b01c5e2006-12-19 18:02:03 -0700921_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
922{
Brian Paul530df582008-07-03 16:21:11 -0600923 struct gl_shader *shader = _mesa_lookup_shader_err(ctx, name, "glGetShaderiv");
Brian5b01c5e2006-12-19 18:02:03 -0700924
925 if (!shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700926 return;
927 }
Brian65a18442006-12-19 18:46:56 -0700928
Brian5b01c5e2006-12-19 18:02:03 -0700929 switch (pname) {
930 case GL_SHADER_TYPE:
931 *params = shader->Type;
932 break;
933 case GL_DELETE_STATUS:
934 *params = shader->DeletePending;
935 break;
936 case GL_COMPILE_STATUS:
937 *params = shader->CompileStatus;
938 break;
939 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600940 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700941 break;
942 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600943 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700944 break;
945 default:
946 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
947 return;
948 }
949}
950
951
Brian Paulfd59f192008-05-18 16:04:55 -0600952static void
Brian5b01c5e2006-12-19 18:02:03 -0700953_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
954 GLsizei *length, GLchar *infoLog)
955{
Brian65a18442006-12-19 18:46:56 -0700956 struct gl_shader_program *shProg
957 = _mesa_lookup_shader_program(ctx, program);
958 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700959 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
960 return;
961 }
Brian65a18442006-12-19 18:46:56 -0700962 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700963}
964
965
Brian Paulfd59f192008-05-18 16:04:55 -0600966static void
Brian5b01c5e2006-12-19 18:02:03 -0700967_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
968 GLsizei *length, GLchar *infoLog)
969{
Brian65a18442006-12-19 18:46:56 -0700970 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
971 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700972 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
973 return;
974 }
Brian65a18442006-12-19 18:46:56 -0700975 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700976}
977
978
979/**
980 * Called via ctx->Driver.GetShaderSource().
981 */
Brian Paulfd59f192008-05-18 16:04:55 -0600982static void
Brian5b01c5e2006-12-19 18:02:03 -0700983_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
984 GLsizei *length, GLchar *sourceOut)
985{
Brian Paul530df582008-07-03 16:21:11 -0600986 struct gl_shader *sh;
987 sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource");
Brian65a18442006-12-19 18:46:56 -0700988 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700989 return;
990 }
Brian65a18442006-12-19 18:46:56 -0700991 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -0700992}
993
994
Brian Paul2be54a82008-07-08 16:17:04 -0600995#define MAX_UNIFORM_ELEMENTS 16
996
Brian5b01c5e2006-12-19 18:02:03 -0700997/**
Brian Paul2be54a82008-07-08 16:17:04 -0600998 * Helper for GetUniformfv(), GetUniformiv()
999 * Returns number of elements written to 'params' output.
Brian5b01c5e2006-12-19 18:02:03 -07001000 */
Brian Paul2be54a82008-07-08 16:17:04 -06001001static GLuint
1002get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1003 GLfloat *params)
Brian5b01c5e2006-12-19 18:02:03 -07001004{
Brian65a18442006-12-19 18:46:56 -07001005 struct gl_shader_program *shProg
1006 = _mesa_lookup_shader_program(ctx, program);
1007 if (shProg) {
Brian Paul6cb12702008-06-28 16:48:31 -06001008 if (shProg->Uniforms &&
1009 location >= 0 && location < shProg->Uniforms->NumUniforms) {
1010 GLint progPos;
1011 GLuint i;
Brian Paulf2632212008-05-16 10:49:44 -06001012 const struct gl_program *prog = NULL;
Brian Paulade50832008-05-14 16:09:46 -06001013
1014 progPos = shProg->Uniforms->Uniforms[location].VertPos;
1015 if (progPos >= 0) {
1016 prog = &shProg->VertexProgram->Base;
Brian5b01c5e2006-12-19 18:02:03 -07001017 }
Brian Paulade50832008-05-14 16:09:46 -06001018 else {
1019 progPos = shProg->Uniforms->Uniforms[location].FragPos;
1020 if (progPos >= 0) {
1021 prog = &shProg->FragmentProgram->Base;
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001022 }
Brian Paulade50832008-05-14 16:09:46 -06001023 }
1024
Brian Paulf2632212008-05-16 10:49:44 -06001025 ASSERT(prog);
1026 if (prog) {
Brian Paul2be54a82008-07-08 16:17:04 -06001027 /* See uniformiv() below */
1028 assert(prog->Parameters->Parameters[progPos].Size <= MAX_UNIFORM_ELEMENTS);
1029
Brian Paulf2632212008-05-16 10:49:44 -06001030 for (i = 0; i < prog->Parameters->Parameters[progPos].Size; i++) {
1031 params[i] = prog->Parameters->ParameterValues[progPos][i];
1032 }
Brian Paul2be54a82008-07-08 16:17:04 -06001033 return prog->Parameters->Parameters[progPos].Size;
Brian Paulade50832008-05-14 16:09:46 -06001034 }
Brian5b01c5e2006-12-19 18:02:03 -07001035 }
1036 else {
Brian Paul6cb12702008-06-28 16:48:31 -06001037 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
Brian5b01c5e2006-12-19 18:02:03 -07001038 }
1039 }
1040 else {
Brian Paul6cb12702008-06-28 16:48:31 -06001041 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
Brian5b01c5e2006-12-19 18:02:03 -07001042 }
Brian Paul2be54a82008-07-08 16:17:04 -06001043 return 0;
1044}
1045
1046
1047/**
1048 * Called via ctx->Driver.GetUniformfv().
1049 */
1050static void
1051_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1052 GLfloat *params)
1053{
1054 (void) get_uniformfv(ctx, program, location, params);
1055}
1056
1057
1058/**
1059 * Called via ctx->Driver.GetUniformiv().
1060 */
1061static void
1062_mesa_get_uniformiv(GLcontext *ctx, GLuint program, GLint location,
1063 GLint *params)
1064{
1065 GLfloat fparams[MAX_UNIFORM_ELEMENTS];
1066 GLuint n = get_uniformfv(ctx, program, location, fparams);
1067 GLuint i;
1068 assert(n <= MAX_UNIFORM_ELEMENTS);
1069 for (i = 0; i < n; i++) {
1070 params[i] = (GLint) fparams[i];
1071 }
Brian5b01c5e2006-12-19 18:02:03 -07001072}
1073
1074
1075/**
1076 * Called via ctx->Driver.GetUniformLocation().
1077 */
Brian Paulfd59f192008-05-18 16:04:55 -06001078static GLint
Brian5b01c5e2006-12-19 18:02:03 -07001079_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
1080{
Brian Paul530df582008-07-03 16:21:11 -06001081 struct gl_shader_program *shProg =
1082 _mesa_lookup_shader_program_err(ctx, program, "glGetUniformLocation");
1083
Brian Paulade50832008-05-14 16:09:46 -06001084 if (!shProg)
1085 return -1;
Brian5b01c5e2006-12-19 18:02:03 -07001086
Brian Paule06565b2008-07-04 09:58:55 -06001087 if (shProg->LinkStatus == GL_FALSE) {
1088 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
1089 return -1;
1090 }
1091
Brian Paul530df582008-07-03 16:21:11 -06001092 /* XXX we should return -1 if the uniform was declared, but not
1093 * actually used.
1094 */
1095
Brian Paulade50832008-05-14 16:09:46 -06001096 return _mesa_lookup_uniform(shProg->Uniforms, name);
Brian5b01c5e2006-12-19 18:02:03 -07001097}
1098
1099
Brian34ae99d2006-12-18 08:28:54 -07001100
Brian5b01c5e2006-12-19 18:02:03 -07001101/**
1102 * Called via ctx->Driver.ShaderSource()
1103 */
Brian Paulfd59f192008-05-18 16:04:55 -06001104static void
Brian5b01c5e2006-12-19 18:02:03 -07001105_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -07001106{
Brian Paul530df582008-07-03 16:21:11 -06001107 struct gl_shader *sh;
1108
1109 sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource");
1110 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001111 return;
Brian34ae99d2006-12-18 08:28:54 -07001112
Brian34ae99d2006-12-18 08:28:54 -07001113 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -07001114 if (sh->Source) {
1115 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -07001116 }
Brian65a18442006-12-19 18:46:56 -07001117 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -07001118 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -07001119}
1120
1121
Brian5b01c5e2006-12-19 18:02:03 -07001122/**
1123 * Called via ctx->Driver.CompileShader()
1124 */
Brian Paulfd59f192008-05-18 16:04:55 -06001125static void
Brian5b01c5e2006-12-19 18:02:03 -07001126_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -07001127{
Brian Paul530df582008-07-03 16:21:11 -06001128 struct gl_shader *sh;
Brian34ae99d2006-12-18 08:28:54 -07001129
Brian Paul530df582008-07-03 16:21:11 -06001130 sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader");
1131 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001132 return;
Brian34ae99d2006-12-18 08:28:54 -07001133
Brian43975832007-01-04 08:21:09 -07001134 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -07001135}
1136
1137
Brian5b01c5e2006-12-19 18:02:03 -07001138/**
1139 * Called via ctx->Driver.LinkProgram()
1140 */
Brian Paulfd59f192008-05-18 16:04:55 -06001141static void
Brian5b01c5e2006-12-19 18:02:03 -07001142_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001143{
Brian65a18442006-12-19 18:46:56 -07001144 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001145
Brian Paul530df582008-07-03 16:21:11 -06001146 shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
1147 if (!shProg)
Brian34ae99d2006-12-18 08:28:54 -07001148 return;
Brian34ae99d2006-12-18 08:28:54 -07001149
Briandf43fb62008-05-06 23:08:51 -06001150 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1151
Brianc1771912007-02-16 09:56:19 -07001152 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001153}
1154
1155
1156/**
Brian5b01c5e2006-12-19 18:02:03 -07001157 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001158 */
Brian5b01c5e2006-12-19 18:02:03 -07001159void
1160_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001161{
Brian3c008a02007-04-12 15:22:32 -06001162 struct gl_shader_program *shProg;
1163
Brian00d63aa2007-02-03 11:35:02 -07001164 if (ctx->Shader.CurrentProgram &&
1165 ctx->Shader.CurrentProgram->Name == program) {
1166 /* no-op */
1167 return;
1168 }
1169
1170 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1171
Brian5b01c5e2006-12-19 18:02:03 -07001172 if (program) {
Brian Paul530df582008-07-03 16:21:11 -06001173 shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
Brian65a18442006-12-19 18:46:56 -07001174 if (!shProg) {
Brian Paul530df582008-07-03 16:21:11 -06001175 return;
1176 }
1177 if (!shProg->LinkStatus) {
1178 _mesa_error(ctx, GL_INVALID_OPERATION, "glUseProgram");
Brian5b01c5e2006-12-19 18:02:03 -07001179 return;
1180 }
Brian5b01c5e2006-12-19 18:02:03 -07001181 }
1182 else {
Brian3c008a02007-04-12 15:22:32 -06001183 shProg = NULL;
1184 }
1185
1186 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001187}
Brian34ae99d2006-12-18 08:28:54 -07001188
Brian5b01c5e2006-12-19 18:02:03 -07001189
Brian Paulade50832008-05-14 16:09:46 -06001190
1191/**
1192 * Update the vertex and fragment program's TexturesUsed arrays.
1193 */
1194static void
1195update_textures_used(struct gl_program *prog)
1196{
1197 GLuint s;
1198
1199 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1200
1201 for (s = 0; s < MAX_SAMPLERS; s++) {
1202 if (prog->SamplersUsed & (1 << s)) {
1203 GLuint u = prog->SamplerUnits[s];
1204 GLuint t = prog->SamplerTargets[s];
1205 assert(u < MAX_TEXTURE_IMAGE_UNITS);
1206 prog->TexturesUsed[u] |= (1 << t);
1207 }
1208 }
1209}
1210
1211
1212/**
Brian Paulffbc66b2008-07-21 13:58:50 -06001213 * Check if the type given by userType is allowed to set a uniform of the
1214 * target type. Generally, equivalence is required, but setting Boolean
1215 * uniforms can be done with glUniformiv or glUniformfv.
1216 */
1217static GLboolean
1218compatible_types(GLenum userType, GLenum targetType)
1219{
1220 if (userType == targetType)
1221 return GL_TRUE;
1222
1223 if (targetType == GL_BOOL && (userType == GL_FLOAT || userType == GL_INT))
1224 return GL_TRUE;
1225
1226 if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 ||
1227 userType == GL_INT_VEC2))
1228 return GL_TRUE;
1229
1230 if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 ||
1231 userType == GL_INT_VEC3))
1232 return GL_TRUE;
1233
1234 if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 ||
1235 userType == GL_INT_VEC4))
1236 return GL_TRUE;
1237
1238 return GL_FALSE;
1239}
1240
1241
1242/**
Brian Paulade50832008-05-14 16:09:46 -06001243 * Set the value of a program's uniform variable.
1244 * \param program the program whose uniform to update
1245 * \param location the location/index of the uniform
1246 * \param type the datatype of the uniform
1247 * \param count the number of uniforms to set
1248 * \param elems number of elements per uniform
1249 * \param values the new values
1250 */
1251static void
1252set_program_uniform(GLcontext *ctx, struct gl_program *program, GLint location,
Brian Paul530df582008-07-03 16:21:11 -06001253 GLenum type, GLsizei count, GLint elems, const void *values)
Brian Paulade50832008-05-14 16:09:46 -06001254{
Brian Paulffbc66b2008-07-21 13:58:50 -06001255 if (!compatible_types(type,
1256 program->Parameters->Parameters[location].DataType)) {
1257 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
1258 return;
1259 }
1260
Brian Paulade50832008-05-14 16:09:46 -06001261 if (program->Parameters->Parameters[location].Type == PROGRAM_SAMPLER) {
1262 /* This controls which texture unit which is used by a sampler */
1263 GLuint texUnit, sampler;
1264
1265 /* data type for setting samplers must be int */
1266 if (type != GL_INT || count != 1) {
1267 _mesa_error(ctx, GL_INVALID_OPERATION,
1268 "glUniform(only glUniform1i can be used "
1269 "to set sampler uniforms)");
1270 return;
1271 }
1272
1273 sampler = (GLuint) program->Parameters->ParameterValues[location][0];
1274 texUnit = ((GLuint *) values)[0];
1275
1276 /* check that the sampler (tex unit index) is legal */
1277 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1278 _mesa_error(ctx, GL_INVALID_VALUE,
1279 "glUniform1(invalid sampler/tex unit index)");
1280 return;
1281 }
1282
1283 /* This maps a sampler to a texture unit: */
1284 program->SamplerUnits[sampler] = texUnit;
1285 update_textures_used(program);
1286
1287 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1288 }
1289 else {
1290 /* ordinary uniform variable */
Brian Paul530df582008-07-03 16:21:11 -06001291 GLsizei k, i;
Brian Paulade50832008-05-14 16:09:46 -06001292
1293 if (count * elems > program->Parameters->Parameters[location].Size) {
1294 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1295 return;
1296 }
1297
1298 for (k = 0; k < count; k++) {
1299 GLfloat *uniformVal = program->Parameters->ParameterValues[location + k];
1300 if (type == GL_INT ||
1301 type == GL_INT_VEC2 ||
1302 type == GL_INT_VEC3 ||
1303 type == GL_INT_VEC4) {
1304 const GLint *iValues = ((const GLint *) values) + k * elems;
1305 for (i = 0; i < elems; i++) {
1306 uniformVal[i] = (GLfloat) iValues[i];
1307 }
1308 }
1309 else {
1310 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1311 for (i = 0; i < elems; i++) {
1312 uniformVal[i] = fValues[i];
1313 }
1314 }
1315 }
1316 }
1317}
1318
1319
Brian5b01c5e2006-12-19 18:02:03 -07001320/**
1321 * Called via ctx->Driver.Uniform().
1322 */
Brian Paulfd59f192008-05-18 16:04:55 -06001323static void
Brian5b01c5e2006-12-19 18:02:03 -07001324_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1325 const GLvoid *values, GLenum type)
1326{
Brian3a8e2772006-12-20 17:19:16 -07001327 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paulade50832008-05-14 16:09:46 -06001328 GLint elems;
Brian3a8e2772006-12-20 17:19:16 -07001329
1330 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001331 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001332 return;
1333 }
1334
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001335 if (location == -1)
1336 return; /* The standard specifies this as a no-op */
1337
Brian Paulade50832008-05-14 16:09:46 -06001338 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
1339 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
Brian3a8e2772006-12-20 17:19:16 -07001340 return;
1341 }
1342
Brian52363952007-03-13 16:50:24 -06001343 if (count < 0) {
1344 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1345 return;
1346 }
1347
Brian98650bd2007-03-13 16:32:48 -06001348 switch (type) {
1349 case GL_FLOAT:
1350 case GL_INT:
1351 elems = 1;
1352 break;
1353 case GL_FLOAT_VEC2:
1354 case GL_INT_VEC2:
1355 elems = 2;
1356 break;
1357 case GL_FLOAT_VEC3:
1358 case GL_INT_VEC3:
1359 elems = 3;
1360 break;
1361 case GL_FLOAT_VEC4:
1362 case GL_INT_VEC4:
1363 elems = 4;
1364 break;
1365 default:
1366 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1367 return;
Brian89dc4852007-01-04 14:35:44 -07001368 }
Brian98650bd2007-03-13 16:32:48 -06001369
Brian Paulade50832008-05-14 16:09:46 -06001370 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
Brian98650bd2007-03-13 16:32:48 -06001371
Brian Paulade50832008-05-14 16:09:46 -06001372 /* A uniform var may be used by both a vertex shader and a fragment
1373 * shader. We may need to update one or both shader's uniform here:
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001374 */
Brian Paulade50832008-05-14 16:09:46 -06001375 if (shProg->VertexProgram) {
1376 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1377 if (loc >= 0) {
1378 set_program_uniform(ctx, &shProg->VertexProgram->Base,
1379 loc, type, count, elems, values);
Bruce Merry2bf2a8c2007-12-21 23:18:40 +02001380 }
Brian5b01c5e2006-12-19 18:02:03 -07001381 }
Brian5cf73262007-01-05 16:02:45 -07001382
Brian Paulade50832008-05-14 16:09:46 -06001383 if (shProg->FragmentProgram) {
1384 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1385 if (loc >= 0) {
1386 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
1387 loc, type, count, elems, values);
1388 }
1389 }
1390}
1391
1392
1393static void
Brian Paulffbc66b2008-07-21 13:58:50 -06001394get_matrix_dims(GLenum type, GLint *rows, GLint *cols)
1395{
1396 switch (type) {
1397 case GL_FLOAT_MAT2:
1398 *rows = *cols = 2;
1399 break;
1400 case GL_FLOAT_MAT2x3:
1401 *rows = 3;
1402 *cols = 2;
1403 break;
1404 case GL_FLOAT_MAT2x4:
1405 *rows = 4;
1406 *cols = 2;
1407 break;
1408 case GL_FLOAT_MAT3:
1409 *rows = 3;
1410 *cols = 3;
1411 break;
1412 case GL_FLOAT_MAT3x2:
1413 *rows = 2;
1414 *cols = 3;
1415 break;
1416 case GL_FLOAT_MAT3x4:
1417 *rows = 4;
1418 *cols = 3;
1419 break;
1420 case GL_FLOAT_MAT4:
1421 *rows = 4;
1422 *cols = 4;
1423 break;
1424 case GL_FLOAT_MAT4x2:
1425 *rows = 2;
1426 *cols = 4;
1427 break;
1428 case GL_FLOAT_MAT4x3:
1429 *rows = 3;
1430 *cols = 4;
1431 break;
1432 default:
1433 *rows = *cols = 0;
1434 }
1435}
1436
1437
1438static void
Brian Paulade50832008-05-14 16:09:46 -06001439set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
Brian Paulf45ed0e2008-07-18 12:51:39 -06001440 GLuint location, GLuint count,
1441 GLuint rows, GLuint cols,
Brian Paulade50832008-05-14 16:09:46 -06001442 GLboolean transpose, const GLfloat *values)
1443{
Brian Paulffbc66b2008-07-21 13:58:50 -06001444 GLuint mat, row, col;
1445 GLuint dst = location, src = 0;
1446 GLint nr, nc;
1447
1448 /* check that the number of rows, columns is correct */
1449 get_matrix_dims(program->Parameters->Parameters[location].DataType, &nr, &nc);
1450 if (rows != nr || cols != nc) {
1451 _mesa_error(ctx, GL_INVALID_OPERATION,
1452 "glUniformMatrix(matrix size mismatch");
1453 return;
1454 }
1455
Brian Paulade50832008-05-14 16:09:46 -06001456 /*
1457 * Note: the _columns_ of a matrix are stored in program registers, not
Brian Paulf45ed0e2008-07-18 12:51:39 -06001458 * the rows. So, the loops below look a little funny.
1459 * XXX could optimize this a bit...
Brian Paulade50832008-05-14 16:09:46 -06001460 */
Brian Paulf45ed0e2008-07-18 12:51:39 -06001461
1462 /* loop over matrices */
1463 for (mat = 0; mat < count; mat++) {
1464
1465 /* each matrix: */
Brian Paulade50832008-05-14 16:09:46 -06001466 for (col = 0; col < cols; col++) {
Brian Paulf45ed0e2008-07-18 12:51:39 -06001467 GLfloat *v = program->Parameters->ParameterValues[dst];
Brian Paulade50832008-05-14 16:09:46 -06001468 for (row = 0; row < rows; row++) {
Brian Paulf45ed0e2008-07-18 12:51:39 -06001469 if (transpose) {
1470 v[row] = values[src + row * cols + col];
1471 }
1472 else {
1473 v[row] = values[src + col * rows + row];
1474 }
Brian Paulade50832008-05-14 16:09:46 -06001475 }
Brian Paulf45ed0e2008-07-18 12:51:39 -06001476 dst++;
Brian Paulade50832008-05-14 16:09:46 -06001477 }
Brian Paulf45ed0e2008-07-18 12:51:39 -06001478
1479 src += rows * cols; /* next matrix */
Brian5cf73262007-01-05 16:02:45 -07001480 }
Brian34ae99d2006-12-18 08:28:54 -07001481}
1482
1483
1484/**
Brian5b01c5e2006-12-19 18:02:03 -07001485 * Called by ctx->Driver.UniformMatrix().
Brian Paulf45ed0e2008-07-18 12:51:39 -06001486 * Note: cols=2, rows=4 ==> array[2] of vec4
Brian34ae99d2006-12-18 08:28:54 -07001487 */
Brian Paulfd59f192008-05-18 16:04:55 -06001488static void
Brian5b01c5e2006-12-19 18:02:03 -07001489_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1490 GLenum matrixType, GLint location, GLsizei count,
1491 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001492{
Brian3a8e2772006-12-20 17:19:16 -07001493 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paulade50832008-05-14 16:09:46 -06001494
Brian3a8e2772006-12-20 17:19:16 -07001495 if (!shProg || !shProg->LinkStatus) {
1496 _mesa_error(ctx, GL_INVALID_OPERATION,
1497 "glUniformMatrix(program not linked)");
1498 return;
1499 }
Brian Paulade50832008-05-14 16:09:46 -06001500
Bruce Merry89b80322007-12-21 15:20:17 +02001501 if (location == -1)
1502 return; /* The standard specifies this as a no-op */
Brian Paulade50832008-05-14 16:09:46 -06001503
1504 if (location < 0 || location >= shProg->Uniforms->NumUniforms) {
1505 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
Brian3a8e2772006-12-20 17:19:16 -07001506 return;
1507 }
Brian34ae99d2006-12-18 08:28:54 -07001508 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001509 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001510 return;
1511 }
1512
1513 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1514
Brian Paulade50832008-05-14 16:09:46 -06001515 if (shProg->VertexProgram) {
1516 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1517 if (loc >= 0) {
1518 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
Brian Paulf45ed0e2008-07-18 12:51:39 -06001519 loc, count, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07001520 }
Brian Paulade50832008-05-14 16:09:46 -06001521 }
1522
1523 if (shProg->FragmentProgram) {
1524 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1525 if (loc >= 0) {
1526 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
Brian Paulf45ed0e2008-07-18 12:51:39 -06001527 loc, count, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07001528 }
Brian34ae99d2006-12-18 08:28:54 -07001529 }
1530}
1531
1532
Brian Paulfd59f192008-05-18 16:04:55 -06001533static void
Brian5b01c5e2006-12-19 18:02:03 -07001534_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001535{
Brian65a18442006-12-19 18:46:56 -07001536 struct gl_shader_program *shProg;
Brian Paulbc985b52008-07-21 14:16:07 -06001537
1538 shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram");
Brian65a18442006-12-19 18:46:56 -07001539 if (!shProg) {
Brian34ae99d2006-12-18 08:28:54 -07001540 return;
1541 }
1542
Brian Paulbc985b52008-07-21 14:16:07 -06001543 if (!shProg->LinkStatus) {
1544 shProg->Validated = GL_FALSE;
1545 return;
1546 }
1547
1548 /* From the GL spec, a program is invalid if any of these are true:
1549
Brian5b01c5e2006-12-19 18:02:03 -07001550 any two active samplers in the current program object are of
1551 different types, but refer to the same texture image unit,
1552
1553 any active sampler in the current program object refers to a texture
1554 image unit where fixed-function fragment processing accesses a
1555 texture target that does not match the sampler type, or
1556
1557 the sum of the number of active samplers in the program and the
1558 number of texture image units enabled for fixed-function fragment
1559 processing exceeds the combined limit on the total number of texture
1560 image units allowed.
1561 */
Brian Paulbc985b52008-07-21 14:16:07 -06001562
1563 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001564}
Brian Paulfd59f192008-05-18 16:04:55 -06001565
1566
1567/**
1568 * Plug in Mesa's GLSL functions into the device driver function table.
1569 */
1570void
1571_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
1572{
1573 driver->AttachShader = _mesa_attach_shader;
1574 driver->BindAttribLocation = _mesa_bind_attrib_location;
1575 driver->CompileShader = _mesa_compile_shader;
1576 driver->CreateProgram = _mesa_create_program;
1577 driver->CreateShader = _mesa_create_shader;
1578 driver->DeleteProgram2 = _mesa_delete_program2;
1579 driver->DeleteShader = _mesa_delete_shader;
1580 driver->DetachShader = _mesa_detach_shader;
1581 driver->GetActiveAttrib = _mesa_get_active_attrib;
1582 driver->GetActiveUniform = _mesa_get_active_uniform;
1583 driver->GetAttachedShaders = _mesa_get_attached_shaders;
1584 driver->GetAttribLocation = _mesa_get_attrib_location;
1585 driver->GetHandle = _mesa_get_handle;
1586 driver->GetProgramiv = _mesa_get_programiv;
1587 driver->GetProgramInfoLog = _mesa_get_program_info_log;
1588 driver->GetShaderiv = _mesa_get_shaderiv;
1589 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
1590 driver->GetShaderSource = _mesa_get_shader_source;
1591 driver->GetUniformfv = _mesa_get_uniformfv;
Brian Paul2be54a82008-07-08 16:17:04 -06001592 driver->GetUniformiv = _mesa_get_uniformiv;
Brian Paulfd59f192008-05-18 16:04:55 -06001593 driver->GetUniformLocation = _mesa_get_uniform_location;
1594 driver->IsProgram = _mesa_is_program;
1595 driver->IsShader = _mesa_is_shader;
1596 driver->LinkProgram = _mesa_link_program;
1597 driver->ShaderSource = _mesa_shader_source;
1598 driver->Uniform = _mesa_uniform;
1599 driver->UniformMatrix = _mesa_uniform_matrix;
1600 driver->UseProgram = _mesa_use_program;
1601 driver->ValidateProgram = _mesa_validate_program;
1602}