blob: badc457c1c09e9ef7e6c6b93016787fc8cc1fc3d [file] [log] [blame]
Brian34ae99d2006-12-18 08:28:54 -07001/*
2 * Mesa 3-D graphics library
Brian3e4302f2007-05-09 08:04:32 -06003 * Version: 7.0
Brian34ae99d2006-12-18 08:28:54 -07004 *
Brian5b01c5e2006-12-19 18:02:03 -07005 * Copyright (C) 2004-2007 Brian Paul All Rights Reserved.
Brian34ae99d2006-12-18 08:28:54 -07006 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25/**
26 * \file shader_api.c
Brian5b01c5e2006-12-19 18:02:03 -070027 * Implementation of GLSL-related API functions
Brian34ae99d2006-12-18 08:28:54 -070028 * \author Brian Paul
29 */
30
31/**
32 * XXX things to do:
33 * 1. Check that the right error code is generated for all _mesa_error() calls.
Brian5b01c5e2006-12-19 18:02:03 -070034 * 2. Insert FLUSH_VERTICES calls in various places
Brian34ae99d2006-12-18 08:28:54 -070035 */
36
37
38#include "glheader.h"
39#include "context.h"
40#include "hash.h"
Brian274ac7a2007-04-18 16:05:53 -060041#include "macros.h"
Brian34ae99d2006-12-18 08:28:54 -070042#include "program.h"
43#include "prog_parameter.h"
Brian3209c3e2007-01-09 17:49:24 -070044#include "prog_print.h"
45#include "prog_statevars.h"
Brianbc029242008-04-04 18:59:21 -060046#include "prog_uniform.h"
Brianc223c6b2007-07-04 13:15:20 -060047#include "shader/shader_api.h"
48#include "shader/slang/slang_compile.h"
49#include "shader/slang/slang_link.h"
Brian34ae99d2006-12-18 08:28:54 -070050
51
52
Brianf2923612006-12-20 09:56:44 -070053/**
54 * Allocate a new gl_shader_program object, initialize it.
55 */
Brian2d2bb352007-12-07 17:11:30 -070056static struct gl_shader_program *
Brianf2923612006-12-20 09:56:44 -070057_mesa_new_shader_program(GLcontext *ctx, GLuint name)
58{
59 struct gl_shader_program *shProg;
60 shProg = CALLOC_STRUCT(gl_shader_program);
61 if (shProg) {
Brianf3e8c322007-04-18 14:53:23 -060062 shProg->Type = GL_SHADER_PROGRAM_MESA;
Brianf2923612006-12-20 09:56:44 -070063 shProg->Name = name;
64 shProg->RefCount = 1;
Brian3209c3e2007-01-09 17:49:24 -070065 shProg->Attributes = _mesa_new_parameter_list();
Brianf2923612006-12-20 09:56:44 -070066 }
67 return shProg;
68}
69
70
Brianb9fbedd2007-03-26 09:23:44 -060071/**
Brian3c008a02007-04-12 15:22:32 -060072 * Clear (free) the shader program state that gets produced by linking.
Brianb9fbedd2007-03-26 09:23:44 -060073 */
Brianf2923612006-12-20 09:56:44 -070074void
Brian3c008a02007-04-12 15:22:32 -060075_mesa_clear_shader_program_data(GLcontext *ctx,
76 struct gl_shader_program *shProg)
Brianf2923612006-12-20 09:56:44 -070077{
Brianf2923612006-12-20 09:56:44 -070078 if (shProg->VertexProgram) {
Brianbc029242008-04-04 18:59:21 -060079 /* Set ptr to NULL since the param list is shared with the
80 * original/unlinked program.
81 */
82 shProg->VertexProgram->Base.Parameters = NULL;
Brian103ae5d2008-05-06 22:13:06 -060083 _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL);
Brianf2923612006-12-20 09:56:44 -070084 }
85
86 if (shProg->FragmentProgram) {
Brianbc029242008-04-04 18:59:21 -060087 /* Set ptr to NULL since the param list is shared with the
88 * original/unlinked program.
89 */
90 shProg->FragmentProgram->Base.Parameters = NULL;
Brian103ae5d2008-05-06 22:13:06 -060091 _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL);
Brianf2923612006-12-20 09:56:44 -070092 }
93
Brianf2923612006-12-20 09:56:44 -070094 if (shProg->Uniforms) {
Brianbc029242008-04-04 18:59:21 -060095 _mesa_free_uniform_list(shProg->Uniforms);
Brianf2923612006-12-20 09:56:44 -070096 shProg->Uniforms = NULL;
97 }
98
99 if (shProg->Varying) {
100 _mesa_free_parameter_list(shProg->Varying);
101 shProg->Varying = NULL;
102 }
103}
104
105
Brianb9fbedd2007-03-26 09:23:44 -0600106/**
Brian3c008a02007-04-12 15:22:32 -0600107 * Free all the data that hangs off a shader program object, but not the
108 * object itself.
109 */
110void
111_mesa_free_shader_program_data(GLcontext *ctx,
112 struct gl_shader_program *shProg)
113{
114 GLuint i;
115
Brianf3e8c322007-04-18 14:53:23 -0600116 assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
Brian3c008a02007-04-12 15:22:32 -0600117
118 _mesa_clear_shader_program_data(ctx, shProg);
119
Brian4b7c6fc2007-04-19 15:23:34 -0600120 if (shProg->Attributes) {
121 _mesa_free_parameter_list(shProg->Attributes);
122 shProg->Attributes = NULL;
123 }
124
Brian3c008a02007-04-12 15:22:32 -0600125 /* detach shaders */
126 for (i = 0; i < shProg->NumShaders; i++) {
127 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
128 }
Brian Paul887bfee2008-05-14 16:44:08 -0600129 shProg->NumShaders = 0;
130
Brian3c008a02007-04-12 15:22:32 -0600131 if (shProg->Shaders) {
132 _mesa_free(shProg->Shaders);
133 shProg->Shaders = NULL;
134 }
Brian Paul887bfee2008-05-14 16:44:08 -0600135
136 if (shProg->InfoLog) {
137 _mesa_free(shProg->InfoLog);
138 shProg->InfoLog = NULL;
139 }
Brian3c008a02007-04-12 15:22:32 -0600140}
141
142
143/**
Brianb9fbedd2007-03-26 09:23:44 -0600144 * Free/delete a shader program object.
145 */
Brianf2923612006-12-20 09:56:44 -0700146void
147_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg)
148{
149 _mesa_free_shader_program_data(ctx, shProg);
Brian Paul887bfee2008-05-14 16:44:08 -0600150
Brianf2923612006-12-20 09:56:44 -0700151 _mesa_free(shProg);
152}
153
154
155/**
Brian3c008a02007-04-12 15:22:32 -0600156 * Set ptr to point to shProg.
157 * If ptr is pointing to another object, decrement its refcount (and delete
158 * if refcount hits zero).
159 * Then set ptr to point to shProg, incrementing its refcount.
160 */
161/* XXX this could be static */
162void
163_mesa_reference_shader_program(GLcontext *ctx,
164 struct gl_shader_program **ptr,
165 struct gl_shader_program *shProg)
166{
167 assert(ptr);
168 if (*ptr == shProg) {
169 /* no-op */
170 return;
171 }
172 if (*ptr) {
173 /* Unreference the old shader program */
174 GLboolean deleteFlag = GL_FALSE;
175 struct gl_shader_program *old = *ptr;
176
177 ASSERT(old->RefCount > 0);
178 old->RefCount--;
179 /*printf("SHPROG DECR %p (%d) to %d\n",
180 (void*) old, old->Name, old->RefCount);*/
181 deleteFlag = (old->RefCount == 0);
182
183 if (deleteFlag) {
184 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
185 _mesa_free_shader_program(ctx, old);
186 }
187
188 *ptr = NULL;
189 }
190 assert(!*ptr);
191
192 if (shProg) {
193 shProg->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600194 /*printf("SHPROG INCR %p (%d) to %d\n",
195 (void*) shProg, shProg->Name, shProg->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600196 *ptr = shProg;
197 }
198}
199
200
201/**
Brianf2923612006-12-20 09:56:44 -0700202 * Lookup a GLSL program object.
203 */
204struct gl_shader_program *
205_mesa_lookup_shader_program(GLcontext *ctx, GLuint name)
206{
207 struct gl_shader_program *shProg;
208 if (name) {
209 shProg = (struct gl_shader_program *)
210 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
211 /* Note that both gl_shader and gl_shader_program objects are kept
212 * in the same hash table. Check the object's type to be sure it's
213 * what we're expecting.
214 */
Brianf3e8c322007-04-18 14:53:23 -0600215 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700216 return NULL;
217 }
218 return shProg;
219 }
220 return NULL;
221}
222
223
224/**
225 * Allocate a new gl_shader object, initialize it.
226 */
227struct gl_shader *
228_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
229{
230 struct gl_shader *shader;
231 assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
232 shader = CALLOC_STRUCT(gl_shader);
233 if (shader) {
234 shader->Type = type;
235 shader->Name = name;
236 shader->RefCount = 1;
237 }
238 return shader;
239}
240
241
242void
243_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh)
244{
245 GLuint i;
246 if (sh->Source)
247 _mesa_free((void *) sh->Source);
248 if (sh->InfoLog)
249 _mesa_free(sh->InfoLog);
Brian Pauld7913862008-05-14 12:19:22 -0600250 for (i = 0; i < sh->NumPrograms; i++)
251 _mesa_reference_program(ctx, &sh->Programs[i], NULL);
Brianf2923612006-12-20 09:56:44 -0700252 if (sh->Programs)
253 _mesa_free(sh->Programs);
254 _mesa_free(sh);
255}
256
257
258/**
Brian3c008a02007-04-12 15:22:32 -0600259 * Set ptr to point to sh.
260 * If ptr is pointing to another shader, decrement its refcount (and delete
261 * if refcount hits zero).
262 * Then set ptr to point to sh, incrementing its refcount.
263 */
264/* XXX this could be static */
265void
266_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr,
267 struct gl_shader *sh)
268{
269 assert(ptr);
270 if (*ptr == sh) {
271 /* no-op */
272 return;
273 }
274 if (*ptr) {
275 /* Unreference the old shader */
276 GLboolean deleteFlag = GL_FALSE;
277 struct gl_shader *old = *ptr;
278
279 ASSERT(old->RefCount > 0);
280 old->RefCount--;
Brian99193e42007-04-12 15:45:02 -0600281 /*printf("SHADER DECR %p (%d) to %d\n",
282 (void*) old, old->Name, old->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600283 deleteFlag = (old->RefCount == 0);
284
285 if (deleteFlag) {
286 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
287 _mesa_free_shader(ctx, old);
288 }
289
290 *ptr = NULL;
291 }
292 assert(!*ptr);
293
294 if (sh) {
295 /* reference new */
296 sh->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600297 /*printf("SHADER INCR %p (%d) to %d\n",
298 (void*) sh, sh->Name, sh->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600299 *ptr = sh;
300 }
301}
302
303
304/**
Brianf2923612006-12-20 09:56:44 -0700305 * Lookup a GLSL shader object.
306 */
307struct gl_shader *
308_mesa_lookup_shader(GLcontext *ctx, GLuint name)
309{
310 if (name) {
311 struct gl_shader *sh = (struct gl_shader *)
312 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
313 /* Note that both gl_shader and gl_shader_program objects are kept
314 * in the same hash table. Check the object's type to be sure it's
315 * what we're expecting.
316 */
Brianf3e8c322007-04-18 14:53:23 -0600317 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700318 return NULL;
319 }
320 return sh;
321 }
322 return NULL;
323}
324
325
Brianfa4d0362007-02-26 18:33:50 -0700326/**
327 * Initialize context's shader state.
328 */
Brianf2923612006-12-20 09:56:44 -0700329void
330_mesa_init_shader_state(GLcontext * ctx)
331{
Brianfa4d0362007-02-26 18:33:50 -0700332 /* Device drivers may override these to control what kind of instructions
333 * are generated by the GLSL compiler.
334 */
335 ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
michal4a470f62007-08-07 15:34:11 +0100336 ctx->Shader.EmitCondCodes = GL_FALSE;/*GL_TRUE;*/ /* XXX probably want GL_FALSE... */
Brianfa4d0362007-02-26 18:33:50 -0700337 ctx->Shader.EmitComments = GL_FALSE;
Brianf2923612006-12-20 09:56:44 -0700338}
339
340
Brian5b01c5e2006-12-19 18:02:03 -0700341/**
Brian935f93f2007-03-24 16:20:02 -0600342 * Free the per-context shader-related state.
343 */
344void
345_mesa_free_shader_state(GLcontext *ctx)
346{
Brian3c008a02007-04-12 15:22:32 -0600347 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
Brian935f93f2007-03-24 16:20:02 -0600348}
349
350
351/**
Brian5b01c5e2006-12-19 18:02:03 -0700352 * Copy string from <src> to <dst>, up to maxLength characters, returning
353 * length of <dst> in <length>.
354 * \param src the strings source
355 * \param maxLength max chars to copy
356 * \param length returns number of chars copied
357 * \param dst the string destination
358 */
359static void
360copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
361{
362 GLsizei len;
363 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
364 dst[len] = src[len];
365 if (maxLength > 0)
366 dst[len] = 0;
367 if (length)
368 *length = len;
369}
370
371
Brian5b01c5e2006-12-19 18:02:03 -0700372/**
373 * Called via ctx->Driver.AttachShader()
374 */
Brian2d2bb352007-12-07 17:11:30 -0700375static void
Brian5b01c5e2006-12-19 18:02:03 -0700376_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
377{
Brian65a18442006-12-19 18:46:56 -0700378 struct gl_shader_program *shProg
379 = _mesa_lookup_shader_program(ctx, program);
380 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
381 const GLuint n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700382 GLuint i;
383
Brian65a18442006-12-19 18:46:56 -0700384 if (!shProg || !sh) {
Brian43975832007-01-04 08:21:09 -0700385 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700386 "glAttachShader(bad program or shader name)");
387 return;
388 }
389
390 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700391 if (shProg->Shaders[i] == sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700392 /* already attached */
393 return;
Brian34ae99d2006-12-18 08:28:54 -0700394 }
395 }
Brian5b01c5e2006-12-19 18:02:03 -0700396
397 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700398 shProg->Shaders = (struct gl_shader **)
399 _mesa_realloc(shProg->Shaders,
400 n * sizeof(struct gl_shader *),
401 (n + 1) * sizeof(struct gl_shader *));
402 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700403 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
404 return;
405 }
406
407 /* append */
Brian3c008a02007-04-12 15:22:32 -0600408 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
409 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700410 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700411}
412
413
Brian2d2bb352007-12-07 17:11:30 -0700414static GLint
415_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
416 const GLchar *name)
417{
418 struct gl_shader_program *shProg
419 = _mesa_lookup_shader_program(ctx, program);
420
421 if (!shProg) {
422 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttribLocation");
423 return -1;
424 }
425
426 if (!shProg->LinkStatus) {
427 _mesa_error(ctx, GL_INVALID_OPERATION,
428 "glGetAttribLocation(program not linked)");
429 return -1;
430 }
431
432 if (!name)
433 return -1;
434
435 if (shProg->Attributes) {
436 GLint i = _mesa_lookup_parameter_index(shProg->Attributes, -1, name);
437 if (i >= 0) {
438 return shProg->Attributes->Parameters[i].StateIndexes[0];
439 }
440 }
441 return -1;
442}
443
444
445static void
Brian5b01c5e2006-12-19 18:02:03 -0700446_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
447 const GLchar *name)
448{
Brian65a18442006-12-19 18:46:56 -0700449 struct gl_shader_program *shProg
450 = _mesa_lookup_shader_program(ctx, program);
Brianb7978af2007-01-09 19:17:17 -0700451 const GLint size = -1; /* unknown size */
452 GLint i, oldIndex;
Brian5b01c5e2006-12-19 18:02:03 -0700453
Brian65a18442006-12-19 18:46:56 -0700454 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700455 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700456 return;
457 }
458
Brian9e4bae92006-12-20 09:27:42 -0700459 if (!name)
460 return;
461
462 if (strncmp(name, "gl_", 3) == 0) {
463 _mesa_error(ctx, GL_INVALID_OPERATION,
464 "glBindAttribLocation(illegal name)");
465 return;
466 }
467
Brian9f660252007-04-11 09:00:56 -0600468 if (shProg->LinkStatus) {
469 /* get current index/location for the attribute */
470 oldIndex = _mesa_get_attrib_location(ctx, program, name);
471 }
472 else {
473 oldIndex = -1;
474 }
Brian3209c3e2007-01-09 17:49:24 -0700475
476 /* this will replace the current value if it's already in the list */
Brianb7978af2007-01-09 19:17:17 -0700477 i = _mesa_add_attribute(shProg->Attributes, name, size, index);
Brian3209c3e2007-01-09 17:49:24 -0700478 if (i < 0) {
479 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
480 }
481
Brian9f660252007-04-11 09:00:56 -0600482 if (shProg->VertexProgram && oldIndex >= 0 && oldIndex != index) {
483 /* If the index changed, need to search/replace references to that attribute
484 * in the vertex program.
485 */
Brian3209c3e2007-01-09 17:49:24 -0700486 _slang_remap_attribute(&shProg->VertexProgram->Base, oldIndex, index);
487 }
Brian34ae99d2006-12-18 08:28:54 -0700488}
489
490
Brian2d2bb352007-12-07 17:11:30 -0700491static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700492_mesa_create_shader(GLcontext *ctx, GLenum type)
493{
Brian65a18442006-12-19 18:46:56 -0700494 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700495 GLuint name;
496
497 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
498
499 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700500 case GL_FRAGMENT_SHADER:
501 case GL_VERTEX_SHADER:
502 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700503 break;
504 default:
505 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
506 return 0;
507 }
508
Brian65a18442006-12-19 18:46:56 -0700509 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700510
511 return name;
512}
513
514
Brian2d2bb352007-12-07 17:11:30 -0700515static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700516_mesa_create_program(GLcontext *ctx)
517{
518 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700519 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700520
Brian65a18442006-12-19 18:46:56 -0700521 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
522 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700523
Brian65a18442006-12-19 18:46:56 -0700524 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700525
Brian3c008a02007-04-12 15:22:32 -0600526 assert(shProg->RefCount == 1);
527
Brian5b01c5e2006-12-19 18:02:03 -0700528 return name;
529}
530
531
Brian3c008a02007-04-12 15:22:32 -0600532/**
533 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
534 * DeleteProgramARB.
535 */
Brian2d2bb352007-12-07 17:11:30 -0700536static void
Brian5b01c5e2006-12-19 18:02:03 -0700537_mesa_delete_program2(GLcontext *ctx, GLuint name)
538{
Brian3c008a02007-04-12 15:22:32 -0600539 /*
540 * NOTE: deleting shaders/programs works a bit differently than
541 * texture objects (and buffer objects, etc). Shader/program
542 * handles/IDs exist in the hash table until the object is really
543 * deleted (refcount==0). With texture objects, the handle/ID is
544 * removed from the hash table in glDeleteTextures() while the tex
545 * object itself might linger until its refcount goes to zero.
546 */
Brian65a18442006-12-19 18:46:56 -0700547 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700548
Brian65a18442006-12-19 18:46:56 -0700549 shProg = _mesa_lookup_shader_program(ctx, name);
550 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700551 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteProgram(name)");
Brian5b01c5e2006-12-19 18:02:03 -0700552 return;
553 }
554
Brian9e4bae92006-12-20 09:27:42 -0700555 shProg->DeletePending = GL_TRUE;
556
Brian3c008a02007-04-12 15:22:32 -0600557 /* effectively, decr shProg's refcount */
558 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700559}
560
561
Brian2d2bb352007-12-07 17:11:30 -0700562static void
Brian5b01c5e2006-12-19 18:02:03 -0700563_mesa_delete_shader(GLcontext *ctx, GLuint shader)
564{
Brian9e4bae92006-12-20 09:27:42 -0700565 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
566 if (!sh) {
567 return;
568 }
Brian5b01c5e2006-12-19 18:02:03 -0700569
Brian9e4bae92006-12-20 09:27:42 -0700570 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600571
572 /* effectively, decr sh's refcount */
573 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700574}
575
576
Brian2d2bb352007-12-07 17:11:30 -0700577static void
Brian5b01c5e2006-12-19 18:02:03 -0700578_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
579{
Brian65a18442006-12-19 18:46:56 -0700580 struct gl_shader_program *shProg
581 = _mesa_lookup_shader_program(ctx, program);
582 const GLuint n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700583 GLuint i, j;
584
Brian65a18442006-12-19 18:46:56 -0700585 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700586 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700587 "glDetachShader(bad program or shader name)");
588 return;
589 }
590
591 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700592 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700593 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600594 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700595
Brian3c008a02007-04-12 15:22:32 -0600596 /* derefernce */
597 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700598
Brian5b01c5e2006-12-19 18:02:03 -0700599 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700600 newList = (struct gl_shader **)
601 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700602 if (!newList) {
603 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
604 return;
605 }
606 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700607 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700608 }
609 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700610 newList[j++] = shProg->Shaders[i];
611 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700612
Brian65a18442006-12-19 18:46:56 -0700613 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600614 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600615
616#ifdef DEBUG
617 /* sanity check */
618 {
619 for (j = 0; j < shProg->NumShaders; j++) {
620 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
621 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
622 assert(shProg->Shaders[j]->RefCount > 0);
623 }
624 }
625#endif
626
Brian5b01c5e2006-12-19 18:02:03 -0700627 return;
628 }
629 }
630
631 /* not found */
Brian43975832007-01-04 08:21:09 -0700632 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700633 "glDetachShader(shader not found)");
634}
635
636
Brian2d2bb352007-12-07 17:11:30 -0700637static void
Brian5b01c5e2006-12-19 18:02:03 -0700638_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
639 GLsizei maxLength, GLsizei *length, GLint *size,
640 GLenum *type, GLchar *nameOut)
641{
642 static const GLenum vec_types[] = {
643 GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4
644 };
Brian65a18442006-12-19 18:46:56 -0700645 struct gl_shader_program *shProg
646 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700647 GLint sz;
648
Brian65a18442006-12-19 18:46:56 -0700649 if (!shProg) {
Brianaaa57412007-04-18 15:22:43 -0600650 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib");
Brian5b01c5e2006-12-19 18:02:03 -0700651 return;
652 }
653
Brian65a18442006-12-19 18:46:56 -0700654 if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600655 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700656 return;
657 }
658
659 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700660 shProg->Attributes->Parameters[index].Name);
661 sz = shProg->Attributes->Parameters[index].Size;
Brian5b01c5e2006-12-19 18:02:03 -0700662 if (size)
663 *size = sz;
664 if (type)
665 *type = vec_types[sz]; /* XXX this is a temporary hack */
666}
667
668
669/**
670 * Called via ctx->Driver.GetActiveUniform().
671 */
Brian2d2bb352007-12-07 17:11:30 -0700672static void
Brian5b01c5e2006-12-19 18:02:03 -0700673_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
674 GLsizei maxLength, GLsizei *length, GLint *size,
675 GLenum *type, GLchar *nameOut)
676{
Brianbc029242008-04-04 18:59:21 -0600677 const struct gl_shader_program *shProg
Brian65a18442006-12-19 18:46:56 -0700678 = _mesa_lookup_shader_program(ctx, program);
Brianbc029242008-04-04 18:59:21 -0600679 const struct gl_program *prog;
680 GLint progPos;
Brian5b01c5e2006-12-19 18:02:03 -0700681
Brian65a18442006-12-19 18:46:56 -0700682 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700683 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform");
Brian5b01c5e2006-12-19 18:02:03 -0700684 return;
685 }
686
Brianbc029242008-04-04 18:59:21 -0600687 if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
Brian5b01c5e2006-12-19 18:02:03 -0700688 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
689 return;
690 }
691
Brianbc029242008-04-04 18:59:21 -0600692 progPos = shProg->Uniforms->Uniforms[index].VertPos;
693 if (progPos >= 0) {
694 prog = &shProg->VertexProgram->Base;
695 }
696 else {
697 progPos = shProg->Uniforms->Uniforms[index].FragPos;
698 if (progPos >= 0) {
699 prog = &shProg->FragmentProgram->Base;
Brian274ac7a2007-04-18 16:05:53 -0600700 }
701 }
702
Brianbc029242008-04-04 18:59:21 -0600703 if (!prog || progPos < 0)
704 return; /* should never happen */
705
706 if (nameOut)
707 copy_string(nameOut, maxLength, length,
708 prog->Parameters->Parameters[progPos].Name);
709 if (size)
710 *size = prog->Parameters->Parameters[progPos].Size;
711
712 if (type)
713 *type = prog->Parameters->Parameters[progPos].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700714}
715
716
717/**
718 * Called via ctx->Driver.GetAttachedShaders().
719 */
Brian2d2bb352007-12-07 17:11:30 -0700720static void
Brian5b01c5e2006-12-19 18:02:03 -0700721_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
722 GLsizei *count, GLuint *obj)
723{
Brian65a18442006-12-19 18:46:56 -0700724 struct gl_shader_program *shProg
725 = _mesa_lookup_shader_program(ctx, program);
726 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700727 GLint i;
Brian65a18442006-12-19 18:46:56 -0700728 for (i = 0; i < maxCount && i < shProg->NumShaders; i++) {
729 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700730 }
731 if (count)
732 *count = i;
733 }
734 else {
Brian43975832007-01-04 08:21:09 -0700735 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttachedShaders");
Brian5b01c5e2006-12-19 18:02:03 -0700736 }
737}
738
739
Brian2d2bb352007-12-07 17:11:30 -0700740static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700741_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700742{
743#if 0
744 GET_CURRENT_CONTEXT(ctx);
745
746 switch (pname) {
747 case GL_PROGRAM_OBJECT_ARB:
748 {
Brian5b01c5e2006-12-19 18:02:03 -0700749 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700750
751 if (pro != NULL)
752 return (**pro)._container._generic.
753 GetName((struct gl2_generic_intf **) (pro));
754 }
755 break;
756 default:
757 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
758 }
759#endif
760 return 0;
761}
762
763
Brian2d2bb352007-12-07 17:11:30 -0700764static void
Brian5b01c5e2006-12-19 18:02:03 -0700765_mesa_get_programiv(GLcontext *ctx, GLuint program,
766 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700767{
Brian65a18442006-12-19 18:46:56 -0700768 struct gl_shader_program *shProg
769 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700770
Brian65a18442006-12-19 18:46:56 -0700771 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700772 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700773 return;
774 }
775
Brian5b01c5e2006-12-19 18:02:03 -0700776 switch (pname) {
777 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700778 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700779 break;
780 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700781 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700782 break;
Brian5b01c5e2006-12-19 18:02:03 -0700783 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700784 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700785 break;
786 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600787 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700788 break;
789 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700790 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700791 break;
792 case GL_ACTIVE_ATTRIBUTES:
Brian3209c3e2007-01-09 17:49:24 -0700793 *params = shProg->Attributes ? shProg->Attributes->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700794 break;
795 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600796 *params = _mesa_longest_parameter_name(shProg->Attributes,
797 PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700798 break;
799 case GL_ACTIVE_UNIFORMS:
Brianbc029242008-04-04 18:59:21 -0600800 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700801 break;
802 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brianbc029242008-04-04 18:59:21 -0600803 *params = _mesa_longest_uniform_name(shProg->Uniforms);
Brian274ac7a2007-04-18 16:05:53 -0600804 if (*params > 0)
805 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700806 break;
807 default:
Brian5b01c5e2006-12-19 18:02:03 -0700808 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
809 return;
Brian34ae99d2006-12-18 08:28:54 -0700810 }
Brian5b01c5e2006-12-19 18:02:03 -0700811}
Brian34ae99d2006-12-18 08:28:54 -0700812
Brian34ae99d2006-12-18 08:28:54 -0700813
Brian2d2bb352007-12-07 17:11:30 -0700814static void
Brian5b01c5e2006-12-19 18:02:03 -0700815_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
816{
Brian65a18442006-12-19 18:46:56 -0700817 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700818
819 if (!shader) {
820 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderiv(shader)");
821 return;
822 }
Brian65a18442006-12-19 18:46:56 -0700823
Brian5b01c5e2006-12-19 18:02:03 -0700824 switch (pname) {
825 case GL_SHADER_TYPE:
826 *params = shader->Type;
827 break;
828 case GL_DELETE_STATUS:
829 *params = shader->DeletePending;
830 break;
831 case GL_COMPILE_STATUS:
832 *params = shader->CompileStatus;
833 break;
834 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600835 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700836 break;
837 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600838 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700839 break;
840 default:
841 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
842 return;
843 }
844}
845
846
Brian2d2bb352007-12-07 17:11:30 -0700847static void
Brian5b01c5e2006-12-19 18:02:03 -0700848_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
849 GLsizei *length, GLchar *infoLog)
850{
Brian65a18442006-12-19 18:46:56 -0700851 struct gl_shader_program *shProg
852 = _mesa_lookup_shader_program(ctx, program);
853 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700854 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
855 return;
856 }
Brian65a18442006-12-19 18:46:56 -0700857 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700858}
859
860
Brian2d2bb352007-12-07 17:11:30 -0700861static void
Brian5b01c5e2006-12-19 18:02:03 -0700862_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
863 GLsizei *length, GLchar *infoLog)
864{
Brian65a18442006-12-19 18:46:56 -0700865 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
866 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700867 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
868 return;
869 }
Brian65a18442006-12-19 18:46:56 -0700870 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700871}
872
873
874/**
875 * Called via ctx->Driver.GetShaderSource().
876 */
Brian2d2bb352007-12-07 17:11:30 -0700877static void
Brian5b01c5e2006-12-19 18:02:03 -0700878_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
879 GLsizei *length, GLchar *sourceOut)
880{
Brian65a18442006-12-19 18:46:56 -0700881 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
882 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700883 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderSource(shader)");
884 return;
885 }
Brian65a18442006-12-19 18:46:56 -0700886 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -0700887}
888
889
890/**
891 * Called via ctx->Driver.GetUniformfv().
892 */
Brian2d2bb352007-12-07 17:11:30 -0700893static void
Brian5b01c5e2006-12-19 18:02:03 -0700894_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
895 GLfloat *params)
896{
Brian65a18442006-12-19 18:46:56 -0700897 struct gl_shader_program *shProg
898 = _mesa_lookup_shader_program(ctx, program);
899 if (shProg) {
Brianbc029242008-04-04 18:59:21 -0600900 if (location < shProg->Uniforms->NumUniforms) {
901 GLint progPos, i;
902 const struct gl_program *prog;
903
904 progPos = shProg->Uniforms->Uniforms[location].VertPos;
905 if (progPos >= 0) {
906 prog = &shProg->VertexProgram->Base;
907 }
908 else {
909 progPos = shProg->Uniforms->Uniforms[location].FragPos;
910 if (progPos >= 0) {
911 prog = &shProg->FragmentProgram->Base;
912 }
913 }
914
915 for (i = 0; i < prog->Parameters->Parameters[progPos].Size; i++) {
916 params[i] = prog->Parameters->ParameterValues[progPos][i];
Brian5b01c5e2006-12-19 18:02:03 -0700917 }
918 }
919 else {
920 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(location)");
921 }
922 }
923 else {
Brian43975832007-01-04 08:21:09 -0700924 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700925 }
926}
927
928
929/**
930 * Called via ctx->Driver.GetUniformLocation().
931 */
Brian2d2bb352007-12-07 17:11:30 -0700932static GLint
Brian5b01c5e2006-12-19 18:02:03 -0700933_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
934{
Brian71623982007-01-30 16:55:03 -0700935 struct gl_shader_program *shProg
936 = _mesa_lookup_shader_program(ctx, program);
Brianbc029242008-04-04 18:59:21 -0600937 if (!shProg)
938 return -1;
Brian5b01c5e2006-12-19 18:02:03 -0700939
Brianbc029242008-04-04 18:59:21 -0600940 return _mesa_lookup_uniform(shProg->Uniforms, name);
Brian5b01c5e2006-12-19 18:02:03 -0700941}
942
943
Brian2d2bb352007-12-07 17:11:30 -0700944static GLboolean
Brian5b01c5e2006-12-19 18:02:03 -0700945_mesa_is_program(GLcontext *ctx, GLuint name)
946{
Brian65a18442006-12-19 18:46:56 -0700947 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
948 return shProg ? GL_TRUE : GL_FALSE;
Brian5b01c5e2006-12-19 18:02:03 -0700949}
950
951
Brian2d2bb352007-12-07 17:11:30 -0700952static GLboolean
Brian5b01c5e2006-12-19 18:02:03 -0700953_mesa_is_shader(GLcontext *ctx, GLuint name)
954{
Brian65a18442006-12-19 18:46:56 -0700955 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700956 return shader ? GL_TRUE : GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700957}
958
959
960
Brian5b01c5e2006-12-19 18:02:03 -0700961/**
962 * Called via ctx->Driver.ShaderSource()
963 */
Brian2d2bb352007-12-07 17:11:30 -0700964static void
Brian5b01c5e2006-12-19 18:02:03 -0700965_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -0700966{
Brian65a18442006-12-19 18:46:56 -0700967 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
968 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700969 _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSource(shaderObj)");
Brian34ae99d2006-12-18 08:28:54 -0700970 return;
971 }
972
Brian34ae99d2006-12-18 08:28:54 -0700973 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -0700974 if (sh->Source) {
975 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -0700976 }
Brian65a18442006-12-19 18:46:56 -0700977 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -0700978 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700979}
980
981
Brian5b01c5e2006-12-19 18:02:03 -0700982/**
983 * Called via ctx->Driver.CompileShader()
984 */
Brian2d2bb352007-12-07 17:11:30 -0700985static void
Brian5b01c5e2006-12-19 18:02:03 -0700986_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -0700987{
Brian65a18442006-12-19 18:46:56 -0700988 struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj);
Brian34ae99d2006-12-18 08:28:54 -0700989
Brian65a18442006-12-19 18:46:56 -0700990 if (!sh) {
Brian34ae99d2006-12-18 08:28:54 -0700991 _mesa_error(ctx, GL_INVALID_VALUE, "glCompileShader(shaderObj)");
992 return;
993 }
994
Brian43975832007-01-04 08:21:09 -0700995 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -0700996}
997
998
Brian5b01c5e2006-12-19 18:02:03 -0700999/**
1000 * Called via ctx->Driver.LinkProgram()
1001 */
Brian2d2bb352007-12-07 17:11:30 -07001002static void
Brian5b01c5e2006-12-19 18:02:03 -07001003_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001004{
Brian65a18442006-12-19 18:46:56 -07001005 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001006
Brian65a18442006-12-19 18:46:56 -07001007 shProg = _mesa_lookup_shader_program(ctx, program);
1008 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001009 _mesa_error(ctx, GL_INVALID_VALUE, "glLinkProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001010 return;
1011 }
1012
Brianc1771912007-02-16 09:56:19 -07001013 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001014}
1015
1016
1017/**
Brian5b01c5e2006-12-19 18:02:03 -07001018 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001019 */
Brian5b01c5e2006-12-19 18:02:03 -07001020void
1021_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001022{
Brian3c008a02007-04-12 15:22:32 -06001023 struct gl_shader_program *shProg;
1024
Brian00d63aa2007-02-03 11:35:02 -07001025 if (ctx->Shader.CurrentProgram &&
1026 ctx->Shader.CurrentProgram->Name == program) {
1027 /* no-op */
1028 return;
1029 }
1030
1031 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1032
Brian5b01c5e2006-12-19 18:02:03 -07001033 if (program) {
Brian65a18442006-12-19 18:46:56 -07001034 shProg = _mesa_lookup_shader_program(ctx, program);
1035 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001036 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -07001037 "glUseProgramObjectARB(programObj)");
1038 return;
1039 }
Brian5b01c5e2006-12-19 18:02:03 -07001040 }
1041 else {
Brian3c008a02007-04-12 15:22:32 -06001042 shProg = NULL;
1043 }
1044
1045 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001046}
Brian34ae99d2006-12-18 08:28:54 -07001047
Brian5b01c5e2006-12-19 18:02:03 -07001048
Brian8fed2462007-10-26 19:19:09 -06001049
1050/**
1051 * Update the vertex and fragment program's TexturesUsed arrays.
1052 */
1053static void
1054update_textures_used(struct gl_program *prog)
1055{
1056 GLuint s;
1057
1058 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1059
1060 for (s = 0; s < MAX_SAMPLERS; s++) {
1061 if (prog->SamplersUsed & (1 << s)) {
1062 GLuint u = prog->SamplerUnits[s];
1063 GLuint t = prog->SamplerTargets[s];
1064 assert(u < MAX_TEXTURE_IMAGE_UNITS);
1065 prog->TexturesUsed[u] |= (1 << t);
1066 }
1067 }
1068}
1069
1070
Brian5b01c5e2006-12-19 18:02:03 -07001071/**
Brianbc029242008-04-04 18:59:21 -06001072 * Set the value of a program's uniform variable.
1073 * \param program the program whose uniform to update
1074 * \param location the location/index of the uniform
1075 * \param type the datatype of the uniform
1076 * \param count the number of uniforms to set
1077 * \param elems number of elements per uniform
1078 * \param values the new values
1079 */
1080static void
1081set_program_uniform(GLcontext *ctx, struct gl_program *program, GLint location,
1082 GLenum type, GLint count, GLint elems, const void *values)
1083{
1084 if (program->Parameters->Parameters[location].Type == PROGRAM_SAMPLER) {
1085 /* This controls which texture unit which is used by a sampler */
1086 GLuint texUnit, sampler;
1087
1088 /* data type for setting samplers must be int */
1089 if (type != GL_INT || count != 1) {
1090 _mesa_error(ctx, GL_INVALID_OPERATION,
1091 "glUniform(only glUniform1i can be used "
1092 "to set sampler uniforms)");
1093 return;
1094 }
1095
1096 sampler = (GLuint) program->Parameters->ParameterValues[location][0];
1097 texUnit = ((GLuint *) values)[0];
1098
1099 /* check that the sampler (tex unit index) is legal */
1100 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1101 _mesa_error(ctx, GL_INVALID_VALUE,
1102 "glUniform1(invalid sampler/tex unit index)");
1103 return;
1104 }
1105
1106 /* This maps a sampler to a texture unit: */
1107 program->SamplerUnits[sampler] = texUnit;
1108 update_textures_used(program);
1109
1110 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1111 }
1112 else {
1113 /* ordinary uniform variable */
1114 GLint k, i;
1115
1116 if (count * elems > program->Parameters->Parameters[location].Size) {
1117 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1118 return;
1119 }
1120
1121 for (k = 0; k < count; k++) {
1122 GLfloat *uniformVal = program->Parameters->ParameterValues[location + k];
1123 if (type == GL_INT ||
1124 type == GL_INT_VEC2 ||
1125 type == GL_INT_VEC3 ||
1126 type == GL_INT_VEC4) {
1127 const GLint *iValues = ((const GLint *) values) + k * elems;
1128 for (i = 0; i < elems; i++) {
1129 uniformVal[i] = (GLfloat) iValues[i];
1130 }
1131 }
1132 else {
1133 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1134 for (i = 0; i < elems; i++) {
1135 uniformVal[i] = fValues[i];
1136 }
1137 }
1138 }
1139 }
1140}
1141
1142
1143/**
Brian5b01c5e2006-12-19 18:02:03 -07001144 * Called via ctx->Driver.Uniform().
1145 */
Brian2d2bb352007-12-07 17:11:30 -07001146static void
Brian5b01c5e2006-12-19 18:02:03 -07001147_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1148 const GLvoid *values, GLenum type)
1149{
Brian3a8e2772006-12-20 17:19:16 -07001150 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brianbc029242008-04-04 18:59:21 -06001151 GLint elems;
Brian3a8e2772006-12-20 17:19:16 -07001152
1153 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001154 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001155 return;
1156 }
1157
Brian Paulf84005c2008-05-14 16:01:31 -06001158 if (location == -1)
1159 return; /* The standard specifies this as a no-op */
1160
1161
Brianbc029242008-04-04 18:59:21 -06001162 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian3a8e2772006-12-20 17:19:16 -07001163 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
1164 return;
1165 }
1166
Brian52363952007-03-13 16:50:24 -06001167 if (count < 0) {
1168 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1169 return;
1170 }
1171
Brian98650bd2007-03-13 16:32:48 -06001172 switch (type) {
1173 case GL_FLOAT:
1174 case GL_INT:
1175 elems = 1;
1176 break;
1177 case GL_FLOAT_VEC2:
1178 case GL_INT_VEC2:
1179 elems = 2;
1180 break;
1181 case GL_FLOAT_VEC3:
1182 case GL_INT_VEC3:
1183 elems = 3;
1184 break;
1185 case GL_FLOAT_VEC4:
1186 case GL_INT_VEC4:
1187 elems = 4;
1188 break;
1189 default:
1190 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1191 return;
Brian89dc4852007-01-04 14:35:44 -07001192 }
Brian98650bd2007-03-13 16:32:48 -06001193
Brianbc029242008-04-04 18:59:21 -06001194 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1195
1196 /* A uniform var may be used by both a vertex shader and a fragment
1197 * shader. We may need to update one or both shader's uniform here:
1198 */
1199 if (shProg->VertexProgram) {
1200 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1201 if (loc >= 0) {
1202 set_program_uniform(ctx, &shProg->VertexProgram->Base,
1203 loc, type, count, elems, values);
1204 }
Brian98650bd2007-03-13 16:32:48 -06001205 }
1206
Brianbc029242008-04-04 18:59:21 -06001207 if (shProg->FragmentProgram) {
1208 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1209 if (loc >= 0) {
1210 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
1211 loc, type, count, elems, values);
Brian8fed2462007-10-26 19:19:09 -06001212 }
Brianbc029242008-04-04 18:59:21 -06001213 }
1214}
Brian8fed2462007-10-26 19:19:09 -06001215
Brian8fed2462007-10-26 19:19:09 -06001216
Brianbc029242008-04-04 18:59:21 -06001217static void
1218set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
1219 GLuint location, GLuint rows, GLuint cols,
1220 GLboolean transpose, const GLfloat *values)
1221{
1222 /*
1223 * Note: the _columns_ of a matrix are stored in program registers, not
1224 * the rows.
1225 */
1226 /* XXXX need to test 3x3 and 2x2 matrices... */
1227 if (transpose) {
1228 GLuint row, col;
1229 for (col = 0; col < cols; col++) {
1230 GLfloat *v = program->Parameters->ParameterValues[location + col];
1231 for (row = 0; row < rows; row++) {
1232 v[row] = values[row * cols + col];
1233 }
Brian8fed2462007-10-26 19:19:09 -06001234 }
Brian5cf73262007-01-05 16:02:45 -07001235 }
Brian8fed2462007-10-26 19:19:09 -06001236 else {
Brianbc029242008-04-04 18:59:21 -06001237 GLuint row, col;
1238 for (col = 0; col < cols; col++) {
1239 GLfloat *v = program->Parameters->ParameterValues[location + col];
1240 for (row = 0; row < rows; row++) {
1241 v[row] = values[col * rows + row];
Brian8fed2462007-10-26 19:19:09 -06001242 }
1243 }
1244 }
Brian34ae99d2006-12-18 08:28:54 -07001245}
1246
1247
1248/**
Brian5b01c5e2006-12-19 18:02:03 -07001249 * Called by ctx->Driver.UniformMatrix().
Brian34ae99d2006-12-18 08:28:54 -07001250 */
Brian2d2bb352007-12-07 17:11:30 -07001251static void
Brian5b01c5e2006-12-19 18:02:03 -07001252_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1253 GLenum matrixType, GLint location, GLsizei count,
1254 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001255{
Brian3a8e2772006-12-20 17:19:16 -07001256 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paulf84005c2008-05-14 16:01:31 -06001257
Brian3a8e2772006-12-20 17:19:16 -07001258 if (!shProg || !shProg->LinkStatus) {
1259 _mesa_error(ctx, GL_INVALID_OPERATION,
1260 "glUniformMatrix(program not linked)");
1261 return;
1262 }
Brian Paulf84005c2008-05-14 16:01:31 -06001263
1264 if (location == -1)
1265 return; /* The standard specifies this as a no-op */
1266
Brianbc029242008-04-04 18:59:21 -06001267 if (location < 0 || location >= shProg->Uniforms->NumUniforms) {
Brian3a8e2772006-12-20 17:19:16 -07001268 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
1269 return;
1270 }
Brian34ae99d2006-12-18 08:28:54 -07001271 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001272 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001273 return;
1274 }
1275
1276 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1277
Brianbc029242008-04-04 18:59:21 -06001278 if (shProg->VertexProgram) {
1279 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1280 if (loc >= 0) {
1281 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
1282 loc, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07001283 }
Brian34ae99d2006-12-18 08:28:54 -07001284 }
Brianbc029242008-04-04 18:59:21 -06001285
1286 if (shProg->FragmentProgram) {
1287 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1288 if (loc >= 0) {
1289 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
1290 loc, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07001291 }
Brian34ae99d2006-12-18 08:28:54 -07001292 }
1293}
1294
1295
Brian2d2bb352007-12-07 17:11:30 -07001296static void
Brian5b01c5e2006-12-19 18:02:03 -07001297_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001298{
Brian65a18442006-12-19 18:46:56 -07001299 struct gl_shader_program *shProg;
1300 shProg = _mesa_lookup_shader_program(ctx, program);
1301 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001302 _mesa_error(ctx, GL_INVALID_VALUE, "glValidateProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001303 return;
1304 }
Brian5b01c5e2006-12-19 18:02:03 -07001305 /* XXX temporary */
Brian65a18442006-12-19 18:46:56 -07001306 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001307
Brian5b01c5e2006-12-19 18:02:03 -07001308 /* From the GL spec:
1309 any two active samplers in the current program object are of
1310 different types, but refer to the same texture image unit,
1311
1312 any active sampler in the current program object refers to a texture
1313 image unit where fixed-function fragment processing accesses a
1314 texture target that does not match the sampler type, or
1315
1316 the sum of the number of active samplers in the program and the
1317 number of texture image units enabled for fixed-function fragment
1318 processing exceeds the combined limit on the total number of texture
1319 image units allowed.
1320 */
Brian34ae99d2006-12-18 08:28:54 -07001321}
Brian2d2bb352007-12-07 17:11:30 -07001322
1323
1324/**
1325 * Plug in Mesa's GLSL functions into the device driver function table.
1326 */
1327void
1328_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
1329{
1330 driver->AttachShader = _mesa_attach_shader;
1331 driver->BindAttribLocation = _mesa_bind_attrib_location;
1332 driver->CompileShader = _mesa_compile_shader;
1333 driver->CreateProgram = _mesa_create_program;
1334 driver->CreateShader = _mesa_create_shader;
1335 driver->DeleteProgram2 = _mesa_delete_program2;
1336 driver->DeleteShader = _mesa_delete_shader;
1337 driver->DetachShader = _mesa_detach_shader;
1338 driver->GetActiveAttrib = _mesa_get_active_attrib;
1339 driver->GetActiveUniform = _mesa_get_active_uniform;
1340 driver->GetAttachedShaders = _mesa_get_attached_shaders;
1341 driver->GetAttribLocation = _mesa_get_attrib_location;
1342 driver->GetHandle = _mesa_get_handle;
1343 driver->GetProgramiv = _mesa_get_programiv;
1344 driver->GetProgramInfoLog = _mesa_get_program_info_log;
1345 driver->GetShaderiv = _mesa_get_shaderiv;
1346 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
1347 driver->GetShaderSource = _mesa_get_shader_source;
1348 driver->GetUniformfv = _mesa_get_uniformfv;
1349 driver->GetUniformLocation = _mesa_get_uniform_location;
1350 driver->IsProgram = _mesa_is_program;
1351 driver->IsShader = _mesa_is_shader;
1352 driver->LinkProgram = _mesa_link_program;
1353 driver->ShaderSource = _mesa_shader_source;
1354 driver->Uniform = _mesa_uniform;
1355 driver->UniformMatrix = _mesa_uniform_matrix;
1356 driver->UseProgram = _mesa_use_program;
1357 driver->ValidateProgram = _mesa_validate_program;
1358}