blob: 99bcc0aeb42e6cb14084d801701ebf015f5269d0 [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"
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);
Brian Paulfbf26e12008-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 Paulfbf26e12008-07-21 13:58:50 -0600548 i = _mesa_add_attribute(shProg->Attributes, name, size, datatype, index);
Brian3209c3e2007-01-09 17:49:24 -0700549 if (i < 0) {
550 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
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
Brian2d2bb352007-12-07 17:11:30 -0700562static 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
Brian2d2bb352007-12-07 17:11:30 -0700586static 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
Brian65a18442006-12-19 18:46:56 -0700592 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
593 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700594
Brian65a18442006-12-19 18:46:56 -0700595 _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 */
Brian2d2bb352007-12-07 17:11:30 -0700607static 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 Pauld4172262008-07-03 16:21:15 -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
Brian2d2bb352007-12-07 17:11:30 -0700631static void
Brian5b01c5e2006-12-19 18:02:03 -0700632_mesa_delete_shader(GLcontext *ctx, GLuint shader)
633{
Brian Pauld4172262008-07-03 16:21:15 -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
Brian2d2bb352007-12-07 17:11:30 -0700647static void
Brian5b01c5e2006-12-19 18:02:03 -0700648_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
649{
Brian Pauld4172262008-07-03 16:21:15 -0600650 struct gl_shader_program *shProg;
Brian Paulfc0a48d2008-05-16 15:48:11 -0600651 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700652 GLuint i, j;
653
Brian Pauld4172262008-07-03 16:21:15 -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
Brian Paulfc0a48d2008-05-16 15:48:11 -0600658 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 Pauld4172262008-07-03 16:21:15 -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 Pauld4172262008-07-03 16:21:15 -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 Paulfbf26e12008-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
Brian2d2bb352007-12-07 17:11:30 -0700754static 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 Pauld4172262008-07-03 16:21:15 -0600759 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700760
Brian Pauld4172262008-07-03 16:21:15 -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 Paulfbf26e12008-07-21 13:58:50 -0600773 *size = shProg->Attributes->Parameters[index].Size
774 / sizeof_glsl_type(shProg->Attributes->Parameters[index].DataType);
Brian5b01c5e2006-12-19 18:02:03 -0700775 if (type)
Brian Paulfbf26e12008-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 */
Brian2d2bb352007-12-07 17:11:30 -0700783static 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 Pauld4172262008-07-03 16:21:15 -0600788 const struct gl_shader_program *shProg;
Brianbc029242008-04-04 18:59:21 -0600789 const struct gl_program *prog;
790 GLint progPos;
Brian5b01c5e2006-12-19 18:02:03 -0700791
Brian Pauld4172262008-07-03 16:21:15 -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
Brianbc029242008-04-04 18:59:21 -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
Brianbc029242008-04-04 18:59:21 -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
Brianbc029242008-04-04 18:59:21 -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 Paulfbf26e12008-07-21 13:58:50 -0600819 *size = prog->Parameters->Parameters[progPos].Size
820 / sizeof_glsl_type(prog->Parameters->Parameters[progPos].DataType);
Brianbc029242008-04-04 18:59:21 -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 */
Brian2d2bb352007-12-07 17:11:30 -0700829static 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 Pauld4172262008-07-03 16:21:15 -0600833 struct gl_shader_program *shProg =
834 _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders");
Brian65a18442006-12-19 18:46:56 -0700835 if (shProg) {
José Fonseca53174af2008-05-31 18:14:09 +0900836 GLuint i;
Brian Pauld4172262008-07-03 16:21:15 -0600837 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
Brian2d2bb352007-12-07 17:11:30 -0700846static 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
Brian2d2bb352007-12-07 17:11:30 -0700870static 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:
Brianbc029242008-04-04 18:59:21 -0600906 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700907 break;
908 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brianbc029242008-04-04 18:59:21 -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
Brian2d2bb352007-12-07 17:11:30 -0700920static void
Brian5b01c5e2006-12-19 18:02:03 -0700921_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
922{
Brian Pauld4172262008-07-03 16:21:15 -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
Brian2d2bb352007-12-07 17:11:30 -0700952static 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
Brian2d2bb352007-12-07 17:11:30 -0700966static 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 */
Brian2d2bb352007-12-07 17:11:30 -0700982static 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 Pauld4172262008-07-03 16:21:15 -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 Paul072c4742008-07-08 16:12:01 -0600995#define MAX_UNIFORM_ELEMENTS 16
996
Brian5b01c5e2006-12-19 18:02:03 -0700997/**
Brian Paul072c4742008-07-08 16:12:01 -0600998 * Helper for GetUniformfv(), GetUniformiv()
999 * Returns number of elements written to 'params' output.
Brian5b01c5e2006-12-19 18:02:03 -07001000 */
Brian Paul072c4742008-07-08 16:12:01 -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 Paul22427692008-06-28 16:47:22 -06001008 if (shProg->Uniforms &&
Michal Krolf9c574d2008-07-15 11:44:47 +02001009 location >= 0 && location < (GLint) shProg->Uniforms->NumUniforms) {
Brian Paul22427692008-06-28 16:47:22 -06001010 GLint progPos;
1011 GLuint i;
Brian Paulfc0a48d2008-05-16 15:48:11 -06001012 const struct gl_program *prog = NULL;
Brianbc029242008-04-04 18:59:21 -06001013
1014 progPos = shProg->Uniforms->Uniforms[location].VertPos;
1015 if (progPos >= 0) {
1016 prog = &shProg->VertexProgram->Base;
1017 }
1018 else {
1019 progPos = shProg->Uniforms->Uniforms[location].FragPos;
1020 if (progPos >= 0) {
1021 prog = &shProg->FragmentProgram->Base;
1022 }
1023 }
1024
Brian Paulfc0a48d2008-05-16 15:48:11 -06001025 ASSERT(prog);
1026 if (prog) {
Brian Paul072c4742008-07-08 16:12:01 -06001027 /* See uniformiv() below */
1028 assert(prog->Parameters->Parameters[progPos].Size <= MAX_UNIFORM_ELEMENTS);
1029
Brian Paulfc0a48d2008-05-16 15:48:11 -06001030 for (i = 0; i < prog->Parameters->Parameters[progPos].Size; i++) {
1031 params[i] = prog->Parameters->ParameterValues[progPos][i];
1032 }
Brian Paul072c4742008-07-08 16:12:01 -06001033 return prog->Parameters->Parameters[progPos].Size;
Brian5b01c5e2006-12-19 18:02:03 -07001034 }
1035 }
1036 else {
Brian Paul22427692008-06-28 16:47:22 -06001037 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
Brian5b01c5e2006-12-19 18:02:03 -07001038 }
1039 }
1040 else {
Brian Paul22427692008-06-28 16:47:22 -06001041 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
Brian5b01c5e2006-12-19 18:02:03 -07001042 }
Brian Paul072c4742008-07-08 16:12:01 -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 */
Brian2d2bb352007-12-07 17:11:30 -07001078static GLint
Brian5b01c5e2006-12-19 18:02:03 -07001079_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
1080{
Brian Pauld4172262008-07-03 16:21:15 -06001081 struct gl_shader_program *shProg =
1082 _mesa_lookup_shader_program_err(ctx, program, "glGetUniformLocation");
1083
Brianbc029242008-04-04 18:59:21 -06001084 if (!shProg)
1085 return -1;
Brian5b01c5e2006-12-19 18:02:03 -07001086
Brian Paul294b0612008-07-04 09:58:14 -06001087 if (shProg->LinkStatus == GL_FALSE) {
1088 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
1089 return -1;
1090 }
1091
Brian Pauld4172262008-07-03 16:21:15 -06001092 /* XXX we should return -1 if the uniform was declared, but not
1093 * actually used.
1094 */
1095
Brianbc029242008-04-04 18:59:21 -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 */
Brian2d2bb352007-12-07 17:11:30 -07001104static 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 Pauld4172262008-07-03 16:21:15 -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 */
Brian2d2bb352007-12-07 17:11:30 -07001125static void
Brian5b01c5e2006-12-19 18:02:03 -07001126_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -07001127{
Brian Pauld4172262008-07-03 16:21:15 -06001128 struct gl_shader *sh;
Brian34ae99d2006-12-18 08:28:54 -07001129
Brian Pauld4172262008-07-03 16:21:15 -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 */
Brian2d2bb352007-12-07 17:11:30 -07001141static 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 Pauld4172262008-07-03 16:21:15 -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
Brian Paulfc0a48d2008-05-16 15:48:11 -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 Pauld4172262008-07-03 16:21:15 -06001173 shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
Brian65a18442006-12-19 18:46:56 -07001174 if (!shProg) {
Brian Pauld4172262008-07-03 16:21:15 -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
Brian8fed2462007-10-26 19:19:09 -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
Brian63025ec2008-07-21 20:42:05 -06001212static GLboolean
1213is_sampler_type(GLenum type)
1214{
1215 switch (type) {
1216 case GL_SAMPLER_1D:
1217 case GL_SAMPLER_2D:
1218 case GL_SAMPLER_3D:
1219 case GL_SAMPLER_CUBE:
1220 case GL_SAMPLER_1D_SHADOW:
1221 case GL_SAMPLER_2D_SHADOW:
1222 case GL_SAMPLER_2D_RECT_ARB:
1223 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
1224 case GL_SAMPLER_1D_ARRAY_EXT:
1225 case GL_SAMPLER_2D_ARRAY_EXT:
1226 return GL_TRUE;
1227 default:
1228 return GL_FALSE;
1229 }
1230}
1231
1232
Brian5b01c5e2006-12-19 18:02:03 -07001233/**
Brian Paulfbf26e12008-07-21 13:58:50 -06001234 * Check if the type given by userType is allowed to set a uniform of the
1235 * target type. Generally, equivalence is required, but setting Boolean
1236 * uniforms can be done with glUniformiv or glUniformfv.
1237 */
1238static GLboolean
1239compatible_types(GLenum userType, GLenum targetType)
1240{
1241 if (userType == targetType)
1242 return GL_TRUE;
1243
1244 if (targetType == GL_BOOL && (userType == GL_FLOAT || userType == GL_INT))
1245 return GL_TRUE;
1246
1247 if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 ||
1248 userType == GL_INT_VEC2))
1249 return GL_TRUE;
1250
1251 if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 ||
1252 userType == GL_INT_VEC3))
1253 return GL_TRUE;
1254
1255 if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 ||
1256 userType == GL_INT_VEC4))
1257 return GL_TRUE;
1258
Brian63025ec2008-07-21 20:42:05 -06001259 if (is_sampler_type(targetType) && userType == GL_INT)
1260 return GL_TRUE;
1261
Brian Paulfbf26e12008-07-21 13:58:50 -06001262 return GL_FALSE;
1263}
1264
1265
1266/**
Brianbc029242008-04-04 18:59:21 -06001267 * Set the value of a program's uniform variable.
1268 * \param program the program whose uniform to update
1269 * \param location the location/index of the uniform
1270 * \param type the datatype of the uniform
1271 * \param count the number of uniforms to set
1272 * \param elems number of elements per uniform
1273 * \param values the new values
1274 */
1275static void
1276set_program_uniform(GLcontext *ctx, struct gl_program *program, GLint location,
José Fonseca18ec1402008-06-24 11:34:46 +09001277 GLenum type, GLsizei count, GLint elems, const void *values)
Brianbc029242008-04-04 18:59:21 -06001278{
Brian Paulfbf26e12008-07-21 13:58:50 -06001279 if (!compatible_types(type,
1280 program->Parameters->Parameters[location].DataType)) {
1281 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
1282 return;
1283 }
1284
Brianbc029242008-04-04 18:59:21 -06001285 if (program->Parameters->Parameters[location].Type == PROGRAM_SAMPLER) {
1286 /* This controls which texture unit which is used by a sampler */
1287 GLuint texUnit, sampler;
1288
1289 /* data type for setting samplers must be int */
1290 if (type != GL_INT || count != 1) {
1291 _mesa_error(ctx, GL_INVALID_OPERATION,
1292 "glUniform(only glUniform1i can be used "
1293 "to set sampler uniforms)");
1294 return;
1295 }
1296
1297 sampler = (GLuint) program->Parameters->ParameterValues[location][0];
1298 texUnit = ((GLuint *) values)[0];
1299
1300 /* check that the sampler (tex unit index) is legal */
1301 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1302 _mesa_error(ctx, GL_INVALID_VALUE,
1303 "glUniform1(invalid sampler/tex unit index)");
1304 return;
1305 }
1306
1307 /* This maps a sampler to a texture unit: */
1308 program->SamplerUnits[sampler] = texUnit;
1309 update_textures_used(program);
1310
1311 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1312 }
1313 else {
1314 /* ordinary uniform variable */
José Fonseca18ec1402008-06-24 11:34:46 +09001315 GLsizei k, i;
Brianbc029242008-04-04 18:59:21 -06001316
Michal Krolf9c574d2008-07-15 11:44:47 +02001317 if (count * elems > (GLint) program->Parameters->Parameters[location].Size) {
Brianbc029242008-04-04 18:59:21 -06001318 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1319 return;
1320 }
1321
1322 for (k = 0; k < count; k++) {
1323 GLfloat *uniformVal = program->Parameters->ParameterValues[location + k];
1324 if (type == GL_INT ||
1325 type == GL_INT_VEC2 ||
1326 type == GL_INT_VEC3 ||
1327 type == GL_INT_VEC4) {
1328 const GLint *iValues = ((const GLint *) values) + k * elems;
1329 for (i = 0; i < elems; i++) {
1330 uniformVal[i] = (GLfloat) iValues[i];
1331 }
1332 }
1333 else {
1334 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1335 for (i = 0; i < elems; i++) {
1336 uniformVal[i] = fValues[i];
1337 }
1338 }
1339 }
1340 }
1341}
1342
1343
1344/**
Brian5b01c5e2006-12-19 18:02:03 -07001345 * Called via ctx->Driver.Uniform().
1346 */
Brian2d2bb352007-12-07 17:11:30 -07001347static void
Brian5b01c5e2006-12-19 18:02:03 -07001348_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1349 const GLvoid *values, GLenum type)
1350{
Brian3a8e2772006-12-20 17:19:16 -07001351 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brianbc029242008-04-04 18:59:21 -06001352 GLint elems;
Brian3a8e2772006-12-20 17:19:16 -07001353
1354 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001355 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001356 return;
1357 }
1358
Brian Paulf84005c2008-05-14 16:01:31 -06001359 if (location == -1)
1360 return; /* The standard specifies this as a no-op */
1361
Brianbc029242008-04-04 18:59:21 -06001362 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian3a8e2772006-12-20 17:19:16 -07001363 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
1364 return;
1365 }
1366
Brian52363952007-03-13 16:50:24 -06001367 if (count < 0) {
1368 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1369 return;
1370 }
1371
Brian98650bd2007-03-13 16:32:48 -06001372 switch (type) {
1373 case GL_FLOAT:
1374 case GL_INT:
1375 elems = 1;
1376 break;
1377 case GL_FLOAT_VEC2:
1378 case GL_INT_VEC2:
1379 elems = 2;
1380 break;
1381 case GL_FLOAT_VEC3:
1382 case GL_INT_VEC3:
1383 elems = 3;
1384 break;
1385 case GL_FLOAT_VEC4:
1386 case GL_INT_VEC4:
1387 elems = 4;
1388 break;
1389 default:
1390 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1391 return;
Brian89dc4852007-01-04 14:35:44 -07001392 }
Brian98650bd2007-03-13 16:32:48 -06001393
Brianbc029242008-04-04 18:59:21 -06001394 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1395
1396 /* A uniform var may be used by both a vertex shader and a fragment
1397 * shader. We may need to update one or both shader's uniform here:
1398 */
1399 if (shProg->VertexProgram) {
1400 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1401 if (loc >= 0) {
1402 set_program_uniform(ctx, &shProg->VertexProgram->Base,
1403 loc, type, count, elems, values);
1404 }
Brian98650bd2007-03-13 16:32:48 -06001405 }
1406
Brianbc029242008-04-04 18:59:21 -06001407 if (shProg->FragmentProgram) {
1408 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1409 if (loc >= 0) {
1410 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
1411 loc, type, count, elems, values);
Brian8fed2462007-10-26 19:19:09 -06001412 }
Brianbc029242008-04-04 18:59:21 -06001413 }
1414}
Brian8fed2462007-10-26 19:19:09 -06001415
Brian8fed2462007-10-26 19:19:09 -06001416
Brianbc029242008-04-04 18:59:21 -06001417static void
Brian Paulfbf26e12008-07-21 13:58:50 -06001418get_matrix_dims(GLenum type, GLint *rows, GLint *cols)
1419{
1420 switch (type) {
1421 case GL_FLOAT_MAT2:
1422 *rows = *cols = 2;
1423 break;
1424 case GL_FLOAT_MAT2x3:
1425 *rows = 3;
1426 *cols = 2;
1427 break;
1428 case GL_FLOAT_MAT2x4:
1429 *rows = 4;
1430 *cols = 2;
1431 break;
1432 case GL_FLOAT_MAT3:
1433 *rows = 3;
1434 *cols = 3;
1435 break;
1436 case GL_FLOAT_MAT3x2:
1437 *rows = 2;
1438 *cols = 3;
1439 break;
1440 case GL_FLOAT_MAT3x4:
1441 *rows = 4;
1442 *cols = 3;
1443 break;
1444 case GL_FLOAT_MAT4:
1445 *rows = 4;
1446 *cols = 4;
1447 break;
1448 case GL_FLOAT_MAT4x2:
1449 *rows = 2;
1450 *cols = 4;
1451 break;
1452 case GL_FLOAT_MAT4x3:
1453 *rows = 3;
1454 *cols = 4;
1455 break;
1456 default:
1457 *rows = *cols = 0;
1458 }
1459}
1460
1461
1462static void
Brianbc029242008-04-04 18:59:21 -06001463set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
Brian Paulb64882d2008-07-18 12:51:39 -06001464 GLuint location, GLuint count,
1465 GLuint rows, GLuint cols,
Brianbc029242008-04-04 18:59:21 -06001466 GLboolean transpose, const GLfloat *values)
1467{
Brian Paulfbf26e12008-07-21 13:58:50 -06001468 GLuint mat, row, col;
1469 GLuint dst = location, src = 0;
1470 GLint nr, nc;
1471
1472 /* check that the number of rows, columns is correct */
1473 get_matrix_dims(program->Parameters->Parameters[location].DataType, &nr, &nc);
1474 if (rows != nr || cols != nc) {
1475 _mesa_error(ctx, GL_INVALID_OPERATION,
1476 "glUniformMatrix(matrix size mismatch");
1477 return;
1478 }
1479
Brianbc029242008-04-04 18:59:21 -06001480 /*
1481 * Note: the _columns_ of a matrix are stored in program registers, not
Brian Paulb64882d2008-07-18 12:51:39 -06001482 * the rows. So, the loops below look a little funny.
1483 * XXX could optimize this a bit...
Brianbc029242008-04-04 18:59:21 -06001484 */
Brian Paulb64882d2008-07-18 12:51:39 -06001485
1486 /* loop over matrices */
1487 for (mat = 0; mat < count; mat++) {
1488
1489 /* each matrix: */
Brianbc029242008-04-04 18:59:21 -06001490 for (col = 0; col < cols; col++) {
Brian Paulb64882d2008-07-18 12:51:39 -06001491 GLfloat *v = program->Parameters->ParameterValues[dst];
Brianbc029242008-04-04 18:59:21 -06001492 for (row = 0; row < rows; row++) {
Brian Paulb64882d2008-07-18 12:51:39 -06001493 if (transpose) {
1494 v[row] = values[src + row * cols + col];
1495 }
1496 else {
1497 v[row] = values[src + col * rows + row];
1498 }
Brianbc029242008-04-04 18:59:21 -06001499 }
Brian Paulb64882d2008-07-18 12:51:39 -06001500 dst++;
Brian8fed2462007-10-26 19:19:09 -06001501 }
Brian Paulb64882d2008-07-18 12:51:39 -06001502
1503 src += rows * cols; /* next matrix */
Brian8fed2462007-10-26 19:19:09 -06001504 }
Brian34ae99d2006-12-18 08:28:54 -07001505}
1506
1507
1508/**
Brian5b01c5e2006-12-19 18:02:03 -07001509 * Called by ctx->Driver.UniformMatrix().
Brian Paulb64882d2008-07-18 12:51:39 -06001510 * Note: cols=2, rows=4 ==> array[2] of vec4
Brian34ae99d2006-12-18 08:28:54 -07001511 */
Brian2d2bb352007-12-07 17:11:30 -07001512static void
Brian5b01c5e2006-12-19 18:02:03 -07001513_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1514 GLenum matrixType, GLint location, GLsizei count,
1515 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001516{
Brian3a8e2772006-12-20 17:19:16 -07001517 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paulf84005c2008-05-14 16:01:31 -06001518
Brian3a8e2772006-12-20 17:19:16 -07001519 if (!shProg || !shProg->LinkStatus) {
1520 _mesa_error(ctx, GL_INVALID_OPERATION,
1521 "glUniformMatrix(program not linked)");
1522 return;
1523 }
Brian Paulf84005c2008-05-14 16:01:31 -06001524
1525 if (location == -1)
1526 return; /* The standard specifies this as a no-op */
1527
Michal Krolf9c574d2008-07-15 11:44:47 +02001528 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian3a8e2772006-12-20 17:19:16 -07001529 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
1530 return;
1531 }
Brian34ae99d2006-12-18 08:28:54 -07001532 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001533 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001534 return;
1535 }
1536
1537 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1538
Brianbc029242008-04-04 18:59:21 -06001539 if (shProg->VertexProgram) {
1540 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1541 if (loc >= 0) {
1542 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
Brian Paulb64882d2008-07-18 12:51:39 -06001543 loc, count, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07001544 }
Brian34ae99d2006-12-18 08:28:54 -07001545 }
Brianbc029242008-04-04 18:59:21 -06001546
1547 if (shProg->FragmentProgram) {
1548 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1549 if (loc >= 0) {
1550 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
Brian Paulb64882d2008-07-18 12:51:39 -06001551 loc, count, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07001552 }
Brian34ae99d2006-12-18 08:28:54 -07001553 }
1554}
1555
1556
Brian2d2bb352007-12-07 17:11:30 -07001557static void
Brian5b01c5e2006-12-19 18:02:03 -07001558_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001559{
Brian65a18442006-12-19 18:46:56 -07001560 struct gl_shader_program *shProg;
Brian Paul70d39282008-07-21 14:16:07 -06001561
1562 shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram");
Brian65a18442006-12-19 18:46:56 -07001563 if (!shProg) {
Brian34ae99d2006-12-18 08:28:54 -07001564 return;
1565 }
1566
Brian Paul70d39282008-07-21 14:16:07 -06001567 if (!shProg->LinkStatus) {
1568 shProg->Validated = GL_FALSE;
1569 return;
1570 }
1571
1572 /* From the GL spec, a program is invalid if any of these are true:
1573
Brian5b01c5e2006-12-19 18:02:03 -07001574 any two active samplers in the current program object are of
1575 different types, but refer to the same texture image unit,
1576
1577 any active sampler in the current program object refers to a texture
1578 image unit where fixed-function fragment processing accesses a
1579 texture target that does not match the sampler type, or
1580
1581 the sum of the number of active samplers in the program and the
1582 number of texture image units enabled for fixed-function fragment
1583 processing exceeds the combined limit on the total number of texture
1584 image units allowed.
1585 */
Brian Paul70d39282008-07-21 14:16:07 -06001586
1587 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001588}
Brian2d2bb352007-12-07 17:11:30 -07001589
1590
1591/**
1592 * Plug in Mesa's GLSL functions into the device driver function table.
1593 */
1594void
1595_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
1596{
1597 driver->AttachShader = _mesa_attach_shader;
1598 driver->BindAttribLocation = _mesa_bind_attrib_location;
1599 driver->CompileShader = _mesa_compile_shader;
1600 driver->CreateProgram = _mesa_create_program;
1601 driver->CreateShader = _mesa_create_shader;
1602 driver->DeleteProgram2 = _mesa_delete_program2;
1603 driver->DeleteShader = _mesa_delete_shader;
1604 driver->DetachShader = _mesa_detach_shader;
1605 driver->GetActiveAttrib = _mesa_get_active_attrib;
1606 driver->GetActiveUniform = _mesa_get_active_uniform;
1607 driver->GetAttachedShaders = _mesa_get_attached_shaders;
1608 driver->GetAttribLocation = _mesa_get_attrib_location;
1609 driver->GetHandle = _mesa_get_handle;
1610 driver->GetProgramiv = _mesa_get_programiv;
1611 driver->GetProgramInfoLog = _mesa_get_program_info_log;
1612 driver->GetShaderiv = _mesa_get_shaderiv;
1613 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
1614 driver->GetShaderSource = _mesa_get_shader_source;
1615 driver->GetUniformfv = _mesa_get_uniformfv;
Brian Paul072c4742008-07-08 16:12:01 -06001616 driver->GetUniformiv = _mesa_get_uniformiv;
Brian2d2bb352007-12-07 17:11:30 -07001617 driver->GetUniformLocation = _mesa_get_uniform_location;
1618 driver->IsProgram = _mesa_is_program;
1619 driver->IsShader = _mesa_is_shader;
1620 driver->LinkProgram = _mesa_link_program;
1621 driver->ShaderSource = _mesa_shader_source;
1622 driver->Uniform = _mesa_uniform;
1623 driver->UniformMatrix = _mesa_uniform_matrix;
1624 driver->UseProgram = _mesa_use_program;
1625 driver->ValidateProgram = _mesa_validate_program;
1626}