blob: 2b3dbff7a084f762eb976653f79224c4e7ab2410 [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 }
129 if (shProg->Shaders) {
130 _mesa_free(shProg->Shaders);
131 shProg->Shaders = NULL;
132 }
133}
134
135
136/**
Brianb9fbedd2007-03-26 09:23:44 -0600137 * Free/delete a shader program object.
138 */
Brianf2923612006-12-20 09:56:44 -0700139void
140_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg)
141{
142 _mesa_free_shader_program_data(ctx, shProg);
Brianb9fbedd2007-03-26 09:23:44 -0600143 if (shProg->Shaders) {
144 _mesa_free(shProg->Shaders);
145 shProg->Shaders = NULL;
146 }
Brianf2923612006-12-20 09:56:44 -0700147 _mesa_free(shProg);
148}
149
150
151/**
Brian3c008a02007-04-12 15:22:32 -0600152 * Set ptr to point to shProg.
153 * If ptr is pointing to another object, decrement its refcount (and delete
154 * if refcount hits zero).
155 * Then set ptr to point to shProg, incrementing its refcount.
156 */
157/* XXX this could be static */
158void
159_mesa_reference_shader_program(GLcontext *ctx,
160 struct gl_shader_program **ptr,
161 struct gl_shader_program *shProg)
162{
163 assert(ptr);
164 if (*ptr == shProg) {
165 /* no-op */
166 return;
167 }
168 if (*ptr) {
169 /* Unreference the old shader program */
170 GLboolean deleteFlag = GL_FALSE;
171 struct gl_shader_program *old = *ptr;
172
173 ASSERT(old->RefCount > 0);
174 old->RefCount--;
175 /*printf("SHPROG DECR %p (%d) to %d\n",
176 (void*) old, old->Name, old->RefCount);*/
177 deleteFlag = (old->RefCount == 0);
178
179 if (deleteFlag) {
180 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
181 _mesa_free_shader_program(ctx, old);
182 }
183
184 *ptr = NULL;
185 }
186 assert(!*ptr);
187
188 if (shProg) {
189 shProg->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600190 /*printf("SHPROG INCR %p (%d) to %d\n",
191 (void*) shProg, shProg->Name, shProg->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600192 *ptr = shProg;
193 }
194}
195
196
197/**
Brianf2923612006-12-20 09:56:44 -0700198 * Lookup a GLSL program object.
199 */
200struct gl_shader_program *
201_mesa_lookup_shader_program(GLcontext *ctx, GLuint name)
202{
203 struct gl_shader_program *shProg;
204 if (name) {
205 shProg = (struct gl_shader_program *)
206 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
207 /* Note that both gl_shader and gl_shader_program objects are kept
208 * in the same hash table. Check the object's type to be sure it's
209 * what we're expecting.
210 */
Brianf3e8c322007-04-18 14:53:23 -0600211 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700212 return NULL;
213 }
214 return shProg;
215 }
216 return NULL;
217}
218
219
220/**
221 * Allocate a new gl_shader object, initialize it.
222 */
223struct gl_shader *
224_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
225{
226 struct gl_shader *shader;
227 assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
228 shader = CALLOC_STRUCT(gl_shader);
229 if (shader) {
230 shader->Type = type;
231 shader->Name = name;
232 shader->RefCount = 1;
233 }
234 return shader;
235}
236
237
238void
239_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh)
240{
241 GLuint i;
242 if (sh->Source)
243 _mesa_free((void *) sh->Source);
244 if (sh->InfoLog)
245 _mesa_free(sh->InfoLog);
Brian Pauld7913862008-05-14 12:19:22 -0600246 for (i = 0; i < sh->NumPrograms; i++)
247 _mesa_reference_program(ctx, &sh->Programs[i], NULL);
Brianf2923612006-12-20 09:56:44 -0700248 if (sh->Programs)
249 _mesa_free(sh->Programs);
250 _mesa_free(sh);
251}
252
253
254/**
Brian3c008a02007-04-12 15:22:32 -0600255 * Set ptr to point to sh.
256 * If ptr is pointing to another shader, decrement its refcount (and delete
257 * if refcount hits zero).
258 * Then set ptr to point to sh, incrementing its refcount.
259 */
260/* XXX this could be static */
261void
262_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr,
263 struct gl_shader *sh)
264{
265 assert(ptr);
266 if (*ptr == sh) {
267 /* no-op */
268 return;
269 }
270 if (*ptr) {
271 /* Unreference the old shader */
272 GLboolean deleteFlag = GL_FALSE;
273 struct gl_shader *old = *ptr;
274
275 ASSERT(old->RefCount > 0);
276 old->RefCount--;
Brian99193e42007-04-12 15:45:02 -0600277 /*printf("SHADER DECR %p (%d) to %d\n",
278 (void*) old, old->Name, old->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600279 deleteFlag = (old->RefCount == 0);
280
281 if (deleteFlag) {
282 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
283 _mesa_free_shader(ctx, old);
284 }
285
286 *ptr = NULL;
287 }
288 assert(!*ptr);
289
290 if (sh) {
291 /* reference new */
292 sh->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600293 /*printf("SHADER INCR %p (%d) to %d\n",
294 (void*) sh, sh->Name, sh->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600295 *ptr = sh;
296 }
297}
298
299
300/**
Brianf2923612006-12-20 09:56:44 -0700301 * Lookup a GLSL shader object.
302 */
303struct gl_shader *
304_mesa_lookup_shader(GLcontext *ctx, GLuint name)
305{
306 if (name) {
307 struct gl_shader *sh = (struct gl_shader *)
308 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
309 /* Note that both gl_shader and gl_shader_program objects are kept
310 * in the same hash table. Check the object's type to be sure it's
311 * what we're expecting.
312 */
Brianf3e8c322007-04-18 14:53:23 -0600313 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700314 return NULL;
315 }
316 return sh;
317 }
318 return NULL;
319}
320
321
Brianfa4d0362007-02-26 18:33:50 -0700322/**
323 * Initialize context's shader state.
324 */
Brianf2923612006-12-20 09:56:44 -0700325void
326_mesa_init_shader_state(GLcontext * ctx)
327{
Brianfa4d0362007-02-26 18:33:50 -0700328 /* Device drivers may override these to control what kind of instructions
329 * are generated by the GLSL compiler.
330 */
331 ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
michal4a470f62007-08-07 15:34:11 +0100332 ctx->Shader.EmitCondCodes = GL_FALSE;/*GL_TRUE;*/ /* XXX probably want GL_FALSE... */
Brianfa4d0362007-02-26 18:33:50 -0700333 ctx->Shader.EmitComments = GL_FALSE;
Brianf2923612006-12-20 09:56:44 -0700334}
335
336
Brian5b01c5e2006-12-19 18:02:03 -0700337/**
Brian935f93f2007-03-24 16:20:02 -0600338 * Free the per-context shader-related state.
339 */
340void
341_mesa_free_shader_state(GLcontext *ctx)
342{
Brian3c008a02007-04-12 15:22:32 -0600343 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
Brian935f93f2007-03-24 16:20:02 -0600344}
345
346
347/**
Brian5b01c5e2006-12-19 18:02:03 -0700348 * Copy string from <src> to <dst>, up to maxLength characters, returning
349 * length of <dst> in <length>.
350 * \param src the strings source
351 * \param maxLength max chars to copy
352 * \param length returns number of chars copied
353 * \param dst the string destination
354 */
355static void
356copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
357{
358 GLsizei len;
359 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
360 dst[len] = src[len];
361 if (maxLength > 0)
362 dst[len] = 0;
363 if (length)
364 *length = len;
365}
366
367
Brian5b01c5e2006-12-19 18:02:03 -0700368/**
369 * Called via ctx->Driver.AttachShader()
370 */
Brian2d2bb352007-12-07 17:11:30 -0700371static void
Brian5b01c5e2006-12-19 18:02:03 -0700372_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
373{
Brian65a18442006-12-19 18:46:56 -0700374 struct gl_shader_program *shProg
375 = _mesa_lookup_shader_program(ctx, program);
376 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
377 const GLuint n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700378 GLuint i;
379
Brian65a18442006-12-19 18:46:56 -0700380 if (!shProg || !sh) {
Brian43975832007-01-04 08:21:09 -0700381 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700382 "glAttachShader(bad program or shader name)");
383 return;
384 }
385
386 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700387 if (shProg->Shaders[i] == sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700388 /* already attached */
389 return;
Brian34ae99d2006-12-18 08:28:54 -0700390 }
391 }
Brian5b01c5e2006-12-19 18:02:03 -0700392
393 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700394 shProg->Shaders = (struct gl_shader **)
395 _mesa_realloc(shProg->Shaders,
396 n * sizeof(struct gl_shader *),
397 (n + 1) * sizeof(struct gl_shader *));
398 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700399 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
400 return;
401 }
402
403 /* append */
Brian3c008a02007-04-12 15:22:32 -0600404 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
405 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700406 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700407}
408
409
Brian2d2bb352007-12-07 17:11:30 -0700410static GLint
411_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
412 const GLchar *name)
413{
414 struct gl_shader_program *shProg
415 = _mesa_lookup_shader_program(ctx, program);
416
417 if (!shProg) {
418 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttribLocation");
419 return -1;
420 }
421
422 if (!shProg->LinkStatus) {
423 _mesa_error(ctx, GL_INVALID_OPERATION,
424 "glGetAttribLocation(program not linked)");
425 return -1;
426 }
427
428 if (!name)
429 return -1;
430
431 if (shProg->Attributes) {
432 GLint i = _mesa_lookup_parameter_index(shProg->Attributes, -1, name);
433 if (i >= 0) {
434 return shProg->Attributes->Parameters[i].StateIndexes[0];
435 }
436 }
437 return -1;
438}
439
440
441static void
Brian5b01c5e2006-12-19 18:02:03 -0700442_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
443 const GLchar *name)
444{
Brian65a18442006-12-19 18:46:56 -0700445 struct gl_shader_program *shProg
446 = _mesa_lookup_shader_program(ctx, program);
Brianb7978af2007-01-09 19:17:17 -0700447 const GLint size = -1; /* unknown size */
448 GLint i, oldIndex;
Brian5b01c5e2006-12-19 18:02:03 -0700449
Brian65a18442006-12-19 18:46:56 -0700450 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700451 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700452 return;
453 }
454
Brian9e4bae92006-12-20 09:27:42 -0700455 if (!name)
456 return;
457
458 if (strncmp(name, "gl_", 3) == 0) {
459 _mesa_error(ctx, GL_INVALID_OPERATION,
460 "glBindAttribLocation(illegal name)");
461 return;
462 }
463
Brian9f660252007-04-11 09:00:56 -0600464 if (shProg->LinkStatus) {
465 /* get current index/location for the attribute */
466 oldIndex = _mesa_get_attrib_location(ctx, program, name);
467 }
468 else {
469 oldIndex = -1;
470 }
Brian3209c3e2007-01-09 17:49:24 -0700471
472 /* this will replace the current value if it's already in the list */
Brianb7978af2007-01-09 19:17:17 -0700473 i = _mesa_add_attribute(shProg->Attributes, name, size, index);
Brian3209c3e2007-01-09 17:49:24 -0700474 if (i < 0) {
475 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
476 }
477
Brian9f660252007-04-11 09:00:56 -0600478 if (shProg->VertexProgram && oldIndex >= 0 && oldIndex != index) {
479 /* If the index changed, need to search/replace references to that attribute
480 * in the vertex program.
481 */
Brian3209c3e2007-01-09 17:49:24 -0700482 _slang_remap_attribute(&shProg->VertexProgram->Base, oldIndex, index);
483 }
Brian34ae99d2006-12-18 08:28:54 -0700484}
485
486
Brian2d2bb352007-12-07 17:11:30 -0700487static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700488_mesa_create_shader(GLcontext *ctx, GLenum type)
489{
Brian65a18442006-12-19 18:46:56 -0700490 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700491 GLuint name;
492
493 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
494
495 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700496 case GL_FRAGMENT_SHADER:
497 case GL_VERTEX_SHADER:
498 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700499 break;
500 default:
501 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
502 return 0;
503 }
504
Brian65a18442006-12-19 18:46:56 -0700505 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700506
507 return name;
508}
509
510
Brian2d2bb352007-12-07 17:11:30 -0700511static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700512_mesa_create_program(GLcontext *ctx)
513{
514 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700515 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700516
Brian65a18442006-12-19 18:46:56 -0700517 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
518 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700519
Brian65a18442006-12-19 18:46:56 -0700520 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700521
Brian3c008a02007-04-12 15:22:32 -0600522 assert(shProg->RefCount == 1);
523
Brian5b01c5e2006-12-19 18:02:03 -0700524 return name;
525}
526
527
Brian3c008a02007-04-12 15:22:32 -0600528/**
529 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
530 * DeleteProgramARB.
531 */
Brian2d2bb352007-12-07 17:11:30 -0700532static void
Brian5b01c5e2006-12-19 18:02:03 -0700533_mesa_delete_program2(GLcontext *ctx, GLuint name)
534{
Brian3c008a02007-04-12 15:22:32 -0600535 /*
536 * NOTE: deleting shaders/programs works a bit differently than
537 * texture objects (and buffer objects, etc). Shader/program
538 * handles/IDs exist in the hash table until the object is really
539 * deleted (refcount==0). With texture objects, the handle/ID is
540 * removed from the hash table in glDeleteTextures() while the tex
541 * object itself might linger until its refcount goes to zero.
542 */
Brian65a18442006-12-19 18:46:56 -0700543 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700544
Brian65a18442006-12-19 18:46:56 -0700545 shProg = _mesa_lookup_shader_program(ctx, name);
546 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700547 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteProgram(name)");
Brian5b01c5e2006-12-19 18:02:03 -0700548 return;
549 }
550
Brian9e4bae92006-12-20 09:27:42 -0700551 shProg->DeletePending = GL_TRUE;
552
Brian3c008a02007-04-12 15:22:32 -0600553 /* effectively, decr shProg's refcount */
554 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700555}
556
557
Brian2d2bb352007-12-07 17:11:30 -0700558static void
Brian5b01c5e2006-12-19 18:02:03 -0700559_mesa_delete_shader(GLcontext *ctx, GLuint shader)
560{
Brian9e4bae92006-12-20 09:27:42 -0700561 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
562 if (!sh) {
563 return;
564 }
Brian5b01c5e2006-12-19 18:02:03 -0700565
Brian9e4bae92006-12-20 09:27:42 -0700566 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600567
568 /* effectively, decr sh's refcount */
569 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700570}
571
572
Brian2d2bb352007-12-07 17:11:30 -0700573static void
Brian5b01c5e2006-12-19 18:02:03 -0700574_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
575{
Brian65a18442006-12-19 18:46:56 -0700576 struct gl_shader_program *shProg
577 = _mesa_lookup_shader_program(ctx, program);
578 const GLuint n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700579 GLuint i, j;
580
Brian65a18442006-12-19 18:46:56 -0700581 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700582 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700583 "glDetachShader(bad program or shader name)");
584 return;
585 }
586
587 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700588 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700589 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600590 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700591
Brian3c008a02007-04-12 15:22:32 -0600592 /* derefernce */
593 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700594
Brian5b01c5e2006-12-19 18:02:03 -0700595 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700596 newList = (struct gl_shader **)
597 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700598 if (!newList) {
599 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
600 return;
601 }
602 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700603 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700604 }
605 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700606 newList[j++] = shProg->Shaders[i];
607 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700608
Brian65a18442006-12-19 18:46:56 -0700609 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600610 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600611
612#ifdef DEBUG
613 /* sanity check */
614 {
615 for (j = 0; j < shProg->NumShaders; j++) {
616 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
617 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
618 assert(shProg->Shaders[j]->RefCount > 0);
619 }
620 }
621#endif
622
Brian5b01c5e2006-12-19 18:02:03 -0700623 return;
624 }
625 }
626
627 /* not found */
Brian43975832007-01-04 08:21:09 -0700628 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700629 "glDetachShader(shader not found)");
630}
631
632
Brian2d2bb352007-12-07 17:11:30 -0700633static void
Brian5b01c5e2006-12-19 18:02:03 -0700634_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
635 GLsizei maxLength, GLsizei *length, GLint *size,
636 GLenum *type, GLchar *nameOut)
637{
638 static const GLenum vec_types[] = {
639 GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4
640 };
Brian65a18442006-12-19 18:46:56 -0700641 struct gl_shader_program *shProg
642 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700643 GLint sz;
644
Brian65a18442006-12-19 18:46:56 -0700645 if (!shProg) {
Brianaaa57412007-04-18 15:22:43 -0600646 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib");
Brian5b01c5e2006-12-19 18:02:03 -0700647 return;
648 }
649
Brian65a18442006-12-19 18:46:56 -0700650 if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600651 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700652 return;
653 }
654
655 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700656 shProg->Attributes->Parameters[index].Name);
657 sz = shProg->Attributes->Parameters[index].Size;
Brian5b01c5e2006-12-19 18:02:03 -0700658 if (size)
659 *size = sz;
660 if (type)
661 *type = vec_types[sz]; /* XXX this is a temporary hack */
662}
663
664
665/**
666 * Called via ctx->Driver.GetActiveUniform().
667 */
Brian2d2bb352007-12-07 17:11:30 -0700668static void
Brian5b01c5e2006-12-19 18:02:03 -0700669_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
670 GLsizei maxLength, GLsizei *length, GLint *size,
671 GLenum *type, GLchar *nameOut)
672{
Brianbc029242008-04-04 18:59:21 -0600673 const struct gl_shader_program *shProg
Brian65a18442006-12-19 18:46:56 -0700674 = _mesa_lookup_shader_program(ctx, program);
Brianbc029242008-04-04 18:59:21 -0600675 const struct gl_program *prog;
676 GLint progPos;
Brian5b01c5e2006-12-19 18:02:03 -0700677
Brian65a18442006-12-19 18:46:56 -0700678 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700679 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform");
Brian5b01c5e2006-12-19 18:02:03 -0700680 return;
681 }
682
Brianbc029242008-04-04 18:59:21 -0600683 if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
Brian5b01c5e2006-12-19 18:02:03 -0700684 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
685 return;
686 }
687
Brianbc029242008-04-04 18:59:21 -0600688 progPos = shProg->Uniforms->Uniforms[index].VertPos;
689 if (progPos >= 0) {
690 prog = &shProg->VertexProgram->Base;
691 }
692 else {
693 progPos = shProg->Uniforms->Uniforms[index].FragPos;
694 if (progPos >= 0) {
695 prog = &shProg->FragmentProgram->Base;
Brian274ac7a2007-04-18 16:05:53 -0600696 }
697 }
698
Brianbc029242008-04-04 18:59:21 -0600699 if (!prog || progPos < 0)
700 return; /* should never happen */
701
702 if (nameOut)
703 copy_string(nameOut, maxLength, length,
704 prog->Parameters->Parameters[progPos].Name);
705 if (size)
706 *size = prog->Parameters->Parameters[progPos].Size;
707
708 if (type)
709 *type = prog->Parameters->Parameters[progPos].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700710}
711
712
713/**
714 * Called via ctx->Driver.GetAttachedShaders().
715 */
Brian2d2bb352007-12-07 17:11:30 -0700716static void
Brian5b01c5e2006-12-19 18:02:03 -0700717_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
718 GLsizei *count, GLuint *obj)
719{
Brian65a18442006-12-19 18:46:56 -0700720 struct gl_shader_program *shProg
721 = _mesa_lookup_shader_program(ctx, program);
722 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700723 GLint i;
Brian65a18442006-12-19 18:46:56 -0700724 for (i = 0; i < maxCount && i < shProg->NumShaders; i++) {
725 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700726 }
727 if (count)
728 *count = i;
729 }
730 else {
Brian43975832007-01-04 08:21:09 -0700731 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttachedShaders");
Brian5b01c5e2006-12-19 18:02:03 -0700732 }
733}
734
735
Brian2d2bb352007-12-07 17:11:30 -0700736static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700737_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700738{
739#if 0
740 GET_CURRENT_CONTEXT(ctx);
741
742 switch (pname) {
743 case GL_PROGRAM_OBJECT_ARB:
744 {
Brian5b01c5e2006-12-19 18:02:03 -0700745 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700746
747 if (pro != NULL)
748 return (**pro)._container._generic.
749 GetName((struct gl2_generic_intf **) (pro));
750 }
751 break;
752 default:
753 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
754 }
755#endif
756 return 0;
757}
758
759
Brian2d2bb352007-12-07 17:11:30 -0700760static void
Brian5b01c5e2006-12-19 18:02:03 -0700761_mesa_get_programiv(GLcontext *ctx, GLuint program,
762 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700763{
Brian65a18442006-12-19 18:46:56 -0700764 struct gl_shader_program *shProg
765 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700766
Brian65a18442006-12-19 18:46:56 -0700767 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700768 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700769 return;
770 }
771
Brian5b01c5e2006-12-19 18:02:03 -0700772 switch (pname) {
773 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700774 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700775 break;
776 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700777 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700778 break;
Brian5b01c5e2006-12-19 18:02:03 -0700779 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700780 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700781 break;
782 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600783 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700784 break;
785 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700786 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700787 break;
788 case GL_ACTIVE_ATTRIBUTES:
Brian3209c3e2007-01-09 17:49:24 -0700789 *params = shProg->Attributes ? shProg->Attributes->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700790 break;
791 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600792 *params = _mesa_longest_parameter_name(shProg->Attributes,
793 PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700794 break;
795 case GL_ACTIVE_UNIFORMS:
Brianbc029242008-04-04 18:59:21 -0600796 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700797 break;
798 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brianbc029242008-04-04 18:59:21 -0600799 *params = _mesa_longest_uniform_name(shProg->Uniforms);
Brian274ac7a2007-04-18 16:05:53 -0600800 if (*params > 0)
801 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700802 break;
803 default:
Brian5b01c5e2006-12-19 18:02:03 -0700804 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
805 return;
Brian34ae99d2006-12-18 08:28:54 -0700806 }
Brian5b01c5e2006-12-19 18:02:03 -0700807}
Brian34ae99d2006-12-18 08:28:54 -0700808
Brian34ae99d2006-12-18 08:28:54 -0700809
Brian2d2bb352007-12-07 17:11:30 -0700810static void
Brian5b01c5e2006-12-19 18:02:03 -0700811_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
812{
Brian65a18442006-12-19 18:46:56 -0700813 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700814
815 if (!shader) {
816 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderiv(shader)");
817 return;
818 }
Brian65a18442006-12-19 18:46:56 -0700819
Brian5b01c5e2006-12-19 18:02:03 -0700820 switch (pname) {
821 case GL_SHADER_TYPE:
822 *params = shader->Type;
823 break;
824 case GL_DELETE_STATUS:
825 *params = shader->DeletePending;
826 break;
827 case GL_COMPILE_STATUS:
828 *params = shader->CompileStatus;
829 break;
830 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600831 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700832 break;
833 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600834 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700835 break;
836 default:
837 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
838 return;
839 }
840}
841
842
Brian2d2bb352007-12-07 17:11:30 -0700843static void
Brian5b01c5e2006-12-19 18:02:03 -0700844_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
845 GLsizei *length, GLchar *infoLog)
846{
Brian65a18442006-12-19 18:46:56 -0700847 struct gl_shader_program *shProg
848 = _mesa_lookup_shader_program(ctx, program);
849 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700850 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
851 return;
852 }
Brian65a18442006-12-19 18:46:56 -0700853 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700854}
855
856
Brian2d2bb352007-12-07 17:11:30 -0700857static void
Brian5b01c5e2006-12-19 18:02:03 -0700858_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
859 GLsizei *length, GLchar *infoLog)
860{
Brian65a18442006-12-19 18:46:56 -0700861 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
862 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700863 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
864 return;
865 }
Brian65a18442006-12-19 18:46:56 -0700866 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700867}
868
869
870/**
871 * Called via ctx->Driver.GetShaderSource().
872 */
Brian2d2bb352007-12-07 17:11:30 -0700873static void
Brian5b01c5e2006-12-19 18:02:03 -0700874_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
875 GLsizei *length, GLchar *sourceOut)
876{
Brian65a18442006-12-19 18:46:56 -0700877 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
878 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700879 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderSource(shader)");
880 return;
881 }
Brian65a18442006-12-19 18:46:56 -0700882 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -0700883}
884
885
886/**
887 * Called via ctx->Driver.GetUniformfv().
888 */
Brian2d2bb352007-12-07 17:11:30 -0700889static void
Brian5b01c5e2006-12-19 18:02:03 -0700890_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
891 GLfloat *params)
892{
Brian65a18442006-12-19 18:46:56 -0700893 struct gl_shader_program *shProg
894 = _mesa_lookup_shader_program(ctx, program);
895 if (shProg) {
Brianbc029242008-04-04 18:59:21 -0600896 if (location < shProg->Uniforms->NumUniforms) {
897 GLint progPos, i;
898 const struct gl_program *prog;
899
900 progPos = shProg->Uniforms->Uniforms[location].VertPos;
901 if (progPos >= 0) {
902 prog = &shProg->VertexProgram->Base;
903 }
904 else {
905 progPos = shProg->Uniforms->Uniforms[location].FragPos;
906 if (progPos >= 0) {
907 prog = &shProg->FragmentProgram->Base;
908 }
909 }
910
911 for (i = 0; i < prog->Parameters->Parameters[progPos].Size; i++) {
912 params[i] = prog->Parameters->ParameterValues[progPos][i];
Brian5b01c5e2006-12-19 18:02:03 -0700913 }
914 }
915 else {
916 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(location)");
917 }
918 }
919 else {
Brian43975832007-01-04 08:21:09 -0700920 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700921 }
922}
923
924
925/**
926 * Called via ctx->Driver.GetUniformLocation().
927 */
Brian2d2bb352007-12-07 17:11:30 -0700928static GLint
Brian5b01c5e2006-12-19 18:02:03 -0700929_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
930{
Brian71623982007-01-30 16:55:03 -0700931 struct gl_shader_program *shProg
932 = _mesa_lookup_shader_program(ctx, program);
Brianbc029242008-04-04 18:59:21 -0600933 if (!shProg)
934 return -1;
Brian5b01c5e2006-12-19 18:02:03 -0700935
Brianbc029242008-04-04 18:59:21 -0600936 return _mesa_lookup_uniform(shProg->Uniforms, name);
Brian5b01c5e2006-12-19 18:02:03 -0700937}
938
939
Brian2d2bb352007-12-07 17:11:30 -0700940static GLboolean
Brian5b01c5e2006-12-19 18:02:03 -0700941_mesa_is_program(GLcontext *ctx, GLuint name)
942{
Brian65a18442006-12-19 18:46:56 -0700943 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
944 return shProg ? GL_TRUE : GL_FALSE;
Brian5b01c5e2006-12-19 18:02:03 -0700945}
946
947
Brian2d2bb352007-12-07 17:11:30 -0700948static GLboolean
Brian5b01c5e2006-12-19 18:02:03 -0700949_mesa_is_shader(GLcontext *ctx, GLuint name)
950{
Brian65a18442006-12-19 18:46:56 -0700951 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700952 return shader ? GL_TRUE : GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700953}
954
955
956
Brian5b01c5e2006-12-19 18:02:03 -0700957/**
958 * Called via ctx->Driver.ShaderSource()
959 */
Brian2d2bb352007-12-07 17:11:30 -0700960static void
Brian5b01c5e2006-12-19 18:02:03 -0700961_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -0700962{
Brian65a18442006-12-19 18:46:56 -0700963 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
964 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700965 _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSource(shaderObj)");
Brian34ae99d2006-12-18 08:28:54 -0700966 return;
967 }
968
Brian34ae99d2006-12-18 08:28:54 -0700969 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -0700970 if (sh->Source) {
971 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -0700972 }
Brian65a18442006-12-19 18:46:56 -0700973 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -0700974 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700975}
976
977
Brian5b01c5e2006-12-19 18:02:03 -0700978/**
979 * Called via ctx->Driver.CompileShader()
980 */
Brian2d2bb352007-12-07 17:11:30 -0700981static void
Brian5b01c5e2006-12-19 18:02:03 -0700982_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -0700983{
Brian65a18442006-12-19 18:46:56 -0700984 struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj);
Brian34ae99d2006-12-18 08:28:54 -0700985
Brian65a18442006-12-19 18:46:56 -0700986 if (!sh) {
Brian34ae99d2006-12-18 08:28:54 -0700987 _mesa_error(ctx, GL_INVALID_VALUE, "glCompileShader(shaderObj)");
988 return;
989 }
990
Brian43975832007-01-04 08:21:09 -0700991 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -0700992}
993
994
Brian5b01c5e2006-12-19 18:02:03 -0700995/**
996 * Called via ctx->Driver.LinkProgram()
997 */
Brian2d2bb352007-12-07 17:11:30 -0700998static void
Brian5b01c5e2006-12-19 18:02:03 -0700999_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001000{
Brian65a18442006-12-19 18:46:56 -07001001 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001002
Brian65a18442006-12-19 18:46:56 -07001003 shProg = _mesa_lookup_shader_program(ctx, program);
1004 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001005 _mesa_error(ctx, GL_INVALID_VALUE, "glLinkProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001006 return;
1007 }
1008
Brianc1771912007-02-16 09:56:19 -07001009 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001010}
1011
1012
1013/**
Brian5b01c5e2006-12-19 18:02:03 -07001014 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001015 */
Brian5b01c5e2006-12-19 18:02:03 -07001016void
1017_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001018{
Brian3c008a02007-04-12 15:22:32 -06001019 struct gl_shader_program *shProg;
1020
Brian00d63aa2007-02-03 11:35:02 -07001021 if (ctx->Shader.CurrentProgram &&
1022 ctx->Shader.CurrentProgram->Name == program) {
1023 /* no-op */
1024 return;
1025 }
1026
1027 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1028
Brian5b01c5e2006-12-19 18:02:03 -07001029 if (program) {
Brian65a18442006-12-19 18:46:56 -07001030 shProg = _mesa_lookup_shader_program(ctx, program);
1031 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001032 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -07001033 "glUseProgramObjectARB(programObj)");
1034 return;
1035 }
Brian5b01c5e2006-12-19 18:02:03 -07001036 }
1037 else {
Brian3c008a02007-04-12 15:22:32 -06001038 shProg = NULL;
1039 }
1040
1041 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001042}
Brian34ae99d2006-12-18 08:28:54 -07001043
Brian5b01c5e2006-12-19 18:02:03 -07001044
Brian8fed2462007-10-26 19:19:09 -06001045
1046/**
1047 * Update the vertex and fragment program's TexturesUsed arrays.
1048 */
1049static void
1050update_textures_used(struct gl_program *prog)
1051{
1052 GLuint s;
1053
1054 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1055
1056 for (s = 0; s < MAX_SAMPLERS; s++) {
1057 if (prog->SamplersUsed & (1 << s)) {
1058 GLuint u = prog->SamplerUnits[s];
1059 GLuint t = prog->SamplerTargets[s];
1060 assert(u < MAX_TEXTURE_IMAGE_UNITS);
1061 prog->TexturesUsed[u] |= (1 << t);
1062 }
1063 }
1064}
1065
1066
Brian5b01c5e2006-12-19 18:02:03 -07001067/**
Brianbc029242008-04-04 18:59:21 -06001068 * Set the value of a program's uniform variable.
1069 * \param program the program whose uniform to update
1070 * \param location the location/index of the uniform
1071 * \param type the datatype of the uniform
1072 * \param count the number of uniforms to set
1073 * \param elems number of elements per uniform
1074 * \param values the new values
1075 */
1076static void
1077set_program_uniform(GLcontext *ctx, struct gl_program *program, GLint location,
1078 GLenum type, GLint count, GLint elems, const void *values)
1079{
1080 if (program->Parameters->Parameters[location].Type == PROGRAM_SAMPLER) {
1081 /* This controls which texture unit which is used by a sampler */
1082 GLuint texUnit, sampler;
1083
1084 /* data type for setting samplers must be int */
1085 if (type != GL_INT || count != 1) {
1086 _mesa_error(ctx, GL_INVALID_OPERATION,
1087 "glUniform(only glUniform1i can be used "
1088 "to set sampler uniforms)");
1089 return;
1090 }
1091
1092 sampler = (GLuint) program->Parameters->ParameterValues[location][0];
1093 texUnit = ((GLuint *) values)[0];
1094
1095 /* check that the sampler (tex unit index) is legal */
1096 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1097 _mesa_error(ctx, GL_INVALID_VALUE,
1098 "glUniform1(invalid sampler/tex unit index)");
1099 return;
1100 }
1101
1102 /* This maps a sampler to a texture unit: */
1103 program->SamplerUnits[sampler] = texUnit;
1104 update_textures_used(program);
1105
1106 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1107 }
1108 else {
1109 /* ordinary uniform variable */
1110 GLint k, i;
1111
1112 if (count * elems > program->Parameters->Parameters[location].Size) {
1113 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1114 return;
1115 }
1116
1117 for (k = 0; k < count; k++) {
1118 GLfloat *uniformVal = program->Parameters->ParameterValues[location + k];
1119 if (type == GL_INT ||
1120 type == GL_INT_VEC2 ||
1121 type == GL_INT_VEC3 ||
1122 type == GL_INT_VEC4) {
1123 const GLint *iValues = ((const GLint *) values) + k * elems;
1124 for (i = 0; i < elems; i++) {
1125 uniformVal[i] = (GLfloat) iValues[i];
1126 }
1127 }
1128 else {
1129 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1130 for (i = 0; i < elems; i++) {
1131 uniformVal[i] = fValues[i];
1132 }
1133 }
1134 }
1135 }
1136}
1137
1138
1139/**
Brian5b01c5e2006-12-19 18:02:03 -07001140 * Called via ctx->Driver.Uniform().
1141 */
Brian2d2bb352007-12-07 17:11:30 -07001142static void
Brian5b01c5e2006-12-19 18:02:03 -07001143_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1144 const GLvoid *values, GLenum type)
1145{
Brian3a8e2772006-12-20 17:19:16 -07001146 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brianbc029242008-04-04 18:59:21 -06001147 GLint elems;
Brian3a8e2772006-12-20 17:19:16 -07001148
1149 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001150 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001151 return;
1152 }
1153
Brianbc029242008-04-04 18:59:21 -06001154 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian3a8e2772006-12-20 17:19:16 -07001155 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
1156 return;
1157 }
1158
Brian52363952007-03-13 16:50:24 -06001159 if (count < 0) {
1160 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1161 return;
1162 }
1163
Brian98650bd2007-03-13 16:32:48 -06001164 switch (type) {
1165 case GL_FLOAT:
1166 case GL_INT:
1167 elems = 1;
1168 break;
1169 case GL_FLOAT_VEC2:
1170 case GL_INT_VEC2:
1171 elems = 2;
1172 break;
1173 case GL_FLOAT_VEC3:
1174 case GL_INT_VEC3:
1175 elems = 3;
1176 break;
1177 case GL_FLOAT_VEC4:
1178 case GL_INT_VEC4:
1179 elems = 4;
1180 break;
1181 default:
1182 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1183 return;
Brian89dc4852007-01-04 14:35:44 -07001184 }
Brian98650bd2007-03-13 16:32:48 -06001185
Brianbc029242008-04-04 18:59:21 -06001186 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1187
1188 /* A uniform var may be used by both a vertex shader and a fragment
1189 * shader. We may need to update one or both shader's uniform here:
1190 */
1191 if (shProg->VertexProgram) {
1192 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1193 if (loc >= 0) {
1194 set_program_uniform(ctx, &shProg->VertexProgram->Base,
1195 loc, type, count, elems, values);
1196 }
Brian98650bd2007-03-13 16:32:48 -06001197 }
1198
Brianbc029242008-04-04 18:59:21 -06001199 if (shProg->FragmentProgram) {
1200 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1201 if (loc >= 0) {
1202 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
1203 loc, type, count, elems, values);
Brian8fed2462007-10-26 19:19:09 -06001204 }
Brianbc029242008-04-04 18:59:21 -06001205 }
1206}
Brian8fed2462007-10-26 19:19:09 -06001207
Brian8fed2462007-10-26 19:19:09 -06001208
Brianbc029242008-04-04 18:59:21 -06001209static void
1210set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
1211 GLuint location, GLuint rows, GLuint cols,
1212 GLboolean transpose, const GLfloat *values)
1213{
1214 /*
1215 * Note: the _columns_ of a matrix are stored in program registers, not
1216 * the rows.
1217 */
1218 /* XXXX need to test 3x3 and 2x2 matrices... */
1219 if (transpose) {
1220 GLuint row, col;
1221 for (col = 0; col < cols; col++) {
1222 GLfloat *v = program->Parameters->ParameterValues[location + col];
1223 for (row = 0; row < rows; row++) {
1224 v[row] = values[row * cols + col];
1225 }
Brian8fed2462007-10-26 19:19:09 -06001226 }
Brian5cf73262007-01-05 16:02:45 -07001227 }
Brian8fed2462007-10-26 19:19:09 -06001228 else {
Brianbc029242008-04-04 18:59:21 -06001229 GLuint row, col;
1230 for (col = 0; col < cols; col++) {
1231 GLfloat *v = program->Parameters->ParameterValues[location + col];
1232 for (row = 0; row < rows; row++) {
1233 v[row] = values[col * rows + row];
Brian8fed2462007-10-26 19:19:09 -06001234 }
1235 }
1236 }
Brian34ae99d2006-12-18 08:28:54 -07001237}
1238
1239
1240/**
Brian5b01c5e2006-12-19 18:02:03 -07001241 * Called by ctx->Driver.UniformMatrix().
Brian34ae99d2006-12-18 08:28:54 -07001242 */
Brian2d2bb352007-12-07 17:11:30 -07001243static void
Brian5b01c5e2006-12-19 18:02:03 -07001244_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1245 GLenum matrixType, GLint location, GLsizei count,
1246 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001247{
Brian3a8e2772006-12-20 17:19:16 -07001248 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
1249 if (!shProg || !shProg->LinkStatus) {
1250 _mesa_error(ctx, GL_INVALID_OPERATION,
1251 "glUniformMatrix(program not linked)");
1252 return;
1253 }
Brianbc029242008-04-04 18:59:21 -06001254 if (location < 0 || location >= shProg->Uniforms->NumUniforms) {
Brian3a8e2772006-12-20 17:19:16 -07001255 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
1256 return;
1257 }
Brian34ae99d2006-12-18 08:28:54 -07001258 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001259 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001260 return;
1261 }
1262
1263 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1264
Brianbc029242008-04-04 18:59:21 -06001265 if (shProg->VertexProgram) {
1266 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1267 if (loc >= 0) {
1268 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
1269 loc, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07001270 }
Brian34ae99d2006-12-18 08:28:54 -07001271 }
Brianbc029242008-04-04 18:59:21 -06001272
1273 if (shProg->FragmentProgram) {
1274 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1275 if (loc >= 0) {
1276 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
1277 loc, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07001278 }
Brian34ae99d2006-12-18 08:28:54 -07001279 }
1280}
1281
1282
Brian2d2bb352007-12-07 17:11:30 -07001283static void
Brian5b01c5e2006-12-19 18:02:03 -07001284_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001285{
Brian65a18442006-12-19 18:46:56 -07001286 struct gl_shader_program *shProg;
1287 shProg = _mesa_lookup_shader_program(ctx, program);
1288 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001289 _mesa_error(ctx, GL_INVALID_VALUE, "glValidateProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001290 return;
1291 }
Brian5b01c5e2006-12-19 18:02:03 -07001292 /* XXX temporary */
Brian65a18442006-12-19 18:46:56 -07001293 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001294
Brian5b01c5e2006-12-19 18:02:03 -07001295 /* From the GL spec:
1296 any two active samplers in the current program object are of
1297 different types, but refer to the same texture image unit,
1298
1299 any active sampler in the current program object refers to a texture
1300 image unit where fixed-function fragment processing accesses a
1301 texture target that does not match the sampler type, or
1302
1303 the sum of the number of active samplers in the program and the
1304 number of texture image units enabled for fixed-function fragment
1305 processing exceeds the combined limit on the total number of texture
1306 image units allowed.
1307 */
Brian34ae99d2006-12-18 08:28:54 -07001308}
Brian2d2bb352007-12-07 17:11:30 -07001309
1310
1311/**
1312 * Plug in Mesa's GLSL functions into the device driver function table.
1313 */
1314void
1315_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
1316{
1317 driver->AttachShader = _mesa_attach_shader;
1318 driver->BindAttribLocation = _mesa_bind_attrib_location;
1319 driver->CompileShader = _mesa_compile_shader;
1320 driver->CreateProgram = _mesa_create_program;
1321 driver->CreateShader = _mesa_create_shader;
1322 driver->DeleteProgram2 = _mesa_delete_program2;
1323 driver->DeleteShader = _mesa_delete_shader;
1324 driver->DetachShader = _mesa_detach_shader;
1325 driver->GetActiveAttrib = _mesa_get_active_attrib;
1326 driver->GetActiveUniform = _mesa_get_active_uniform;
1327 driver->GetAttachedShaders = _mesa_get_attached_shaders;
1328 driver->GetAttribLocation = _mesa_get_attrib_location;
1329 driver->GetHandle = _mesa_get_handle;
1330 driver->GetProgramiv = _mesa_get_programiv;
1331 driver->GetProgramInfoLog = _mesa_get_program_info_log;
1332 driver->GetShaderiv = _mesa_get_shaderiv;
1333 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
1334 driver->GetShaderSource = _mesa_get_shader_source;
1335 driver->GetUniformfv = _mesa_get_uniformfv;
1336 driver->GetUniformLocation = _mesa_get_uniform_location;
1337 driver->IsProgram = _mesa_is_program;
1338 driver->IsShader = _mesa_is_shader;
1339 driver->LinkProgram = _mesa_link_program;
1340 driver->ShaderSource = _mesa_shader_source;
1341 driver->Uniform = _mesa_uniform;
1342 driver->UniformMatrix = _mesa_uniform_matrix;
1343 driver->UseProgram = _mesa_use_program;
1344 driver->ValidateProgram = _mesa_validate_program;
1345}