blob: 9c419c9903fea3d4a7db309515521be46e459631 [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;
Brianf8acc392008-03-22 10:27:55 -060083 ctx->Driver.DeleteProgram(ctx, &shProg->VertexProgram->Base);
Brianf2923612006-12-20 09:56:44 -070084 shProg->VertexProgram = NULL;
85 }
86
87 if (shProg->FragmentProgram) {
Brianbc029242008-04-04 18:59:21 -060088 /* Set ptr to NULL since the param list is shared with the
89 * original/unlinked program.
90 */
91 shProg->FragmentProgram->Base.Parameters = NULL;
Brianf8acc392008-03-22 10:27:55 -060092 ctx->Driver.DeleteProgram(ctx, &shProg->FragmentProgram->Base);
Brianf2923612006-12-20 09:56:44 -070093 shProg->FragmentProgram = NULL;
94 }
95
Brianf2923612006-12-20 09:56:44 -070096 if (shProg->Uniforms) {
Brianbc029242008-04-04 18:59:21 -060097 _mesa_free_uniform_list(shProg->Uniforms);
Brianf2923612006-12-20 09:56:44 -070098 shProg->Uniforms = NULL;
99 }
100
101 if (shProg->Varying) {
102 _mesa_free_parameter_list(shProg->Varying);
103 shProg->Varying = NULL;
104 }
105}
106
107
Brianb9fbedd2007-03-26 09:23:44 -0600108/**
Brian3c008a02007-04-12 15:22:32 -0600109 * Free all the data that hangs off a shader program object, but not the
110 * object itself.
111 */
112void
113_mesa_free_shader_program_data(GLcontext *ctx,
114 struct gl_shader_program *shProg)
115{
116 GLuint i;
117
Brianf3e8c322007-04-18 14:53:23 -0600118 assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
Brian3c008a02007-04-12 15:22:32 -0600119
120 _mesa_clear_shader_program_data(ctx, shProg);
121
Brian4b7c6fc2007-04-19 15:23:34 -0600122 if (shProg->Attributes) {
123 _mesa_free_parameter_list(shProg->Attributes);
124 shProg->Attributes = NULL;
125 }
126
Brian3c008a02007-04-12 15:22:32 -0600127 /* detach shaders */
128 for (i = 0; i < shProg->NumShaders; i++) {
129 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
130 }
131 if (shProg->Shaders) {
132 _mesa_free(shProg->Shaders);
133 shProg->Shaders = NULL;
134 }
135}
136
137
138/**
Brianb9fbedd2007-03-26 09:23:44 -0600139 * Free/delete a shader program object.
140 */
Brianf2923612006-12-20 09:56:44 -0700141void
142_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg)
143{
144 _mesa_free_shader_program_data(ctx, shProg);
Brianb9fbedd2007-03-26 09:23:44 -0600145 if (shProg->Shaders) {
146 _mesa_free(shProg->Shaders);
147 shProg->Shaders = NULL;
148 }
Brianf2923612006-12-20 09:56:44 -0700149 _mesa_free(shProg);
150}
151
152
153/**
Brian3c008a02007-04-12 15:22:32 -0600154 * Set ptr to point to shProg.
155 * If ptr is pointing to another object, decrement its refcount (and delete
156 * if refcount hits zero).
157 * Then set ptr to point to shProg, incrementing its refcount.
158 */
159/* XXX this could be static */
160void
161_mesa_reference_shader_program(GLcontext *ctx,
162 struct gl_shader_program **ptr,
163 struct gl_shader_program *shProg)
164{
165 assert(ptr);
166 if (*ptr == shProg) {
167 /* no-op */
168 return;
169 }
170 if (*ptr) {
171 /* Unreference the old shader program */
172 GLboolean deleteFlag = GL_FALSE;
173 struct gl_shader_program *old = *ptr;
174
175 ASSERT(old->RefCount > 0);
176 old->RefCount--;
177 /*printf("SHPROG DECR %p (%d) to %d\n",
178 (void*) old, old->Name, old->RefCount);*/
179 deleteFlag = (old->RefCount == 0);
180
181 if (deleteFlag) {
182 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
183 _mesa_free_shader_program(ctx, old);
184 }
185
186 *ptr = NULL;
187 }
188 assert(!*ptr);
189
190 if (shProg) {
191 shProg->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600192 /*printf("SHPROG INCR %p (%d) to %d\n",
193 (void*) shProg, shProg->Name, shProg->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600194 *ptr = shProg;
195 }
196}
197
198
199/**
Brianf2923612006-12-20 09:56:44 -0700200 * Lookup a GLSL program object.
201 */
202struct gl_shader_program *
203_mesa_lookup_shader_program(GLcontext *ctx, GLuint name)
204{
205 struct gl_shader_program *shProg;
206 if (name) {
207 shProg = (struct gl_shader_program *)
208 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
209 /* Note that both gl_shader and gl_shader_program objects are kept
210 * in the same hash table. Check the object's type to be sure it's
211 * what we're expecting.
212 */
Brianf3e8c322007-04-18 14:53:23 -0600213 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700214 return NULL;
215 }
216 return shProg;
217 }
218 return NULL;
219}
220
221
222/**
223 * Allocate a new gl_shader object, initialize it.
224 */
225struct gl_shader *
226_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
227{
228 struct gl_shader *shader;
229 assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
230 shader = CALLOC_STRUCT(gl_shader);
231 if (shader) {
232 shader->Type = type;
233 shader->Name = name;
234 shader->RefCount = 1;
235 }
236 return shader;
237}
238
239
240void
241_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh)
242{
243 GLuint i;
244 if (sh->Source)
245 _mesa_free((void *) sh->Source);
246 if (sh->InfoLog)
247 _mesa_free(sh->InfoLog);
248 for (i = 0; i < sh->NumPrograms; i++) {
249 assert(sh->Programs[i]);
Brianf8acc392008-03-22 10:27:55 -0600250 ctx->Driver.DeleteProgram(ctx, sh->Programs[i]);
Brianf2923612006-12-20 09:56:44 -0700251 }
252 if (sh->Programs)
253 _mesa_free(sh->Programs);
254 _mesa_free(sh);
255}
256
257
258/**
Brian3c008a02007-04-12 15:22:32 -0600259 * Set ptr to point to sh.
260 * If ptr is pointing to another shader, decrement its refcount (and delete
261 * if refcount hits zero).
262 * Then set ptr to point to sh, incrementing its refcount.
263 */
264/* XXX this could be static */
265void
266_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr,
267 struct gl_shader *sh)
268{
269 assert(ptr);
270 if (*ptr == sh) {
271 /* no-op */
272 return;
273 }
274 if (*ptr) {
275 /* Unreference the old shader */
276 GLboolean deleteFlag = GL_FALSE;
277 struct gl_shader *old = *ptr;
278
279 ASSERT(old->RefCount > 0);
280 old->RefCount--;
Brian99193e42007-04-12 15:45:02 -0600281 /*printf("SHADER DECR %p (%d) to %d\n",
282 (void*) old, old->Name, old->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600283 deleteFlag = (old->RefCount == 0);
284
285 if (deleteFlag) {
286 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
287 _mesa_free_shader(ctx, old);
288 }
289
290 *ptr = NULL;
291 }
292 assert(!*ptr);
293
294 if (sh) {
295 /* reference new */
296 sh->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600297 /*printf("SHADER INCR %p (%d) to %d\n",
298 (void*) sh, sh->Name, sh->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600299 *ptr = sh;
300 }
301}
302
303
304/**
Brianf2923612006-12-20 09:56:44 -0700305 * Lookup a GLSL shader object.
306 */
307struct gl_shader *
308_mesa_lookup_shader(GLcontext *ctx, GLuint name)
309{
310 if (name) {
311 struct gl_shader *sh = (struct gl_shader *)
312 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
313 /* Note that both gl_shader and gl_shader_program objects are kept
314 * in the same hash table. Check the object's type to be sure it's
315 * what we're expecting.
316 */
Brianf3e8c322007-04-18 14:53:23 -0600317 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700318 return NULL;
319 }
320 return sh;
321 }
322 return NULL;
323}
324
325
Brianfa4d0362007-02-26 18:33:50 -0700326/**
327 * Initialize context's shader state.
328 */
Brianf2923612006-12-20 09:56:44 -0700329void
330_mesa_init_shader_state(GLcontext * ctx)
331{
Brianfa4d0362007-02-26 18:33:50 -0700332 /* Device drivers may override these to control what kind of instructions
333 * are generated by the GLSL compiler.
334 */
335 ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
michal4a470f62007-08-07 15:34:11 +0100336 ctx->Shader.EmitCondCodes = GL_FALSE;/*GL_TRUE;*/ /* XXX probably want GL_FALSE... */
Brianfa4d0362007-02-26 18:33:50 -0700337 ctx->Shader.EmitComments = GL_FALSE;
Brianf2923612006-12-20 09:56:44 -0700338}
339
340
Brian5b01c5e2006-12-19 18:02:03 -0700341/**
Brian935f93f2007-03-24 16:20:02 -0600342 * Free the per-context shader-related state.
343 */
344void
345_mesa_free_shader_state(GLcontext *ctx)
346{
Brian3c008a02007-04-12 15:22:32 -0600347 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
Brian935f93f2007-03-24 16:20:02 -0600348}
349
350
351/**
Brian5b01c5e2006-12-19 18:02:03 -0700352 * Copy string from <src> to <dst>, up to maxLength characters, returning
353 * length of <dst> in <length>.
354 * \param src the strings source
355 * \param maxLength max chars to copy
356 * \param length returns number of chars copied
357 * \param dst the string destination
358 */
359static void
360copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
361{
362 GLsizei len;
363 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
364 dst[len] = src[len];
365 if (maxLength > 0)
366 dst[len] = 0;
367 if (length)
368 *length = len;
369}
370
371
Brian5b01c5e2006-12-19 18:02:03 -0700372/**
373 * Called via ctx->Driver.AttachShader()
374 */
Brian2d2bb352007-12-07 17:11:30 -0700375static void
Brian5b01c5e2006-12-19 18:02:03 -0700376_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
377{
Brian65a18442006-12-19 18:46:56 -0700378 struct gl_shader_program *shProg
379 = _mesa_lookup_shader_program(ctx, program);
380 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
381 const GLuint n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700382 GLuint i;
383
Brian65a18442006-12-19 18:46:56 -0700384 if (!shProg || !sh) {
Brian43975832007-01-04 08:21:09 -0700385 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700386 "glAttachShader(bad program or shader name)");
387 return;
388 }
389
390 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700391 if (shProg->Shaders[i] == sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700392 /* already attached */
393 return;
Brian34ae99d2006-12-18 08:28:54 -0700394 }
395 }
Brian5b01c5e2006-12-19 18:02:03 -0700396
397 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700398 shProg->Shaders = (struct gl_shader **)
399 _mesa_realloc(shProg->Shaders,
400 n * sizeof(struct gl_shader *),
401 (n + 1) * sizeof(struct gl_shader *));
402 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700403 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
404 return;
405 }
406
407 /* append */
Brian3c008a02007-04-12 15:22:32 -0600408 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
409 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700410 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700411}
412
413
Brian2d2bb352007-12-07 17:11:30 -0700414static GLint
415_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
416 const GLchar *name)
417{
418 struct gl_shader_program *shProg
419 = _mesa_lookup_shader_program(ctx, program);
420
421 if (!shProg) {
422 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttribLocation");
423 return -1;
424 }
425
426 if (!shProg->LinkStatus) {
427 _mesa_error(ctx, GL_INVALID_OPERATION,
428 "glGetAttribLocation(program not linked)");
429 return -1;
430 }
431
432 if (!name)
433 return -1;
434
435 if (shProg->Attributes) {
436 GLint i = _mesa_lookup_parameter_index(shProg->Attributes, -1, name);
437 if (i >= 0) {
438 return shProg->Attributes->Parameters[i].StateIndexes[0];
439 }
440 }
441 return -1;
442}
443
444
445static void
Brian5b01c5e2006-12-19 18:02:03 -0700446_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
447 const GLchar *name)
448{
Brian65a18442006-12-19 18:46:56 -0700449 struct gl_shader_program *shProg
450 = _mesa_lookup_shader_program(ctx, program);
Brianb7978af2007-01-09 19:17:17 -0700451 const GLint size = -1; /* unknown size */
452 GLint i, oldIndex;
Brian5b01c5e2006-12-19 18:02:03 -0700453
Brian65a18442006-12-19 18:46:56 -0700454 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700455 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700456 return;
457 }
458
Brian9e4bae92006-12-20 09:27:42 -0700459 if (!name)
460 return;
461
462 if (strncmp(name, "gl_", 3) == 0) {
463 _mesa_error(ctx, GL_INVALID_OPERATION,
464 "glBindAttribLocation(illegal name)");
465 return;
466 }
467
Brian9f660252007-04-11 09:00:56 -0600468 if (shProg->LinkStatus) {
469 /* get current index/location for the attribute */
470 oldIndex = _mesa_get_attrib_location(ctx, program, name);
471 }
472 else {
473 oldIndex = -1;
474 }
Brian3209c3e2007-01-09 17:49:24 -0700475
476 /* this will replace the current value if it's already in the list */
Brianb7978af2007-01-09 19:17:17 -0700477 i = _mesa_add_attribute(shProg->Attributes, name, size, index);
Brian3209c3e2007-01-09 17:49:24 -0700478 if (i < 0) {
479 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
480 }
481
Brian9f660252007-04-11 09:00:56 -0600482 if (shProg->VertexProgram && oldIndex >= 0 && oldIndex != index) {
483 /* If the index changed, need to search/replace references to that attribute
484 * in the vertex program.
485 */
Brian3209c3e2007-01-09 17:49:24 -0700486 _slang_remap_attribute(&shProg->VertexProgram->Base, oldIndex, index);
487 }
Brian34ae99d2006-12-18 08:28:54 -0700488}
489
490
Brian2d2bb352007-12-07 17:11:30 -0700491static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700492_mesa_create_shader(GLcontext *ctx, GLenum type)
493{
Brian65a18442006-12-19 18:46:56 -0700494 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700495 GLuint name;
496
497 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
498
499 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700500 case GL_FRAGMENT_SHADER:
501 case GL_VERTEX_SHADER:
502 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700503 break;
504 default:
505 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
506 return 0;
507 }
508
Brian65a18442006-12-19 18:46:56 -0700509 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700510
511 return name;
512}
513
514
Brian2d2bb352007-12-07 17:11:30 -0700515static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700516_mesa_create_program(GLcontext *ctx)
517{
518 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700519 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700520
Brian65a18442006-12-19 18:46:56 -0700521 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
522 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700523
Brian65a18442006-12-19 18:46:56 -0700524 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700525
Brian3c008a02007-04-12 15:22:32 -0600526 assert(shProg->RefCount == 1);
527
Brian5b01c5e2006-12-19 18:02:03 -0700528 return name;
529}
530
531
Brian3c008a02007-04-12 15:22:32 -0600532/**
533 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
534 * DeleteProgramARB.
535 */
Brian2d2bb352007-12-07 17:11:30 -0700536static void
Brian5b01c5e2006-12-19 18:02:03 -0700537_mesa_delete_program2(GLcontext *ctx, GLuint name)
538{
Brian3c008a02007-04-12 15:22:32 -0600539 /*
540 * NOTE: deleting shaders/programs works a bit differently than
541 * texture objects (and buffer objects, etc). Shader/program
542 * handles/IDs exist in the hash table until the object is really
543 * deleted (refcount==0). With texture objects, the handle/ID is
544 * removed from the hash table in glDeleteTextures() while the tex
545 * object itself might linger until its refcount goes to zero.
546 */
Brian65a18442006-12-19 18:46:56 -0700547 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700548
Brian65a18442006-12-19 18:46:56 -0700549 shProg = _mesa_lookup_shader_program(ctx, name);
550 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700551 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteProgram(name)");
Brian5b01c5e2006-12-19 18:02:03 -0700552 return;
553 }
554
Brian9e4bae92006-12-20 09:27:42 -0700555 shProg->DeletePending = GL_TRUE;
556
Brian3c008a02007-04-12 15:22:32 -0600557 /* effectively, decr shProg's refcount */
558 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700559}
560
561
Brian2d2bb352007-12-07 17:11:30 -0700562static void
Brian5b01c5e2006-12-19 18:02:03 -0700563_mesa_delete_shader(GLcontext *ctx, GLuint shader)
564{
Brian9e4bae92006-12-20 09:27:42 -0700565 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
566 if (!sh) {
567 return;
568 }
Brian5b01c5e2006-12-19 18:02:03 -0700569
Brian9e4bae92006-12-20 09:27:42 -0700570 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600571
572 /* effectively, decr sh's refcount */
573 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700574}
575
576
Brian2d2bb352007-12-07 17:11:30 -0700577static void
Brian5b01c5e2006-12-19 18:02:03 -0700578_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
579{
Brian65a18442006-12-19 18:46:56 -0700580 struct gl_shader_program *shProg
581 = _mesa_lookup_shader_program(ctx, program);
582 const GLuint n = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700583 GLuint i, j;
584
Brian65a18442006-12-19 18:46:56 -0700585 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700586 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700587 "glDetachShader(bad program or shader name)");
588 return;
589 }
590
591 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700592 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700593 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600594 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700595
Brian3c008a02007-04-12 15:22:32 -0600596 /* derefernce */
597 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700598
Brian5b01c5e2006-12-19 18:02:03 -0700599 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700600 newList = (struct gl_shader **)
601 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700602 if (!newList) {
603 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
604 return;
605 }
606 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700607 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700608 }
609 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700610 newList[j++] = shProg->Shaders[i];
611 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700612
Brian65a18442006-12-19 18:46:56 -0700613 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600614 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600615
616#ifdef DEBUG
617 /* sanity check */
618 {
619 for (j = 0; j < shProg->NumShaders; j++) {
620 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
621 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
622 assert(shProg->Shaders[j]->RefCount > 0);
623 }
624 }
625#endif
626
Brian5b01c5e2006-12-19 18:02:03 -0700627 return;
628 }
629 }
630
631 /* not found */
Brian43975832007-01-04 08:21:09 -0700632 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700633 "glDetachShader(shader not found)");
634}
635
636
Brian2d2bb352007-12-07 17:11:30 -0700637static void
Brian5b01c5e2006-12-19 18:02:03 -0700638_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
639 GLsizei maxLength, GLsizei *length, GLint *size,
640 GLenum *type, GLchar *nameOut)
641{
642 static const GLenum vec_types[] = {
643 GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4
644 };
Brian65a18442006-12-19 18:46:56 -0700645 struct gl_shader_program *shProg
646 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700647 GLint sz;
648
Brian65a18442006-12-19 18:46:56 -0700649 if (!shProg) {
Brianaaa57412007-04-18 15:22:43 -0600650 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib");
Brian5b01c5e2006-12-19 18:02:03 -0700651 return;
652 }
653
Brian65a18442006-12-19 18:46:56 -0700654 if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600655 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700656 return;
657 }
658
659 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700660 shProg->Attributes->Parameters[index].Name);
661 sz = shProg->Attributes->Parameters[index].Size;
Brian5b01c5e2006-12-19 18:02:03 -0700662 if (size)
663 *size = sz;
664 if (type)
665 *type = vec_types[sz]; /* XXX this is a temporary hack */
666}
667
668
669/**
670 * Called via ctx->Driver.GetActiveUniform().
671 */
Brian2d2bb352007-12-07 17:11:30 -0700672static void
Brian5b01c5e2006-12-19 18:02:03 -0700673_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
674 GLsizei maxLength, GLsizei *length, GLint *size,
675 GLenum *type, GLchar *nameOut)
676{
Brianbc029242008-04-04 18:59:21 -0600677 const struct gl_shader_program *shProg
Brian65a18442006-12-19 18:46:56 -0700678 = _mesa_lookup_shader_program(ctx, program);
Brianbc029242008-04-04 18:59:21 -0600679 const struct gl_program *prog;
680 GLint progPos;
Brian5b01c5e2006-12-19 18:02:03 -0700681
Brian65a18442006-12-19 18:46:56 -0700682 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700683 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform");
Brian5b01c5e2006-12-19 18:02:03 -0700684 return;
685 }
686
Brianbc029242008-04-04 18:59:21 -0600687 if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
Brian5b01c5e2006-12-19 18:02:03 -0700688 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
689 return;
690 }
691
Brianbc029242008-04-04 18:59:21 -0600692 progPos = shProg->Uniforms->Uniforms[index].VertPos;
693 if (progPos >= 0) {
694 prog = &shProg->VertexProgram->Base;
695 }
696 else {
697 progPos = shProg->Uniforms->Uniforms[index].FragPos;
698 if (progPos >= 0) {
699 prog = &shProg->FragmentProgram->Base;
Brian274ac7a2007-04-18 16:05:53 -0600700 }
701 }
702
Brianbc029242008-04-04 18:59:21 -0600703 if (!prog || progPos < 0)
704 return; /* should never happen */
705
706 if (nameOut)
707 copy_string(nameOut, maxLength, length,
708 prog->Parameters->Parameters[progPos].Name);
709 if (size)
710 *size = prog->Parameters->Parameters[progPos].Size;
711
712 if (type)
713 *type = prog->Parameters->Parameters[progPos].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700714}
715
716
717/**
718 * Called via ctx->Driver.GetAttachedShaders().
719 */
Brian2d2bb352007-12-07 17:11:30 -0700720static void
Brian5b01c5e2006-12-19 18:02:03 -0700721_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
722 GLsizei *count, GLuint *obj)
723{
Brian65a18442006-12-19 18:46:56 -0700724 struct gl_shader_program *shProg
725 = _mesa_lookup_shader_program(ctx, program);
726 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700727 GLint i;
Brian65a18442006-12-19 18:46:56 -0700728 for (i = 0; i < maxCount && i < shProg->NumShaders; i++) {
729 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700730 }
731 if (count)
732 *count = i;
733 }
734 else {
Brian43975832007-01-04 08:21:09 -0700735 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttachedShaders");
Brian5b01c5e2006-12-19 18:02:03 -0700736 }
737}
738
739
Brian2d2bb352007-12-07 17:11:30 -0700740static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700741_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700742{
743#if 0
744 GET_CURRENT_CONTEXT(ctx);
745
746 switch (pname) {
747 case GL_PROGRAM_OBJECT_ARB:
748 {
Brian5b01c5e2006-12-19 18:02:03 -0700749 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700750
751 if (pro != NULL)
752 return (**pro)._container._generic.
753 GetName((struct gl2_generic_intf **) (pro));
754 }
755 break;
756 default:
757 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
758 }
759#endif
760 return 0;
761}
762
763
Brian2d2bb352007-12-07 17:11:30 -0700764static void
Brian5b01c5e2006-12-19 18:02:03 -0700765_mesa_get_programiv(GLcontext *ctx, GLuint program,
766 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700767{
Brian65a18442006-12-19 18:46:56 -0700768 struct gl_shader_program *shProg
769 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700770
Brian65a18442006-12-19 18:46:56 -0700771 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700772 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700773 return;
774 }
775
Brian5b01c5e2006-12-19 18:02:03 -0700776 switch (pname) {
777 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700778 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700779 break;
780 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700781 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700782 break;
Brian5b01c5e2006-12-19 18:02:03 -0700783 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700784 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700785 break;
786 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600787 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700788 break;
789 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700790 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700791 break;
792 case GL_ACTIVE_ATTRIBUTES:
Brian3209c3e2007-01-09 17:49:24 -0700793 *params = shProg->Attributes ? shProg->Attributes->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700794 break;
795 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600796 *params = _mesa_longest_parameter_name(shProg->Attributes,
797 PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700798 break;
799 case GL_ACTIVE_UNIFORMS:
Brianbc029242008-04-04 18:59:21 -0600800 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700801 break;
802 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brianbc029242008-04-04 18:59:21 -0600803 *params = _mesa_longest_uniform_name(shProg->Uniforms);
Brian274ac7a2007-04-18 16:05:53 -0600804 if (*params > 0)
805 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700806 break;
807 default:
Brian5b01c5e2006-12-19 18:02:03 -0700808 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
809 return;
Brian34ae99d2006-12-18 08:28:54 -0700810 }
Brian5b01c5e2006-12-19 18:02:03 -0700811}
Brian34ae99d2006-12-18 08:28:54 -0700812
Brian34ae99d2006-12-18 08:28:54 -0700813
Brian2d2bb352007-12-07 17:11:30 -0700814static void
Brian5b01c5e2006-12-19 18:02:03 -0700815_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
816{
Brian65a18442006-12-19 18:46:56 -0700817 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700818
819 if (!shader) {
820 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderiv(shader)");
821 return;
822 }
Brian65a18442006-12-19 18:46:56 -0700823
Brian5b01c5e2006-12-19 18:02:03 -0700824 switch (pname) {
825 case GL_SHADER_TYPE:
826 *params = shader->Type;
827 break;
828 case GL_DELETE_STATUS:
829 *params = shader->DeletePending;
830 break;
831 case GL_COMPILE_STATUS:
832 *params = shader->CompileStatus;
833 break;
834 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600835 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700836 break;
837 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600838 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700839 break;
840 default:
841 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
842 return;
843 }
844}
845
846
Brian2d2bb352007-12-07 17:11:30 -0700847static void
Brian5b01c5e2006-12-19 18:02:03 -0700848_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
849 GLsizei *length, GLchar *infoLog)
850{
Brian65a18442006-12-19 18:46:56 -0700851 struct gl_shader_program *shProg
852 = _mesa_lookup_shader_program(ctx, program);
853 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700854 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
855 return;
856 }
Brian65a18442006-12-19 18:46:56 -0700857 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700858}
859
860
Brian2d2bb352007-12-07 17:11:30 -0700861static void
Brian5b01c5e2006-12-19 18:02:03 -0700862_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
863 GLsizei *length, GLchar *infoLog)
864{
Brian65a18442006-12-19 18:46:56 -0700865 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
866 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700867 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
868 return;
869 }
Brian65a18442006-12-19 18:46:56 -0700870 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700871}
872
873
874/**
875 * Called via ctx->Driver.GetShaderSource().
876 */
Brian2d2bb352007-12-07 17:11:30 -0700877static void
Brian5b01c5e2006-12-19 18:02:03 -0700878_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
879 GLsizei *length, GLchar *sourceOut)
880{
Brian65a18442006-12-19 18:46:56 -0700881 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
882 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700883 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderSource(shader)");
884 return;
885 }
Brian65a18442006-12-19 18:46:56 -0700886 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -0700887}
888
889
890/**
891 * Called via ctx->Driver.GetUniformfv().
892 */
Brian2d2bb352007-12-07 17:11:30 -0700893static void
Brian5b01c5e2006-12-19 18:02:03 -0700894_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
895 GLfloat *params)
896{
Brian65a18442006-12-19 18:46:56 -0700897 struct gl_shader_program *shProg
898 = _mesa_lookup_shader_program(ctx, program);
899 if (shProg) {
Brianbc029242008-04-04 18:59:21 -0600900 if (location < shProg->Uniforms->NumUniforms) {
901 GLint progPos, i;
902 const struct gl_program *prog;
903
904 progPos = shProg->Uniforms->Uniforms[location].VertPos;
905 if (progPos >= 0) {
906 prog = &shProg->VertexProgram->Base;
907 }
908 else {
909 progPos = shProg->Uniforms->Uniforms[location].FragPos;
910 if (progPos >= 0) {
911 prog = &shProg->FragmentProgram->Base;
912 }
913 }
914
915 for (i = 0; i < prog->Parameters->Parameters[progPos].Size; i++) {
916 params[i] = prog->Parameters->ParameterValues[progPos][i];
Brian5b01c5e2006-12-19 18:02:03 -0700917 }
918 }
919 else {
920 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(location)");
921 }
922 }
923 else {
Brian43975832007-01-04 08:21:09 -0700924 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700925 }
926}
927
928
929/**
930 * Called via ctx->Driver.GetUniformLocation().
931 */
Brian2d2bb352007-12-07 17:11:30 -0700932static GLint
Brian5b01c5e2006-12-19 18:02:03 -0700933_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
934{
Brian71623982007-01-30 16:55:03 -0700935 struct gl_shader_program *shProg
936 = _mesa_lookup_shader_program(ctx, program);
Brianbc029242008-04-04 18:59:21 -0600937 if (!shProg)
938 return -1;
Brian5b01c5e2006-12-19 18:02:03 -0700939
Brianbc029242008-04-04 18:59:21 -0600940 return _mesa_lookup_uniform(shProg->Uniforms, name);
Brian5b01c5e2006-12-19 18:02:03 -0700941}
942
943
Brian2d2bb352007-12-07 17:11:30 -0700944static GLboolean
Brian5b01c5e2006-12-19 18:02:03 -0700945_mesa_is_program(GLcontext *ctx, GLuint name)
946{
Brian65a18442006-12-19 18:46:56 -0700947 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
948 return shProg ? GL_TRUE : GL_FALSE;
Brian5b01c5e2006-12-19 18:02:03 -0700949}
950
951
Brian2d2bb352007-12-07 17:11:30 -0700952static GLboolean
Brian5b01c5e2006-12-19 18:02:03 -0700953_mesa_is_shader(GLcontext *ctx, GLuint name)
954{
Brian65a18442006-12-19 18:46:56 -0700955 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700956 return shader ? GL_TRUE : GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700957}
958
959
960
Brian5b01c5e2006-12-19 18:02:03 -0700961/**
962 * Called via ctx->Driver.ShaderSource()
963 */
Brian2d2bb352007-12-07 17:11:30 -0700964static void
Brian5b01c5e2006-12-19 18:02:03 -0700965_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -0700966{
Brian65a18442006-12-19 18:46:56 -0700967 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
968 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700969 _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSource(shaderObj)");
Brian34ae99d2006-12-18 08:28:54 -0700970 return;
971 }
972
Brian34ae99d2006-12-18 08:28:54 -0700973 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -0700974 if (sh->Source) {
975 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -0700976 }
Brian65a18442006-12-19 18:46:56 -0700977 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -0700978 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700979}
980
981
Brian5b01c5e2006-12-19 18:02:03 -0700982/**
983 * Called via ctx->Driver.CompileShader()
984 */
Brian2d2bb352007-12-07 17:11:30 -0700985static void
Brian5b01c5e2006-12-19 18:02:03 -0700986_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -0700987{
Brian65a18442006-12-19 18:46:56 -0700988 struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj);
Brian34ae99d2006-12-18 08:28:54 -0700989
Brian65a18442006-12-19 18:46:56 -0700990 if (!sh) {
Brian34ae99d2006-12-18 08:28:54 -0700991 _mesa_error(ctx, GL_INVALID_VALUE, "glCompileShader(shaderObj)");
992 return;
993 }
994
Brian43975832007-01-04 08:21:09 -0700995 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -0700996}
997
998
Brian5b01c5e2006-12-19 18:02:03 -0700999/**
1000 * Called via ctx->Driver.LinkProgram()
1001 */
Brian2d2bb352007-12-07 17:11:30 -07001002static void
Brian5b01c5e2006-12-19 18:02:03 -07001003_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001004{
Brian65a18442006-12-19 18:46:56 -07001005 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001006
Brian65a18442006-12-19 18:46:56 -07001007 shProg = _mesa_lookup_shader_program(ctx, program);
1008 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001009 _mesa_error(ctx, GL_INVALID_VALUE, "glLinkProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001010 return;
1011 }
1012
Brianc1771912007-02-16 09:56:19 -07001013 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001014}
1015
1016
1017/**
Brian5b01c5e2006-12-19 18:02:03 -07001018 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001019 */
Brian5b01c5e2006-12-19 18:02:03 -07001020void
1021_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001022{
Brian3c008a02007-04-12 15:22:32 -06001023 struct gl_shader_program *shProg;
1024
Brian00d63aa2007-02-03 11:35:02 -07001025 if (ctx->Shader.CurrentProgram &&
1026 ctx->Shader.CurrentProgram->Name == program) {
1027 /* no-op */
1028 return;
1029 }
1030
1031 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1032
Brian5b01c5e2006-12-19 18:02:03 -07001033 if (program) {
Brian65a18442006-12-19 18:46:56 -07001034 shProg = _mesa_lookup_shader_program(ctx, program);
1035 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001036 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -07001037 "glUseProgramObjectARB(programObj)");
1038 return;
1039 }
Brian5b01c5e2006-12-19 18:02:03 -07001040 }
1041 else {
Brian3c008a02007-04-12 15:22:32 -06001042 shProg = NULL;
1043 }
1044
1045 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001046}
Brian34ae99d2006-12-18 08:28:54 -07001047
Brian5b01c5e2006-12-19 18:02:03 -07001048
Brian8fed2462007-10-26 19:19:09 -06001049
1050/**
1051 * Update the vertex and fragment program's TexturesUsed arrays.
1052 */
1053static void
1054update_textures_used(struct gl_program *prog)
1055{
1056 GLuint s;
1057
1058 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1059
1060 for (s = 0; s < MAX_SAMPLERS; s++) {
1061 if (prog->SamplersUsed & (1 << s)) {
1062 GLuint u = prog->SamplerUnits[s];
1063 GLuint t = prog->SamplerTargets[s];
1064 assert(u < MAX_TEXTURE_IMAGE_UNITS);
1065 prog->TexturesUsed[u] |= (1 << t);
1066 }
1067 }
1068}
1069
1070
Brian5b01c5e2006-12-19 18:02:03 -07001071/**
Brianbc029242008-04-04 18:59:21 -06001072 * Set the value of a program's uniform variable.
1073 * \param program the program whose uniform to update
1074 * \param location the location/index of the uniform
1075 * \param type the datatype of the uniform
1076 * \param count the number of uniforms to set
1077 * \param elems number of elements per uniform
1078 * \param values the new values
1079 */
1080static void
1081set_program_uniform(GLcontext *ctx, struct gl_program *program, GLint location,
1082 GLenum type, GLint count, GLint elems, const void *values)
1083{
1084 if (program->Parameters->Parameters[location].Type == PROGRAM_SAMPLER) {
1085 /* This controls which texture unit which is used by a sampler */
1086 GLuint texUnit, sampler;
1087
1088 /* data type for setting samplers must be int */
1089 if (type != GL_INT || count != 1) {
1090 _mesa_error(ctx, GL_INVALID_OPERATION,
1091 "glUniform(only glUniform1i can be used "
1092 "to set sampler uniforms)");
1093 return;
1094 }
1095
1096 sampler = (GLuint) program->Parameters->ParameterValues[location][0];
1097 texUnit = ((GLuint *) values)[0];
1098
1099 /* check that the sampler (tex unit index) is legal */
1100 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1101 _mesa_error(ctx, GL_INVALID_VALUE,
1102 "glUniform1(invalid sampler/tex unit index)");
1103 return;
1104 }
1105
1106 /* This maps a sampler to a texture unit: */
1107 program->SamplerUnits[sampler] = texUnit;
1108 update_textures_used(program);
1109
1110 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1111 }
1112 else {
1113 /* ordinary uniform variable */
1114 GLint k, i;
1115
1116 if (count * elems > program->Parameters->Parameters[location].Size) {
1117 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1118 return;
1119 }
1120
1121 for (k = 0; k < count; k++) {
1122 GLfloat *uniformVal = program->Parameters->ParameterValues[location + k];
1123 if (type == GL_INT ||
1124 type == GL_INT_VEC2 ||
1125 type == GL_INT_VEC3 ||
1126 type == GL_INT_VEC4) {
1127 const GLint *iValues = ((const GLint *) values) + k * elems;
1128 for (i = 0; i < elems; i++) {
1129 uniformVal[i] = (GLfloat) iValues[i];
1130 }
1131 }
1132 else {
1133 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1134 for (i = 0; i < elems; i++) {
1135 uniformVal[i] = fValues[i];
1136 }
1137 }
1138 }
1139 }
1140}
1141
1142
1143/**
Brian5b01c5e2006-12-19 18:02:03 -07001144 * Called via ctx->Driver.Uniform().
1145 */
Brian2d2bb352007-12-07 17:11:30 -07001146static void
Brian5b01c5e2006-12-19 18:02:03 -07001147_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1148 const GLvoid *values, GLenum type)
1149{
Brian3a8e2772006-12-20 17:19:16 -07001150 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brianbc029242008-04-04 18:59:21 -06001151 GLint elems;
Brian3a8e2772006-12-20 17:19:16 -07001152
1153 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001154 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001155 return;
1156 }
1157
Brianbc029242008-04-04 18:59:21 -06001158 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
Brian3a8e2772006-12-20 17:19:16 -07001159 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
1160 return;
1161 }
1162
Brian52363952007-03-13 16:50:24 -06001163 if (count < 0) {
1164 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1165 return;
1166 }
1167
Brian98650bd2007-03-13 16:32:48 -06001168 switch (type) {
1169 case GL_FLOAT:
1170 case GL_INT:
1171 elems = 1;
1172 break;
1173 case GL_FLOAT_VEC2:
1174 case GL_INT_VEC2:
1175 elems = 2;
1176 break;
1177 case GL_FLOAT_VEC3:
1178 case GL_INT_VEC3:
1179 elems = 3;
1180 break;
1181 case GL_FLOAT_VEC4:
1182 case GL_INT_VEC4:
1183 elems = 4;
1184 break;
1185 default:
1186 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1187 return;
Brian89dc4852007-01-04 14:35:44 -07001188 }
Brian98650bd2007-03-13 16:32:48 -06001189
Brianbc029242008-04-04 18:59:21 -06001190 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1191
1192 /* A uniform var may be used by both a vertex shader and a fragment
1193 * shader. We may need to update one or both shader's uniform here:
1194 */
1195 if (shProg->VertexProgram) {
1196 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1197 if (loc >= 0) {
1198 set_program_uniform(ctx, &shProg->VertexProgram->Base,
1199 loc, type, count, elems, values);
1200 }
Brian98650bd2007-03-13 16:32:48 -06001201 }
1202
Brianbc029242008-04-04 18:59:21 -06001203 if (shProg->FragmentProgram) {
1204 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1205 if (loc >= 0) {
1206 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
1207 loc, type, count, elems, values);
Brian8fed2462007-10-26 19:19:09 -06001208 }
Brianbc029242008-04-04 18:59:21 -06001209 }
1210}
Brian8fed2462007-10-26 19:19:09 -06001211
Brian8fed2462007-10-26 19:19:09 -06001212
Brianbc029242008-04-04 18:59:21 -06001213static void
1214set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
1215 GLuint location, GLuint rows, GLuint cols,
1216 GLboolean transpose, const GLfloat *values)
1217{
1218 /*
1219 * Note: the _columns_ of a matrix are stored in program registers, not
1220 * the rows.
1221 */
1222 /* XXXX need to test 3x3 and 2x2 matrices... */
1223 if (transpose) {
1224 GLuint row, col;
1225 for (col = 0; col < cols; col++) {
1226 GLfloat *v = program->Parameters->ParameterValues[location + col];
1227 for (row = 0; row < rows; row++) {
1228 v[row] = values[row * cols + col];
1229 }
Brian8fed2462007-10-26 19:19:09 -06001230 }
Brian5cf73262007-01-05 16:02:45 -07001231 }
Brian8fed2462007-10-26 19:19:09 -06001232 else {
Brianbc029242008-04-04 18:59:21 -06001233 GLuint row, col;
1234 for (col = 0; col < cols; col++) {
1235 GLfloat *v = program->Parameters->ParameterValues[location + col];
1236 for (row = 0; row < rows; row++) {
1237 v[row] = values[col * rows + row];
Brian8fed2462007-10-26 19:19:09 -06001238 }
1239 }
1240 }
Brian34ae99d2006-12-18 08:28:54 -07001241}
1242
1243
1244/**
Brian5b01c5e2006-12-19 18:02:03 -07001245 * Called by ctx->Driver.UniformMatrix().
Brian34ae99d2006-12-18 08:28:54 -07001246 */
Brian2d2bb352007-12-07 17:11:30 -07001247static void
Brian5b01c5e2006-12-19 18:02:03 -07001248_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1249 GLenum matrixType, GLint location, GLsizei count,
1250 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001251{
Brian3a8e2772006-12-20 17:19:16 -07001252 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
1253 if (!shProg || !shProg->LinkStatus) {
1254 _mesa_error(ctx, GL_INVALID_OPERATION,
1255 "glUniformMatrix(program not linked)");
1256 return;
1257 }
Brianbc029242008-04-04 18:59:21 -06001258 if (location < 0 || location >= shProg->Uniforms->NumUniforms) {
Brian3a8e2772006-12-20 17:19:16 -07001259 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
1260 return;
1261 }
Brian34ae99d2006-12-18 08:28:54 -07001262 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001263 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001264 return;
1265 }
1266
1267 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1268
Brianbc029242008-04-04 18:59:21 -06001269 if (shProg->VertexProgram) {
1270 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1271 if (loc >= 0) {
1272 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
1273 loc, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07001274 }
Brian34ae99d2006-12-18 08:28:54 -07001275 }
Brianbc029242008-04-04 18:59:21 -06001276
1277 if (shProg->FragmentProgram) {
1278 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1279 if (loc >= 0) {
1280 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
1281 loc, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07001282 }
Brian34ae99d2006-12-18 08:28:54 -07001283 }
1284}
1285
1286
Brian2d2bb352007-12-07 17:11:30 -07001287static void
Brian5b01c5e2006-12-19 18:02:03 -07001288_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001289{
Brian65a18442006-12-19 18:46:56 -07001290 struct gl_shader_program *shProg;
1291 shProg = _mesa_lookup_shader_program(ctx, program);
1292 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001293 _mesa_error(ctx, GL_INVALID_VALUE, "glValidateProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001294 return;
1295 }
Brian5b01c5e2006-12-19 18:02:03 -07001296 /* XXX temporary */
Brian65a18442006-12-19 18:46:56 -07001297 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001298
Brian5b01c5e2006-12-19 18:02:03 -07001299 /* From the GL spec:
1300 any two active samplers in the current program object are of
1301 different types, but refer to the same texture image unit,
1302
1303 any active sampler in the current program object refers to a texture
1304 image unit where fixed-function fragment processing accesses a
1305 texture target that does not match the sampler type, or
1306
1307 the sum of the number of active samplers in the program and the
1308 number of texture image units enabled for fixed-function fragment
1309 processing exceeds the combined limit on the total number of texture
1310 image units allowed.
1311 */
Brian34ae99d2006-12-18 08:28:54 -07001312}
Brian2d2bb352007-12-07 17:11:30 -07001313
1314
1315/**
1316 * Plug in Mesa's GLSL functions into the device driver function table.
1317 */
1318void
1319_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
1320{
1321 driver->AttachShader = _mesa_attach_shader;
1322 driver->BindAttribLocation = _mesa_bind_attrib_location;
1323 driver->CompileShader = _mesa_compile_shader;
1324 driver->CreateProgram = _mesa_create_program;
1325 driver->CreateShader = _mesa_create_shader;
1326 driver->DeleteProgram2 = _mesa_delete_program2;
1327 driver->DeleteShader = _mesa_delete_shader;
1328 driver->DetachShader = _mesa_detach_shader;
1329 driver->GetActiveAttrib = _mesa_get_active_attrib;
1330 driver->GetActiveUniform = _mesa_get_active_uniform;
1331 driver->GetAttachedShaders = _mesa_get_attached_shaders;
1332 driver->GetAttribLocation = _mesa_get_attrib_location;
1333 driver->GetHandle = _mesa_get_handle;
1334 driver->GetProgramiv = _mesa_get_programiv;
1335 driver->GetProgramInfoLog = _mesa_get_program_info_log;
1336 driver->GetShaderiv = _mesa_get_shaderiv;
1337 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
1338 driver->GetShaderSource = _mesa_get_shader_source;
1339 driver->GetUniformfv = _mesa_get_uniformfv;
1340 driver->GetUniformLocation = _mesa_get_uniform_location;
1341 driver->IsProgram = _mesa_is_program;
1342 driver->IsShader = _mesa_is_shader;
1343 driver->LinkProgram = _mesa_link_program;
1344 driver->ShaderSource = _mesa_shader_source;
1345 driver->Uniform = _mesa_uniform;
1346 driver->UniformMatrix = _mesa_uniform_matrix;
1347 driver->UseProgram = _mesa_use_program;
1348 driver->ValidateProgram = _mesa_validate_program;
1349}