blob: 161e8b6160081fbba1b1b30573cae92decb9679e [file] [log] [blame]
Brian34ae99d2006-12-18 08:28:54 -07001/*
2 * Mesa 3-D graphics library
Brian Paul27341a92008-09-16 16:28:36 -06003 * Version: 7.2
Brian34ae99d2006-12-18 08:28:54 -07004 *
Brian Paul8c51e002008-08-11 15:09:47 -06005 * Copyright (C) 2004-2008 Brian Paul All Rights Reserved.
Brian34ae99d2006-12-18 08:28:54 -07006 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25/**
26 * \file shader_api.c
Brian5b01c5e2006-12-19 18:02:03 -070027 * Implementation of GLSL-related API functions
Brian34ae99d2006-12-18 08:28:54 -070028 * \author Brian Paul
29 */
30
31/**
32 * XXX things to do:
33 * 1. Check that the right error code is generated for all _mesa_error() calls.
Brian5b01c5e2006-12-19 18:02:03 -070034 * 2. Insert FLUSH_VERTICES calls in various places
Brian34ae99d2006-12-18 08:28:54 -070035 */
36
37
Brian Paulbbd28712008-09-18 12:26:54 -060038#include "main/glheader.h"
39#include "main/context.h"
40#include "main/hash.h"
41#include "main/macros.h"
42#include "shader/program.h"
43#include "shader/prog_parameter.h"
44#include "shader/prog_print.h"
45#include "shader/prog_statevars.h"
46#include "shader/prog_uniform.h"
Brianc223c6b2007-07-04 13:15:20 -060047#include "shader/shader_api.h"
48#include "shader/slang/slang_compile.h"
49#include "shader/slang/slang_link.h"
Brian34ae99d2006-12-18 08:28:54 -070050
51
52
Brianf2923612006-12-20 09:56:44 -070053/**
54 * Allocate a new gl_shader_program object, initialize it.
55 */
Brian Paulfd59f192008-05-18 16:04:55 -060056static struct gl_shader_program *
Brianf2923612006-12-20 09:56:44 -070057_mesa_new_shader_program(GLcontext *ctx, GLuint name)
58{
59 struct gl_shader_program *shProg;
60 shProg = CALLOC_STRUCT(gl_shader_program);
61 if (shProg) {
Brianf3e8c322007-04-18 14:53:23 -060062 shProg->Type = GL_SHADER_PROGRAM_MESA;
Brianf2923612006-12-20 09:56:44 -070063 shProg->Name = name;
64 shProg->RefCount = 1;
Brian3209c3e2007-01-09 17:49:24 -070065 shProg->Attributes = _mesa_new_parameter_list();
Brianf2923612006-12-20 09:56:44 -070066 }
67 return shProg;
68}
69
70
Brianb9fbedd2007-03-26 09:23:44 -060071/**
Brian3c008a02007-04-12 15:22:32 -060072 * Clear (free) the shader program state that gets produced by linking.
Brianb9fbedd2007-03-26 09:23:44 -060073 */
Brianf2923612006-12-20 09:56:44 -070074void
Brian3c008a02007-04-12 15:22:32 -060075_mesa_clear_shader_program_data(GLcontext *ctx,
76 struct gl_shader_program *shProg)
Brianf2923612006-12-20 09:56:44 -070077{
Brian Paul8bdf5b62008-05-16 09:56:59 -060078 _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL);
79 _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL);
Brianf2923612006-12-20 09:56:44 -070080
Brianf2923612006-12-20 09:56:44 -070081 if (shProg->Uniforms) {
Brian Paulade50832008-05-14 16:09:46 -060082 _mesa_free_uniform_list(shProg->Uniforms);
Brianf2923612006-12-20 09:56:44 -070083 shProg->Uniforms = NULL;
84 }
85
86 if (shProg->Varying) {
87 _mesa_free_parameter_list(shProg->Varying);
88 shProg->Varying = NULL;
89 }
90}
91
92
Brianb9fbedd2007-03-26 09:23:44 -060093/**
Brian3c008a02007-04-12 15:22:32 -060094 * Free all the data that hangs off a shader program object, but not the
95 * object itself.
96 */
97void
98_mesa_free_shader_program_data(GLcontext *ctx,
99 struct gl_shader_program *shProg)
100{
101 GLuint i;
102
Brianf3e8c322007-04-18 14:53:23 -0600103 assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
Brian3c008a02007-04-12 15:22:32 -0600104
105 _mesa_clear_shader_program_data(ctx, shProg);
106
Brian4b7c6fc2007-04-19 15:23:34 -0600107 if (shProg->Attributes) {
108 _mesa_free_parameter_list(shProg->Attributes);
109 shProg->Attributes = NULL;
110 }
111
Brian3c008a02007-04-12 15:22:32 -0600112 /* detach shaders */
113 for (i = 0; i < shProg->NumShaders; i++) {
114 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
115 }
Xiang, Haihao63d8a842008-03-31 17:02:47 +0800116 shProg->NumShaders = 0;
117
Brian3c008a02007-04-12 15:22:32 -0600118 if (shProg->Shaders) {
119 _mesa_free(shProg->Shaders);
120 shProg->Shaders = NULL;
121 }
Alan Hourihaneeec20c32008-04-22 20:29:42 +0100122
123 if (shProg->InfoLog) {
124 _mesa_free(shProg->InfoLog);
125 shProg->InfoLog = NULL;
126 }
Brian3c008a02007-04-12 15:22:32 -0600127}
128
129
130/**
Brianb9fbedd2007-03-26 09:23:44 -0600131 * Free/delete a shader program object.
132 */
Brianf2923612006-12-20 09:56:44 -0700133void
134_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg)
135{
136 _mesa_free_shader_program_data(ctx, shProg);
Alan Hourihaneeec20c32008-04-22 20:29:42 +0100137
Brianf2923612006-12-20 09:56:44 -0700138 _mesa_free(shProg);
139}
140
141
142/**
Brian3c008a02007-04-12 15:22:32 -0600143 * Set ptr to point to shProg.
144 * If ptr is pointing to another object, decrement its refcount (and delete
145 * if refcount hits zero).
146 * Then set ptr to point to shProg, incrementing its refcount.
147 */
148/* XXX this could be static */
149void
150_mesa_reference_shader_program(GLcontext *ctx,
151 struct gl_shader_program **ptr,
152 struct gl_shader_program *shProg)
153{
154 assert(ptr);
155 if (*ptr == shProg) {
156 /* no-op */
157 return;
158 }
159 if (*ptr) {
160 /* Unreference the old shader program */
161 GLboolean deleteFlag = GL_FALSE;
162 struct gl_shader_program *old = *ptr;
163
164 ASSERT(old->RefCount > 0);
165 old->RefCount--;
Brian Paul8bdf5b62008-05-16 09:56:59 -0600166#if 0
167 printf("ShaderProgram %p ID=%u RefCount-- to %d\n",
168 (void *) old, old->Name, old->RefCount);
169#endif
Brian3c008a02007-04-12 15:22:32 -0600170 deleteFlag = (old->RefCount == 0);
171
172 if (deleteFlag) {
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800173 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
Brian3c008a02007-04-12 15:22:32 -0600174 _mesa_free_shader_program(ctx, old);
175 }
176
177 *ptr = NULL;
178 }
179 assert(!*ptr);
180
181 if (shProg) {
182 shProg->RefCount++;
Brian Paul8bdf5b62008-05-16 09:56:59 -0600183#if 0
184 printf("ShaderProgram %p ID=%u RefCount++ to %d\n",
185 (void *) shProg, shProg->Name, shProg->RefCount);
186#endif
Brian3c008a02007-04-12 15:22:32 -0600187 *ptr = shProg;
188 }
189}
190
191
192/**
Brianf2923612006-12-20 09:56:44 -0700193 * Lookup a GLSL program object.
194 */
195struct gl_shader_program *
196_mesa_lookup_shader_program(GLcontext *ctx, GLuint name)
197{
198 struct gl_shader_program *shProg;
199 if (name) {
200 shProg = (struct gl_shader_program *)
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800201 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
Brianf2923612006-12-20 09:56:44 -0700202 /* Note that both gl_shader and gl_shader_program objects are kept
203 * in the same hash table. Check the object's type to be sure it's
204 * what we're expecting.
205 */
Brianf3e8c322007-04-18 14:53:23 -0600206 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700207 return NULL;
208 }
209 return shProg;
210 }
211 return NULL;
212}
213
214
215/**
Brian Paul530df582008-07-03 16:21:11 -0600216 * As above, but record an error if program is not found.
217 */
218static struct gl_shader_program *
219_mesa_lookup_shader_program_err(GLcontext *ctx, GLuint name,
220 const char *caller)
221{
222 if (!name) {
223 _mesa_error(ctx, GL_INVALID_VALUE, caller);
224 return NULL;
225 }
226 else {
227 struct gl_shader_program *shProg = (struct gl_shader_program *)
228 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
229 if (!shProg) {
230 _mesa_error(ctx, GL_INVALID_VALUE, caller);
231 return NULL;
232 }
233 if (shProg->Type != GL_SHADER_PROGRAM_MESA) {
234 _mesa_error(ctx, GL_INVALID_OPERATION, caller);
235 return NULL;
236 }
237 return shProg;
238 }
239}
240
241
242
243
244/**
Brianf2923612006-12-20 09:56:44 -0700245 * Allocate a new gl_shader object, initialize it.
246 */
247struct gl_shader *
248_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
249{
250 struct gl_shader *shader;
251 assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
252 shader = CALLOC_STRUCT(gl_shader);
253 if (shader) {
254 shader->Type = type;
255 shader->Name = name;
256 shader->RefCount = 1;
257 }
258 return shader;
259}
260
261
262void
263_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh)
264{
Brianf2923612006-12-20 09:56:44 -0700265 if (sh->Source)
266 _mesa_free((void *) sh->Source);
267 if (sh->InfoLog)
268 _mesa_free(sh->InfoLog);
Brian Paul3d500f02008-07-24 14:56:54 -0600269 _mesa_reference_program(ctx, &sh->Program, NULL);
Brianf2923612006-12-20 09:56:44 -0700270 _mesa_free(sh);
271}
272
273
274/**
Brian3c008a02007-04-12 15:22:32 -0600275 * Set ptr to point to sh.
276 * If ptr is pointing to another shader, decrement its refcount (and delete
277 * if refcount hits zero).
278 * Then set ptr to point to sh, incrementing its refcount.
279 */
280/* XXX this could be static */
281void
282_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr,
283 struct gl_shader *sh)
284{
285 assert(ptr);
286 if (*ptr == sh) {
287 /* no-op */
288 return;
289 }
290 if (*ptr) {
291 /* Unreference the old shader */
292 GLboolean deleteFlag = GL_FALSE;
293 struct gl_shader *old = *ptr;
294
295 ASSERT(old->RefCount > 0);
296 old->RefCount--;
Brian99193e42007-04-12 15:45:02 -0600297 /*printf("SHADER DECR %p (%d) to %d\n",
298 (void*) old, old->Name, old->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600299 deleteFlag = (old->RefCount == 0);
300
301 if (deleteFlag) {
302 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
303 _mesa_free_shader(ctx, old);
304 }
305
306 *ptr = NULL;
307 }
308 assert(!*ptr);
309
310 if (sh) {
311 /* reference new */
312 sh->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600313 /*printf("SHADER INCR %p (%d) to %d\n",
314 (void*) sh, sh->Name, sh->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600315 *ptr = sh;
316 }
317}
318
319
320/**
Brianf2923612006-12-20 09:56:44 -0700321 * Lookup a GLSL shader object.
322 */
323struct gl_shader *
324_mesa_lookup_shader(GLcontext *ctx, GLuint name)
325{
326 if (name) {
327 struct gl_shader *sh = (struct gl_shader *)
328 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
329 /* Note that both gl_shader and gl_shader_program objects are kept
330 * in the same hash table. Check the object's type to be sure it's
331 * what we're expecting.
332 */
Brianf3e8c322007-04-18 14:53:23 -0600333 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700334 return NULL;
335 }
336 return sh;
337 }
338 return NULL;
339}
340
341
Brianfa4d0362007-02-26 18:33:50 -0700342/**
Brian Paul530df582008-07-03 16:21:11 -0600343 * As above, but record an error if shader is not found.
344 */
345static struct gl_shader *
346_mesa_lookup_shader_err(GLcontext *ctx, GLuint name, const char *caller)
347{
348 if (!name) {
349 _mesa_error(ctx, GL_INVALID_VALUE, caller);
350 return NULL;
351 }
352 else {
353 struct gl_shader *sh = (struct gl_shader *)
354 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
355 if (!sh) {
356 _mesa_error(ctx, GL_INVALID_VALUE, caller);
357 return NULL;
358 }
359 if (sh->Type == GL_SHADER_PROGRAM_MESA) {
360 _mesa_error(ctx, GL_INVALID_OPERATION, caller);
361 return NULL;
362 }
363 return sh;
364 }
365}
366
367
368
369/**
Brianfa4d0362007-02-26 18:33:50 -0700370 * Initialize context's shader state.
371 */
Brianf2923612006-12-20 09:56:44 -0700372void
373_mesa_init_shader_state(GLcontext * ctx)
374{
Brianfa4d0362007-02-26 18:33:50 -0700375 /* Device drivers may override these to control what kind of instructions
376 * are generated by the GLSL compiler.
377 */
378 ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
Brian63556fa2007-03-23 14:47:46 -0600379 ctx->Shader.EmitCondCodes = GL_TRUE; /* XXX probably want GL_FALSE... */
Brianfa4d0362007-02-26 18:33:50 -0700380 ctx->Shader.EmitComments = GL_FALSE;
Brianf2923612006-12-20 09:56:44 -0700381}
382
383
Brian5b01c5e2006-12-19 18:02:03 -0700384/**
Brian935f93f2007-03-24 16:20:02 -0600385 * Free the per-context shader-related state.
386 */
387void
388_mesa_free_shader_state(GLcontext *ctx)
389{
Brian3c008a02007-04-12 15:22:32 -0600390 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
Brian935f93f2007-03-24 16:20:02 -0600391}
392
393
394/**
Brian5b01c5e2006-12-19 18:02:03 -0700395 * Copy string from <src> to <dst>, up to maxLength characters, returning
396 * length of <dst> in <length>.
397 * \param src the strings source
398 * \param maxLength max chars to copy
399 * \param length returns number of chars copied
400 * \param dst the string destination
401 */
402static void
403copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
404{
405 GLsizei len;
406 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
407 dst[len] = src[len];
408 if (maxLength > 0)
409 dst[len] = 0;
410 if (length)
411 *length = len;
412}
413
414
Brian Paul7acb7c12008-07-03 13:49:48 -0600415static GLboolean
416_mesa_is_program(GLcontext *ctx, GLuint name)
417{
418 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
419 return shProg ? GL_TRUE : GL_FALSE;
420}
421
422
423static GLboolean
424_mesa_is_shader(GLcontext *ctx, GLuint name)
425{
426 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
427 return shader ? GL_TRUE : GL_FALSE;
428}
429
430
Brian5b01c5e2006-12-19 18:02:03 -0700431/**
432 * Called via ctx->Driver.AttachShader()
433 */
Brian Paulfd59f192008-05-18 16:04:55 -0600434static void
Brian5b01c5e2006-12-19 18:02:03 -0700435_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
436{
Brian Paul530df582008-07-03 16:21:11 -0600437 struct gl_shader_program *shProg;
438 struct gl_shader *sh;
439 GLuint i, n;
Brian5b01c5e2006-12-19 18:02:03 -0700440
Brian Paul530df582008-07-03 16:21:11 -0600441 shProg = _mesa_lookup_shader_program_err(ctx, program, "glAttachShader");
442 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700443 return;
Brian5b01c5e2006-12-19 18:02:03 -0700444
Brian Paul530df582008-07-03 16:21:11 -0600445 sh = _mesa_lookup_shader_err(ctx, shader, "glAttachShader");
Brian Paul7acb7c12008-07-03 13:49:48 -0600446 if (!sh) {
Brian Paul7acb7c12008-07-03 13:49:48 -0600447 return;
448 }
449
Brian237b9852007-08-07 21:48:31 +0100450 n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700451 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700452 if (shProg->Shaders[i] == sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700453 /* already attached */
454 return;
Brian34ae99d2006-12-18 08:28:54 -0700455 }
456 }
Brian5b01c5e2006-12-19 18:02:03 -0700457
458 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700459 shProg->Shaders = (struct gl_shader **)
460 _mesa_realloc(shProg->Shaders,
461 n * sizeof(struct gl_shader *),
462 (n + 1) * sizeof(struct gl_shader *));
463 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700464 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
465 return;
466 }
467
468 /* append */
Brian3c008a02007-04-12 15:22:32 -0600469 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
470 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700471 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700472}
473
474
Brian Paulfd59f192008-05-18 16:04:55 -0600475static GLint
Brian Paul896c0cc2008-05-16 15:47:55 -0600476_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
477 const GLchar *name)
478{
479 struct gl_shader_program *shProg
Brian Paul530df582008-07-03 16:21:11 -0600480 = _mesa_lookup_shader_program_err(ctx, program, "glGetAttribLocation");
Brian Paul896c0cc2008-05-16 15:47:55 -0600481
482 if (!shProg) {
Brian Paul896c0cc2008-05-16 15:47:55 -0600483 return -1;
484 }
485
486 if (!shProg->LinkStatus) {
487 _mesa_error(ctx, GL_INVALID_OPERATION,
488 "glGetAttribLocation(program not linked)");
489 return -1;
490 }
491
492 if (!name)
493 return -1;
494
Brian Paul27341a92008-09-16 16:28:36 -0600495 if (shProg->VertexProgram) {
496 const struct gl_program_parameter_list *attribs =
497 shProg->VertexProgram->Base.Attributes;
498 if (attribs) {
499 GLint i = _mesa_lookup_parameter_index(attribs, -1, name);
500 if (i >= 0) {
501 return attribs->Parameters[i].StateIndexes[0];
502 }
Brian Paul896c0cc2008-05-16 15:47:55 -0600503 }
504 }
505 return -1;
506}
507
508
Brian Paulfd59f192008-05-18 16:04:55 -0600509static void
Brian5b01c5e2006-12-19 18:02:03 -0700510_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
511 const GLchar *name)
512{
Brian Paul530df582008-07-03 16:21:11 -0600513 struct gl_shader_program *shProg;
Brianb7978af2007-01-09 19:17:17 -0700514 const GLint size = -1; /* unknown size */
Brian Paul6bc87492008-07-25 08:34:54 -0600515 GLint i, oldIndex;
Brian Paul6f1abb92008-07-29 17:27:22 -0600516 GLenum datatype = GL_FLOAT_VEC4;
Brian5b01c5e2006-12-19 18:02:03 -0700517
Brian Paul530df582008-07-03 16:21:11 -0600518 shProg = _mesa_lookup_shader_program_err(ctx, program,
519 "glBindAttribLocation");
Brian65a18442006-12-19 18:46:56 -0700520 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700521 return;
522 }
523
Brian9e4bae92006-12-20 09:27:42 -0700524 if (!name)
525 return;
526
527 if (strncmp(name, "gl_", 3) == 0) {
528 _mesa_error(ctx, GL_INVALID_OPERATION,
529 "glBindAttribLocation(illegal name)");
530 return;
531 }
532
Brian Paul7acb7c12008-07-03 13:49:48 -0600533 if (index >= ctx->Const.VertexProgram.MaxAttribs) {
534 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
535 return;
536 }
537
Brian Paul6bc87492008-07-25 08:34:54 -0600538 if (shProg->LinkStatus) {
539 /* get current index/location for the attribute */
540 oldIndex = _mesa_get_attrib_location(ctx, program, name);
541 }
542 else {
543 oldIndex = -1;
544 }
545
Brian3209c3e2007-01-09 17:49:24 -0700546 /* this will replace the current value if it's already in the list */
Brian Paulffbc66b2008-07-21 13:58:50 -0600547 i = _mesa_add_attribute(shProg->Attributes, name, size, datatype, index);
Brian3209c3e2007-01-09 17:49:24 -0700548 if (i < 0) {
549 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
Brian Paul6f1abb92008-07-29 17:27:22 -0600550 return;
Brian3209c3e2007-01-09 17:49:24 -0700551 }
552
Brian Paul27341a92008-09-16 16:28:36 -0600553 /*
554 * Note that this attribute binding won't go into effect until
555 * glLinkProgram is called again.
556 */
Brian34ae99d2006-12-18 08:28:54 -0700557}
558
559
Brian Paulfd59f192008-05-18 16:04:55 -0600560static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700561_mesa_create_shader(GLcontext *ctx, GLenum type)
562{
Brian65a18442006-12-19 18:46:56 -0700563 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700564 GLuint name;
565
566 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
567
568 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700569 case GL_FRAGMENT_SHADER:
570 case GL_VERTEX_SHADER:
571 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700572 break;
573 default:
574 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
575 return 0;
576 }
577
Brian65a18442006-12-19 18:46:56 -0700578 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700579
580 return name;
581}
582
583
Brian Paulfd59f192008-05-18 16:04:55 -0600584static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700585_mesa_create_program(GLcontext *ctx)
586{
587 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700588 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700589
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800590 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
Brian65a18442006-12-19 18:46:56 -0700591 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700592
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800593 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700594
Brian3c008a02007-04-12 15:22:32 -0600595 assert(shProg->RefCount == 1);
596
Brian5b01c5e2006-12-19 18:02:03 -0700597 return name;
598}
599
600
Brian3c008a02007-04-12 15:22:32 -0600601/**
602 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
603 * DeleteProgramARB.
604 */
Brian Paulfd59f192008-05-18 16:04:55 -0600605static void
Brian5b01c5e2006-12-19 18:02:03 -0700606_mesa_delete_program2(GLcontext *ctx, GLuint name)
607{
Brian3c008a02007-04-12 15:22:32 -0600608 /*
609 * NOTE: deleting shaders/programs works a bit differently than
610 * texture objects (and buffer objects, etc). Shader/program
611 * handles/IDs exist in the hash table until the object is really
612 * deleted (refcount==0). With texture objects, the handle/ID is
613 * removed from the hash table in glDeleteTextures() while the tex
614 * object itself might linger until its refcount goes to zero.
615 */
Brian65a18442006-12-19 18:46:56 -0700616 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700617
Brian Paul530df582008-07-03 16:21:11 -0600618 shProg = _mesa_lookup_shader_program_err(ctx, name, "glDeleteProgram");
619 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700620 return;
Brian5b01c5e2006-12-19 18:02:03 -0700621
Brian9e4bae92006-12-20 09:27:42 -0700622 shProg->DeletePending = GL_TRUE;
623
Brian3c008a02007-04-12 15:22:32 -0600624 /* effectively, decr shProg's refcount */
625 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700626}
627
628
Brian Paulfd59f192008-05-18 16:04:55 -0600629static void
Brian5b01c5e2006-12-19 18:02:03 -0700630_mesa_delete_shader(GLcontext *ctx, GLuint shader)
631{
Brian Paul530df582008-07-03 16:21:11 -0600632 struct gl_shader *sh;
633
634 sh = _mesa_lookup_shader_err(ctx, shader, "glDeleteShader");
635 if (!sh)
Brian9e4bae92006-12-20 09:27:42 -0700636 return;
Brian5b01c5e2006-12-19 18:02:03 -0700637
Brian9e4bae92006-12-20 09:27:42 -0700638 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600639
640 /* effectively, decr sh's refcount */
641 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700642}
643
644
Brian Paulfd59f192008-05-18 16:04:55 -0600645static void
Brian5b01c5e2006-12-19 18:02:03 -0700646_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
647{
Brian Paul530df582008-07-03 16:21:11 -0600648 struct gl_shader_program *shProg;
Brian237b9852007-08-07 21:48:31 +0100649 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700650 GLuint i, j;
651
Brian Paul530df582008-07-03 16:21:11 -0600652 shProg = _mesa_lookup_shader_program_err(ctx, program, "glDetachShader");
653 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700654 return;
Brian5b01c5e2006-12-19 18:02:03 -0700655
Brian237b9852007-08-07 21:48:31 +0100656 n = shProg->NumShaders;
657
Brian5b01c5e2006-12-19 18:02:03 -0700658 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700659 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700660 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600661 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700662
Brian Paul530df582008-07-03 16:21:11 -0600663 /* release */
Brian3c008a02007-04-12 15:22:32 -0600664 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700665
Brian5b01c5e2006-12-19 18:02:03 -0700666 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700667 newList = (struct gl_shader **)
668 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700669 if (!newList) {
670 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
671 return;
672 }
673 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700674 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700675 }
676 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700677 newList[j++] = shProg->Shaders[i];
678 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700679
Brian65a18442006-12-19 18:46:56 -0700680 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600681 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600682
683#ifdef DEBUG
684 /* sanity check */
685 {
686 for (j = 0; j < shProg->NumShaders; j++) {
687 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
688 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
689 assert(shProg->Shaders[j]->RefCount > 0);
690 }
691 }
692#endif
693
Brian5b01c5e2006-12-19 18:02:03 -0700694 return;
695 }
696 }
697
698 /* not found */
Brian Paul530df582008-07-03 16:21:11 -0600699 {
700 GLenum err;
701 if (_mesa_is_shader(ctx, shader))
702 err = GL_INVALID_OPERATION;
703 else if (_mesa_is_program(ctx, shader))
704 err = GL_INVALID_OPERATION;
705 else
706 err = GL_INVALID_VALUE;
707 _mesa_error(ctx, err, "glDetachProgram(shader)");
708 return;
709 }
Brian5b01c5e2006-12-19 18:02:03 -0700710}
711
712
Brian Paulffbc66b2008-07-21 13:58:50 -0600713static GLint
714sizeof_glsl_type(GLenum type)
715{
716 switch (type) {
717 case GL_FLOAT:
718 case GL_INT:
719 case GL_BOOL:
Brian Paul8c51e002008-08-11 15:09:47 -0600720 case GL_SAMPLER_1D:
721 case GL_SAMPLER_2D:
722 case GL_SAMPLER_3D:
723 case GL_SAMPLER_CUBE:
724 case GL_SAMPLER_1D_SHADOW:
725 case GL_SAMPLER_2D_SHADOW:
726 case GL_SAMPLER_2D_RECT_ARB:
727 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
728 case GL_SAMPLER_1D_ARRAY_SHADOW_EXT:
729 case GL_SAMPLER_2D_ARRAY_SHADOW_EXT:
730 case GL_SAMPLER_CUBE_SHADOW_EXT:
Brian Paulffbc66b2008-07-21 13:58:50 -0600731 return 1;
732 case GL_FLOAT_VEC2:
733 case GL_INT_VEC2:
734 case GL_BOOL_VEC2:
735 return 2;
736 case GL_FLOAT_VEC3:
737 case GL_INT_VEC3:
738 case GL_BOOL_VEC3:
739 return 3;
740 case GL_FLOAT_VEC4:
741 case GL_INT_VEC4:
742 case GL_BOOL_VEC4:
743 return 4;
744 case GL_FLOAT_MAT2:
745 case GL_FLOAT_MAT2x3:
746 case GL_FLOAT_MAT2x4:
747 return 8; /* two float[4] vectors */
748 case GL_FLOAT_MAT3:
749 case GL_FLOAT_MAT3x2:
750 case GL_FLOAT_MAT3x4:
751 return 12; /* three float[4] vectors */
752 case GL_FLOAT_MAT4:
753 case GL_FLOAT_MAT4x2:
754 case GL_FLOAT_MAT4x3:
755 return 16; /* four float[4] vectors */
756 default:
757 _mesa_problem(NULL, "Invalid type in sizeof_glsl_type()");
758 return 1;
759 }
760}
761
762
Brian Paulfd59f192008-05-18 16:04:55 -0600763static void
Brian5b01c5e2006-12-19 18:02:03 -0700764_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
765 GLsizei maxLength, GLsizei *length, GLint *size,
766 GLenum *type, GLchar *nameOut)
767{
Brian Paul27341a92008-09-16 16:28:36 -0600768 const struct gl_program_parameter_list *attribs = NULL;
Brian Paul530df582008-07-03 16:21:11 -0600769 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700770
Brian Paul530df582008-07-03 16:21:11 -0600771 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveAttrib");
772 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700773 return;
Brian5b01c5e2006-12-19 18:02:03 -0700774
Brian Paul27341a92008-09-16 16:28:36 -0600775 if (shProg->VertexProgram)
776 attribs = shProg->VertexProgram->Base.Attributes;
777
778 if (!attribs || index >= attribs->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600779 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700780 return;
781 }
782
Brian Paul27341a92008-09-16 16:28:36 -0600783 copy_string(nameOut, maxLength, length, attribs->Parameters[index].Name);
784
Brian5b01c5e2006-12-19 18:02:03 -0700785 if (size)
Brian Paul27341a92008-09-16 16:28:36 -0600786 *size = attribs->Parameters[index].Size
787 / sizeof_glsl_type(attribs->Parameters[index].DataType);
788
Brian Paulade50832008-05-14 16:09:46 -0600789 if (type)
Brian Paul27341a92008-09-16 16:28:36 -0600790 *type = attribs->Parameters[index].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700791}
792
793
794/**
795 * Called via ctx->Driver.GetActiveUniform().
796 */
Brian Paulfd59f192008-05-18 16:04:55 -0600797static void
Brian5b01c5e2006-12-19 18:02:03 -0700798_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
799 GLsizei maxLength, GLsizei *length, GLint *size,
800 GLenum *type, GLchar *nameOut)
801{
Brian Paul530df582008-07-03 16:21:11 -0600802 const struct gl_shader_program *shProg;
Brian Paulade50832008-05-14 16:09:46 -0600803 const struct gl_program *prog;
804 GLint progPos;
Brian5b01c5e2006-12-19 18:02:03 -0700805
Brian Paul530df582008-07-03 16:21:11 -0600806 shProg = _mesa_lookup_shader_program_err(ctx, program, "glGetActiveUniform");
807 if (!shProg)
Brian5b01c5e2006-12-19 18:02:03 -0700808 return;
Brian5b01c5e2006-12-19 18:02:03 -0700809
Brian Paulade50832008-05-14 16:09:46 -0600810 if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
Brian5b01c5e2006-12-19 18:02:03 -0700811 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
812 return;
813 }
814
Brian Paulade50832008-05-14 16:09:46 -0600815 progPos = shProg->Uniforms->Uniforms[index].VertPos;
816 if (progPos >= 0) {
817 prog = &shProg->VertexProgram->Base;
818 }
819 else {
820 progPos = shProg->Uniforms->Uniforms[index].FragPos;
821 if (progPos >= 0) {
822 prog = &shProg->FragmentProgram->Base;
Brian274ac7a2007-04-18 16:05:53 -0600823 }
824 }
825
Brian Paulade50832008-05-14 16:09:46 -0600826 if (!prog || progPos < 0)
827 return; /* should never happen */
828
829 if (nameOut)
830 copy_string(nameOut, maxLength, length,
831 prog->Parameters->Parameters[progPos].Name);
832 if (size)
Brian Paulffbc66b2008-07-21 13:58:50 -0600833 *size = prog->Parameters->Parameters[progPos].Size
834 / sizeof_glsl_type(prog->Parameters->Parameters[progPos].DataType);
Brian Paulade50832008-05-14 16:09:46 -0600835 if (type)
836 *type = prog->Parameters->Parameters[progPos].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700837}
838
839
840/**
841 * Called via ctx->Driver.GetAttachedShaders().
842 */
Brian Paulfd59f192008-05-18 16:04:55 -0600843static void
Brian5b01c5e2006-12-19 18:02:03 -0700844_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
845 GLsizei *count, GLuint *obj)
846{
Brian Paul530df582008-07-03 16:21:11 -0600847 struct gl_shader_program *shProg =
848 _mesa_lookup_shader_program_err(ctx, program, "glGetAttachedShaders");
Brian65a18442006-12-19 18:46:56 -0700849 if (shProg) {
Brian Paul530df582008-07-03 16:21:11 -0600850 GLuint i;
851 for (i = 0; i < (GLuint) maxCount && i < shProg->NumShaders; i++) {
Brian65a18442006-12-19 18:46:56 -0700852 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700853 }
854 if (count)
855 *count = i;
856 }
Brian5b01c5e2006-12-19 18:02:03 -0700857}
858
859
Brian Paulfd59f192008-05-18 16:04:55 -0600860static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700861_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700862{
863#if 0
864 GET_CURRENT_CONTEXT(ctx);
865
866 switch (pname) {
867 case GL_PROGRAM_OBJECT_ARB:
868 {
Brian5b01c5e2006-12-19 18:02:03 -0700869 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700870
871 if (pro != NULL)
872 return (**pro)._container._generic.
873 GetName((struct gl2_generic_intf **) (pro));
874 }
875 break;
876 default:
877 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
878 }
879#endif
880 return 0;
881}
882
883
Brian Paulfd59f192008-05-18 16:04:55 -0600884static void
Brian5b01c5e2006-12-19 18:02:03 -0700885_mesa_get_programiv(GLcontext *ctx, GLuint program,
886 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700887{
Brian Paul27341a92008-09-16 16:28:36 -0600888 const struct gl_program_parameter_list *attribs;
Brian65a18442006-12-19 18:46:56 -0700889 struct gl_shader_program *shProg
890 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700891
Brian65a18442006-12-19 18:46:56 -0700892 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700893 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700894 return;
895 }
896
Brian Paul27341a92008-09-16 16:28:36 -0600897 if (shProg->VertexProgram)
898 attribs = shProg->VertexProgram->Base.Attributes;
899 else
900 attribs = NULL;
901
Brian5b01c5e2006-12-19 18:02:03 -0700902 switch (pname) {
903 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700904 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700905 break;
906 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700907 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700908 break;
Brian5b01c5e2006-12-19 18:02:03 -0700909 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700910 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700911 break;
912 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600913 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700914 break;
915 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700916 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700917 break;
918 case GL_ACTIVE_ATTRIBUTES:
Brian Paul27341a92008-09-16 16:28:36 -0600919 *params = attribs ? attribs->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700920 break;
921 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian Paul27341a92008-09-16 16:28:36 -0600922 *params = _mesa_longest_parameter_name(attribs, PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700923 break;
924 case GL_ACTIVE_UNIFORMS:
Brian Paulade50832008-05-14 16:09:46 -0600925 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700926 break;
927 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian Paulade50832008-05-14 16:09:46 -0600928 *params = _mesa_longest_uniform_name(shProg->Uniforms);
Brian274ac7a2007-04-18 16:05:53 -0600929 if (*params > 0)
930 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700931 break;
932 default:
Brian5b01c5e2006-12-19 18:02:03 -0700933 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
934 return;
Brian34ae99d2006-12-18 08:28:54 -0700935 }
Brian5b01c5e2006-12-19 18:02:03 -0700936}
Brian34ae99d2006-12-18 08:28:54 -0700937
Brian34ae99d2006-12-18 08:28:54 -0700938
Brian Paulfd59f192008-05-18 16:04:55 -0600939static void
Brian5b01c5e2006-12-19 18:02:03 -0700940_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
941{
Brian Paul530df582008-07-03 16:21:11 -0600942 struct gl_shader *shader = _mesa_lookup_shader_err(ctx, name, "glGetShaderiv");
Brian5b01c5e2006-12-19 18:02:03 -0700943
944 if (!shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700945 return;
946 }
Brian65a18442006-12-19 18:46:56 -0700947
Brian5b01c5e2006-12-19 18:02:03 -0700948 switch (pname) {
949 case GL_SHADER_TYPE:
950 *params = shader->Type;
951 break;
952 case GL_DELETE_STATUS:
953 *params = shader->DeletePending;
954 break;
955 case GL_COMPILE_STATUS:
956 *params = shader->CompileStatus;
957 break;
958 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600959 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700960 break;
961 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600962 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700963 break;
964 default:
965 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
966 return;
967 }
968}
969
970
Brian Paulfd59f192008-05-18 16:04:55 -0600971static void
Brian5b01c5e2006-12-19 18:02:03 -0700972_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
973 GLsizei *length, GLchar *infoLog)
974{
Brian65a18442006-12-19 18:46:56 -0700975 struct gl_shader_program *shProg
976 = _mesa_lookup_shader_program(ctx, program);
977 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700978 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
979 return;
980 }
Brian65a18442006-12-19 18:46:56 -0700981 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700982}
983
984
Brian Paulfd59f192008-05-18 16:04:55 -0600985static void
Brian5b01c5e2006-12-19 18:02:03 -0700986_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
987 GLsizei *length, GLchar *infoLog)
988{
Brian65a18442006-12-19 18:46:56 -0700989 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
990 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700991 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
992 return;
993 }
Brian65a18442006-12-19 18:46:56 -0700994 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700995}
996
997
998/**
999 * Called via ctx->Driver.GetShaderSource().
1000 */
Brian Paulfd59f192008-05-18 16:04:55 -06001001static void
Brian5b01c5e2006-12-19 18:02:03 -07001002_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
1003 GLsizei *length, GLchar *sourceOut)
1004{
Brian Paul530df582008-07-03 16:21:11 -06001005 struct gl_shader *sh;
1006 sh = _mesa_lookup_shader_err(ctx, shader, "glGetShaderSource");
Brian65a18442006-12-19 18:46:56 -07001007 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001008 return;
1009 }
Brian65a18442006-12-19 18:46:56 -07001010 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -07001011}
1012
1013
Brian Paul2be54a82008-07-08 16:17:04 -06001014#define MAX_UNIFORM_ELEMENTS 16
1015
Brian5b01c5e2006-12-19 18:02:03 -07001016/**
Brian Paul2be54a82008-07-08 16:17:04 -06001017 * Helper for GetUniformfv(), GetUniformiv()
1018 * Returns number of elements written to 'params' output.
Brian5b01c5e2006-12-19 18:02:03 -07001019 */
Brian Paul2be54a82008-07-08 16:17:04 -06001020static GLuint
1021get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1022 GLfloat *params)
Brian5b01c5e2006-12-19 18:02:03 -07001023{
Brian65a18442006-12-19 18:46:56 -07001024 struct gl_shader_program *shProg
1025 = _mesa_lookup_shader_program(ctx, program);
1026 if (shProg) {
Brian Paul6cb12702008-06-28 16:48:31 -06001027 if (shProg->Uniforms &&
Brian Paul016701f2008-07-29 17:43:35 -06001028 location >= 0 && location < (GLint) shProg->Uniforms->NumUniforms) {
Brian Paul6cb12702008-06-28 16:48:31 -06001029 GLint progPos;
1030 GLuint i;
Brian Paulf2632212008-05-16 10:49:44 -06001031 const struct gl_program *prog = NULL;
Brian Paulade50832008-05-14 16:09:46 -06001032
1033 progPos = shProg->Uniforms->Uniforms[location].VertPos;
1034 if (progPos >= 0) {
1035 prog = &shProg->VertexProgram->Base;
Brian5b01c5e2006-12-19 18:02:03 -07001036 }
Brian Paulade50832008-05-14 16:09:46 -06001037 else {
1038 progPos = shProg->Uniforms->Uniforms[location].FragPos;
1039 if (progPos >= 0) {
1040 prog = &shProg->FragmentProgram->Base;
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001041 }
Brian Paulade50832008-05-14 16:09:46 -06001042 }
1043
Brian Paulf2632212008-05-16 10:49:44 -06001044 ASSERT(prog);
1045 if (prog) {
Brian Paul2be54a82008-07-08 16:17:04 -06001046 /* See uniformiv() below */
1047 assert(prog->Parameters->Parameters[progPos].Size <= MAX_UNIFORM_ELEMENTS);
1048
Brian Paulf2632212008-05-16 10:49:44 -06001049 for (i = 0; i < prog->Parameters->Parameters[progPos].Size; i++) {
1050 params[i] = prog->Parameters->ParameterValues[progPos][i];
1051 }
Brian Paul2be54a82008-07-08 16:17:04 -06001052 return prog->Parameters->Parameters[progPos].Size;
Brian Paulade50832008-05-14 16:09:46 -06001053 }
Brian5b01c5e2006-12-19 18:02:03 -07001054 }
1055 else {
Brian Paul6cb12702008-06-28 16:48:31 -06001056 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
Brian5b01c5e2006-12-19 18:02:03 -07001057 }
1058 }
1059 else {
Brian Paul6cb12702008-06-28 16:48:31 -06001060 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
Brian5b01c5e2006-12-19 18:02:03 -07001061 }
Brian Paul2be54a82008-07-08 16:17:04 -06001062 return 0;
1063}
1064
1065
1066/**
1067 * Called via ctx->Driver.GetUniformfv().
1068 */
1069static void
1070_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
1071 GLfloat *params)
1072{
1073 (void) get_uniformfv(ctx, program, location, params);
1074}
1075
1076
1077/**
1078 * Called via ctx->Driver.GetUniformiv().
1079 */
1080static void
1081_mesa_get_uniformiv(GLcontext *ctx, GLuint program, GLint location,
1082 GLint *params)
1083{
1084 GLfloat fparams[MAX_UNIFORM_ELEMENTS];
1085 GLuint n = get_uniformfv(ctx, program, location, fparams);
1086 GLuint i;
1087 assert(n <= MAX_UNIFORM_ELEMENTS);
1088 for (i = 0; i < n; i++) {
1089 params[i] = (GLint) fparams[i];
1090 }
Brian5b01c5e2006-12-19 18:02:03 -07001091}
1092
1093
1094/**
1095 * Called via ctx->Driver.GetUniformLocation().
1096 */
Brian Paulfd59f192008-05-18 16:04:55 -06001097static GLint
Brian5b01c5e2006-12-19 18:02:03 -07001098_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
1099{
Brian Paul530df582008-07-03 16:21:11 -06001100 struct gl_shader_program *shProg =
1101 _mesa_lookup_shader_program_err(ctx, program, "glGetUniformLocation");
1102
Brian Paulade50832008-05-14 16:09:46 -06001103 if (!shProg)
1104 return -1;
Brian5b01c5e2006-12-19 18:02:03 -07001105
Brian Paule06565b2008-07-04 09:58:55 -06001106 if (shProg->LinkStatus == GL_FALSE) {
1107 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
1108 return -1;
1109 }
1110
Brian Paul530df582008-07-03 16:21:11 -06001111 /* XXX we should return -1 if the uniform was declared, but not
1112 * actually used.
1113 */
1114
Brian Paulade50832008-05-14 16:09:46 -06001115 return _mesa_lookup_uniform(shProg->Uniforms, name);
Brian5b01c5e2006-12-19 18:02:03 -07001116}
1117
1118
Brian34ae99d2006-12-18 08:28:54 -07001119
Brian5b01c5e2006-12-19 18:02:03 -07001120/**
1121 * Called via ctx->Driver.ShaderSource()
1122 */
Brian Paulfd59f192008-05-18 16:04:55 -06001123static void
Brian5b01c5e2006-12-19 18:02:03 -07001124_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -07001125{
Brian Paul530df582008-07-03 16:21:11 -06001126 struct gl_shader *sh;
1127
1128 sh = _mesa_lookup_shader_err(ctx, shader, "glShaderSource");
1129 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001130 return;
Brian34ae99d2006-12-18 08:28:54 -07001131
Brian34ae99d2006-12-18 08:28:54 -07001132 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -07001133 if (sh->Source) {
1134 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -07001135 }
Brian65a18442006-12-19 18:46:56 -07001136 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -07001137 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -07001138}
1139
1140
Brian5b01c5e2006-12-19 18:02:03 -07001141/**
1142 * Called via ctx->Driver.CompileShader()
1143 */
Brian Paulfd59f192008-05-18 16:04:55 -06001144static void
Brian5b01c5e2006-12-19 18:02:03 -07001145_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -07001146{
Brian Paul530df582008-07-03 16:21:11 -06001147 struct gl_shader *sh;
Brian34ae99d2006-12-18 08:28:54 -07001148
Brian Paul530df582008-07-03 16:21:11 -06001149 sh = _mesa_lookup_shader_err(ctx, shaderObj, "glCompileShader");
1150 if (!sh)
Brian34ae99d2006-12-18 08:28:54 -07001151 return;
Brian34ae99d2006-12-18 08:28:54 -07001152
Brian43975832007-01-04 08:21:09 -07001153 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -07001154}
1155
1156
Brian5b01c5e2006-12-19 18:02:03 -07001157/**
1158 * Called via ctx->Driver.LinkProgram()
1159 */
Brian Paulfd59f192008-05-18 16:04:55 -06001160static void
Brian5b01c5e2006-12-19 18:02:03 -07001161_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001162{
Brian65a18442006-12-19 18:46:56 -07001163 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001164
Brian Paul530df582008-07-03 16:21:11 -06001165 shProg = _mesa_lookup_shader_program_err(ctx, program, "glLinkProgram");
1166 if (!shProg)
Brian34ae99d2006-12-18 08:28:54 -07001167 return;
Brian34ae99d2006-12-18 08:28:54 -07001168
Briandf43fb62008-05-06 23:08:51 -06001169 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1170
Brianc1771912007-02-16 09:56:19 -07001171 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001172}
1173
1174
1175/**
Brian5b01c5e2006-12-19 18:02:03 -07001176 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001177 */
Brian5b01c5e2006-12-19 18:02:03 -07001178void
1179_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001180{
Brian3c008a02007-04-12 15:22:32 -06001181 struct gl_shader_program *shProg;
1182
Brian00d63aa2007-02-03 11:35:02 -07001183 if (ctx->Shader.CurrentProgram &&
1184 ctx->Shader.CurrentProgram->Name == program) {
1185 /* no-op */
1186 return;
1187 }
1188
1189 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1190
Brian5b01c5e2006-12-19 18:02:03 -07001191 if (program) {
Brian Paul530df582008-07-03 16:21:11 -06001192 shProg = _mesa_lookup_shader_program_err(ctx, program, "glUseProgram");
Brian65a18442006-12-19 18:46:56 -07001193 if (!shProg) {
Brian Paul530df582008-07-03 16:21:11 -06001194 return;
1195 }
1196 if (!shProg->LinkStatus) {
1197 _mesa_error(ctx, GL_INVALID_OPERATION, "glUseProgram");
Brian5b01c5e2006-12-19 18:02:03 -07001198 return;
1199 }
Brian5b01c5e2006-12-19 18:02:03 -07001200 }
1201 else {
Brian3c008a02007-04-12 15:22:32 -06001202 shProg = NULL;
1203 }
1204
1205 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001206}
Brian34ae99d2006-12-18 08:28:54 -07001207
Brian5b01c5e2006-12-19 18:02:03 -07001208
Brian Paulade50832008-05-14 16:09:46 -06001209
1210/**
1211 * Update the vertex and fragment program's TexturesUsed arrays.
1212 */
1213static void
1214update_textures_used(struct gl_program *prog)
1215{
1216 GLuint s;
1217
1218 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1219
1220 for (s = 0; s < MAX_SAMPLERS; s++) {
1221 if (prog->SamplersUsed & (1 << s)) {
1222 GLuint u = prog->SamplerUnits[s];
1223 GLuint t = prog->SamplerTargets[s];
1224 assert(u < MAX_TEXTURE_IMAGE_UNITS);
1225 prog->TexturesUsed[u] |= (1 << t);
1226 }
1227 }
1228}
1229
1230
Brianb36749d2008-07-21 20:42:05 -06001231static GLboolean
1232is_sampler_type(GLenum type)
1233{
1234 switch (type) {
1235 case GL_SAMPLER_1D:
1236 case GL_SAMPLER_2D:
1237 case GL_SAMPLER_3D:
1238 case GL_SAMPLER_CUBE:
1239 case GL_SAMPLER_1D_SHADOW:
1240 case GL_SAMPLER_2D_SHADOW:
1241 case GL_SAMPLER_2D_RECT_ARB:
1242 case GL_SAMPLER_2D_RECT_SHADOW_ARB:
1243 case GL_SAMPLER_1D_ARRAY_EXT:
1244 case GL_SAMPLER_2D_ARRAY_EXT:
1245 return GL_TRUE;
1246 default:
1247 return GL_FALSE;
1248 }
1249}
1250
1251
Brian Paulade50832008-05-14 16:09:46 -06001252/**
Brian Paulffbc66b2008-07-21 13:58:50 -06001253 * Check if the type given by userType is allowed to set a uniform of the
1254 * target type. Generally, equivalence is required, but setting Boolean
1255 * uniforms can be done with glUniformiv or glUniformfv.
1256 */
1257static GLboolean
1258compatible_types(GLenum userType, GLenum targetType)
1259{
1260 if (userType == targetType)
1261 return GL_TRUE;
1262
1263 if (targetType == GL_BOOL && (userType == GL_FLOAT || userType == GL_INT))
1264 return GL_TRUE;
1265
1266 if (targetType == GL_BOOL_VEC2 && (userType == GL_FLOAT_VEC2 ||
1267 userType == GL_INT_VEC2))
1268 return GL_TRUE;
1269
1270 if (targetType == GL_BOOL_VEC3 && (userType == GL_FLOAT_VEC3 ||
1271 userType == GL_INT_VEC3))
1272 return GL_TRUE;
1273
1274 if (targetType == GL_BOOL_VEC4 && (userType == GL_FLOAT_VEC4 ||
1275 userType == GL_INT_VEC4))
1276 return GL_TRUE;
1277
Brianb36749d2008-07-21 20:42:05 -06001278 if (is_sampler_type(targetType) && userType == GL_INT)
1279 return GL_TRUE;
1280
Brian Paulffbc66b2008-07-21 13:58:50 -06001281 return GL_FALSE;
1282}
1283
1284
1285/**
Brian Paulade50832008-05-14 16:09:46 -06001286 * Set the value of a program's uniform variable.
1287 * \param program the program whose uniform to update
1288 * \param location the location/index of the uniform
1289 * \param type the datatype of the uniform
1290 * \param count the number of uniforms to set
1291 * \param elems number of elements per uniform
1292 * \param values the new values
1293 */
1294static void
1295set_program_uniform(GLcontext *ctx, struct gl_program *program, GLint location,
Brian Paul530df582008-07-03 16:21:11 -06001296 GLenum type, GLsizei count, GLint elems, const void *values)
Brian Paulade50832008-05-14 16:09:46 -06001297{
Brian Paulffbc66b2008-07-21 13:58:50 -06001298 if (!compatible_types(type,
1299 program->Parameters->Parameters[location].DataType)) {
1300 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
1301 return;
1302 }
1303
Brian Paulade50832008-05-14 16:09:46 -06001304 if (program->Parameters->Parameters[location].Type == PROGRAM_SAMPLER) {
1305 /* This controls which texture unit which is used by a sampler */
1306 GLuint texUnit, sampler;
1307
1308 /* data type for setting samplers must be int */
1309 if (type != GL_INT || count != 1) {
1310 _mesa_error(ctx, GL_INVALID_OPERATION,
1311 "glUniform(only glUniform1i can be used "
1312 "to set sampler uniforms)");
1313 return;
1314 }
1315
1316 sampler = (GLuint) program->Parameters->ParameterValues[location][0];
1317 texUnit = ((GLuint *) values)[0];
1318
1319 /* check that the sampler (tex unit index) is legal */
1320 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1321 _mesa_error(ctx, GL_INVALID_VALUE,
1322 "glUniform1(invalid sampler/tex unit index)");
1323 return;
1324 }
1325
1326 /* This maps a sampler to a texture unit: */
1327 program->SamplerUnits[sampler] = texUnit;
1328 update_textures_used(program);
1329
1330 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1331 }
1332 else {
1333 /* ordinary uniform variable */
Brian Paul530df582008-07-03 16:21:11 -06001334 GLsizei k, i;
Brian Paulade50832008-05-14 16:09:46 -06001335
Brian Paul016701f2008-07-29 17:43:35 -06001336 if (count * elems > (GLint) program->Parameters->Parameters[location].Size) {
Brian Paulade50832008-05-14 16:09:46 -06001337 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1338 return;
1339 }
1340
1341 for (k = 0; k < count; k++) {
1342 GLfloat *uniformVal = program->Parameters->ParameterValues[location + k];
1343 if (type == GL_INT ||
1344 type == GL_INT_VEC2 ||
1345 type == GL_INT_VEC3 ||
1346 type == GL_INT_VEC4) {
1347 const GLint *iValues = ((const GLint *) values) + k * elems;
1348 for (i = 0; i < elems; i++) {
1349 uniformVal[i] = (GLfloat) iValues[i];
1350 }
1351 }
1352 else {
1353 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1354 for (i = 0; i < elems; i++) {
1355 uniformVal[i] = fValues[i];
1356 }
1357 }
1358 }
1359 }
1360}
1361
1362
Brian5b01c5e2006-12-19 18:02:03 -07001363/**
1364 * Called via ctx->Driver.Uniform().
1365 */
Brian Paulfd59f192008-05-18 16:04:55 -06001366static void
Brian5b01c5e2006-12-19 18:02:03 -07001367_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1368 const GLvoid *values, GLenum type)
1369{
Brian3a8e2772006-12-20 17:19:16 -07001370 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paulade50832008-05-14 16:09:46 -06001371 GLint elems;
Brian3a8e2772006-12-20 17:19:16 -07001372
1373 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001374 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001375 return;
1376 }
1377
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001378 if (location == -1)
1379 return; /* The standard specifies this as a no-op */
1380
Brian Paulade50832008-05-14 16:09:46 -06001381 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
1382 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
Brian3a8e2772006-12-20 17:19:16 -07001383 return;
1384 }
1385
Brian52363952007-03-13 16:50:24 -06001386 if (count < 0) {
1387 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1388 return;
1389 }
1390
Brian98650bd2007-03-13 16:32:48 -06001391 switch (type) {
1392 case GL_FLOAT:
1393 case GL_INT:
1394 elems = 1;
1395 break;
1396 case GL_FLOAT_VEC2:
1397 case GL_INT_VEC2:
1398 elems = 2;
1399 break;
1400 case GL_FLOAT_VEC3:
1401 case GL_INT_VEC3:
1402 elems = 3;
1403 break;
1404 case GL_FLOAT_VEC4:
1405 case GL_INT_VEC4:
1406 elems = 4;
1407 break;
1408 default:
1409 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1410 return;
Brian89dc4852007-01-04 14:35:44 -07001411 }
Brian98650bd2007-03-13 16:32:48 -06001412
Brian Paulade50832008-05-14 16:09:46 -06001413 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
Brian98650bd2007-03-13 16:32:48 -06001414
Brian Paulade50832008-05-14 16:09:46 -06001415 /* A uniform var may be used by both a vertex shader and a fragment
1416 * shader. We may need to update one or both shader's uniform here:
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001417 */
Brian Paulade50832008-05-14 16:09:46 -06001418 if (shProg->VertexProgram) {
1419 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1420 if (loc >= 0) {
1421 set_program_uniform(ctx, &shProg->VertexProgram->Base,
1422 loc, type, count, elems, values);
Bruce Merry2bf2a8c2007-12-21 23:18:40 +02001423 }
Brian5b01c5e2006-12-19 18:02:03 -07001424 }
Brian5cf73262007-01-05 16:02:45 -07001425
Brian Paulade50832008-05-14 16:09:46 -06001426 if (shProg->FragmentProgram) {
1427 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1428 if (loc >= 0) {
1429 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
1430 loc, type, count, elems, values);
1431 }
1432 }
1433}
1434
1435
1436static void
Brian Paulffbc66b2008-07-21 13:58:50 -06001437get_matrix_dims(GLenum type, GLint *rows, GLint *cols)
1438{
1439 switch (type) {
1440 case GL_FLOAT_MAT2:
1441 *rows = *cols = 2;
1442 break;
1443 case GL_FLOAT_MAT2x3:
1444 *rows = 3;
1445 *cols = 2;
1446 break;
1447 case GL_FLOAT_MAT2x4:
1448 *rows = 4;
1449 *cols = 2;
1450 break;
1451 case GL_FLOAT_MAT3:
1452 *rows = 3;
1453 *cols = 3;
1454 break;
1455 case GL_FLOAT_MAT3x2:
1456 *rows = 2;
1457 *cols = 3;
1458 break;
1459 case GL_FLOAT_MAT3x4:
1460 *rows = 4;
1461 *cols = 3;
1462 break;
1463 case GL_FLOAT_MAT4:
1464 *rows = 4;
1465 *cols = 4;
1466 break;
1467 case GL_FLOAT_MAT4x2:
1468 *rows = 2;
1469 *cols = 4;
1470 break;
1471 case GL_FLOAT_MAT4x3:
1472 *rows = 3;
1473 *cols = 4;
1474 break;
1475 default:
1476 *rows = *cols = 0;
1477 }
1478}
1479
1480
1481static void
Brian Paulade50832008-05-14 16:09:46 -06001482set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
Brian Paulf45ed0e2008-07-18 12:51:39 -06001483 GLuint location, GLuint count,
1484 GLuint rows, GLuint cols,
Brian Paulade50832008-05-14 16:09:46 -06001485 GLboolean transpose, const GLfloat *values)
1486{
Brian Paulffbc66b2008-07-21 13:58:50 -06001487 GLuint mat, row, col;
1488 GLuint dst = location, src = 0;
1489 GLint nr, nc;
1490
1491 /* check that the number of rows, columns is correct */
1492 get_matrix_dims(program->Parameters->Parameters[location].DataType, &nr, &nc);
1493 if (rows != nr || cols != nc) {
1494 _mesa_error(ctx, GL_INVALID_OPERATION,
1495 "glUniformMatrix(matrix size mismatch");
1496 return;
1497 }
1498
Brian Paulade50832008-05-14 16:09:46 -06001499 /*
1500 * Note: the _columns_ of a matrix are stored in program registers, not
Brian Paulf45ed0e2008-07-18 12:51:39 -06001501 * the rows. So, the loops below look a little funny.
1502 * XXX could optimize this a bit...
Brian Paulade50832008-05-14 16:09:46 -06001503 */
Brian Paulf45ed0e2008-07-18 12:51:39 -06001504
1505 /* loop over matrices */
1506 for (mat = 0; mat < count; mat++) {
1507
1508 /* each matrix: */
Brian Paulade50832008-05-14 16:09:46 -06001509 for (col = 0; col < cols; col++) {
Brian Paulf45ed0e2008-07-18 12:51:39 -06001510 GLfloat *v = program->Parameters->ParameterValues[dst];
Brian Paulade50832008-05-14 16:09:46 -06001511 for (row = 0; row < rows; row++) {
Brian Paulf45ed0e2008-07-18 12:51:39 -06001512 if (transpose) {
1513 v[row] = values[src + row * cols + col];
1514 }
1515 else {
1516 v[row] = values[src + col * rows + row];
1517 }
Brian Paulade50832008-05-14 16:09:46 -06001518 }
Brian Paulf45ed0e2008-07-18 12:51:39 -06001519 dst++;
Brian Paulade50832008-05-14 16:09:46 -06001520 }
Brian Paulf45ed0e2008-07-18 12:51:39 -06001521
1522 src += rows * cols; /* next matrix */
Brian5cf73262007-01-05 16:02:45 -07001523 }
Brian34ae99d2006-12-18 08:28:54 -07001524}
1525
1526
1527/**
Brian5b01c5e2006-12-19 18:02:03 -07001528 * Called by ctx->Driver.UniformMatrix().
Brian Paulf45ed0e2008-07-18 12:51:39 -06001529 * Note: cols=2, rows=4 ==> array[2] of vec4
Brian34ae99d2006-12-18 08:28:54 -07001530 */
Brian Paulfd59f192008-05-18 16:04:55 -06001531static void
Brian5b01c5e2006-12-19 18:02:03 -07001532_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1533 GLenum matrixType, GLint location, GLsizei count,
1534 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001535{
Brian3a8e2772006-12-20 17:19:16 -07001536 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paulade50832008-05-14 16:09:46 -06001537
Brian3a8e2772006-12-20 17:19:16 -07001538 if (!shProg || !shProg->LinkStatus) {
1539 _mesa_error(ctx, GL_INVALID_OPERATION,
1540 "glUniformMatrix(program not linked)");
1541 return;
1542 }
Brian Paulade50832008-05-14 16:09:46 -06001543
Bruce Merry89b80322007-12-21 15:20:17 +02001544 if (location == -1)
1545 return; /* The standard specifies this as a no-op */
Brian Paulade50832008-05-14 16:09:46 -06001546
Brian Paul016701f2008-07-29 17:43:35 -06001547 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian Paulade50832008-05-14 16:09:46 -06001548 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
Brian3a8e2772006-12-20 17:19:16 -07001549 return;
1550 }
Brian34ae99d2006-12-18 08:28:54 -07001551 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001552 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001553 return;
1554 }
1555
1556 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1557
Brian Paulade50832008-05-14 16:09:46 -06001558 if (shProg->VertexProgram) {
1559 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1560 if (loc >= 0) {
1561 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
Brian Paulf45ed0e2008-07-18 12:51:39 -06001562 loc, count, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07001563 }
Brian Paulade50832008-05-14 16:09:46 -06001564 }
1565
1566 if (shProg->FragmentProgram) {
1567 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1568 if (loc >= 0) {
1569 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
Brian Paulf45ed0e2008-07-18 12:51:39 -06001570 loc, count, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07001571 }
Brian34ae99d2006-12-18 08:28:54 -07001572 }
1573}
1574
1575
Brian Paulfd59f192008-05-18 16:04:55 -06001576static void
Brian5b01c5e2006-12-19 18:02:03 -07001577_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001578{
Brian65a18442006-12-19 18:46:56 -07001579 struct gl_shader_program *shProg;
Brian Paulbc985b52008-07-21 14:16:07 -06001580
1581 shProg = _mesa_lookup_shader_program_err(ctx, program, "glValidateProgram");
Brian65a18442006-12-19 18:46:56 -07001582 if (!shProg) {
Brian34ae99d2006-12-18 08:28:54 -07001583 return;
1584 }
1585
Brian Paulbc985b52008-07-21 14:16:07 -06001586 if (!shProg->LinkStatus) {
1587 shProg->Validated = GL_FALSE;
1588 return;
1589 }
1590
1591 /* From the GL spec, a program is invalid if any of these are true:
1592
Brian5b01c5e2006-12-19 18:02:03 -07001593 any two active samplers in the current program object are of
1594 different types, but refer to the same texture image unit,
1595
1596 any active sampler in the current program object refers to a texture
1597 image unit where fixed-function fragment processing accesses a
1598 texture target that does not match the sampler type, or
1599
1600 the sum of the number of active samplers in the program and the
1601 number of texture image units enabled for fixed-function fragment
1602 processing exceeds the combined limit on the total number of texture
1603 image units allowed.
1604 */
Brian Paulbc985b52008-07-21 14:16:07 -06001605
1606 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001607}
Brian Paulfd59f192008-05-18 16:04:55 -06001608
1609
1610/**
1611 * Plug in Mesa's GLSL functions into the device driver function table.
1612 */
1613void
1614_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
1615{
1616 driver->AttachShader = _mesa_attach_shader;
1617 driver->BindAttribLocation = _mesa_bind_attrib_location;
1618 driver->CompileShader = _mesa_compile_shader;
1619 driver->CreateProgram = _mesa_create_program;
1620 driver->CreateShader = _mesa_create_shader;
1621 driver->DeleteProgram2 = _mesa_delete_program2;
1622 driver->DeleteShader = _mesa_delete_shader;
1623 driver->DetachShader = _mesa_detach_shader;
1624 driver->GetActiveAttrib = _mesa_get_active_attrib;
1625 driver->GetActiveUniform = _mesa_get_active_uniform;
1626 driver->GetAttachedShaders = _mesa_get_attached_shaders;
1627 driver->GetAttribLocation = _mesa_get_attrib_location;
1628 driver->GetHandle = _mesa_get_handle;
1629 driver->GetProgramiv = _mesa_get_programiv;
1630 driver->GetProgramInfoLog = _mesa_get_program_info_log;
1631 driver->GetShaderiv = _mesa_get_shaderiv;
1632 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
1633 driver->GetShaderSource = _mesa_get_shader_source;
1634 driver->GetUniformfv = _mesa_get_uniformfv;
Brian Paul2be54a82008-07-08 16:17:04 -06001635 driver->GetUniformiv = _mesa_get_uniformiv;
Brian Paulfd59f192008-05-18 16:04:55 -06001636 driver->GetUniformLocation = _mesa_get_uniform_location;
1637 driver->IsProgram = _mesa_is_program;
1638 driver->IsShader = _mesa_is_shader;
1639 driver->LinkProgram = _mesa_link_program;
1640 driver->ShaderSource = _mesa_shader_source;
1641 driver->Uniform = _mesa_uniform;
1642 driver->UniformMatrix = _mesa_uniform_matrix;
1643 driver->UseProgram = _mesa_use_program;
1644 driver->ValidateProgram = _mesa_validate_program;
1645}