blob: b33dfd66636d5f4a343d5acf8a07ec5ae072a037 [file] [log] [blame]
Brian34ae99d2006-12-18 08:28:54 -07001/*
2 * Mesa 3-D graphics library
Brian3e4302f2007-05-09 08:04:32 -06003 * Version: 7.0
Brian34ae99d2006-12-18 08:28:54 -07004 *
Brian5b01c5e2006-12-19 18:02:03 -07005 * Copyright (C) 2004-2007 Brian Paul All Rights Reserved.
Brian34ae99d2006-12-18 08:28:54 -07006 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25/**
26 * \file shader_api.c
Brian5b01c5e2006-12-19 18:02:03 -070027 * Implementation of GLSL-related API functions
Brian34ae99d2006-12-18 08:28:54 -070028 * \author Brian Paul
29 */
30
31/**
32 * XXX things to do:
33 * 1. Check that the right error code is generated for all _mesa_error() calls.
Brian5b01c5e2006-12-19 18:02:03 -070034 * 2. Insert FLUSH_VERTICES calls in various places
Brian34ae99d2006-12-18 08:28:54 -070035 */
36
37
José Fonseca101d1a62008-07-23 21:06:01 +090038#include "main/glheader.h"
39#include "main/context.h"
40#include "main/hash.h"
41#include "main/macros.h"
Brian34ae99d2006-12-18 08:28:54 -070042#include "program.h"
43#include "prog_parameter.h"
Brian3209c3e2007-01-09 17:49:24 -070044#include "prog_print.h"
45#include "prog_statevars.h"
Brianbc029242008-04-04 18:59:21 -060046#include "prog_uniform.h"
Brianc223c6b2007-07-04 13:15:20 -060047#include "shader/shader_api.h"
48#include "shader/slang/slang_compile.h"
49#include "shader/slang/slang_link.h"
Brian34ae99d2006-12-18 08:28:54 -070050
51
52
Brianf2923612006-12-20 09:56:44 -070053/**
54 * Allocate a new gl_shader_program object, initialize it.
55 */
Brian2d2bb352007-12-07 17:11:30 -070056static 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 Paul470f6992008-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) {
Brianbc029242008-04-04 18:59:21 -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 }
Brian Paul887bfee2008-05-14 16:44:08 -0600116 shProg->NumShaders = 0;
117
Brian3c008a02007-04-12 15:22:32 -0600118 if (shProg->Shaders) {
119 _mesa_free(shProg->Shaders);
120 shProg->Shaders = NULL;
121 }
Brian Paul887bfee2008-05-14 16:44:08 -0600122
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);
Brian Paul887bfee2008-05-14 16:44:08 -0600137
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 Paul470f6992008-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) {
173 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
174 _mesa_free_shader_program(ctx, old);
175 }
176
177 *ptr = NULL;
178 }
179 assert(!*ptr);
180
181 if (shProg) {
182 shProg->RefCount++;
Brian Paul470f6992008-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 *)
201 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
202 /* 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 Pauld4172262008-07-03 16:21:15 -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 Pauld7913862008-05-14 12:19:22 -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 Pauld4172262008-07-03 16:21:15 -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;
michal4a470f62007-08-07 15:34:11 +0100383 ctx->Shader.EmitCondCodes = GL_FALSE;/*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 Pauld4172262008-07-03 16:21:15 -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 */
Brian2d2bb352007-12-07 17:11:30 -0700438static void
Brian5b01c5e2006-12-19 18:02:03 -0700439_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
440{
Brian Pauld4172262008-07-03 16:21:15 -0600441 struct gl_shader_program *shProg;
442 struct gl_shader *sh;
443 GLuint i, n;
Brian5b01c5e2006-12-19 18:02:03 -0700444
Brian Pauld4172262008-07-03 16:21:15 -0600445 shProg = _mesa_lookup_shader_program_err(ctx, program, "glAttachShader");
446 if (!shProg)
447 return;
448
449 sh = _mesa_lookup_shader_err(ctx, shader, "glAttachShader");
450 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700451 return;
452 }
453
Brian Paulfc0a48d2008-05-16 15:48:11 -0600454 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
Brian2d2bb352007-12-07 17:11:30 -0700479static GLint
480_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
481 const GLchar *name)
482{
483 struct gl_shader_program *shProg
Brian Pauld4172262008-07-03 16:21:15 -0600484 = _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
Brian2d2bb352007-12-07 17:11:30 -0700485
486 if (!shProg) {
Brian2d2bb352007-12-07 17:11:30 -0700487 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
509static void
Brian5b01c5e2006-12-19 18:02:03 -0700510_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
511 const GLchar *name)
512{
Brian Pauld4172262008-07-03 16:21:15 -0600513 struct gl_shader_program *shProg;
Brianb7978af2007-01-09 19:17:17 -0700514 const GLint size = -1; /* unknown size */
515 GLint i, oldIndex;
Brian Paulfbf26e12008-07-21 13:58:50 -0600516 GLenum datatype;
Brian5b01c5e2006-12-19 18:02:03 -0700517
Brian Pauld4172262008-07-03 16:21:15 -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 Pauld4172262008-07-03 16:21:15 -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);
541 }
542 else {
543 oldIndex = -1;
544 }
Brian3209c3e2007-01-09 17:49:24 -0700545
546 /* this will replace the current value if it's already in the list */
Brian Paulfbf26e12008-07-21 13:58:50 -0600547 i = _mesa_add_attribute(shProg->Attributes, name, size, datatype, index);
Brian3209c3e2007-01-09 17:49:24 -0700548 if (i < 0) {
549 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
550 }
551
Brian9f660252007-04-11 09:00:56 -0600552 if (shProg->VertexProgram && oldIndex >= 0 && oldIndex != index) {
553 /* If the index changed, need to search/replace references to that attribute
554 * in the vertex program.
555 */
Brian3209c3e2007-01-09 17:49:24 -0700556 _slang_remap_attribute(&shProg->VertexProgram->Base, oldIndex, index);
557 }
Brian34ae99d2006-12-18 08:28:54 -0700558}
559
560
Brian2d2bb352007-12-07 17:11:30 -0700561static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700562_mesa_create_shader(GLcontext *ctx, GLenum type)
563{
Brian65a18442006-12-19 18:46:56 -0700564 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700565 GLuint name;
566
567 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
568
569 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700570 case GL_FRAGMENT_SHADER:
571 case GL_VERTEX_SHADER:
572 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700573 break;
574 default:
575 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
576 return 0;
577 }
578
Brian65a18442006-12-19 18:46:56 -0700579 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700580
581 return name;
582}
583
584
Brian2d2bb352007-12-07 17:11:30 -0700585static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700586_mesa_create_program(GLcontext *ctx)
587{
588 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700589 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700590
Brian65a18442006-12-19 18:46:56 -0700591 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
592 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700593
Brian65a18442006-12-19 18:46:56 -0700594 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700595
Brian3c008a02007-04-12 15:22:32 -0600596 assert(shProg->RefCount == 1);
597
Brian5b01c5e2006-12-19 18:02:03 -0700598 return name;
599}
600
601
Brian3c008a02007-04-12 15:22:32 -0600602/**
603 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
604 * DeleteProgramARB.
605 */
Brian2d2bb352007-12-07 17:11:30 -0700606static void
Brian5b01c5e2006-12-19 18:02:03 -0700607_mesa_delete_program2(GLcontext *ctx, GLuint name)
608{
Brian3c008a02007-04-12 15:22:32 -0600609 /*
610 * NOTE: deleting shaders/programs works a bit differently than
611 * texture objects (and buffer objects, etc). Shader/program
612 * handles/IDs exist in the hash table until the object is really
613 * deleted (refcount==0). With texture objects, the handle/ID is
614 * removed from the hash table in glDeleteTextures() while the tex
615 * object itself might linger until its refcount goes to zero.
616 */
Brian65a18442006-12-19 18:46:56 -0700617 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700618
Brian Pauld4172262008-07-03 16:21:15 -0600619 shProg = _mesa_lookup_shader_program_err(ctx, name, "glDeleteProgram");
620 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700621 return;
Brian5b01c5e2006-12-19 18:02:03 -0700622
Brian9e4bae92006-12-20 09:27:42 -0700623 shProg->DeletePending = GL_TRUE;
624
Brian3c008a02007-04-12 15:22:32 -0600625 /* effectively, decr shProg's refcount */
626 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700627}
628
629
Brian2d2bb352007-12-07 17:11:30 -0700630static void
Brian5b01c5e2006-12-19 18:02:03 -0700631_mesa_delete_shader(GLcontext *ctx, GLuint shader)
632{
Brian Pauld4172262008-07-03 16:21:15 -0600633 struct gl_shader *sh;
634
635 sh = _mesa_lookup_shader_err(ctx, shader, "glDeleteShader");
636 if (!sh)
Brian9e4bae92006-12-20 09:27:42 -0700637 return;
Brian5b01c5e2006-12-19 18:02:03 -0700638
Brian9e4bae92006-12-20 09:27:42 -0700639 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600640
641 /* effectively, decr sh's refcount */
642 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700643}
644
645
Brian2d2bb352007-12-07 17:11:30 -0700646static void
Brian5b01c5e2006-12-19 18:02:03 -0700647_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
648{
Brian Pauld4172262008-07-03 16:21:15 -0600649 struct gl_shader_program *shProg;
Brian Paulfc0a48d2008-05-16 15:48:11 -0600650 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700651 GLuint i, j;
652
Brian Pauld4172262008-07-03 16:21:15 -0600653 shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader");
654 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700655 return;
Brian5b01c5e2006-12-19 18:02:03 -0700656
Brian Paulfc0a48d2008-05-16 15:48:11 -0600657 n = shProg->NumShaders;
658
Brian5b01c5e2006-12-19 18:02:03 -0700659 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700660 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700661 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600662 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700663
Brian Pauld4172262008-07-03 16:21:15 -0600664 /* release */
Brian3c008a02007-04-12 15:22:32 -0600665 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700666
Brian5b01c5e2006-12-19 18:02:03 -0700667 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700668 newList = (struct gl_shader **)
669 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700670 if (!newList) {
671 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
672 return;
673 }
674 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700675 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700676 }
677 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700678 newList[j++] = shProg->Shaders[i];
679 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700680
Brian65a18442006-12-19 18:46:56 -0700681 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600682 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600683
684#ifdef DEBUG
685 /* sanity check */
686 {
687 for (j = 0; j < shProg->NumShaders; j++) {
688 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
689 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
690 assert(shProg->Shaders[j]->RefCount > 0);
691 }
692 }
693#endif
694
Brian5b01c5e2006-12-19 18:02:03 -0700695 return;
696 }
697 }
698
699 /* not found */
Brian Pauld4172262008-07-03 16:21:15 -0600700 {
701 GLenum err;
702 if (_mesa_is_shader(ctx, shader))
703 err = GL_INVALID_OPERATION;
704 else if (_mesa_is_program(ctx, shader))
705 err = GL_INVALID_OPERATION;
706 else
707 err = GL_INVALID_VALUE;
708 _mesa_error(ctx, err, "glDetachProgram(shader)");
709 return;
710 }
Brian5b01c5e2006-12-19 18:02:03 -0700711}
712
713
Brian Paulfbf26e12008-07-21 13:58:50 -0600714static GLint
715sizeof_glsl_type(GLenum type)
716{
717 switch (type) {
718 case GL_FLOAT:
719 case GL_INT:
720 case GL_BOOL:
721 return 1;
722 case GL_FLOAT_VEC2:
723 case GL_INT_VEC2:
724 case GL_BOOL_VEC2:
725 return 2;
726 case GL_FLOAT_VEC3:
727 case GL_INT_VEC3:
728 case GL_BOOL_VEC3:
729 return 3;
730 case GL_FLOAT_VEC4:
731 case GL_INT_VEC4:
732 case GL_BOOL_VEC4:
733 return 4;
734 case GL_FLOAT_MAT2:
735 case GL_FLOAT_MAT2x3:
736 case GL_FLOAT_MAT2x4:
737 return 8; /* two float[4] vectors */
738 case GL_FLOAT_MAT3:
739 case GL_FLOAT_MAT3x2:
740 case GL_FLOAT_MAT3x4:
741 return 12; /* three float[4] vectors */
742 case GL_FLOAT_MAT4:
743 case GL_FLOAT_MAT4x2:
744 case GL_FLOAT_MAT4x3:
745 return 16; /* four float[4] vectors */
746 default:
747 _mesa_problem(NULL, "Invalid type in sizeof_glsl_type()");
748 return 1;
749 }
750}
751
752
Brian2d2bb352007-12-07 17:11:30 -0700753static void
Brian5b01c5e2006-12-19 18:02:03 -0700754_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
755 GLsizei maxLength, GLsizei *length, GLint *size,
756 GLenum *type, GLchar *nameOut)
757{
Brian Pauld4172262008-07-03 16:21:15 -0600758 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700759
Brian Pauld4172262008-07-03 16:21:15 -0600760 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
761 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700762 return;
Brian5b01c5e2006-12-19 18:02:03 -0700763
Brian65a18442006-12-19 18:46:56 -0700764 if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600765 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700766 return;
767 }
768
769 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700770 shProg->Attributes->Parameters[index].Name);
Brian5b01c5e2006-12-19 18:02:03 -0700771 if (size)
Brian Paulfbf26e12008-07-21 13:58:50 -0600772 *size = shProg->Attributes->Parameters[index].Size
773 / sizeof_glsl_type(shProg->Attributes->Parameters[index].DataType);
Brian5b01c5e2006-12-19 18:02:03 -0700774 if (type)
Brian Paulfbf26e12008-07-21 13:58:50 -0600775 *type = shProg->Attributes->Parameters[index].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700776}
777
778
779/**
780 * Called via ctx->Driver.GetActiveUniform().
781 */
Brian2d2bb352007-12-07 17:11:30 -0700782static void
Brian5b01c5e2006-12-19 18:02:03 -0700783_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
784 GLsizei maxLength, GLsizei *length, GLint *size,
785 GLenum *type, GLchar *nameOut)
786{
Brian Pauld4172262008-07-03 16:21:15 -0600787 const struct gl_shader_program *shProg;
Brianbc029242008-04-04 18:59:21 -0600788 const struct gl_program *prog;
789 GLint progPos;
Brian5b01c5e2006-12-19 18:02:03 -0700790
Brian Pauld4172262008-07-03 16:21:15 -0600791 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
792 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700793 return;
Brian5b01c5e2006-12-19 18:02:03 -0700794
Brianbc029242008-04-04 18:59:21 -0600795 if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
Brian5b01c5e2006-12-19 18:02:03 -0700796 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
797 return;
798 }
799
Brianbc029242008-04-04 18:59:21 -0600800 progPos = shProg->Uniforms->Uniforms[index].VertPos;
801 if (progPos >= 0) {
802 prog = &shProg->VertexProgram->Base;
803 }
804 else {
805 progPos = shProg->Uniforms->Uniforms[index].FragPos;
806 if (progPos >= 0) {
807 prog = &shProg->FragmentProgram->Base;
Brian274ac7a2007-04-18 16:05:53 -0600808 }
809 }
810
Brianbc029242008-04-04 18:59:21 -0600811 if (!prog || progPos < 0)
812 return; /* should never happen */
813
814 if (nameOut)
815 copy_string(nameOut, maxLength, length,
816 prog->Parameters->Parameters[progPos].Name);
817 if (size)
Brian Paulfbf26e12008-07-21 13:58:50 -0600818 *size = prog->Parameters->Parameters[progPos].Size
819 / sizeof_glsl_type(prog->Parameters->Parameters[progPos].DataType);
Brianbc029242008-04-04 18:59:21 -0600820 if (type)
821 *type = prog->Parameters->Parameters[progPos].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700822}
823
824
825/**
826 * Called via ctx->Driver.GetAttachedShaders().
827 */
Brian2d2bb352007-12-07 17:11:30 -0700828static void
Brian5b01c5e2006-12-19 18:02:03 -0700829_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
830 GLsizei *count, GLuint *obj)
831{
Brian Pauld4172262008-07-03 16:21:15 -0600832 struct gl_shader_program *shProg =
833 _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders");
Brian65a18442006-12-19 18:46:56 -0700834 if (shProg) {
José Fonseca53174af2008-05-31 18:14:09 +0900835 GLuint i;
Brian Pauld4172262008-07-03 16:21:15 -0600836 for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) {
Brian65a18442006-12-19 18:46:56 -0700837 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700838 }
839 if (count)
840 *count = i;
841 }
Brian5b01c5e2006-12-19 18:02:03 -0700842}
843
844
Brian2d2bb352007-12-07 17:11:30 -0700845static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700846_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700847{
848#if 0
849 GET_CURRENT_CONTEXT(ctx);
850
851 switch (pname) {
852 case GL_PROGRAM_OBJECT_ARB:
853 {
Brian5b01c5e2006-12-19 18:02:03 -0700854 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700855
856 if (pro != NULL)
857 return (**pro)._container._generic.
858 GetName((struct gl2_generic_intf **) (pro));
859 }
860 break;
861 default:
862 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
863 }
864#endif
865 return 0;
866}
867
868
Brian2d2bb352007-12-07 17:11:30 -0700869static void
Brian5b01c5e2006-12-19 18:02:03 -0700870_mesa_get_programiv(GLcontext *ctx, GLuint program,
871 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700872{
Brian65a18442006-12-19 18:46:56 -0700873 struct gl_shader_program *shProg
874 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700875
Brian65a18442006-12-19 18:46:56 -0700876 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700877 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700878 return;
879 }
880
Brian5b01c5e2006-12-19 18:02:03 -0700881 switch (pname) {
882 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700883 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700884 break;
885 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700886 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700887 break;
Brian5b01c5e2006-12-19 18:02:03 -0700888 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700889 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700890 break;
891 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600892 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700893 break;
894 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700895 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700896 break;
897 case GL_ACTIVE_ATTRIBUTES:
Brian3209c3e2007-01-09 17:49:24 -0700898 *params = shProg->Attributes ? shProg->Attributes->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700899 break;
900 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600901 *params = _mesa_longest_parameter_name(shProg->Attributes,
902 PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700903 break;
904 case GL_ACTIVE_UNIFORMS:
Brianbc029242008-04-04 18:59:21 -0600905 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700906 break;
907 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brianbc029242008-04-04 18:59:21 -0600908 *params = _mesa_longest_uniform_name(shProg->Uniforms);
Brian274ac7a2007-04-18 16:05:53 -0600909 if (*params > 0)
910 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700911 break;
912 default:
Brian5b01c5e2006-12-19 18:02:03 -0700913 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
914 return;
Brian34ae99d2006-12-18 08:28:54 -0700915 }
Brian5b01c5e2006-12-19 18:02:03 -0700916}
Brian34ae99d2006-12-18 08:28:54 -0700917
Brian34ae99d2006-12-18 08:28:54 -0700918
Brian2d2bb352007-12-07 17:11:30 -0700919static void
Brian5b01c5e2006-12-19 18:02:03 -0700920_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
921{
Brian Pauld4172262008-07-03 16:21:15 -0600922 struct gl_shader *shader = _mesa_lookup_shader_err(ctx, name, "glGetShaderiv");
Brian5b01c5e2006-12-19 18:02:03 -0700923
924 if (!shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700925 return;
926 }
Brian65a18442006-12-19 18:46:56 -0700927
Brian5b01c5e2006-12-19 18:02:03 -0700928 switch (pname) {
929 case GL_SHADER_TYPE:
930 *params = shader->Type;
931 break;
932 case GL_DELETE_STATUS:
933 *params = shader->DeletePending;
934 break;
935 case GL_COMPILE_STATUS:
936 *params = shader->CompileStatus;
937 break;
938 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600939 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700940 break;
941 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600942 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700943 break;
944 default:
945 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
946 return;
947 }
948}
949
950
Brian2d2bb352007-12-07 17:11:30 -0700951static void
Brian5b01c5e2006-12-19 18:02:03 -0700952_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
953 GLsizei *length, GLchar *infoLog)
954{
Brian65a18442006-12-19 18:46:56 -0700955 struct gl_shader_program *shProg
956 = _mesa_lookup_shader_program(ctx, program);
957 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700958 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
959 return;
960 }
Brian65a18442006-12-19 18:46:56 -0700961 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700962}
963
964
Brian2d2bb352007-12-07 17:11:30 -0700965static void
Brian5b01c5e2006-12-19 18:02:03 -0700966_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
967 GLsizei *length, GLchar *infoLog)
968{
Brian65a18442006-12-19 18:46:56 -0700969 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
970 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700971 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
972 return;
973 }
Brian65a18442006-12-19 18:46:56 -0700974 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700975}
976
977
978/**
979 * Called via ctx->Driver.GetShaderSource().
980 */
Brian2d2bb352007-12-07 17:11:30 -0700981static void
Brian5b01c5e2006-12-19 18:02:03 -0700982_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
983 GLsizei *length, GLchar *sourceOut)
984{
Brian Pauld4172262008-07-03 16:21:15 -0600985 struct gl_shader *sh;
986 sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource");
Brian65a18442006-12-19 18:46:56 -0700987 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700988 return;
989 }
Brian65a18442006-12-19 18:46:56 -0700990 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -0700991}
992
993
Brian Paul072c4742008-07-08 16:12:01 -0600994#define MAX_UNIFORM_ELEMENTS 16
995
Brian5b01c5e2006-12-19 18:02:03 -0700996/**
Brian Paul072c4742008-07-08 16:12:01 -0600997 * Helper for GetUniformfv(), GetUniformiv()
998 * Returns number of elements written to 'params' output.
Brian5b01c5e2006-12-19 18:02:03 -0700999 */
Brian Paul072c4742008-07-08 16:12:01 -06001000static GLuint
1001get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1002 GLfloat *params)
Brian5b01c5e2006-12-19 18:02:03 -07001003{
Brian65a18442006-12-19 18:46:56 -07001004 struct gl_shader_program *shProg
1005 = _mesa_lookup_shader_program(ctx, program);
1006 if (shProg) {
Brian Paul22427692008-06-28 16:47:22 -06001007 if (shProg->Uniforms &&
Michal Krolf9c574d2008-07-15 11:44:47 +02001008 location >= 0 && location < (GLint) shProg->Uniforms->NumUniforms) {
Brian Paul22427692008-06-28 16:47:22 -06001009 GLint progPos;
1010 GLuint i;
Brian Paulfc0a48d2008-05-16 15:48:11 -06001011 const struct gl_program *prog = NULL;
Brianbc029242008-04-04 18:59:21 -06001012
1013 progPos = shProg->Uniforms->Uniforms[location].VertPos;
1014 if (progPos >= 0) {
1015 prog = &shProg->VertexProgram->Base;
1016 }
1017 else {
1018 progPos = shProg->Uniforms->Uniforms[location].FragPos;
1019 if (progPos >= 0) {
1020 prog = &shProg->FragmentProgram->Base;
1021 }
1022 }
1023
Brian Paulfc0a48d2008-05-16 15:48:11 -06001024 ASSERT(prog);
1025 if (prog) {
Brian Paul072c4742008-07-08 16:12:01 -06001026 /* See uniformiv() below */
1027 assert(prog->Parameters->Parameters[progPos].Size <= MAX_UNIFORM_ELEMENTS);
1028
Brian Paulfc0a48d2008-05-16 15:48:11 -06001029 for (i = 0; i < prog->Parameters->Parameters[progPos].Size; i++) {
1030 params[i] = prog->Parameters->ParameterValues[progPos][i];
1031 }
Brian Paul072c4742008-07-08 16:12:01 -06001032 return prog->Parameters->Parameters[progPos].Size;
Brian5b01c5e2006-12-19 18:02:03 -07001033 }
1034 }
1035 else {
Brian Paul22427692008-06-28 16:47:22 -06001036 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
Brian5b01c5e2006-12-19 18:02:03 -07001037 }
1038 }
1039 else {
Brian Paul22427692008-06-28 16:47:22 -06001040 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
Brian5b01c5e2006-12-19 18:02:03 -07001041 }
Brian Paul072c4742008-07-08 16:12:01 -06001042 return 0;
1043}
1044
1045
1046/**
1047 * Called via ctx->Driver.GetUniformfv().
1048 */
1049static void
1050_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1051 GLfloat *params)
1052{
1053 (void) get_uniformfv(ctx, program, location, params);
1054}
1055
1056
1057/**
1058 * Called via ctx->Driver.GetUniformiv().
1059 */
1060static void
1061_mesa_get_uniformiv(GLcontext *ctx, GLuint program, GLint location,
1062 GLint *params)
1063{
1064 GLfloat fparams[MAX_UNIFORM_ELEMENTS];
1065 GLuint n = get_uniformfv(ctx, program, location, fparams);
1066 GLuint i;
1067 assert(n <= MAX_UNIFORM_ELEMENTS);
1068 for (i = 0; i < n; i++) {
1069 params[i] = (GLint) fparams[i];
1070 }
Brian5b01c5e2006-12-19 18:02:03 -07001071}
1072
1073
1074/**
1075 * Called via ctx->Driver.GetUniformLocation().
1076 */
Brian2d2bb352007-12-07 17:11:30 -07001077static GLint
Brian5b01c5e2006-12-19 18:02:03 -07001078_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
1079{
Brian Pauld4172262008-07-03 16:21:15 -06001080 struct gl_shader_program *shProg =
1081 _mesa_lookup_shader_program_err(ctx, program, "glGetUniformLocation");
1082
Brianbc029242008-04-04 18:59:21 -06001083 if (!shProg)
1084 return -1;
Brian5b01c5e2006-12-19 18:02:03 -07001085
Brian Paul294b0612008-07-04 09:58:14 -06001086 if (shProg->LinkStatus == GL_FALSE) {
1087 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
1088 return -1;
1089 }
1090
Brian Pauld4172262008-07-03 16:21:15 -06001091 /* XXX we should return -1 if the uniform was declared, but not
1092 * actually used.
1093 */
1094
Brianbc029242008-04-04 18:59:21 -06001095 return _mesa_lookup_uniform(shProg->Uniforms, name);
Brian5b01c5e2006-12-19 18:02:03 -07001096}
1097
1098
Brian34ae99d2006-12-18 08:28:54 -07001099
Brian5b01c5e2006-12-19 18:02:03 -07001100/**
1101 * Called via ctx->Driver.ShaderSource()
1102 */
Brian2d2bb352007-12-07 17:11:30 -07001103static void
Brian5b01c5e2006-12-19 18:02:03 -07001104_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -07001105{
Brian Pauld4172262008-07-03 16:21:15 -06001106 struct gl_shader *sh;
1107
1108 sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource");
1109 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001110 return;
Brian34ae99d2006-12-18 08:28:54 -07001111
Brian34ae99d2006-12-18 08:28:54 -07001112 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -07001113 if (sh->Source) {
1114 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -07001115 }
Brian65a18442006-12-19 18:46:56 -07001116 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -07001117 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -07001118}
1119
1120
Brian5b01c5e2006-12-19 18:02:03 -07001121/**
1122 * Called via ctx->Driver.CompileShader()
1123 */
Brian2d2bb352007-12-07 17:11:30 -07001124static void
Brian5b01c5e2006-12-19 18:02:03 -07001125_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -07001126{
Brian Pauld4172262008-07-03 16:21:15 -06001127 struct gl_shader *sh;
Brian34ae99d2006-12-18 08:28:54 -07001128
Brian Pauld4172262008-07-03 16:21:15 -06001129 sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader");
1130 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001131 return;
Brian34ae99d2006-12-18 08:28:54 -07001132
Brian43975832007-01-04 08:21:09 -07001133 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -07001134}
1135
1136
Brian5b01c5e2006-12-19 18:02:03 -07001137/**
1138 * Called via ctx->Driver.LinkProgram()
1139 */
Brian2d2bb352007-12-07 17:11:30 -07001140static void
Brian5b01c5e2006-12-19 18:02:03 -07001141_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001142{
Brian65a18442006-12-19 18:46:56 -07001143 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001144
Brian Pauld4172262008-07-03 16:21:15 -06001145 shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
1146 if (!shProg)
Brian34ae99d2006-12-18 08:28:54 -07001147 return;
Brian34ae99d2006-12-18 08:28:54 -07001148
Brian Paulfc0a48d2008-05-16 15:48:11 -06001149 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1150
Brianc1771912007-02-16 09:56:19 -07001151 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001152}
1153
1154
1155/**
Brian5b01c5e2006-12-19 18:02:03 -07001156 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001157 */
Brian5b01c5e2006-12-19 18:02:03 -07001158void
1159_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001160{
Brian3c008a02007-04-12 15:22:32 -06001161 struct gl_shader_program *shProg;
1162
Brian00d63aa2007-02-03 11:35:02 -07001163 if (ctx->Shader.CurrentProgram &&
1164 ctx->Shader.CurrentProgram->Name == program) {
1165 /* no-op */
1166 return;
1167 }
1168
1169 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1170
Brian5b01c5e2006-12-19 18:02:03 -07001171 if (program) {
Brian Pauld4172262008-07-03 16:21:15 -06001172 shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
Brian65a18442006-12-19 18:46:56 -07001173 if (!shProg) {
Brian Pauld4172262008-07-03 16:21:15 -06001174 return;
1175 }
1176 if (!shProg->LinkStatus) {
1177 _mesa_error(ctx, GL_INVALID_OPERATION, "glUseProgram");
Brian5b01c5e2006-12-19 18:02:03 -07001178 return;
1179 }
Brian5b01c5e2006-12-19 18:02:03 -07001180 }
1181 else {
Brian3c008a02007-04-12 15:22:32 -06001182 shProg = NULL;
1183 }
1184
1185 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001186}
Brian34ae99d2006-12-18 08:28:54 -07001187
Brian5b01c5e2006-12-19 18:02:03 -07001188
Brian8fed2462007-10-26 19:19:09 -06001189
1190/**
1191 * Update the vertex and fragment program's TexturesUsed arrays.
1192 */
1193static void
1194update_textures_used(struct gl_program *prog)
1195{
1196 GLuint s;
1197
1198 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1199
1200 for (s = 0; s < MAX_SAMPLERS; s++) {
1201 if (prog->SamplersUsed & (1 << s)) {
1202 GLuint u = prog->SamplerUnits[s];
1203 GLuint t = prog->SamplerTargets[s];
1204 assert(u < MAX_TEXTURE_IMAGE_UNITS);
1205 prog->TexturesUsed[u] |= (1 << t);
1206 }
1207 }
1208}
1209
1210
Brian63025ec2008-07-21 20:42:05 -06001211static GLboolean
1212is_sampler_type(GLenum type)
1213{
1214 switch (type) {
1215 case GL_SAMPLER_1D:
1216 case GL_SAMPLER_2D:
1217 case GL_SAMPLER_3D:
1218 case GL_SAMPLER_CUBE:
1219 case GL_SAMPLER_1D_SHADOW:
1220 case GL_SAMPLER_2D_SHADOW:
1221 case GL_SAMPLER_2D_RECT_ARB:
1222 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
1223 case GL_SAMPLER_1D_ARRAY_EXT:
1224 case GL_SAMPLER_2D_ARRAY_EXT:
1225 return GL_TRUE;
1226 default:
1227 return GL_FALSE;
1228 }
1229}
1230
1231
Brian5b01c5e2006-12-19 18:02:03 -07001232/**
Brian Paulfbf26e12008-07-21 13:58:50 -06001233 * Check if the type given by userType is allowed to set a uniform of the
1234 * target type. Generally, equivalence is required, but setting Boolean
1235 * uniforms can be done with glUniformiv or glUniformfv.
1236 */
1237static GLboolean
1238compatible_types(GLenum userType, GLenum targetType)
1239{
1240 if (userType == targetType)
1241 return GL_TRUE;
1242
1243 if (targetType == GL_BOOL && (userType == GL_FLOAT || userType == GL_INT))
1244 return GL_TRUE;
1245
1246 if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 ||
1247 userType == GL_INT_VEC2))
1248 return GL_TRUE;
1249
1250 if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 ||
1251 userType == GL_INT_VEC3))
1252 return GL_TRUE;
1253
1254 if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 ||
1255 userType == GL_INT_VEC4))
1256 return GL_TRUE;
1257
Brian63025ec2008-07-21 20:42:05 -06001258 if (is_sampler_type(targetType) && userType == GL_INT)
1259 return GL_TRUE;
1260
Brian Paulfbf26e12008-07-21 13:58:50 -06001261 return GL_FALSE;
1262}
1263
1264
1265/**
Brianbc029242008-04-04 18:59:21 -06001266 * Set the value of a program's uniform variable.
1267 * \param program the program whose uniform to update
1268 * \param location the location/index of the uniform
1269 * \param type the datatype of the uniform
1270 * \param count the number of uniforms to set
1271 * \param elems number of elements per uniform
1272 * \param values the new values
1273 */
1274static void
1275set_program_uniform(GLcontext *ctx, struct gl_program *program, GLint location,
José Fonseca18ec1402008-06-24 11:34:46 +09001276 GLenum type, GLsizei count, GLint elems, const void *values)
Brianbc029242008-04-04 18:59:21 -06001277{
Brian Paulfbf26e12008-07-21 13:58:50 -06001278 if (!compatible_types(type,
1279 program->Parameters->Parameters[location].DataType)) {
1280 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
1281 return;
1282 }
1283
Brianbc029242008-04-04 18:59:21 -06001284 if (program->Parameters->Parameters[location].Type == PROGRAM_SAMPLER) {
1285 /* This controls which texture unit which is used by a sampler */
1286 GLuint texUnit, sampler;
1287
1288 /* data type for setting samplers must be int */
1289 if (type != GL_INT || count != 1) {
1290 _mesa_error(ctx, GL_INVALID_OPERATION,
1291 "glUniform(only glUniform1i can be used "
1292 "to set sampler uniforms)");
1293 return;
1294 }
1295
1296 sampler = (GLuint) program->Parameters->ParameterValues[location][0];
1297 texUnit = ((GLuint *) values)[0];
1298
1299 /* check that the sampler (tex unit index) is legal */
1300 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1301 _mesa_error(ctx, GL_INVALID_VALUE,
1302 "glUniform1(invalid sampler/tex unit index)");
1303 return;
1304 }
1305
1306 /* This maps a sampler to a texture unit: */
1307 program->SamplerUnits[sampler] = texUnit;
1308 update_textures_used(program);
1309
1310 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1311 }
1312 else {
1313 /* ordinary uniform variable */
José Fonseca18ec1402008-06-24 11:34:46 +09001314 GLsizei k, i;
Brianbc029242008-04-04 18:59:21 -06001315
Michal Krolf9c574d2008-07-15 11:44:47 +02001316 if (count * elems > (GLint) program->Parameters->Parameters[location].Size) {
Brianbc029242008-04-04 18:59:21 -06001317 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1318 return;
1319 }
1320
1321 for (k = 0; k < count; k++) {
1322 GLfloat *uniformVal = program->Parameters->ParameterValues[location + k];
1323 if (type == GL_INT ||
1324 type == GL_INT_VEC2 ||
1325 type == GL_INT_VEC3 ||
1326 type == GL_INT_VEC4) {
1327 const GLint *iValues = ((const GLint *) values) + k * elems;
1328 for (i = 0; i < elems; i++) {
1329 uniformVal[i] = (GLfloat) iValues[i];
1330 }
1331 }
1332 else {
1333 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1334 for (i = 0; i < elems; i++) {
1335 uniformVal[i] = fValues[i];
1336 }
1337 }
1338 }
1339 }
1340}
1341
1342
1343/**
Brian5b01c5e2006-12-19 18:02:03 -07001344 * Called via ctx->Driver.Uniform().
1345 */
Brian2d2bb352007-12-07 17:11:30 -07001346static void
Brian5b01c5e2006-12-19 18:02:03 -07001347_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1348 const GLvoid *values, GLenum type)
1349{
Brian3a8e2772006-12-20 17:19:16 -07001350 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brianbc029242008-04-04 18:59:21 -06001351 GLint elems;
Brian3a8e2772006-12-20 17:19:16 -07001352
1353 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001354 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001355 return;
1356 }
1357
Brian Paulf84005c2008-05-14 16:01:31 -06001358 if (location == -1)
1359 return; /* The standard specifies this as a no-op */
1360
Brianbc029242008-04-04 18:59:21 -06001361 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian3a8e2772006-12-20 17:19:16 -07001362 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
1363 return;
1364 }
1365
Brian52363952007-03-13 16:50:24 -06001366 if (count < 0) {
1367 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1368 return;
1369 }
1370
Brian98650bd2007-03-13 16:32:48 -06001371 switch (type) {
1372 case GL_FLOAT:
1373 case GL_INT:
1374 elems = 1;
1375 break;
1376 case GL_FLOAT_VEC2:
1377 case GL_INT_VEC2:
1378 elems = 2;
1379 break;
1380 case GL_FLOAT_VEC3:
1381 case GL_INT_VEC3:
1382 elems = 3;
1383 break;
1384 case GL_FLOAT_VEC4:
1385 case GL_INT_VEC4:
1386 elems = 4;
1387 break;
1388 default:
1389 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1390 return;
Brian89dc4852007-01-04 14:35:44 -07001391 }
Brian98650bd2007-03-13 16:32:48 -06001392
Brianbc029242008-04-04 18:59:21 -06001393 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1394
1395 /* A uniform var may be used by both a vertex shader and a fragment
1396 * shader. We may need to update one or both shader's uniform here:
1397 */
1398 if (shProg->VertexProgram) {
1399 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1400 if (loc >= 0) {
1401 set_program_uniform(ctx, &shProg->VertexProgram->Base,
1402 loc, type, count, elems, values);
1403 }
Brian98650bd2007-03-13 16:32:48 -06001404 }
1405
Brianbc029242008-04-04 18:59:21 -06001406 if (shProg->FragmentProgram) {
1407 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1408 if (loc >= 0) {
1409 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
1410 loc, type, count, elems, values);
Brian8fed2462007-10-26 19:19:09 -06001411 }
Brianbc029242008-04-04 18:59:21 -06001412 }
1413}
Brian8fed2462007-10-26 19:19:09 -06001414
Brian8fed2462007-10-26 19:19:09 -06001415
Brianbc029242008-04-04 18:59:21 -06001416static void
Brian Paulfbf26e12008-07-21 13:58:50 -06001417get_matrix_dims(GLenum type, GLint *rows, GLint *cols)
1418{
1419 switch (type) {
1420 case GL_FLOAT_MAT2:
1421 *rows = *cols = 2;
1422 break;
1423 case GL_FLOAT_MAT2x3:
1424 *rows = 3;
1425 *cols = 2;
1426 break;
1427 case GL_FLOAT_MAT2x4:
1428 *rows = 4;
1429 *cols = 2;
1430 break;
1431 case GL_FLOAT_MAT3:
1432 *rows = 3;
1433 *cols = 3;
1434 break;
1435 case GL_FLOAT_MAT3x2:
1436 *rows = 2;
1437 *cols = 3;
1438 break;
1439 case GL_FLOAT_MAT3x4:
1440 *rows = 4;
1441 *cols = 3;
1442 break;
1443 case GL_FLOAT_MAT4:
1444 *rows = 4;
1445 *cols = 4;
1446 break;
1447 case GL_FLOAT_MAT4x2:
1448 *rows = 2;
1449 *cols = 4;
1450 break;
1451 case GL_FLOAT_MAT4x3:
1452 *rows = 3;
1453 *cols = 4;
1454 break;
1455 default:
1456 *rows = *cols = 0;
1457 }
1458}
1459
1460
1461static void
Brianbc029242008-04-04 18:59:21 -06001462set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
Brian Paulb64882d2008-07-18 12:51:39 -06001463 GLuint location, GLuint count,
1464 GLuint rows, GLuint cols,
Brianbc029242008-04-04 18:59:21 -06001465 GLboolean transpose, const GLfloat *values)
1466{
Brian Paulfbf26e12008-07-21 13:58:50 -06001467 GLuint mat, row, col;
1468 GLuint dst = location, src = 0;
1469 GLint nr, nc;
1470
1471 /* check that the number of rows, columns is correct */
1472 get_matrix_dims(program->Parameters->Parameters[location].DataType, &nr, &nc);
1473 if (rows != nr || cols != nc) {
1474 _mesa_error(ctx, GL_INVALID_OPERATION,
1475 "glUniformMatrix(matrix size mismatch");
1476 return;
1477 }
1478
Brianbc029242008-04-04 18:59:21 -06001479 /*
1480 * Note: the _columns_ of a matrix are stored in program registers, not
Brian Paulb64882d2008-07-18 12:51:39 -06001481 * the rows. So, the loops below look a little funny.
1482 * XXX could optimize this a bit...
Brianbc029242008-04-04 18:59:21 -06001483 */
Brian Paulb64882d2008-07-18 12:51:39 -06001484
1485 /* loop over matrices */
1486 for (mat = 0; mat < count; mat++) {
1487
1488 /* each matrix: */
Brianbc029242008-04-04 18:59:21 -06001489 for (col = 0; col < cols; col++) {
Brian Paulb64882d2008-07-18 12:51:39 -06001490 GLfloat *v = program->Parameters->ParameterValues[dst];
Brianbc029242008-04-04 18:59:21 -06001491 for (row = 0; row < rows; row++) {
Brian Paulb64882d2008-07-18 12:51:39 -06001492 if (transpose) {
1493 v[row] = values[src + row * cols + col];
1494 }
1495 else {
1496 v[row] = values[src + col * rows + row];
1497 }
Brianbc029242008-04-04 18:59:21 -06001498 }
Brian Paulb64882d2008-07-18 12:51:39 -06001499 dst++;
Brian8fed2462007-10-26 19:19:09 -06001500 }
Brian Paulb64882d2008-07-18 12:51:39 -06001501
1502 src += rows * cols; /* next matrix */
Brian8fed2462007-10-26 19:19:09 -06001503 }
Brian34ae99d2006-12-18 08:28:54 -07001504}
1505
1506
1507/**
Brian5b01c5e2006-12-19 18:02:03 -07001508 * Called by ctx->Driver.UniformMatrix().
Brian Paulb64882d2008-07-18 12:51:39 -06001509 * Note: cols=2, rows=4 ==> array[2] of vec4
Brian34ae99d2006-12-18 08:28:54 -07001510 */
Brian2d2bb352007-12-07 17:11:30 -07001511static void
Brian5b01c5e2006-12-19 18:02:03 -07001512_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1513 GLenum matrixType, GLint location, GLsizei count,
1514 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001515{
Brian3a8e2772006-12-20 17:19:16 -07001516 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paulf84005c2008-05-14 16:01:31 -06001517
Brian3a8e2772006-12-20 17:19:16 -07001518 if (!shProg || !shProg->LinkStatus) {
1519 _mesa_error(ctx, GL_INVALID_OPERATION,
1520 "glUniformMatrix(program not linked)");
1521 return;
1522 }
Brian Paulf84005c2008-05-14 16:01:31 -06001523
1524 if (location == -1)
1525 return; /* The standard specifies this as a no-op */
1526
Michal Krolf9c574d2008-07-15 11:44:47 +02001527 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian3a8e2772006-12-20 17:19:16 -07001528 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
1529 return;
1530 }
Brian34ae99d2006-12-18 08:28:54 -07001531 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001532 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001533 return;
1534 }
1535
1536 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1537
Brianbc029242008-04-04 18:59:21 -06001538 if (shProg->VertexProgram) {
1539 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1540 if (loc >= 0) {
1541 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
Brian Paulb64882d2008-07-18 12:51:39 -06001542 loc, count, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07001543 }
Brian34ae99d2006-12-18 08:28:54 -07001544 }
Brianbc029242008-04-04 18:59:21 -06001545
1546 if (shProg->FragmentProgram) {
1547 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1548 if (loc >= 0) {
1549 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
Brian Paulb64882d2008-07-18 12:51:39 -06001550 loc, count, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07001551 }
Brian34ae99d2006-12-18 08:28:54 -07001552 }
1553}
1554
1555
Brian2d2bb352007-12-07 17:11:30 -07001556static void
Brian5b01c5e2006-12-19 18:02:03 -07001557_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001558{
Brian65a18442006-12-19 18:46:56 -07001559 struct gl_shader_program *shProg;
Brian Paul70d39282008-07-21 14:16:07 -06001560
1561 shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram");
Brian65a18442006-12-19 18:46:56 -07001562 if (!shProg) {
Brian34ae99d2006-12-18 08:28:54 -07001563 return;
1564 }
1565
Brian Paul70d39282008-07-21 14:16:07 -06001566 if (!shProg->LinkStatus) {
1567 shProg->Validated = GL_FALSE;
1568 return;
1569 }
1570
1571 /* From the GL spec, a program is invalid if any of these are true:
1572
Brian5b01c5e2006-12-19 18:02:03 -07001573 any two active samplers in the current program object are of
1574 different types, but refer to the same texture image unit,
1575
1576 any active sampler in the current program object refers to a texture
1577 image unit where fixed-function fragment processing accesses a
1578 texture target that does not match the sampler type, or
1579
1580 the sum of the number of active samplers in the program and the
1581 number of texture image units enabled for fixed-function fragment
1582 processing exceeds the combined limit on the total number of texture
1583 image units allowed.
1584 */
Brian Paul70d39282008-07-21 14:16:07 -06001585
1586 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001587}
Brian2d2bb352007-12-07 17:11:30 -07001588
1589
1590/**
1591 * Plug in Mesa's GLSL functions into the device driver function table.
1592 */
1593void
1594_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
1595{
1596 driver->AttachShader = _mesa_attach_shader;
1597 driver->BindAttribLocation = _mesa_bind_attrib_location;
1598 driver->CompileShader = _mesa_compile_shader;
1599 driver->CreateProgram = _mesa_create_program;
1600 driver->CreateShader = _mesa_create_shader;
1601 driver->DeleteProgram2 = _mesa_delete_program2;
1602 driver->DeleteShader = _mesa_delete_shader;
1603 driver->DetachShader = _mesa_detach_shader;
1604 driver->GetActiveAttrib = _mesa_get_active_attrib;
1605 driver->GetActiveUniform = _mesa_get_active_uniform;
1606 driver->GetAttachedShaders = _mesa_get_attached_shaders;
1607 driver->GetAttribLocation = _mesa_get_attrib_location;
1608 driver->GetHandle = _mesa_get_handle;
1609 driver->GetProgramiv = _mesa_get_programiv;
1610 driver->GetProgramInfoLog = _mesa_get_program_info_log;
1611 driver->GetShaderiv = _mesa_get_shaderiv;
1612 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
1613 driver->GetShaderSource = _mesa_get_shader_source;
1614 driver->GetUniformfv = _mesa_get_uniformfv;
Brian Paul072c4742008-07-08 16:12:01 -06001615 driver->GetUniformiv = _mesa_get_uniformiv;
Brian2d2bb352007-12-07 17:11:30 -07001616 driver->GetUniformLocation = _mesa_get_uniform_location;
1617 driver->IsProgram = _mesa_is_program;
1618 driver->IsShader = _mesa_is_shader;
1619 driver->LinkProgram = _mesa_link_program;
1620 driver->ShaderSource = _mesa_shader_source;
1621 driver->Uniform = _mesa_uniform;
1622 driver->UniformMatrix = _mesa_uniform_matrix;
1623 driver->UseProgram = _mesa_use_program;
1624 driver->ValidateProgram = _mesa_validate_program;
1625}