blob: f12fa28d97bb4d21407bed38bcec429a4918a74e [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);
246 for (i = 0; i < sh->NumPrograms; i++) {
247 assert(sh->Programs[i]);
Brianf8acc392008-03-22 10:27:55 -0600248 ctx->Driver.DeleteProgram(ctx, sh->Programs[i]);
Brianf2923612006-12-20 09:56:44 -0700249 }
250 if (sh->Programs)
251 _mesa_free(sh->Programs);
252 _mesa_free(sh);
253}
254
255
256/**
Brian3c008a02007-04-12 15:22:32 -0600257 * Set ptr to point to sh.
258 * If ptr is pointing to another shader, decrement its refcount (and delete
259 * if refcount hits zero).
260 * Then set ptr to point to sh, incrementing its refcount.
261 */
262/* XXX this could be static */
263void
264_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr,
265 struct gl_shader *sh)
266{
267 assert(ptr);
268 if (*ptr == sh) {
269 /* no-op */
270 return;
271 }
272 if (*ptr) {
273 /* Unreference the old shader */
274 GLboolean deleteFlag = GL_FALSE;
275 struct gl_shader *old = *ptr;
276
277 ASSERT(old->RefCount > 0);
278 old->RefCount--;
Brian99193e42007-04-12 15:45:02 -0600279 /*printf("SHADER DECR %p (%d) to %d\n",
280 (void*) old, old->Name, old->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600281 deleteFlag = (old->RefCount == 0);
282
283 if (deleteFlag) {
284 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
285 _mesa_free_shader(ctx, old);
286 }
287
288 *ptr = NULL;
289 }
290 assert(!*ptr);
291
292 if (sh) {
293 /* reference new */
294 sh->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600295 /*printf("SHADER INCR %p (%d) to %d\n",
296 (void*) sh, sh->Name, sh->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600297 *ptr = sh;
298 }
299}
300
301
302/**
Brianf2923612006-12-20 09:56:44 -0700303 * Lookup a GLSL shader object.
304 */
305struct gl_shader *
306_mesa_lookup_shader(GLcontext *ctx, GLuint name)
307{
308 if (name) {
309 struct gl_shader *sh = (struct gl_shader *)
310 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
311 /* Note that both gl_shader and gl_shader_program objects are kept
312 * in the same hash table. Check the object's type to be sure it's
313 * what we're expecting.
314 */
Brianf3e8c322007-04-18 14:53:23 -0600315 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700316 return NULL;
317 }
318 return sh;
319 }
320 return NULL;
321}
322
323
Brianfa4d0362007-02-26 18:33:50 -0700324/**
325 * Initialize context's shader state.
326 */
Brianf2923612006-12-20 09:56:44 -0700327void
328_mesa_init_shader_state(GLcontext * ctx)
329{
Brianfa4d0362007-02-26 18:33:50 -0700330 /* Device drivers may override these to control what kind of instructions
331 * are generated by the GLSL compiler.
332 */
333 ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
michal4a470f62007-08-07 15:34:11 +0100334 ctx->Shader.EmitCondCodes = GL_FALSE;/*GL_TRUE;*/ /* XXX probably want GL_FALSE... */
Brianfa4d0362007-02-26 18:33:50 -0700335 ctx->Shader.EmitComments = GL_FALSE;
Brianf2923612006-12-20 09:56:44 -0700336}
337
338
Brian5b01c5e2006-12-19 18:02:03 -0700339/**
Brian935f93f2007-03-24 16:20:02 -0600340 * Free the per-context shader-related state.
341 */
342void
343_mesa_free_shader_state(GLcontext *ctx)
344{
Brian3c008a02007-04-12 15:22:32 -0600345 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
Brian935f93f2007-03-24 16:20:02 -0600346}
347
348
349/**
Brian5b01c5e2006-12-19 18:02:03 -0700350 * Copy string from <src> to <dst>, up to maxLength characters, returning
351 * length of <dst> in <length>.
352 * \param src the strings source
353 * \param maxLength max chars to copy
354 * \param length returns number of chars copied
355 * \param dst the string destination
356 */
357static void
358copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
359{
360 GLsizei len;
361 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
362 dst[len] = src[len];
363 if (maxLength > 0)
364 dst[len] = 0;
365 if (length)
366 *length = len;
367}
368
369
Brian5b01c5e2006-12-19 18:02:03 -0700370/**
371 * Called via ctx->Driver.AttachShader()
372 */
Brian2d2bb352007-12-07 17:11:30 -0700373static void
Brian5b01c5e2006-12-19 18:02:03 -0700374_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
375{
Brian65a18442006-12-19 18:46:56 -0700376 struct gl_shader_program *shProg
377 = _mesa_lookup_shader_program(ctx, program);
378 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
379 const GLuint n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700380 GLuint i;
381
Brian65a18442006-12-19 18:46:56 -0700382 if (!shProg || !sh) {
Brian43975832007-01-04 08:21:09 -0700383 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700384 "glAttachShader(bad program or shader name)");
385 return;
386 }
387
388 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700389 if (shProg->Shaders[i] == sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700390 /* already attached */
391 return;
Brian34ae99d2006-12-18 08:28:54 -0700392 }
393 }
Brian5b01c5e2006-12-19 18:02:03 -0700394
395 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700396 shProg->Shaders = (struct gl_shader **)
397 _mesa_realloc(shProg->Shaders,
398 n * sizeof(struct gl_shader *),
399 (n + 1) * sizeof(struct gl_shader *));
400 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700401 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
402 return;
403 }
404
405 /* append */
Brian3c008a02007-04-12 15:22:32 -0600406 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
407 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700408 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700409}
410
411
Brian2d2bb352007-12-07 17:11:30 -0700412static GLint
413_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
414 const GLchar *name)
415{
416 struct gl_shader_program *shProg
417 = _mesa_lookup_shader_program(ctx, program);
418
419 if (!shProg) {
420 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttribLocation");
421 return -1;
422 }
423
424 if (!shProg->LinkStatus) {
425 _mesa_error(ctx, GL_INVALID_OPERATION,
426 "glGetAttribLocation(program not linked)");
427 return -1;
428 }
429
430 if (!name)
431 return -1;
432
433 if (shProg->Attributes) {
434 GLint i = _mesa_lookup_parameter_index(shProg->Attributes, -1, name);
435 if (i >= 0) {
436 return shProg->Attributes->Parameters[i].StateIndexes[0];
437 }
438 }
439 return -1;
440}
441
442
443static void
Brian5b01c5e2006-12-19 18:02:03 -0700444_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
445 const GLchar *name)
446{
Brian65a18442006-12-19 18:46:56 -0700447 struct gl_shader_program *shProg
448 = _mesa_lookup_shader_program(ctx, program);
Brianb7978af2007-01-09 19:17:17 -0700449 const GLint size = -1; /* unknown size */
450 GLint i, oldIndex;
Brian5b01c5e2006-12-19 18:02:03 -0700451
Brian65a18442006-12-19 18:46:56 -0700452 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700453 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700454 return;
455 }
456
Brian9e4bae92006-12-20 09:27:42 -0700457 if (!name)
458 return;
459
460 if (strncmp(name, "gl_", 3) == 0) {
461 _mesa_error(ctx, GL_INVALID_OPERATION,
462 "glBindAttribLocation(illegal name)");
463 return;
464 }
465
Brian9f660252007-04-11 09:00:56 -0600466 if (shProg->LinkStatus) {
467 /* get current index/location for the attribute */
468 oldIndex = _mesa_get_attrib_location(ctx, program, name);
469 }
470 else {
471 oldIndex = -1;
472 }
Brian3209c3e2007-01-09 17:49:24 -0700473
474 /* this will replace the current value if it's already in the list */
Brianb7978af2007-01-09 19:17:17 -0700475 i = _mesa_add_attribute(shProg->Attributes, name, size, index);
Brian3209c3e2007-01-09 17:49:24 -0700476 if (i < 0) {
477 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
478 }
479
Brian9f660252007-04-11 09:00:56 -0600480 if (shProg->VertexProgram && oldIndex >= 0 && oldIndex != index) {
481 /* If the index changed, need to search/replace references to that attribute
482 * in the vertex program.
483 */
Brian3209c3e2007-01-09 17:49:24 -0700484 _slang_remap_attribute(&shProg->VertexProgram->Base, oldIndex, index);
485 }
Brian34ae99d2006-12-18 08:28:54 -0700486}
487
488
Brian2d2bb352007-12-07 17:11:30 -0700489static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700490_mesa_create_shader(GLcontext *ctx, GLenum type)
491{
Brian65a18442006-12-19 18:46:56 -0700492 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700493 GLuint name;
494
495 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
496
497 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700498 case GL_FRAGMENT_SHADER:
499 case GL_VERTEX_SHADER:
500 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700501 break;
502 default:
503 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
504 return 0;
505 }
506
Brian65a18442006-12-19 18:46:56 -0700507 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700508
509 return name;
510}
511
512
Brian2d2bb352007-12-07 17:11:30 -0700513static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700514_mesa_create_program(GLcontext *ctx)
515{
516 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700517 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700518
Brian65a18442006-12-19 18:46:56 -0700519 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
520 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700521
Brian65a18442006-12-19 18:46:56 -0700522 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700523
Brian3c008a02007-04-12 15:22:32 -0600524 assert(shProg->RefCount == 1);
525
Brian5b01c5e2006-12-19 18:02:03 -0700526 return name;
527}
528
529
Brian3c008a02007-04-12 15:22:32 -0600530/**
531 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
532 * DeleteProgramARB.
533 */
Brian2d2bb352007-12-07 17:11:30 -0700534static void
Brian5b01c5e2006-12-19 18:02:03 -0700535_mesa_delete_program2(GLcontext *ctx, GLuint name)
536{
Brian3c008a02007-04-12 15:22:32 -0600537 /*
538 * NOTE: deleting shaders/programs works a bit differently than
539 * texture objects (and buffer objects, etc). Shader/program
540 * handles/IDs exist in the hash table until the object is really
541 * deleted (refcount==0). With texture objects, the handle/ID is
542 * removed from the hash table in glDeleteTextures() while the tex
543 * object itself might linger until its refcount goes to zero.
544 */
Brian65a18442006-12-19 18:46:56 -0700545 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700546
Brian65a18442006-12-19 18:46:56 -0700547 shProg = _mesa_lookup_shader_program(ctx, name);
548 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700549 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteProgram(name)");
Brian5b01c5e2006-12-19 18:02:03 -0700550 return;
551 }
552
Brian9e4bae92006-12-20 09:27:42 -0700553 shProg->DeletePending = GL_TRUE;
554
Brian3c008a02007-04-12 15:22:32 -0600555 /* effectively, decr shProg's refcount */
556 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700557}
558
559
Brian2d2bb352007-12-07 17:11:30 -0700560static void
Brian5b01c5e2006-12-19 18:02:03 -0700561_mesa_delete_shader(GLcontext *ctx, GLuint shader)
562{
Brian9e4bae92006-12-20 09:27:42 -0700563 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
564 if (!sh) {
565 return;
566 }
Brian5b01c5e2006-12-19 18:02:03 -0700567
Brian9e4bae92006-12-20 09:27:42 -0700568 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600569
570 /* effectively, decr sh's refcount */
571 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700572}
573
574
Brian2d2bb352007-12-07 17:11:30 -0700575static void
Brian5b01c5e2006-12-19 18:02:03 -0700576_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
577{
Brian65a18442006-12-19 18:46:56 -0700578 struct gl_shader_program *shProg
579 = _mesa_lookup_shader_program(ctx, program);
580 const GLuint n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700581 GLuint i, j;
582
Brian65a18442006-12-19 18:46:56 -0700583 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700584 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700585 "glDetachShader(bad program or shader name)");
586 return;
587 }
588
589 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700590 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700591 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600592 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700593
Brian3c008a02007-04-12 15:22:32 -0600594 /* derefernce */
595 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700596
Brian5b01c5e2006-12-19 18:02:03 -0700597 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700598 newList = (struct gl_shader **)
599 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700600 if (!newList) {
601 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
602 return;
603 }
604 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700605 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700606 }
607 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700608 newList[j++] = shProg->Shaders[i];
609 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700610
Brian65a18442006-12-19 18:46:56 -0700611 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600612 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600613
614#ifdef DEBUG
615 /* sanity check */
616 {
617 for (j = 0; j < shProg->NumShaders; j++) {
618 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
619 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
620 assert(shProg->Shaders[j]->RefCount > 0);
621 }
622 }
623#endif
624
Brian5b01c5e2006-12-19 18:02:03 -0700625 return;
626 }
627 }
628
629 /* not found */
Brian43975832007-01-04 08:21:09 -0700630 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700631 "glDetachShader(shader not found)");
632}
633
634
Brian2d2bb352007-12-07 17:11:30 -0700635static void
Brian5b01c5e2006-12-19 18:02:03 -0700636_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
637 GLsizei maxLength, GLsizei *length, GLint *size,
638 GLenum *type, GLchar *nameOut)
639{
640 static const GLenum vec_types[] = {
641 GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4
642 };
Brian65a18442006-12-19 18:46:56 -0700643 struct gl_shader_program *shProg
644 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700645 GLint sz;
646
Brian65a18442006-12-19 18:46:56 -0700647 if (!shProg) {
Brianaaa57412007-04-18 15:22:43 -0600648 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib");
Brian5b01c5e2006-12-19 18:02:03 -0700649 return;
650 }
651
Brian65a18442006-12-19 18:46:56 -0700652 if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600653 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700654 return;
655 }
656
657 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700658 shProg->Attributes->Parameters[index].Name);
659 sz = shProg->Attributes->Parameters[index].Size;
Brian5b01c5e2006-12-19 18:02:03 -0700660 if (size)
661 *size = sz;
662 if (type)
663 *type = vec_types[sz]; /* XXX this is a temporary hack */
664}
665
666
667/**
668 * Called via ctx->Driver.GetActiveUniform().
669 */
Brian2d2bb352007-12-07 17:11:30 -0700670static void
Brian5b01c5e2006-12-19 18:02:03 -0700671_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
672 GLsizei maxLength, GLsizei *length, GLint *size,
673 GLenum *type, GLchar *nameOut)
674{
Brianbc029242008-04-04 18:59:21 -0600675 const struct gl_shader_program *shProg
Brian65a18442006-12-19 18:46:56 -0700676 = _mesa_lookup_shader_program(ctx, program);
Brianbc029242008-04-04 18:59:21 -0600677 const struct gl_program *prog;
678 GLint progPos;
Brian5b01c5e2006-12-19 18:02:03 -0700679
Brian65a18442006-12-19 18:46:56 -0700680 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700681 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform");
Brian5b01c5e2006-12-19 18:02:03 -0700682 return;
683 }
684
Brianbc029242008-04-04 18:59:21 -0600685 if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
Brian5b01c5e2006-12-19 18:02:03 -0700686 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
687 return;
688 }
689
Brianbc029242008-04-04 18:59:21 -0600690 progPos = shProg->Uniforms->Uniforms[index].VertPos;
691 if (progPos >= 0) {
692 prog = &shProg->VertexProgram->Base;
693 }
694 else {
695 progPos = shProg->Uniforms->Uniforms[index].FragPos;
696 if (progPos >= 0) {
697 prog = &shProg->FragmentProgram->Base;
Brian274ac7a2007-04-18 16:05:53 -0600698 }
699 }
700
Brianbc029242008-04-04 18:59:21 -0600701 if (!prog || progPos < 0)
702 return; /* should never happen */
703
704 if (nameOut)
705 copy_string(nameOut, maxLength, length,
706 prog->Parameters->Parameters[progPos].Name);
707 if (size)
708 *size = prog->Parameters->Parameters[progPos].Size;
709
710 if (type)
711 *type = prog->Parameters->Parameters[progPos].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700712}
713
714
715/**
716 * Called via ctx->Driver.GetAttachedShaders().
717 */
Brian2d2bb352007-12-07 17:11:30 -0700718static void
Brian5b01c5e2006-12-19 18:02:03 -0700719_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
720 GLsizei *count, GLuint *obj)
721{
Brian65a18442006-12-19 18:46:56 -0700722 struct gl_shader_program *shProg
723 = _mesa_lookup_shader_program(ctx, program);
724 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700725 GLint i;
Brian65a18442006-12-19 18:46:56 -0700726 for (i = 0; i < maxCount && i < shProg->NumShaders; i++) {
727 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700728 }
729 if (count)
730 *count = i;
731 }
732 else {
Brian43975832007-01-04 08:21:09 -0700733 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttachedShaders");
Brian5b01c5e2006-12-19 18:02:03 -0700734 }
735}
736
737
Brian2d2bb352007-12-07 17:11:30 -0700738static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700739_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700740{
741#if 0
742 GET_CURRENT_CONTEXT(ctx);
743
744 switch (pname) {
745 case GL_PROGRAM_OBJECT_ARB:
746 {
Brian5b01c5e2006-12-19 18:02:03 -0700747 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700748
749 if (pro != NULL)
750 return (**pro)._container._generic.
751 GetName((struct gl2_generic_intf **) (pro));
752 }
753 break;
754 default:
755 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
756 }
757#endif
758 return 0;
759}
760
761
Brian2d2bb352007-12-07 17:11:30 -0700762static void
Brian5b01c5e2006-12-19 18:02:03 -0700763_mesa_get_programiv(GLcontext *ctx, GLuint program,
764 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700765{
Brian65a18442006-12-19 18:46:56 -0700766 struct gl_shader_program *shProg
767 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700768
Brian65a18442006-12-19 18:46:56 -0700769 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700770 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700771 return;
772 }
773
Brian5b01c5e2006-12-19 18:02:03 -0700774 switch (pname) {
775 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700776 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700777 break;
778 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700779 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700780 break;
Brian5b01c5e2006-12-19 18:02:03 -0700781 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700782 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700783 break;
784 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600785 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700786 break;
787 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700788 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700789 break;
790 case GL_ACTIVE_ATTRIBUTES:
Brian3209c3e2007-01-09 17:49:24 -0700791 *params = shProg->Attributes ? shProg->Attributes->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700792 break;
793 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600794 *params = _mesa_longest_parameter_name(shProg->Attributes,
795 PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700796 break;
797 case GL_ACTIVE_UNIFORMS:
Brianbc029242008-04-04 18:59:21 -0600798 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700799 break;
800 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brianbc029242008-04-04 18:59:21 -0600801 *params = _mesa_longest_uniform_name(shProg->Uniforms);
Brian274ac7a2007-04-18 16:05:53 -0600802 if (*params > 0)
803 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700804 break;
805 default:
Brian5b01c5e2006-12-19 18:02:03 -0700806 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
807 return;
Brian34ae99d2006-12-18 08:28:54 -0700808 }
Brian5b01c5e2006-12-19 18:02:03 -0700809}
Brian34ae99d2006-12-18 08:28:54 -0700810
Brian34ae99d2006-12-18 08:28:54 -0700811
Brian2d2bb352007-12-07 17:11:30 -0700812static void
Brian5b01c5e2006-12-19 18:02:03 -0700813_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
814{
Brian65a18442006-12-19 18:46:56 -0700815 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700816
817 if (!shader) {
818 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderiv(shader)");
819 return;
820 }
Brian65a18442006-12-19 18:46:56 -0700821
Brian5b01c5e2006-12-19 18:02:03 -0700822 switch (pname) {
823 case GL_SHADER_TYPE:
824 *params = shader->Type;
825 break;
826 case GL_DELETE_STATUS:
827 *params = shader->DeletePending;
828 break;
829 case GL_COMPILE_STATUS:
830 *params = shader->CompileStatus;
831 break;
832 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600833 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700834 break;
835 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600836 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700837 break;
838 default:
839 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
840 return;
841 }
842}
843
844
Brian2d2bb352007-12-07 17:11:30 -0700845static void
Brian5b01c5e2006-12-19 18:02:03 -0700846_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
847 GLsizei *length, GLchar *infoLog)
848{
Brian65a18442006-12-19 18:46:56 -0700849 struct gl_shader_program *shProg
850 = _mesa_lookup_shader_program(ctx, program);
851 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700852 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
853 return;
854 }
Brian65a18442006-12-19 18:46:56 -0700855 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700856}
857
858
Brian2d2bb352007-12-07 17:11:30 -0700859static void
Brian5b01c5e2006-12-19 18:02:03 -0700860_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
861 GLsizei *length, GLchar *infoLog)
862{
Brian65a18442006-12-19 18:46:56 -0700863 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
864 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700865 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
866 return;
867 }
Brian65a18442006-12-19 18:46:56 -0700868 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700869}
870
871
872/**
873 * Called via ctx->Driver.GetShaderSource().
874 */
Brian2d2bb352007-12-07 17:11:30 -0700875static void
Brian5b01c5e2006-12-19 18:02:03 -0700876_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
877 GLsizei *length, GLchar *sourceOut)
878{
Brian65a18442006-12-19 18:46:56 -0700879 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
880 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700881 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderSource(shader)");
882 return;
883 }
Brian65a18442006-12-19 18:46:56 -0700884 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -0700885}
886
887
888/**
889 * Called via ctx->Driver.GetUniformfv().
890 */
Brian2d2bb352007-12-07 17:11:30 -0700891static void
Brian5b01c5e2006-12-19 18:02:03 -0700892_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
893 GLfloat *params)
894{
Brian65a18442006-12-19 18:46:56 -0700895 struct gl_shader_program *shProg
896 = _mesa_lookup_shader_program(ctx, program);
897 if (shProg) {
Brianbc029242008-04-04 18:59:21 -0600898 if (location < shProg->Uniforms->NumUniforms) {
899 GLint progPos, i;
900 const struct gl_program *prog;
901
902 progPos = shProg->Uniforms->Uniforms[location].VertPos;
903 if (progPos >= 0) {
904 prog = &shProg->VertexProgram->Base;
905 }
906 else {
907 progPos = shProg->Uniforms->Uniforms[location].FragPos;
908 if (progPos >= 0) {
909 prog = &shProg->FragmentProgram->Base;
910 }
911 }
912
913 for (i = 0; i < prog->Parameters->Parameters[progPos].Size; i++) {
914 params[i] = prog->Parameters->ParameterValues[progPos][i];
Brian5b01c5e2006-12-19 18:02:03 -0700915 }
916 }
917 else {
918 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(location)");
919 }
920 }
921 else {
Brian43975832007-01-04 08:21:09 -0700922 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700923 }
924}
925
926
927/**
928 * Called via ctx->Driver.GetUniformLocation().
929 */
Brian2d2bb352007-12-07 17:11:30 -0700930static GLint
Brian5b01c5e2006-12-19 18:02:03 -0700931_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
932{
Brian71623982007-01-30 16:55:03 -0700933 struct gl_shader_program *shProg
934 = _mesa_lookup_shader_program(ctx, program);
Brianbc029242008-04-04 18:59:21 -0600935 if (!shProg)
936 return -1;
Brian5b01c5e2006-12-19 18:02:03 -0700937
Brianbc029242008-04-04 18:59:21 -0600938 return _mesa_lookup_uniform(shProg->Uniforms, name);
Brian5b01c5e2006-12-19 18:02:03 -0700939}
940
941
Brian2d2bb352007-12-07 17:11:30 -0700942static GLboolean
Brian5b01c5e2006-12-19 18:02:03 -0700943_mesa_is_program(GLcontext *ctx, GLuint name)
944{
Brian65a18442006-12-19 18:46:56 -0700945 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
946 return shProg ? GL_TRUE : GL_FALSE;
Brian5b01c5e2006-12-19 18:02:03 -0700947}
948
949
Brian2d2bb352007-12-07 17:11:30 -0700950static GLboolean
Brian5b01c5e2006-12-19 18:02:03 -0700951_mesa_is_shader(GLcontext *ctx, GLuint name)
952{
Brian65a18442006-12-19 18:46:56 -0700953 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700954 return shader ? GL_TRUE : GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700955}
956
957
958
Brian5b01c5e2006-12-19 18:02:03 -0700959/**
960 * Called via ctx->Driver.ShaderSource()
961 */
Brian2d2bb352007-12-07 17:11:30 -0700962static void
Brian5b01c5e2006-12-19 18:02:03 -0700963_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -0700964{
Brian65a18442006-12-19 18:46:56 -0700965 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
966 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700967 _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSource(shaderObj)");
Brian34ae99d2006-12-18 08:28:54 -0700968 return;
969 }
970
Brian34ae99d2006-12-18 08:28:54 -0700971 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -0700972 if (sh->Source) {
973 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -0700974 }
Brian65a18442006-12-19 18:46:56 -0700975 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -0700976 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700977}
978
979
Brian5b01c5e2006-12-19 18:02:03 -0700980/**
981 * Called via ctx->Driver.CompileShader()
982 */
Brian2d2bb352007-12-07 17:11:30 -0700983static void
Brian5b01c5e2006-12-19 18:02:03 -0700984_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -0700985{
Brian65a18442006-12-19 18:46:56 -0700986 struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj);
Brian34ae99d2006-12-18 08:28:54 -0700987
Brian65a18442006-12-19 18:46:56 -0700988 if (!sh) {
Brian34ae99d2006-12-18 08:28:54 -0700989 _mesa_error(ctx, GL_INVALID_VALUE, "glCompileShader(shaderObj)");
990 return;
991 }
992
Brian43975832007-01-04 08:21:09 -0700993 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -0700994}
995
996
Brian5b01c5e2006-12-19 18:02:03 -0700997/**
998 * Called via ctx->Driver.LinkProgram()
999 */
Brian2d2bb352007-12-07 17:11:30 -07001000static void
Brian5b01c5e2006-12-19 18:02:03 -07001001_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001002{
Brian65a18442006-12-19 18:46:56 -07001003 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001004
Brian65a18442006-12-19 18:46:56 -07001005 shProg = _mesa_lookup_shader_program(ctx, program);
1006 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001007 _mesa_error(ctx, GL_INVALID_VALUE, "glLinkProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001008 return;
1009 }
1010
Brianc1771912007-02-16 09:56:19 -07001011 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001012}
1013
1014
1015/**
Brian5b01c5e2006-12-19 18:02:03 -07001016 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001017 */
Brian5b01c5e2006-12-19 18:02:03 -07001018void
1019_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001020{
Brian3c008a02007-04-12 15:22:32 -06001021 struct gl_shader_program *shProg;
1022
Brian00d63aa2007-02-03 11:35:02 -07001023 if (ctx->Shader.CurrentProgram &&
1024 ctx->Shader.CurrentProgram->Name == program) {
1025 /* no-op */
1026 return;
1027 }
1028
1029 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1030
Brian5b01c5e2006-12-19 18:02:03 -07001031 if (program) {
Brian65a18442006-12-19 18:46:56 -07001032 shProg = _mesa_lookup_shader_program(ctx, program);
1033 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001034 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -07001035 "glUseProgramObjectARB(programObj)");
1036 return;
1037 }
Brian5b01c5e2006-12-19 18:02:03 -07001038 }
1039 else {
Brian3c008a02007-04-12 15:22:32 -06001040 shProg = NULL;
1041 }
1042
1043 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001044}
Brian34ae99d2006-12-18 08:28:54 -07001045
Brian5b01c5e2006-12-19 18:02:03 -07001046
Brian8fed2462007-10-26 19:19:09 -06001047
1048/**
1049 * Update the vertex and fragment program's TexturesUsed arrays.
1050 */
1051static void
1052update_textures_used(struct gl_program *prog)
1053{
1054 GLuint s;
1055
1056 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1057
1058 for (s = 0; s < MAX_SAMPLERS; s++) {
1059 if (prog->SamplersUsed & (1 << s)) {
1060 GLuint u = prog->SamplerUnits[s];
1061 GLuint t = prog->SamplerTargets[s];
1062 assert(u < MAX_TEXTURE_IMAGE_UNITS);
1063 prog->TexturesUsed[u] |= (1 << t);
1064 }
1065 }
1066}
1067
1068
Brian5b01c5e2006-12-19 18:02:03 -07001069/**
Brianbc029242008-04-04 18:59:21 -06001070 * Set the value of a program's uniform variable.
1071 * \param program the program whose uniform to update
1072 * \param location the location/index of the uniform
1073 * \param type the datatype of the uniform
1074 * \param count the number of uniforms to set
1075 * \param elems number of elements per uniform
1076 * \param values the new values
1077 */
1078static void
1079set_program_uniform(GLcontext *ctx, struct gl_program *program, GLint location,
1080 GLenum type, GLint count, GLint elems, const void *values)
1081{
1082 if (program->Parameters->Parameters[location].Type == PROGRAM_SAMPLER) {
1083 /* This controls which texture unit which is used by a sampler */
1084 GLuint texUnit, sampler;
1085
1086 /* data type for setting samplers must be int */
1087 if (type != GL_INT || count != 1) {
1088 _mesa_error(ctx, GL_INVALID_OPERATION,
1089 "glUniform(only glUniform1i can be used "
1090 "to set sampler uniforms)");
1091 return;
1092 }
1093
1094 sampler = (GLuint) program->Parameters->ParameterValues[location][0];
1095 texUnit = ((GLuint *) values)[0];
1096
1097 /* check that the sampler (tex unit index) is legal */
1098 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1099 _mesa_error(ctx, GL_INVALID_VALUE,
1100 "glUniform1(invalid sampler/tex unit index)");
1101 return;
1102 }
1103
1104 /* This maps a sampler to a texture unit: */
1105 program->SamplerUnits[sampler] = texUnit;
1106 update_textures_used(program);
1107
1108 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1109 }
1110 else {
1111 /* ordinary uniform variable */
1112 GLint k, i;
1113
1114 if (count * elems > program->Parameters->Parameters[location].Size) {
1115 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1116 return;
1117 }
1118
1119 for (k = 0; k < count; k++) {
1120 GLfloat *uniformVal = program->Parameters->ParameterValues[location + k];
1121 if (type == GL_INT ||
1122 type == GL_INT_VEC2 ||
1123 type == GL_INT_VEC3 ||
1124 type == GL_INT_VEC4) {
1125 const GLint *iValues = ((const GLint *) values) + k * elems;
1126 for (i = 0; i < elems; i++) {
1127 uniformVal[i] = (GLfloat) iValues[i];
1128 }
1129 }
1130 else {
1131 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1132 for (i = 0; i < elems; i++) {
1133 uniformVal[i] = fValues[i];
1134 }
1135 }
1136 }
1137 }
1138}
1139
1140
1141/**
Brian5b01c5e2006-12-19 18:02:03 -07001142 * Called via ctx->Driver.Uniform().
1143 */
Brian2d2bb352007-12-07 17:11:30 -07001144static void
Brian5b01c5e2006-12-19 18:02:03 -07001145_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1146 const GLvoid *values, GLenum type)
1147{
Brian3a8e2772006-12-20 17:19:16 -07001148 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brianbc029242008-04-04 18:59:21 -06001149 GLint elems;
Brian3a8e2772006-12-20 17:19:16 -07001150
1151 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001152 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001153 return;
1154 }
1155
Brianbc029242008-04-04 18:59:21 -06001156 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian3a8e2772006-12-20 17:19:16 -07001157 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
1158 return;
1159 }
1160
Brian52363952007-03-13 16:50:24 -06001161 if (count < 0) {
1162 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1163 return;
1164 }
1165
Brian98650bd2007-03-13 16:32:48 -06001166 switch (type) {
1167 case GL_FLOAT:
1168 case GL_INT:
1169 elems = 1;
1170 break;
1171 case GL_FLOAT_VEC2:
1172 case GL_INT_VEC2:
1173 elems = 2;
1174 break;
1175 case GL_FLOAT_VEC3:
1176 case GL_INT_VEC3:
1177 elems = 3;
1178 break;
1179 case GL_FLOAT_VEC4:
1180 case GL_INT_VEC4:
1181 elems = 4;
1182 break;
1183 default:
1184 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1185 return;
Brian89dc4852007-01-04 14:35:44 -07001186 }
Brian98650bd2007-03-13 16:32:48 -06001187
Brianbc029242008-04-04 18:59:21 -06001188 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1189
1190 /* A uniform var may be used by both a vertex shader and a fragment
1191 * shader. We may need to update one or both shader's uniform here:
1192 */
1193 if (shProg->VertexProgram) {
1194 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1195 if (loc >= 0) {
1196 set_program_uniform(ctx, &shProg->VertexProgram->Base,
1197 loc, type, count, elems, values);
1198 }
Brian98650bd2007-03-13 16:32:48 -06001199 }
1200
Brianbc029242008-04-04 18:59:21 -06001201 if (shProg->FragmentProgram) {
1202 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1203 if (loc >= 0) {
1204 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
1205 loc, type, count, elems, values);
Brian8fed2462007-10-26 19:19:09 -06001206 }
Brianbc029242008-04-04 18:59:21 -06001207 }
1208}
Brian8fed2462007-10-26 19:19:09 -06001209
Brian8fed2462007-10-26 19:19:09 -06001210
Brianbc029242008-04-04 18:59:21 -06001211static void
1212set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
1213 GLuint location, GLuint rows, GLuint cols,
1214 GLboolean transpose, const GLfloat *values)
1215{
1216 /*
1217 * Note: the _columns_ of a matrix are stored in program registers, not
1218 * the rows.
1219 */
1220 /* XXXX need to test 3x3 and 2x2 matrices... */
1221 if (transpose) {
1222 GLuint row, col;
1223 for (col = 0; col < cols; col++) {
1224 GLfloat *v = program->Parameters->ParameterValues[location + col];
1225 for (row = 0; row < rows; row++) {
1226 v[row] = values[row * cols + col];
1227 }
Brian8fed2462007-10-26 19:19:09 -06001228 }
Brian5cf73262007-01-05 16:02:45 -07001229 }
Brian8fed2462007-10-26 19:19:09 -06001230 else {
Brianbc029242008-04-04 18:59:21 -06001231 GLuint row, col;
1232 for (col = 0; col < cols; col++) {
1233 GLfloat *v = program->Parameters->ParameterValues[location + col];
1234 for (row = 0; row < rows; row++) {
1235 v[row] = values[col * rows + row];
Brian8fed2462007-10-26 19:19:09 -06001236 }
1237 }
1238 }
Brian34ae99d2006-12-18 08:28:54 -07001239}
1240
1241
1242/**
Brian5b01c5e2006-12-19 18:02:03 -07001243 * Called by ctx->Driver.UniformMatrix().
Brian34ae99d2006-12-18 08:28:54 -07001244 */
Brian2d2bb352007-12-07 17:11:30 -07001245static void
Brian5b01c5e2006-12-19 18:02:03 -07001246_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1247 GLenum matrixType, GLint location, GLsizei count,
1248 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001249{
Brian3a8e2772006-12-20 17:19:16 -07001250 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
1251 if (!shProg || !shProg->LinkStatus) {
1252 _mesa_error(ctx, GL_INVALID_OPERATION,
1253 "glUniformMatrix(program not linked)");
1254 return;
1255 }
Brianbc029242008-04-04 18:59:21 -06001256 if (location < 0 || location >= shProg->Uniforms->NumUniforms) {
Brian3a8e2772006-12-20 17:19:16 -07001257 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
1258 return;
1259 }
Brian34ae99d2006-12-18 08:28:54 -07001260 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001261 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001262 return;
1263 }
1264
1265 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1266
Brianbc029242008-04-04 18:59:21 -06001267 if (shProg->VertexProgram) {
1268 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1269 if (loc >= 0) {
1270 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
1271 loc, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07001272 }
Brian34ae99d2006-12-18 08:28:54 -07001273 }
Brianbc029242008-04-04 18:59:21 -06001274
1275 if (shProg->FragmentProgram) {
1276 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1277 if (loc >= 0) {
1278 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
1279 loc, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07001280 }
Brian34ae99d2006-12-18 08:28:54 -07001281 }
1282}
1283
1284
Brian2d2bb352007-12-07 17:11:30 -07001285static void
Brian5b01c5e2006-12-19 18:02:03 -07001286_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001287{
Brian65a18442006-12-19 18:46:56 -07001288 struct gl_shader_program *shProg;
1289 shProg = _mesa_lookup_shader_program(ctx, program);
1290 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001291 _mesa_error(ctx, GL_INVALID_VALUE, "glValidateProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001292 return;
1293 }
Brian5b01c5e2006-12-19 18:02:03 -07001294 /* XXX temporary */
Brian65a18442006-12-19 18:46:56 -07001295 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001296
Brian5b01c5e2006-12-19 18:02:03 -07001297 /* From the GL spec:
1298 any two active samplers in the current program object are of
1299 different types, but refer to the same texture image unit,
1300
1301 any active sampler in the current program object refers to a texture
1302 image unit where fixed-function fragment processing accesses a
1303 texture target that does not match the sampler type, or
1304
1305 the sum of the number of active samplers in the program and the
1306 number of texture image units enabled for fixed-function fragment
1307 processing exceeds the combined limit on the total number of texture
1308 image units allowed.
1309 */
Brian34ae99d2006-12-18 08:28:54 -07001310}
Brian2d2bb352007-12-07 17:11:30 -07001311
1312
1313/**
1314 * Plug in Mesa's GLSL functions into the device driver function table.
1315 */
1316void
1317_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
1318{
1319 driver->AttachShader = _mesa_attach_shader;
1320 driver->BindAttribLocation = _mesa_bind_attrib_location;
1321 driver->CompileShader = _mesa_compile_shader;
1322 driver->CreateProgram = _mesa_create_program;
1323 driver->CreateShader = _mesa_create_shader;
1324 driver->DeleteProgram2 = _mesa_delete_program2;
1325 driver->DeleteShader = _mesa_delete_shader;
1326 driver->DetachShader = _mesa_detach_shader;
1327 driver->GetActiveAttrib = _mesa_get_active_attrib;
1328 driver->GetActiveUniform = _mesa_get_active_uniform;
1329 driver->GetAttachedShaders = _mesa_get_attached_shaders;
1330 driver->GetAttribLocation = _mesa_get_attrib_location;
1331 driver->GetHandle = _mesa_get_handle;
1332 driver->GetProgramiv = _mesa_get_programiv;
1333 driver->GetProgramInfoLog = _mesa_get_program_info_log;
1334 driver->GetShaderiv = _mesa_get_shaderiv;
1335 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
1336 driver->GetShaderSource = _mesa_get_shader_source;
1337 driver->GetUniformfv = _mesa_get_uniformfv;
1338 driver->GetUniformLocation = _mesa_get_uniform_location;
1339 driver->IsProgram = _mesa_is_program;
1340 driver->IsShader = _mesa_is_shader;
1341 driver->LinkProgram = _mesa_link_program;
1342 driver->ShaderSource = _mesa_shader_source;
1343 driver->Uniform = _mesa_uniform;
1344 driver->UniformMatrix = _mesa_uniform_matrix;
1345 driver->UseProgram = _mesa_use_program;
1346 driver->ValidateProgram = _mesa_validate_program;
1347}