blob: 3a85f476740d8e1897c8b3cee2210fab03338966 [file] [log] [blame]
Brian34ae99d2006-12-18 08:28:54 -07001/*
2 * Mesa 3-D graphics library
Brian3e4302f2007-05-09 08:04:32 -06003 * Version: 7.0
Brian34ae99d2006-12-18 08:28:54 -07004 *
Brian5b01c5e2006-12-19 18:02:03 -07005 * Copyright (C) 2004-2007 Brian Paul All Rights Reserved.
Brian34ae99d2006-12-18 08:28:54 -07006 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25/**
26 * \file shader_api.c
Brian5b01c5e2006-12-19 18:02:03 -070027 * Implementation of GLSL-related API functions
Brian34ae99d2006-12-18 08:28:54 -070028 * \author Brian Paul
29 */
30
31/**
32 * XXX things to do:
33 * 1. Check that the right error code is generated for all _mesa_error() calls.
Brian5b01c5e2006-12-19 18:02:03 -070034 * 2. Insert FLUSH_VERTICES calls in various places
Brian34ae99d2006-12-18 08:28:54 -070035 */
36
37
José Fonseca101d1a62008-07-23 21:06:01 +090038#include "main/glheader.h"
39#include "main/context.h"
40#include "main/hash.h"
41#include "main/macros.h"
Brian34ae99d2006-12-18 08:28:54 -070042#include "program.h"
43#include "prog_parameter.h"
Brian3209c3e2007-01-09 17:49:24 -070044#include "prog_print.h"
45#include "prog_statevars.h"
Brianbc029242008-04-04 18:59:21 -060046#include "prog_uniform.h"
Brianc223c6b2007-07-04 13:15:20 -060047#include "shader/shader_api.h"
48#include "shader/slang/slang_compile.h"
49#include "shader/slang/slang_link.h"
Brian34ae99d2006-12-18 08:28:54 -070050
51
52
Brian Paul18cd9c22008-08-06 12:45:14 -060053#ifndef GL_PROGRAM_BINARY_LENGTH_OES
54#define GL_PROGRAM_BINARY_LENGTH_OES 0x8741
55#endif
56
57
Brianf2923612006-12-20 09:56:44 -070058/**
59 * Allocate a new gl_shader_program object, initialize it.
60 */
Brian2d2bb352007-12-07 17:11:30 -070061static struct gl_shader_program *
Brianf2923612006-12-20 09:56:44 -070062_mesa_new_shader_program(GLcontext *ctx, GLuint name)
63{
64 struct gl_shader_program *shProg;
65 shProg = CALLOC_STRUCT(gl_shader_program);
66 if (shProg) {
Brianf3e8c322007-04-18 14:53:23 -060067 shProg->Type = GL_SHADER_PROGRAM_MESA;
Brianf2923612006-12-20 09:56:44 -070068 shProg->Name = name;
69 shProg->RefCount = 1;
Brian3209c3e2007-01-09 17:49:24 -070070 shProg->Attributes = _mesa_new_parameter_list();
Brianf2923612006-12-20 09:56:44 -070071 }
72 return shProg;
73}
74
75
Brianb9fbedd2007-03-26 09:23:44 -060076/**
Brian3c008a02007-04-12 15:22:32 -060077 * Clear (free) the shader program state that gets produced by linking.
Brianb9fbedd2007-03-26 09:23:44 -060078 */
Brianf2923612006-12-20 09:56:44 -070079void
Brian3c008a02007-04-12 15:22:32 -060080_mesa_clear_shader_program_data(GLcontext *ctx,
81 struct gl_shader_program *shProg)
Brianf2923612006-12-20 09:56:44 -070082{
Brian Paul470f6992008-05-16 09:56:59 -060083 _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL);
84 _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL);
Brianf2923612006-12-20 09:56:44 -070085
Brianf2923612006-12-20 09:56:44 -070086 if (shProg->Uniforms) {
Brianbc029242008-04-04 18:59:21 -060087 _mesa_free_uniform_list(shProg->Uniforms);
Brianf2923612006-12-20 09:56:44 -070088 shProg->Uniforms = NULL;
89 }
90
91 if (shProg->Varying) {
92 _mesa_free_parameter_list(shProg->Varying);
93 shProg->Varying = NULL;
94 }
95}
96
97
Brianb9fbedd2007-03-26 09:23:44 -060098/**
Brian3c008a02007-04-12 15:22:32 -060099 * Free all the data that hangs off a shader program object, but not the
100 * object itself.
101 */
102void
103_mesa_free_shader_program_data(GLcontext *ctx,
104 struct gl_shader_program *shProg)
105{
106 GLuint i;
107
Brianf3e8c322007-04-18 14:53:23 -0600108 assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
Brian3c008a02007-04-12 15:22:32 -0600109
110 _mesa_clear_shader_program_data(ctx, shProg);
111
Brian4b7c6fc2007-04-19 15:23:34 -0600112 if (shProg->Attributes) {
113 _mesa_free_parameter_list(shProg->Attributes);
114 shProg->Attributes = NULL;
115 }
116
Brian3c008a02007-04-12 15:22:32 -0600117 /* detach shaders */
118 for (i = 0; i < shProg->NumShaders; i++) {
119 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
120 }
Brian Paul887bfee2008-05-14 16:44:08 -0600121 shProg->NumShaders = 0;
122
Brian3c008a02007-04-12 15:22:32 -0600123 if (shProg->Shaders) {
124 _mesa_free(shProg->Shaders);
125 shProg->Shaders = NULL;
126 }
Brian Paul887bfee2008-05-14 16:44:08 -0600127
128 if (shProg->InfoLog) {
129 _mesa_free(shProg->InfoLog);
130 shProg->InfoLog = NULL;
131 }
Brian3c008a02007-04-12 15:22:32 -0600132}
133
134
135/**
Brianb9fbedd2007-03-26 09:23:44 -0600136 * Free/delete a shader program object.
137 */
Brianf2923612006-12-20 09:56:44 -0700138void
139_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg)
140{
141 _mesa_free_shader_program_data(ctx, shProg);
Brian Paul887bfee2008-05-14 16:44:08 -0600142
Brianf2923612006-12-20 09:56:44 -0700143 _mesa_free(shProg);
144}
145
146
147/**
Brian3c008a02007-04-12 15:22:32 -0600148 * Set ptr to point to shProg.
149 * If ptr is pointing to another object, decrement its refcount (and delete
150 * if refcount hits zero).
151 * Then set ptr to point to shProg, incrementing its refcount.
152 */
153/* XXX this could be static */
154void
155_mesa_reference_shader_program(GLcontext *ctx,
156 struct gl_shader_program **ptr,
157 struct gl_shader_program *shProg)
158{
159 assert(ptr);
160 if (*ptr == shProg) {
161 /* no-op */
162 return;
163 }
164 if (*ptr) {
165 /* Unreference the old shader program */
166 GLboolean deleteFlag = GL_FALSE;
167 struct gl_shader_program *old = *ptr;
168
169 ASSERT(old->RefCount > 0);
170 old->RefCount--;
Brian Paul470f6992008-05-16 09:56:59 -0600171#if 0
172 printf("ShaderProgram %p ID=%u RefCount-- to %d\n",
173 (void *) old, old->Name, old->RefCount);
174#endif
Brian3c008a02007-04-12 15:22:32 -0600175 deleteFlag = (old->RefCount == 0);
176
177 if (deleteFlag) {
178 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
179 _mesa_free_shader_program(ctx, old);
180 }
181
182 *ptr = NULL;
183 }
184 assert(!*ptr);
185
186 if (shProg) {
187 shProg->RefCount++;
Brian Paul470f6992008-05-16 09:56:59 -0600188#if 0
189 printf("ShaderProgram %p ID=%u RefCount++ to %d\n",
190 (void *) shProg, shProg->Name, shProg->RefCount);
191#endif
Brian3c008a02007-04-12 15:22:32 -0600192 *ptr = shProg;
193 }
194}
195
196
197/**
Brianf2923612006-12-20 09:56:44 -0700198 * Lookup a GLSL program object.
199 */
200struct gl_shader_program *
201_mesa_lookup_shader_program(GLcontext *ctx, GLuint name)
202{
203 struct gl_shader_program *shProg;
204 if (name) {
205 shProg = (struct gl_shader_program *)
206 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
207 /* Note that both gl_shader and gl_shader_program objects are kept
208 * in the same hash table. Check the object's type to be sure it's
209 * what we're expecting.
210 */
Brianf3e8c322007-04-18 14:53:23 -0600211 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700212 return NULL;
213 }
214 return shProg;
215 }
216 return NULL;
217}
218
219
220/**
Brian Pauld4172262008-07-03 16:21:15 -0600221 * As above, but record an error if program is not found.
222 */
223static struct gl_shader_program *
224_mesa_lookup_shader_program_err(GLcontext *ctx, GLuint name,
225 const char *caller)
226{
227 if (!name) {
228 _mesa_error(ctx, GL_INVALID_VALUE, caller);
229 return NULL;
230 }
231 else {
232 struct gl_shader_program *shProg = (struct gl_shader_program *)
233 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
234 if (!shProg) {
235 _mesa_error(ctx, GL_INVALID_VALUE, caller);
236 return NULL;
237 }
238 if (shProg->Type != GL_SHADER_PROGRAM_MESA) {
239 _mesa_error(ctx, GL_INVALID_OPERATION, caller);
240 return NULL;
241 }
242 return shProg;
243 }
244}
245
246
247
248
249/**
Brianf2923612006-12-20 09:56:44 -0700250 * Allocate a new gl_shader object, initialize it.
251 */
252struct gl_shader *
253_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
254{
255 struct gl_shader *shader;
256 assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
257 shader = CALLOC_STRUCT(gl_shader);
258 if (shader) {
259 shader->Type = type;
260 shader->Name = name;
261 shader->RefCount = 1;
262 }
263 return shader;
264}
265
266
267void
268_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh)
269{
Brianf2923612006-12-20 09:56:44 -0700270 if (sh->Source)
271 _mesa_free((void *) sh->Source);
272 if (sh->InfoLog)
273 _mesa_free(sh->InfoLog);
Brian Paul90a3af72008-07-24 14:56:54 -0600274 _mesa_reference_program(ctx, &sh->Program, NULL);
Brianf2923612006-12-20 09:56:44 -0700275 _mesa_free(sh);
276}
277
278
279/**
Brian3c008a02007-04-12 15:22:32 -0600280 * Set ptr to point to sh.
281 * If ptr is pointing to another shader, decrement its refcount (and delete
282 * if refcount hits zero).
283 * Then set ptr to point to sh, incrementing its refcount.
284 */
285/* XXX this could be static */
286void
287_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr,
288 struct gl_shader *sh)
289{
290 assert(ptr);
291 if (*ptr == sh) {
292 /* no-op */
293 return;
294 }
295 if (*ptr) {
296 /* Unreference the old shader */
297 GLboolean deleteFlag = GL_FALSE;
298 struct gl_shader *old = *ptr;
299
300 ASSERT(old->RefCount > 0);
301 old->RefCount--;
Brian99193e42007-04-12 15:45:02 -0600302 /*printf("SHADER DECR %p (%d) to %d\n",
303 (void*) old, old->Name, old->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600304 deleteFlag = (old->RefCount == 0);
305
306 if (deleteFlag) {
307 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
308 _mesa_free_shader(ctx, old);
309 }
310
311 *ptr = NULL;
312 }
313 assert(!*ptr);
314
315 if (sh) {
316 /* reference new */
317 sh->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600318 /*printf("SHADER INCR %p (%d) to %d\n",
319 (void*) sh, sh->Name, sh->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600320 *ptr = sh;
321 }
322}
323
324
325/**
Brianf2923612006-12-20 09:56:44 -0700326 * Lookup a GLSL shader object.
327 */
328struct gl_shader *
329_mesa_lookup_shader(GLcontext *ctx, GLuint name)
330{
331 if (name) {
332 struct gl_shader *sh = (struct gl_shader *)
333 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
334 /* Note that both gl_shader and gl_shader_program objects are kept
335 * in the same hash table. Check the object's type to be sure it's
336 * what we're expecting.
337 */
Brianf3e8c322007-04-18 14:53:23 -0600338 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700339 return NULL;
340 }
341 return sh;
342 }
343 return NULL;
344}
345
346
Brianfa4d0362007-02-26 18:33:50 -0700347/**
Brian Pauld4172262008-07-03 16:21:15 -0600348 * As above, but record an error if shader is not found.
349 */
350static struct gl_shader *
351_mesa_lookup_shader_err(GLcontext *ctx, GLuint name, const char *caller)
352{
353 if (!name) {
354 _mesa_error(ctx, GL_INVALID_VALUE, caller);
355 return NULL;
356 }
357 else {
358 struct gl_shader *sh = (struct gl_shader *)
359 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
360 if (!sh) {
361 _mesa_error(ctx, GL_INVALID_VALUE, caller);
362 return NULL;
363 }
364 if (sh->Type == GL_SHADER_PROGRAM_MESA) {
365 _mesa_error(ctx, GL_INVALID_OPERATION, caller);
366 return NULL;
367 }
368 return sh;
369 }
370}
371
372
373
374/**
Brianfa4d0362007-02-26 18:33:50 -0700375 * Initialize context's shader state.
376 */
Brianf2923612006-12-20 09:56:44 -0700377void
378_mesa_init_shader_state(GLcontext * ctx)
379{
Brianfa4d0362007-02-26 18:33:50 -0700380 /* Device drivers may override these to control what kind of instructions
381 * are generated by the GLSL compiler.
382 */
383 ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
michal4a470f62007-08-07 15:34:11 +0100384 ctx->Shader.EmitCondCodes = GL_FALSE;/*GL_TRUE;*/ /* XXX probably want GL_FALSE... */
Brianfa4d0362007-02-26 18:33:50 -0700385 ctx->Shader.EmitComments = GL_FALSE;
Brianf2923612006-12-20 09:56:44 -0700386}
387
388
Brian5b01c5e2006-12-19 18:02:03 -0700389/**
Brian935f93f2007-03-24 16:20:02 -0600390 * Free the per-context shader-related state.
391 */
392void
393_mesa_free_shader_state(GLcontext *ctx)
394{
Brian3c008a02007-04-12 15:22:32 -0600395 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
Brian935f93f2007-03-24 16:20:02 -0600396}
397
398
399/**
Brian5b01c5e2006-12-19 18:02:03 -0700400 * Copy string from <src> to <dst>, up to maxLength characters, returning
401 * length of <dst> in <length>.
402 * \param src the strings source
403 * \param maxLength max chars to copy
404 * \param length returns number of chars copied
405 * \param dst the string destination
406 */
407static void
408copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
409{
410 GLsizei len;
411 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
412 dst[len] = src[len];
413 if (maxLength > 0)
414 dst[len] = 0;
415 if (length)
416 *length = len;
417}
418
419
Brian Pauld4172262008-07-03 16:21:15 -0600420static GLboolean
421_mesa_is_program(GLcontext *ctx, GLuint name)
422{
423 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
424 return shProg ? GL_TRUE : GL_FALSE;
425}
426
427
428static GLboolean
429_mesa_is_shader(GLcontext *ctx, GLuint name)
430{
431 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
432 return shader ? GL_TRUE : GL_FALSE;
433}
434
435
Brian5b01c5e2006-12-19 18:02:03 -0700436/**
437 * Called via ctx->Driver.AttachShader()
438 */
Brian2d2bb352007-12-07 17:11:30 -0700439static void
Brian5b01c5e2006-12-19 18:02:03 -0700440_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
441{
Brian Pauld4172262008-07-03 16:21:15 -0600442 struct gl_shader_program *shProg;
443 struct gl_shader *sh;
444 GLuint i, n;
Brian5b01c5e2006-12-19 18:02:03 -0700445
Brian Pauld4172262008-07-03 16:21:15 -0600446 shProg = _mesa_lookup_shader_program_err(ctx, program, "glAttachShader");
447 if (!shProg)
448 return;
449
450 sh = _mesa_lookup_shader_err(ctx, shader, "glAttachShader");
451 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700452 return;
453 }
454
Brian Paulfc0a48d2008-05-16 15:48:11 -0600455 n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700456 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700457 if (shProg->Shaders[i] == sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700458 /* already attached */
459 return;
Brian34ae99d2006-12-18 08:28:54 -0700460 }
461 }
Brian5b01c5e2006-12-19 18:02:03 -0700462
463 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700464 shProg->Shaders = (struct gl_shader **)
465 _mesa_realloc(shProg->Shaders,
466 n * sizeof(struct gl_shader *),
467 (n + 1) * sizeof(struct gl_shader *));
468 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700469 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
470 return;
471 }
472
473 /* append */
Brian3c008a02007-04-12 15:22:32 -0600474 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
475 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700476 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700477}
478
479
Brian2d2bb352007-12-07 17:11:30 -0700480static GLint
481_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
482 const GLchar *name)
483{
484 struct gl_shader_program *shProg
Brian Pauld4172262008-07-03 16:21:15 -0600485 = _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
Brian2d2bb352007-12-07 17:11:30 -0700486
487 if (!shProg) {
Brian2d2bb352007-12-07 17:11:30 -0700488 return -1;
489 }
490
491 if (!shProg->LinkStatus) {
492 _mesa_error(ctx, GL_INVALID_OPERATION,
493 "glGetAttribLocation(program not linked)");
494 return -1;
495 }
496
497 if (!name)
498 return -1;
499
500 if (shProg->Attributes) {
501 GLint i = _mesa_lookup_parameter_index(shProg->Attributes, -1, name);
502 if (i >= 0) {
503 return shProg->Attributes->Parameters[i].StateIndexes[0];
504 }
505 }
506 return -1;
507}
508
509
510static void
Brian5b01c5e2006-12-19 18:02:03 -0700511_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
512 const GLchar *name)
513{
Brian Pauld4172262008-07-03 16:21:15 -0600514 struct gl_shader_program *shProg;
Brianb7978af2007-01-09 19:17:17 -0700515 const GLint size = -1; /* unknown size */
516 GLint i, oldIndex;
Brian Paul72809f32008-07-25 08:34:54 -0600517 GLenum datatype = GL_FLOAT_VEC4;
Brian5b01c5e2006-12-19 18:02:03 -0700518
Brian Pauld4172262008-07-03 16:21:15 -0600519 shProg = _mesa_lookup_shader_program_err(ctx, program,
520 "glBindAttribLocation");
Brian65a18442006-12-19 18:46:56 -0700521 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700522 return;
523 }
524
Brian9e4bae92006-12-20 09:27:42 -0700525 if (!name)
526 return;
527
528 if (strncmp(name, "gl_", 3) == 0) {
529 _mesa_error(ctx, GL_INVALID_OPERATION,
530 "glBindAttribLocation(illegal name)");
531 return;
532 }
533
Brian Pauld4172262008-07-03 16:21:15 -0600534 if (index >= ctx->Const.VertexProgram.MaxAttribs) {
535 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
536 return;
537 }
538
Brian9f660252007-04-11 09:00:56 -0600539 if (shProg->LinkStatus) {
540 /* get current index/location for the attribute */
541 oldIndex = _mesa_get_attrib_location(ctx, program, name);
542 }
543 else {
544 oldIndex = -1;
545 }
Brian3209c3e2007-01-09 17:49:24 -0700546
547 /* this will replace the current value if it's already in the list */
Brian Paulfbf26e12008-07-21 13:58:50 -0600548 i = _mesa_add_attribute(shProg->Attributes, name, size, datatype, index);
Brian3209c3e2007-01-09 17:49:24 -0700549 if (i < 0) {
550 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
Brian Paul72809f32008-07-25 08:34:54 -0600551 return;
Brian3209c3e2007-01-09 17:49:24 -0700552 }
553
Brian9f660252007-04-11 09:00:56 -0600554 if (shProg->VertexProgram && oldIndex >= 0 && oldIndex != index) {
555 /* If the index changed, need to search/replace references to that attribute
556 * in the vertex program.
557 */
Brian3209c3e2007-01-09 17:49:24 -0700558 _slang_remap_attribute(&shProg->VertexProgram->Base, oldIndex, index);
559 }
Brian34ae99d2006-12-18 08:28:54 -0700560}
561
562
Brian2d2bb352007-12-07 17:11:30 -0700563static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700564_mesa_create_shader(GLcontext *ctx, GLenum type)
565{
Brian65a18442006-12-19 18:46:56 -0700566 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700567 GLuint name;
568
569 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
570
571 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700572 case GL_FRAGMENT_SHADER:
573 case GL_VERTEX_SHADER:
574 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700575 break;
576 default:
577 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
578 return 0;
579 }
580
Brian65a18442006-12-19 18:46:56 -0700581 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700582
583 return name;
584}
585
586
Brian2d2bb352007-12-07 17:11:30 -0700587static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700588_mesa_create_program(GLcontext *ctx)
589{
590 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700591 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700592
Brian65a18442006-12-19 18:46:56 -0700593 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
594 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700595
Brian65a18442006-12-19 18:46:56 -0700596 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700597
Brian3c008a02007-04-12 15:22:32 -0600598 assert(shProg->RefCount == 1);
599
Brian5b01c5e2006-12-19 18:02:03 -0700600 return name;
601}
602
603
Brian3c008a02007-04-12 15:22:32 -0600604/**
605 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
606 * DeleteProgramARB.
607 */
Brian2d2bb352007-12-07 17:11:30 -0700608static void
Brian5b01c5e2006-12-19 18:02:03 -0700609_mesa_delete_program2(GLcontext *ctx, GLuint name)
610{
Brian3c008a02007-04-12 15:22:32 -0600611 /*
612 * NOTE: deleting shaders/programs works a bit differently than
613 * texture objects (and buffer objects, etc). Shader/program
614 * handles/IDs exist in the hash table until the object is really
615 * deleted (refcount==0). With texture objects, the handle/ID is
616 * removed from the hash table in glDeleteTextures() while the tex
617 * object itself might linger until its refcount goes to zero.
618 */
Brian65a18442006-12-19 18:46:56 -0700619 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700620
Brian Pauld4172262008-07-03 16:21:15 -0600621 shProg = _mesa_lookup_shader_program_err(ctx, name, "glDeleteProgram");
622 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700623 return;
Brian5b01c5e2006-12-19 18:02:03 -0700624
Brian9e4bae92006-12-20 09:27:42 -0700625 shProg->DeletePending = GL_TRUE;
626
Brian3c008a02007-04-12 15:22:32 -0600627 /* effectively, decr shProg's refcount */
628 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700629}
630
631
Brian2d2bb352007-12-07 17:11:30 -0700632static void
Brian5b01c5e2006-12-19 18:02:03 -0700633_mesa_delete_shader(GLcontext *ctx, GLuint shader)
634{
Brian Pauld4172262008-07-03 16:21:15 -0600635 struct gl_shader *sh;
636
637 sh = _mesa_lookup_shader_err(ctx, shader, "glDeleteShader");
638 if (!sh)
Brian9e4bae92006-12-20 09:27:42 -0700639 return;
Brian5b01c5e2006-12-19 18:02:03 -0700640
Brian9e4bae92006-12-20 09:27:42 -0700641 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600642
643 /* effectively, decr sh's refcount */
644 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700645}
646
647
Brian2d2bb352007-12-07 17:11:30 -0700648static void
Brian5b01c5e2006-12-19 18:02:03 -0700649_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
650{
Brian Pauld4172262008-07-03 16:21:15 -0600651 struct gl_shader_program *shProg;
Brian Paulfc0a48d2008-05-16 15:48:11 -0600652 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700653 GLuint i, j;
654
Brian Pauld4172262008-07-03 16:21:15 -0600655 shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader");
656 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700657 return;
Brian5b01c5e2006-12-19 18:02:03 -0700658
Brian Paulfc0a48d2008-05-16 15:48:11 -0600659 n = shProg->NumShaders;
660
Brian5b01c5e2006-12-19 18:02:03 -0700661 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700662 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700663 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600664 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700665
Brian Pauld4172262008-07-03 16:21:15 -0600666 /* release */
Brian3c008a02007-04-12 15:22:32 -0600667 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700668
Brian5b01c5e2006-12-19 18:02:03 -0700669 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700670 newList = (struct gl_shader **)
671 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700672 if (!newList) {
673 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
674 return;
675 }
676 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700677 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700678 }
679 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700680 newList[j++] = shProg->Shaders[i];
681 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700682
Brian65a18442006-12-19 18:46:56 -0700683 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600684 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600685
686#ifdef DEBUG
687 /* sanity check */
688 {
689 for (j = 0; j < shProg->NumShaders; j++) {
690 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
691 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
692 assert(shProg->Shaders[j]->RefCount > 0);
693 }
694 }
695#endif
696
Brian5b01c5e2006-12-19 18:02:03 -0700697 return;
698 }
699 }
700
701 /* not found */
Brian Pauld4172262008-07-03 16:21:15 -0600702 {
703 GLenum err;
704 if (_mesa_is_shader(ctx, shader))
705 err = GL_INVALID_OPERATION;
706 else if (_mesa_is_program(ctx, shader))
707 err = GL_INVALID_OPERATION;
708 else
709 err = GL_INVALID_VALUE;
710 _mesa_error(ctx, err, "glDetachProgram(shader)");
711 return;
712 }
Brian5b01c5e2006-12-19 18:02:03 -0700713}
714
715
Brian Paulfbf26e12008-07-21 13:58:50 -0600716static GLint
717sizeof_glsl_type(GLenum type)
718{
719 switch (type) {
720 case GL_FLOAT:
721 case GL_INT:
722 case GL_BOOL:
723 return 1;
724 case GL_FLOAT_VEC2:
725 case GL_INT_VEC2:
726 case GL_BOOL_VEC2:
727 return 2;
728 case GL_FLOAT_VEC3:
729 case GL_INT_VEC3:
730 case GL_BOOL_VEC3:
731 return 3;
732 case GL_FLOAT_VEC4:
733 case GL_INT_VEC4:
734 case GL_BOOL_VEC4:
735 return 4;
736 case GL_FLOAT_MAT2:
737 case GL_FLOAT_MAT2x3:
738 case GL_FLOAT_MAT2x4:
739 return 8; /* two float[4] vectors */
740 case GL_FLOAT_MAT3:
741 case GL_FLOAT_MAT3x2:
742 case GL_FLOAT_MAT3x4:
743 return 12; /* three float[4] vectors */
744 case GL_FLOAT_MAT4:
745 case GL_FLOAT_MAT4x2:
746 case GL_FLOAT_MAT4x3:
747 return 16; /* four float[4] vectors */
748 default:
749 _mesa_problem(NULL, "Invalid type in sizeof_glsl_type()");
750 return 1;
751 }
752}
753
754
Brian2d2bb352007-12-07 17:11:30 -0700755static void
Brian5b01c5e2006-12-19 18:02:03 -0700756_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
757 GLsizei maxLength, GLsizei *length, GLint *size,
758 GLenum *type, GLchar *nameOut)
759{
Brian Pauld4172262008-07-03 16:21:15 -0600760 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700761
Brian Pauld4172262008-07-03 16:21:15 -0600762 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
763 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700764 return;
Brian5b01c5e2006-12-19 18:02:03 -0700765
Brian65a18442006-12-19 18:46:56 -0700766 if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600767 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700768 return;
769 }
770
771 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700772 shProg->Attributes->Parameters[index].Name);
Brian5b01c5e2006-12-19 18:02:03 -0700773 if (size)
Brian Paulfbf26e12008-07-21 13:58:50 -0600774 *size = shProg->Attributes->Parameters[index].Size
775 / sizeof_glsl_type(shProg->Attributes->Parameters[index].DataType);
Brian5b01c5e2006-12-19 18:02:03 -0700776 if (type)
Brian Paulfbf26e12008-07-21 13:58:50 -0600777 *type = shProg->Attributes->Parameters[index].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700778}
779
780
781/**
782 * Called via ctx->Driver.GetActiveUniform().
783 */
Brian2d2bb352007-12-07 17:11:30 -0700784static void
Brian5b01c5e2006-12-19 18:02:03 -0700785_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
786 GLsizei maxLength, GLsizei *length, GLint *size,
787 GLenum *type, GLchar *nameOut)
788{
Brian Pauld4172262008-07-03 16:21:15 -0600789 const struct gl_shader_program *shProg;
Brianbc029242008-04-04 18:59:21 -0600790 const struct gl_program *prog;
791 GLint progPos;
Brian5b01c5e2006-12-19 18:02:03 -0700792
Brian Pauld4172262008-07-03 16:21:15 -0600793 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
794 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700795 return;
Brian5b01c5e2006-12-19 18:02:03 -0700796
Brianbc029242008-04-04 18:59:21 -0600797 if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
Brian5b01c5e2006-12-19 18:02:03 -0700798 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
799 return;
800 }
801
Brianbc029242008-04-04 18:59:21 -0600802 progPos = shProg->Uniforms->Uniforms[index].VertPos;
803 if (progPos >= 0) {
804 prog = &shProg->VertexProgram->Base;
805 }
806 else {
807 progPos = shProg->Uniforms->Uniforms[index].FragPos;
808 if (progPos >= 0) {
809 prog = &shProg->FragmentProgram->Base;
Brian274ac7a2007-04-18 16:05:53 -0600810 }
811 }
812
Brianbc029242008-04-04 18:59:21 -0600813 if (!prog || progPos < 0)
814 return; /* should never happen */
815
816 if (nameOut)
817 copy_string(nameOut, maxLength, length,
818 prog->Parameters->Parameters[progPos].Name);
819 if (size)
Brian Paulfbf26e12008-07-21 13:58:50 -0600820 *size = prog->Parameters->Parameters[progPos].Size
821 / sizeof_glsl_type(prog->Parameters->Parameters[progPos].DataType);
Brianbc029242008-04-04 18:59:21 -0600822 if (type)
823 *type = prog->Parameters->Parameters[progPos].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700824}
825
826
827/**
828 * Called via ctx->Driver.GetAttachedShaders().
829 */
Brian2d2bb352007-12-07 17:11:30 -0700830static void
Brian5b01c5e2006-12-19 18:02:03 -0700831_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
832 GLsizei *count, GLuint *obj)
833{
Brian Pauld4172262008-07-03 16:21:15 -0600834 struct gl_shader_program *shProg =
835 _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders");
Brian65a18442006-12-19 18:46:56 -0700836 if (shProg) {
José Fonseca53174af2008-05-31 18:14:09 +0900837 GLuint i;
Brian Pauld4172262008-07-03 16:21:15 -0600838 for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) {
Brian65a18442006-12-19 18:46:56 -0700839 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700840 }
841 if (count)
842 *count = i;
843 }
Brian5b01c5e2006-12-19 18:02:03 -0700844}
845
846
Brian2d2bb352007-12-07 17:11:30 -0700847static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700848_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700849{
850#if 0
851 GET_CURRENT_CONTEXT(ctx);
852
853 switch (pname) {
854 case GL_PROGRAM_OBJECT_ARB:
855 {
Brian5b01c5e2006-12-19 18:02:03 -0700856 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700857
858 if (pro != NULL)
859 return (**pro)._container._generic.
860 GetName((struct gl2_generic_intf **) (pro));
861 }
862 break;
863 default:
864 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
865 }
866#endif
867 return 0;
868}
869
870
Brian2d2bb352007-12-07 17:11:30 -0700871static void
Brian5b01c5e2006-12-19 18:02:03 -0700872_mesa_get_programiv(GLcontext *ctx, GLuint program,
873 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700874{
Brian65a18442006-12-19 18:46:56 -0700875 struct gl_shader_program *shProg
876 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700877
Brian65a18442006-12-19 18:46:56 -0700878 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700879 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700880 return;
881 }
882
Brian5b01c5e2006-12-19 18:02:03 -0700883 switch (pname) {
884 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700885 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700886 break;
887 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700888 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700889 break;
Brian5b01c5e2006-12-19 18:02:03 -0700890 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700891 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700892 break;
893 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600894 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700895 break;
896 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700897 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700898 break;
899 case GL_ACTIVE_ATTRIBUTES:
Brian3209c3e2007-01-09 17:49:24 -0700900 *params = shProg->Attributes ? shProg->Attributes->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700901 break;
902 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600903 *params = _mesa_longest_parameter_name(shProg->Attributes,
904 PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700905 break;
906 case GL_ACTIVE_UNIFORMS:
Brianbc029242008-04-04 18:59:21 -0600907 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700908 break;
909 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brianbc029242008-04-04 18:59:21 -0600910 *params = _mesa_longest_uniform_name(shProg->Uniforms);
Brian274ac7a2007-04-18 16:05:53 -0600911 if (*params > 0)
912 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700913 break;
Brian Paul18cd9c22008-08-06 12:45:14 -0600914 case GL_PROGRAM_BINARY_LENGTH_OES:
915 *params = 0;
916 break;
Brian34ae99d2006-12-18 08:28:54 -0700917 default:
Brian5b01c5e2006-12-19 18:02:03 -0700918 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
919 return;
Brian34ae99d2006-12-18 08:28:54 -0700920 }
Brian5b01c5e2006-12-19 18:02:03 -0700921}
Brian34ae99d2006-12-18 08:28:54 -0700922
Brian34ae99d2006-12-18 08:28:54 -0700923
Brian2d2bb352007-12-07 17:11:30 -0700924static void
Brian5b01c5e2006-12-19 18:02:03 -0700925_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
926{
Brian Pauld4172262008-07-03 16:21:15 -0600927 struct gl_shader *shader = _mesa_lookup_shader_err(ctx, name, "glGetShaderiv");
Brian5b01c5e2006-12-19 18:02:03 -0700928
929 if (!shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700930 return;
931 }
Brian65a18442006-12-19 18:46:56 -0700932
Brian5b01c5e2006-12-19 18:02:03 -0700933 switch (pname) {
934 case GL_SHADER_TYPE:
935 *params = shader->Type;
936 break;
937 case GL_DELETE_STATUS:
938 *params = shader->DeletePending;
939 break;
940 case GL_COMPILE_STATUS:
941 *params = shader->CompileStatus;
942 break;
943 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600944 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700945 break;
946 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600947 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700948 break;
949 default:
950 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
951 return;
952 }
953}
954
955
Brian2d2bb352007-12-07 17:11:30 -0700956static void
Brian5b01c5e2006-12-19 18:02:03 -0700957_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
958 GLsizei *length, GLchar *infoLog)
959{
Brian65a18442006-12-19 18:46:56 -0700960 struct gl_shader_program *shProg
961 = _mesa_lookup_shader_program(ctx, program);
962 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700963 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
964 return;
965 }
Brian65a18442006-12-19 18:46:56 -0700966 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700967}
968
969
Brian2d2bb352007-12-07 17:11:30 -0700970static void
Brian5b01c5e2006-12-19 18:02:03 -0700971_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
972 GLsizei *length, GLchar *infoLog)
973{
Brian65a18442006-12-19 18:46:56 -0700974 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
975 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700976 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
977 return;
978 }
Brian65a18442006-12-19 18:46:56 -0700979 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700980}
981
982
983/**
984 * Called via ctx->Driver.GetShaderSource().
985 */
Brian2d2bb352007-12-07 17:11:30 -0700986static void
Brian5b01c5e2006-12-19 18:02:03 -0700987_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
988 GLsizei *length, GLchar *sourceOut)
989{
Brian Pauld4172262008-07-03 16:21:15 -0600990 struct gl_shader *sh;
991 sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource");
Brian65a18442006-12-19 18:46:56 -0700992 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700993 return;
994 }
Brian65a18442006-12-19 18:46:56 -0700995 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -0700996}
997
998
Brian Paul7a6eba52008-08-06 13:07:09 -0600999static void
1000get_matrix_dims(GLenum type, GLint *rows, GLint *cols)
1001{
1002 switch (type) {
1003 case GL_FLOAT_MAT2:
1004 *rows = *cols = 2;
1005 break;
1006 case GL_FLOAT_MAT2x3:
1007 *rows = 3;
1008 *cols = 2;
1009 break;
1010 case GL_FLOAT_MAT2x4:
1011 *rows = 4;
1012 *cols = 2;
1013 break;
1014 case GL_FLOAT_MAT3:
1015 *rows = 3;
1016 *cols = 3;
1017 break;
1018 case GL_FLOAT_MAT3x2:
1019 *rows = 2;
1020 *cols = 3;
1021 break;
1022 case GL_FLOAT_MAT3x4:
1023 *rows = 4;
1024 *cols = 3;
1025 break;
1026 case GL_FLOAT_MAT4:
1027 *rows = 4;
1028 *cols = 4;
1029 break;
1030 case GL_FLOAT_MAT4x2:
1031 *rows = 2;
1032 *cols = 4;
1033 break;
1034 case GL_FLOAT_MAT4x3:
1035 *rows = 3;
1036 *cols = 4;
1037 break;
1038 default:
1039 *rows = *cols = 0;
1040 }
1041}
1042
1043
1044/**
1045 * Determine the number of rows and columns occupied by a uniform
1046 * according to its datatype.
1047 */
1048static void
1049get_uniform_rows_cols(const struct gl_program_parameter *p,
1050 GLint *rows, GLint *cols)
1051{
1052 get_matrix_dims(p->DataType, rows, cols);
1053 if (*rows == 0 && *cols == 0) {
1054 /* not a matrix type, probably a float or vector */
1055 *rows = p->Size / 4 + 1;
1056 if (p->Size % 4 == 0)
1057 *cols = 4;
1058 else
1059 *cols = p->Size % 4;
1060 }
1061}
1062
1063
Brian Paul072c4742008-07-08 16:12:01 -06001064#define MAX_UNIFORM_ELEMENTS 16
1065
Brian5b01c5e2006-12-19 18:02:03 -07001066/**
Brian Paul072c4742008-07-08 16:12:01 -06001067 * Helper for GetUniformfv(), GetUniformiv()
1068 * Returns number of elements written to 'params' output.
Brian5b01c5e2006-12-19 18:02:03 -07001069 */
Brian Paul072c4742008-07-08 16:12:01 -06001070static GLuint
1071get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1072 GLfloat *params)
Brian5b01c5e2006-12-19 18:02:03 -07001073{
Brian65a18442006-12-19 18:46:56 -07001074 struct gl_shader_program *shProg
Brian Paul18cd9c22008-08-06 12:45:14 -06001075 = _mesa_lookup_shader_program_err(ctx, program, "glGetUniform[if]v");
Brian65a18442006-12-19 18:46:56 -07001076 if (shProg) {
Brian Paul22427692008-06-28 16:47:22 -06001077 if (shProg->Uniforms &&
Michal Krolf9c574d2008-07-15 11:44:47 +02001078 location >= 0 && location < (GLint) shProg->Uniforms->NumUniforms) {
Brian Paul22427692008-06-28 16:47:22 -06001079 GLint progPos;
Brian Paulfc0a48d2008-05-16 15:48:11 -06001080 const struct gl_program *prog = NULL;
Brianbc029242008-04-04 18:59:21 -06001081
1082 progPos = shProg->Uniforms->Uniforms[location].VertPos;
1083 if (progPos >= 0) {
1084 prog = &shProg->VertexProgram->Base;
1085 }
1086 else {
1087 progPos = shProg->Uniforms->Uniforms[location].FragPos;
1088 if (progPos >= 0) {
1089 prog = &shProg->FragmentProgram->Base;
1090 }
1091 }
1092
Brian Paulfc0a48d2008-05-16 15:48:11 -06001093 ASSERT(prog);
1094 if (prog) {
Brian Paul7a6eba52008-08-06 13:07:09 -06001095 const struct gl_program_parameter *p =
1096 &prog->Parameters->Parameters[progPos];
1097 GLint rows, cols, i, j, k;
Brian Paul072c4742008-07-08 16:12:01 -06001098
Brian Paul7a6eba52008-08-06 13:07:09 -06001099 /* See uniformiv() below */
1100 assert(p->Size <= MAX_UNIFORM_ELEMENTS);
1101
1102 get_uniform_rows_cols(p, &rows, &cols);
1103
1104 k = 0;
1105 for (i = 0; i < rows; i++) {
1106 for (j = 0; j < cols; j++ ) {
1107 params[k++] = prog->Parameters->ParameterValues[progPos+i][j];
1108 }
Brian Paulfc0a48d2008-05-16 15:48:11 -06001109 }
Brian Paul7a6eba52008-08-06 13:07:09 -06001110
1111 return p->Size;
Brian5b01c5e2006-12-19 18:02:03 -07001112 }
1113 }
1114 else {
Brian Paul22427692008-06-28 16:47:22 -06001115 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
Brian5b01c5e2006-12-19 18:02:03 -07001116 }
1117 }
Brian Paul072c4742008-07-08 16:12:01 -06001118 return 0;
1119}
1120
1121
1122/**
1123 * Called via ctx->Driver.GetUniformfv().
1124 */
1125static void
1126_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1127 GLfloat *params)
1128{
1129 (void) get_uniformfv(ctx, program, location, params);
1130}
1131
1132
1133/**
1134 * Called via ctx->Driver.GetUniformiv().
1135 */
1136static void
1137_mesa_get_uniformiv(GLcontext *ctx, GLuint program, GLint location,
1138 GLint *params)
1139{
1140 GLfloat fparams[MAX_UNIFORM_ELEMENTS];
1141 GLuint n = get_uniformfv(ctx, program, location, fparams);
1142 GLuint i;
1143 assert(n <= MAX_UNIFORM_ELEMENTS);
1144 for (i = 0; i < n; i++) {
1145 params[i] = (GLint) fparams[i];
1146 }
Brian5b01c5e2006-12-19 18:02:03 -07001147}
1148
1149
1150/**
1151 * Called via ctx->Driver.GetUniformLocation().
1152 */
Brian2d2bb352007-12-07 17:11:30 -07001153static GLint
Brian5b01c5e2006-12-19 18:02:03 -07001154_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
1155{
Brian Pauld4172262008-07-03 16:21:15 -06001156 struct gl_shader_program *shProg =
1157 _mesa_lookup_shader_program_err(ctx, program, "glGetUniformLocation");
1158
Brianbc029242008-04-04 18:59:21 -06001159 if (!shProg)
1160 return -1;
Brian5b01c5e2006-12-19 18:02:03 -07001161
Brian Paul294b0612008-07-04 09:58:14 -06001162 if (shProg->LinkStatus == GL_FALSE) {
1163 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
1164 return -1;
1165 }
1166
Brian Pauld4172262008-07-03 16:21:15 -06001167 /* XXX we should return -1 if the uniform was declared, but not
1168 * actually used.
1169 */
1170
Brianbc029242008-04-04 18:59:21 -06001171 return _mesa_lookup_uniform(shProg->Uniforms, name);
Brian5b01c5e2006-12-19 18:02:03 -07001172}
1173
1174
Brian34ae99d2006-12-18 08:28:54 -07001175
Brian5b01c5e2006-12-19 18:02:03 -07001176/**
1177 * Called via ctx->Driver.ShaderSource()
1178 */
Brian2d2bb352007-12-07 17:11:30 -07001179static void
Brian5b01c5e2006-12-19 18:02:03 -07001180_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -07001181{
Brian Pauld4172262008-07-03 16:21:15 -06001182 struct gl_shader *sh;
1183
1184 sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource");
1185 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001186 return;
Brian34ae99d2006-12-18 08:28:54 -07001187
Brian34ae99d2006-12-18 08:28:54 -07001188 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -07001189 if (sh->Source) {
1190 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -07001191 }
Brian65a18442006-12-19 18:46:56 -07001192 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -07001193 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -07001194}
1195
1196
Brian5b01c5e2006-12-19 18:02:03 -07001197/**
1198 * Called via ctx->Driver.CompileShader()
1199 */
Brian2d2bb352007-12-07 17:11:30 -07001200static void
Brian5b01c5e2006-12-19 18:02:03 -07001201_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -07001202{
Brian Pauld4172262008-07-03 16:21:15 -06001203 struct gl_shader *sh;
Brian34ae99d2006-12-18 08:28:54 -07001204
Brian Pauld4172262008-07-03 16:21:15 -06001205 sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader");
1206 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001207 return;
Brian34ae99d2006-12-18 08:28:54 -07001208
Brian43975832007-01-04 08:21:09 -07001209 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -07001210}
1211
1212
Brian5b01c5e2006-12-19 18:02:03 -07001213/**
1214 * Called via ctx->Driver.LinkProgram()
1215 */
Brian2d2bb352007-12-07 17:11:30 -07001216static void
Brian5b01c5e2006-12-19 18:02:03 -07001217_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001218{
Brian65a18442006-12-19 18:46:56 -07001219 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001220
Brian Pauld4172262008-07-03 16:21:15 -06001221 shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
1222 if (!shProg)
Brian34ae99d2006-12-18 08:28:54 -07001223 return;
Brian34ae99d2006-12-18 08:28:54 -07001224
Brian Paulfc0a48d2008-05-16 15:48:11 -06001225 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1226
Brianc1771912007-02-16 09:56:19 -07001227 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001228}
1229
1230
1231/**
Brian5b01c5e2006-12-19 18:02:03 -07001232 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001233 */
Brian5b01c5e2006-12-19 18:02:03 -07001234void
1235_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001236{
Brian3c008a02007-04-12 15:22:32 -06001237 struct gl_shader_program *shProg;
1238
Brian00d63aa2007-02-03 11:35:02 -07001239 if (ctx->Shader.CurrentProgram &&
1240 ctx->Shader.CurrentProgram->Name == program) {
1241 /* no-op */
1242 return;
1243 }
1244
1245 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1246
Brian5b01c5e2006-12-19 18:02:03 -07001247 if (program) {
Brian Pauld4172262008-07-03 16:21:15 -06001248 shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
Brian65a18442006-12-19 18:46:56 -07001249 if (!shProg) {
Brian Pauld4172262008-07-03 16:21:15 -06001250 return;
1251 }
1252 if (!shProg->LinkStatus) {
1253 _mesa_error(ctx, GL_INVALID_OPERATION, "glUseProgram");
Brian5b01c5e2006-12-19 18:02:03 -07001254 return;
1255 }
Brian5b01c5e2006-12-19 18:02:03 -07001256 }
1257 else {
Brian3c008a02007-04-12 15:22:32 -06001258 shProg = NULL;
1259 }
1260
1261 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001262}
Brian34ae99d2006-12-18 08:28:54 -07001263
Brian5b01c5e2006-12-19 18:02:03 -07001264
Brian8fed2462007-10-26 19:19:09 -06001265
1266/**
1267 * Update the vertex and fragment program's TexturesUsed arrays.
1268 */
1269static void
1270update_textures_used(struct gl_program *prog)
1271{
1272 GLuint s;
1273
1274 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1275
1276 for (s = 0; s < MAX_SAMPLERS; s++) {
1277 if (prog->SamplersUsed & (1 << s)) {
1278 GLuint u = prog->SamplerUnits[s];
1279 GLuint t = prog->SamplerTargets[s];
1280 assert(u < MAX_TEXTURE_IMAGE_UNITS);
1281 prog->TexturesUsed[u] |= (1 << t);
1282 }
1283 }
1284}
1285
1286
Brian63025ec2008-07-21 20:42:05 -06001287static GLboolean
1288is_sampler_type(GLenum type)
1289{
1290 switch (type) {
1291 case GL_SAMPLER_1D:
1292 case GL_SAMPLER_2D:
1293 case GL_SAMPLER_3D:
1294 case GL_SAMPLER_CUBE:
1295 case GL_SAMPLER_1D_SHADOW:
1296 case GL_SAMPLER_2D_SHADOW:
1297 case GL_SAMPLER_2D_RECT_ARB:
1298 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
1299 case GL_SAMPLER_1D_ARRAY_EXT:
1300 case GL_SAMPLER_2D_ARRAY_EXT:
1301 return GL_TRUE;
1302 default:
1303 return GL_FALSE;
1304 }
1305}
1306
1307
Brian5b01c5e2006-12-19 18:02:03 -07001308/**
Brian Paulfbf26e12008-07-21 13:58:50 -06001309 * Check if the type given by userType is allowed to set a uniform of the
1310 * target type. Generally, equivalence is required, but setting Boolean
1311 * uniforms can be done with glUniformiv or glUniformfv.
1312 */
1313static GLboolean
1314compatible_types(GLenum userType, GLenum targetType)
1315{
1316 if (userType == targetType)
1317 return GL_TRUE;
1318
1319 if (targetType == GL_BOOL && (userType == GL_FLOAT || userType == GL_INT))
1320 return GL_TRUE;
1321
1322 if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 ||
1323 userType == GL_INT_VEC2))
1324 return GL_TRUE;
1325
1326 if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 ||
1327 userType == GL_INT_VEC3))
1328 return GL_TRUE;
1329
1330 if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 ||
1331 userType == GL_INT_VEC4))
1332 return GL_TRUE;
1333
Brian63025ec2008-07-21 20:42:05 -06001334 if (is_sampler_type(targetType) && userType == GL_INT)
1335 return GL_TRUE;
1336
Brian Paulfbf26e12008-07-21 13:58:50 -06001337 return GL_FALSE;
1338}
1339
1340
1341/**
Brianbc029242008-04-04 18:59:21 -06001342 * Set the value of a program's uniform variable.
1343 * \param program the program whose uniform to update
1344 * \param location the location/index of the uniform
1345 * \param type the datatype of the uniform
1346 * \param count the number of uniforms to set
1347 * \param elems number of elements per uniform
1348 * \param values the new values
1349 */
1350static void
1351set_program_uniform(GLcontext *ctx, struct gl_program *program, GLint location,
José Fonseca18ec1402008-06-24 11:34:46 +09001352 GLenum type, GLsizei count, GLint elems, const void *values)
Brianbc029242008-04-04 18:59:21 -06001353{
Brian Paulfbf26e12008-07-21 13:58:50 -06001354 if (!compatible_types(type,
1355 program->Parameters->Parameters[location].DataType)) {
1356 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
1357 return;
1358 }
1359
Brianbc029242008-04-04 18:59:21 -06001360 if (program->Parameters->Parameters[location].Type == PROGRAM_SAMPLER) {
1361 /* This controls which texture unit which is used by a sampler */
1362 GLuint texUnit, sampler;
1363
1364 /* data type for setting samplers must be int */
1365 if (type != GL_INT || count != 1) {
1366 _mesa_error(ctx, GL_INVALID_OPERATION,
1367 "glUniform(only glUniform1i can be used "
1368 "to set sampler uniforms)");
1369 return;
1370 }
1371
1372 sampler = (GLuint) program->Parameters->ParameterValues[location][0];
1373 texUnit = ((GLuint *) values)[0];
1374
1375 /* check that the sampler (tex unit index) is legal */
1376 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1377 _mesa_error(ctx, GL_INVALID_VALUE,
1378 "glUniform1(invalid sampler/tex unit index)");
1379 return;
1380 }
1381
1382 /* This maps a sampler to a texture unit: */
1383 program->SamplerUnits[sampler] = texUnit;
1384 update_textures_used(program);
1385
1386 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1387 }
1388 else {
1389 /* ordinary uniform variable */
José Fonseca18ec1402008-06-24 11:34:46 +09001390 GLsizei k, i;
Brianbc029242008-04-04 18:59:21 -06001391
Michal Krolf9c574d2008-07-15 11:44:47 +02001392 if (count * elems > (GLint) program->Parameters->Parameters[location].Size) {
Brianbc029242008-04-04 18:59:21 -06001393 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1394 return;
1395 }
1396
1397 for (k = 0; k < count; k++) {
1398 GLfloat *uniformVal = program->Parameters->ParameterValues[location + k];
1399 if (type == GL_INT ||
1400 type == GL_INT_VEC2 ||
1401 type == GL_INT_VEC3 ||
1402 type == GL_INT_VEC4) {
1403 const GLint *iValues = ((const GLint *) values) + k * elems;
1404 for (i = 0; i < elems; i++) {
1405 uniformVal[i] = (GLfloat) iValues[i];
1406 }
1407 }
1408 else {
1409 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1410 for (i = 0; i < elems; i++) {
1411 uniformVal[i] = fValues[i];
1412 }
1413 }
1414 }
1415 }
1416}
1417
1418
1419/**
Brian5b01c5e2006-12-19 18:02:03 -07001420 * Called via ctx->Driver.Uniform().
1421 */
Brian2d2bb352007-12-07 17:11:30 -07001422static void
Brian5b01c5e2006-12-19 18:02:03 -07001423_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1424 const GLvoid *values, GLenum type)
1425{
Brian3a8e2772006-12-20 17:19:16 -07001426 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brianbc029242008-04-04 18:59:21 -06001427 GLint elems;
Brian3a8e2772006-12-20 17:19:16 -07001428
1429 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001430 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001431 return;
1432 }
1433
Brian Paulf84005c2008-05-14 16:01:31 -06001434 if (location == -1)
1435 return; /* The standard specifies this as a no-op */
1436
Brianbc029242008-04-04 18:59:21 -06001437 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian3a8e2772006-12-20 17:19:16 -07001438 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
1439 return;
1440 }
1441
Brian52363952007-03-13 16:50:24 -06001442 if (count < 0) {
1443 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1444 return;
1445 }
1446
Brian98650bd2007-03-13 16:32:48 -06001447 switch (type) {
1448 case GL_FLOAT:
1449 case GL_INT:
1450 elems = 1;
1451 break;
1452 case GL_FLOAT_VEC2:
1453 case GL_INT_VEC2:
1454 elems = 2;
1455 break;
1456 case GL_FLOAT_VEC3:
1457 case GL_INT_VEC3:
1458 elems = 3;
1459 break;
1460 case GL_FLOAT_VEC4:
1461 case GL_INT_VEC4:
1462 elems = 4;
1463 break;
1464 default:
1465 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1466 return;
Brian89dc4852007-01-04 14:35:44 -07001467 }
Brian98650bd2007-03-13 16:32:48 -06001468
Brianbc029242008-04-04 18:59:21 -06001469 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1470
1471 /* A uniform var may be used by both a vertex shader and a fragment
1472 * shader. We may need to update one or both shader's uniform here:
1473 */
1474 if (shProg->VertexProgram) {
1475 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1476 if (loc >= 0) {
1477 set_program_uniform(ctx, &shProg->VertexProgram->Base,
1478 loc, type, count, elems, values);
1479 }
Brian98650bd2007-03-13 16:32:48 -06001480 }
1481
Brianbc029242008-04-04 18:59:21 -06001482 if (shProg->FragmentProgram) {
1483 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1484 if (loc >= 0) {
1485 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
1486 loc, type, count, elems, values);
Brian8fed2462007-10-26 19:19:09 -06001487 }
Brianbc029242008-04-04 18:59:21 -06001488 }
1489}
Brian8fed2462007-10-26 19:19:09 -06001490
Brian8fed2462007-10-26 19:19:09 -06001491
Brianbc029242008-04-04 18:59:21 -06001492static void
1493set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
Brian Paulb64882d2008-07-18 12:51:39 -06001494 GLuint location, GLuint count,
1495 GLuint rows, GLuint cols,
Brianbc029242008-04-04 18:59:21 -06001496 GLboolean transpose, const GLfloat *values)
1497{
Brian Paulfbf26e12008-07-21 13:58:50 -06001498 GLuint mat, row, col;
1499 GLuint dst = location, src = 0;
1500 GLint nr, nc;
1501
1502 /* check that the number of rows, columns is correct */
1503 get_matrix_dims(program->Parameters->Parameters[location].DataType, &nr, &nc);
1504 if (rows != nr || cols != nc) {
1505 _mesa_error(ctx, GL_INVALID_OPERATION,
1506 "glUniformMatrix(matrix size mismatch");
1507 return;
1508 }
1509
Brianbc029242008-04-04 18:59:21 -06001510 /*
1511 * Note: the _columns_ of a matrix are stored in program registers, not
Brian Paulb64882d2008-07-18 12:51:39 -06001512 * the rows. So, the loops below look a little funny.
1513 * XXX could optimize this a bit...
Brianbc029242008-04-04 18:59:21 -06001514 */
Brian Paulb64882d2008-07-18 12:51:39 -06001515
1516 /* loop over matrices */
1517 for (mat = 0; mat < count; mat++) {
1518
1519 /* each matrix: */
Brianbc029242008-04-04 18:59:21 -06001520 for (col = 0; col < cols; col++) {
Brian Paulb64882d2008-07-18 12:51:39 -06001521 GLfloat *v = program->Parameters->ParameterValues[dst];
Brianbc029242008-04-04 18:59:21 -06001522 for (row = 0; row < rows; row++) {
Brian Paulb64882d2008-07-18 12:51:39 -06001523 if (transpose) {
1524 v[row] = values[src + row * cols + col];
1525 }
1526 else {
1527 v[row] = values[src + col * rows + row];
1528 }
Brianbc029242008-04-04 18:59:21 -06001529 }
Brian Paulb64882d2008-07-18 12:51:39 -06001530 dst++;
Brian8fed2462007-10-26 19:19:09 -06001531 }
Brian Paulb64882d2008-07-18 12:51:39 -06001532
1533 src += rows * cols; /* next matrix */
Brian8fed2462007-10-26 19:19:09 -06001534 }
Brian34ae99d2006-12-18 08:28:54 -07001535}
1536
1537
1538/**
Brian5b01c5e2006-12-19 18:02:03 -07001539 * Called by ctx->Driver.UniformMatrix().
Brian Paulb64882d2008-07-18 12:51:39 -06001540 * Note: cols=2, rows=4 ==> array[2] of vec4
Brian34ae99d2006-12-18 08:28:54 -07001541 */
Brian2d2bb352007-12-07 17:11:30 -07001542static void
Brian5b01c5e2006-12-19 18:02:03 -07001543_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1544 GLenum matrixType, GLint location, GLsizei count,
1545 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001546{
Brian3a8e2772006-12-20 17:19:16 -07001547 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paulf84005c2008-05-14 16:01:31 -06001548
Brian3a8e2772006-12-20 17:19:16 -07001549 if (!shProg || !shProg->LinkStatus) {
1550 _mesa_error(ctx, GL_INVALID_OPERATION,
1551 "glUniformMatrix(program not linked)");
1552 return;
1553 }
Brian Paulf84005c2008-05-14 16:01:31 -06001554
1555 if (location == -1)
1556 return; /* The standard specifies this as a no-op */
1557
Michal Krolf9c574d2008-07-15 11:44:47 +02001558 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian3a8e2772006-12-20 17:19:16 -07001559 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
1560 return;
1561 }
Brian34ae99d2006-12-18 08:28:54 -07001562 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001563 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001564 return;
1565 }
1566
1567 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1568
Brianbc029242008-04-04 18:59:21 -06001569 if (shProg->VertexProgram) {
1570 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1571 if (loc >= 0) {
1572 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
Brian Paulb64882d2008-07-18 12:51:39 -06001573 loc, count, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07001574 }
Brian34ae99d2006-12-18 08:28:54 -07001575 }
Brianbc029242008-04-04 18:59:21 -06001576
1577 if (shProg->FragmentProgram) {
1578 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1579 if (loc >= 0) {
1580 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
Brian Paulb64882d2008-07-18 12:51:39 -06001581 loc, count, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07001582 }
Brian34ae99d2006-12-18 08:28:54 -07001583 }
1584}
1585
1586
Brian2d2bb352007-12-07 17:11:30 -07001587static void
Brian5b01c5e2006-12-19 18:02:03 -07001588_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001589{
Brian65a18442006-12-19 18:46:56 -07001590 struct gl_shader_program *shProg;
Brian Paul70d39282008-07-21 14:16:07 -06001591
1592 shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram");
Brian65a18442006-12-19 18:46:56 -07001593 if (!shProg) {
Brian34ae99d2006-12-18 08:28:54 -07001594 return;
1595 }
1596
Brian Paul70d39282008-07-21 14:16:07 -06001597 if (!shProg->LinkStatus) {
1598 shProg->Validated = GL_FALSE;
1599 return;
1600 }
1601
1602 /* From the GL spec, a program is invalid if any of these are true:
1603
Brian5b01c5e2006-12-19 18:02:03 -07001604 any two active samplers in the current program object are of
1605 different types, but refer to the same texture image unit,
1606
1607 any active sampler in the current program object refers to a texture
1608 image unit where fixed-function fragment processing accesses a
1609 texture target that does not match the sampler type, or
1610
1611 the sum of the number of active samplers in the program and the
1612 number of texture image units enabled for fixed-function fragment
1613 processing exceeds the combined limit on the total number of texture
1614 image units allowed.
1615 */
Brian Paul70d39282008-07-21 14:16:07 -06001616
1617 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001618}
Brian2d2bb352007-12-07 17:11:30 -07001619
1620
1621/**
1622 * Plug in Mesa's GLSL functions into the device driver function table.
1623 */
1624void
1625_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
1626{
1627 driver->AttachShader = _mesa_attach_shader;
1628 driver->BindAttribLocation = _mesa_bind_attrib_location;
1629 driver->CompileShader = _mesa_compile_shader;
1630 driver->CreateProgram = _mesa_create_program;
1631 driver->CreateShader = _mesa_create_shader;
1632 driver->DeleteProgram2 = _mesa_delete_program2;
1633 driver->DeleteShader = _mesa_delete_shader;
1634 driver->DetachShader = _mesa_detach_shader;
1635 driver->GetActiveAttrib = _mesa_get_active_attrib;
1636 driver->GetActiveUniform = _mesa_get_active_uniform;
1637 driver->GetAttachedShaders = _mesa_get_attached_shaders;
1638 driver->GetAttribLocation = _mesa_get_attrib_location;
1639 driver->GetHandle = _mesa_get_handle;
1640 driver->GetProgramiv = _mesa_get_programiv;
1641 driver->GetProgramInfoLog = _mesa_get_program_info_log;
1642 driver->GetShaderiv = _mesa_get_shaderiv;
1643 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
1644 driver->GetShaderSource = _mesa_get_shader_source;
1645 driver->GetUniformfv = _mesa_get_uniformfv;
Brian Paul072c4742008-07-08 16:12:01 -06001646 driver->GetUniformiv = _mesa_get_uniformiv;
Brian2d2bb352007-12-07 17:11:30 -07001647 driver->GetUniformLocation = _mesa_get_uniform_location;
1648 driver->IsProgram = _mesa_is_program;
1649 driver->IsShader = _mesa_is_shader;
1650 driver->LinkProgram = _mesa_link_program;
1651 driver->ShaderSource = _mesa_shader_source;
1652 driver->Uniform = _mesa_uniform;
1653 driver->UniformMatrix = _mesa_uniform_matrix;
1654 driver->UseProgram = _mesa_use_program;
1655 driver->ValidateProgram = _mesa_validate_program;
1656}