blob: 65a8c6cc54af53cf040900634f1f413857c044b2 [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"
Brianc223c6b2007-07-04 13:15:20 -060046#include "shader/shader_api.h"
47#include "shader/slang/slang_compile.h"
48#include "shader/slang/slang_link.h"
Brian34ae99d2006-12-18 08:28:54 -070049
50
51
Brianf2923612006-12-20 09:56:44 -070052/**
53 * Allocate a new gl_shader_program object, initialize it.
54 */
55struct gl_shader_program *
56_mesa_new_shader_program(GLcontext *ctx, GLuint name)
57{
58 struct gl_shader_program *shProg;
59 shProg = CALLOC_STRUCT(gl_shader_program);
60 if (shProg) {
Brianf3e8c322007-04-18 14:53:23 -060061 shProg->Type = GL_SHADER_PROGRAM_MESA;
Brianf2923612006-12-20 09:56:44 -070062 shProg->Name = name;
63 shProg->RefCount = 1;
Brian3209c3e2007-01-09 17:49:24 -070064 shProg->Attributes = _mesa_new_parameter_list();
Brianf2923612006-12-20 09:56:44 -070065 }
66 return shProg;
67}
68
69
Brianb9fbedd2007-03-26 09:23:44 -060070/**
Brian3c008a02007-04-12 15:22:32 -060071 * Clear (free) the shader program state that gets produced by linking.
Brianb9fbedd2007-03-26 09:23:44 -060072 */
Brianf2923612006-12-20 09:56:44 -070073void
Brian3c008a02007-04-12 15:22:32 -060074_mesa_clear_shader_program_data(GLcontext *ctx,
75 struct gl_shader_program *shProg)
Brianf2923612006-12-20 09:56:44 -070076{
Brianf2923612006-12-20 09:56:44 -070077 if (shProg->VertexProgram) {
78 if (shProg->VertexProgram->Base.Parameters == shProg->Uniforms) {
79 /* to prevent a double-free in the next call */
80 shProg->VertexProgram->Base.Parameters = NULL;
81 }
Briandf43fb62008-05-06 23:08:51 -060082 _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL);
Brianf2923612006-12-20 09:56:44 -070083 }
84
85 if (shProg->FragmentProgram) {
86 if (shProg->FragmentProgram->Base.Parameters == shProg->Uniforms) {
87 /* to prevent a double-free in the next call */
88 shProg->FragmentProgram->Base.Parameters = NULL;
89 }
Briandf43fb62008-05-06 23:08:51 -060090 _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL);
Brianf2923612006-12-20 09:56:44 -070091 }
92
Brianf2923612006-12-20 09:56:44 -070093 if (shProg->Uniforms) {
94 _mesa_free_parameter_list(shProg->Uniforms);
95 shProg->Uniforms = NULL;
96 }
97
98 if (shProg->Varying) {
99 _mesa_free_parameter_list(shProg->Varying);
100 shProg->Varying = NULL;
101 }
102}
103
104
Brianb9fbedd2007-03-26 09:23:44 -0600105/**
Brian3c008a02007-04-12 15:22:32 -0600106 * Free all the data that hangs off a shader program object, but not the
107 * object itself.
108 */
109void
110_mesa_free_shader_program_data(GLcontext *ctx,
111 struct gl_shader_program *shProg)
112{
113 GLuint i;
114
Brianf3e8c322007-04-18 14:53:23 -0600115 assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
Brian3c008a02007-04-12 15:22:32 -0600116
117 _mesa_clear_shader_program_data(ctx, shProg);
118
Brian4b7c6fc2007-04-19 15:23:34 -0600119 if (shProg->Attributes) {
120 _mesa_free_parameter_list(shProg->Attributes);
121 shProg->Attributes = NULL;
122 }
123
Brian3c008a02007-04-12 15:22:32 -0600124 /* detach shaders */
125 for (i = 0; i < shProg->NumShaders; i++) {
126 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
127 }
Xiang, Haihao63d8a842008-03-31 17:02:47 +0800128 shProg->NumShaders = 0;
129
Brian3c008a02007-04-12 15:22:32 -0600130 if (shProg->Shaders) {
131 _mesa_free(shProg->Shaders);
132 shProg->Shaders = NULL;
133 }
Alan Hourihaneeec20c32008-04-22 20:29:42 +0100134
135 if (shProg->InfoLog) {
136 _mesa_free(shProg->InfoLog);
137 shProg->InfoLog = NULL;
138 }
Brian3c008a02007-04-12 15:22:32 -0600139}
140
141
142/**
Brianb9fbedd2007-03-26 09:23:44 -0600143 * Free/delete a shader program object.
144 */
Brianf2923612006-12-20 09:56:44 -0700145void
146_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg)
147{
148 _mesa_free_shader_program_data(ctx, shProg);
Alan Hourihaneeec20c32008-04-22 20:29:42 +0100149
Brianf2923612006-12-20 09:56:44 -0700150 _mesa_free(shProg);
151}
152
153
154/**
Brian3c008a02007-04-12 15:22:32 -0600155 * Set ptr to point to shProg.
156 * If ptr is pointing to another object, decrement its refcount (and delete
157 * if refcount hits zero).
158 * Then set ptr to point to shProg, incrementing its refcount.
159 */
160/* XXX this could be static */
161void
162_mesa_reference_shader_program(GLcontext *ctx,
163 struct gl_shader_program **ptr,
164 struct gl_shader_program *shProg)
165{
166 assert(ptr);
167 if (*ptr == shProg) {
168 /* no-op */
169 return;
170 }
171 if (*ptr) {
172 /* Unreference the old shader program */
173 GLboolean deleteFlag = GL_FALSE;
174 struct gl_shader_program *old = *ptr;
175
176 ASSERT(old->RefCount > 0);
177 old->RefCount--;
178 /*printf("SHPROG DECR %p (%d) to %d\n",
179 (void*) old, old->Name, old->RefCount);*/
180 deleteFlag = (old->RefCount == 0);
181
182 if (deleteFlag) {
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800183 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
Brian3c008a02007-04-12 15:22:32 -0600184 _mesa_free_shader_program(ctx, old);
185 }
186
187 *ptr = NULL;
188 }
189 assert(!*ptr);
190
191 if (shProg) {
192 shProg->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600193 /*printf("SHPROG INCR %p (%d) to %d\n",
194 (void*) shProg, shProg->Name, shProg->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600195 *ptr = shProg;
196 }
197}
198
199
200/**
Brianf2923612006-12-20 09:56:44 -0700201 * Lookup a GLSL program object.
202 */
203struct gl_shader_program *
204_mesa_lookup_shader_program(GLcontext *ctx, GLuint name)
205{
206 struct gl_shader_program *shProg;
207 if (name) {
208 shProg = (struct gl_shader_program *)
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800209 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
Brianf2923612006-12-20 09:56:44 -0700210 /* Note that both gl_shader and gl_shader_program objects are kept
211 * in the same hash table. Check the object's type to be sure it's
212 * what we're expecting.
213 */
Brianf3e8c322007-04-18 14:53:23 -0600214 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700215 return NULL;
216 }
217 return shProg;
218 }
219 return NULL;
220}
221
222
223/**
224 * Allocate a new gl_shader object, initialize it.
225 */
226struct gl_shader *
227_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
228{
229 struct gl_shader *shader;
230 assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
231 shader = CALLOC_STRUCT(gl_shader);
232 if (shader) {
233 shader->Type = type;
234 shader->Name = name;
235 shader->RefCount = 1;
236 }
237 return shader;
238}
239
240
241void
242_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh)
243{
244 GLuint i;
245 if (sh->Source)
246 _mesa_free((void *) sh->Source);
247 if (sh->InfoLog)
248 _mesa_free(sh->InfoLog);
Brian Paul57e222d2008-05-14 12:10:45 -0600249 for (i = 0; i < sh->NumPrograms; i++)
250 _mesa_reference_program(ctx, &sh->Programs[i], NULL);
Brianf2923612006-12-20 09:56:44 -0700251 if (sh->Programs)
252 _mesa_free(sh->Programs);
253 _mesa_free(sh);
254}
255
256
257/**
Brian3c008a02007-04-12 15:22:32 -0600258 * Set ptr to point to sh.
259 * If ptr is pointing to another shader, decrement its refcount (and delete
260 * if refcount hits zero).
261 * Then set ptr to point to sh, incrementing its refcount.
262 */
263/* XXX this could be static */
264void
265_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr,
266 struct gl_shader *sh)
267{
268 assert(ptr);
269 if (*ptr == sh) {
270 /* no-op */
271 return;
272 }
273 if (*ptr) {
274 /* Unreference the old shader */
275 GLboolean deleteFlag = GL_FALSE;
276 struct gl_shader *old = *ptr;
277
278 ASSERT(old->RefCount > 0);
279 old->RefCount--;
Brian99193e42007-04-12 15:45:02 -0600280 /*printf("SHADER DECR %p (%d) to %d\n",
281 (void*) old, old->Name, old->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600282 deleteFlag = (old->RefCount == 0);
283
284 if (deleteFlag) {
285 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
286 _mesa_free_shader(ctx, old);
287 }
288
289 *ptr = NULL;
290 }
291 assert(!*ptr);
292
293 if (sh) {
294 /* reference new */
295 sh->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600296 /*printf("SHADER INCR %p (%d) to %d\n",
297 (void*) sh, sh->Name, sh->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600298 *ptr = sh;
299 }
300}
301
302
303/**
Brianf2923612006-12-20 09:56:44 -0700304 * Lookup a GLSL shader object.
305 */
306struct gl_shader *
307_mesa_lookup_shader(GLcontext *ctx, GLuint name)
308{
309 if (name) {
310 struct gl_shader *sh = (struct gl_shader *)
311 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
312 /* Note that both gl_shader and gl_shader_program objects are kept
313 * in the same hash table. Check the object's type to be sure it's
314 * what we're expecting.
315 */
Brianf3e8c322007-04-18 14:53:23 -0600316 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700317 return NULL;
318 }
319 return sh;
320 }
321 return NULL;
322}
323
324
Brianfa4d0362007-02-26 18:33:50 -0700325/**
326 * Initialize context's shader state.
327 */
Brianf2923612006-12-20 09:56:44 -0700328void
329_mesa_init_shader_state(GLcontext * ctx)
330{
Brianfa4d0362007-02-26 18:33:50 -0700331 /* Device drivers may override these to control what kind of instructions
332 * are generated by the GLSL compiler.
333 */
334 ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
Brian63556fa2007-03-23 14:47:46 -0600335 ctx->Shader.EmitCondCodes = GL_TRUE; /* XXX probably want GL_FALSE... */
Brianfa4d0362007-02-26 18:33:50 -0700336 ctx->Shader.EmitComments = GL_FALSE;
Brianf2923612006-12-20 09:56:44 -0700337}
338
339
Brian5b01c5e2006-12-19 18:02:03 -0700340/**
Brian935f93f2007-03-24 16:20:02 -0600341 * Free the per-context shader-related state.
342 */
343void
344_mesa_free_shader_state(GLcontext *ctx)
345{
Brian3c008a02007-04-12 15:22:32 -0600346 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
Brian935f93f2007-03-24 16:20:02 -0600347}
348
349
350/**
Brian5b01c5e2006-12-19 18:02:03 -0700351 * Copy string from <src> to <dst>, up to maxLength characters, returning
352 * length of <dst> in <length>.
353 * \param src the strings source
354 * \param maxLength max chars to copy
355 * \param length returns number of chars copied
356 * \param dst the string destination
357 */
358static void
359copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
360{
361 GLsizei len;
362 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
363 dst[len] = src[len];
364 if (maxLength > 0)
365 dst[len] = 0;
366 if (length)
367 *length = len;
368}
369
370
Brian5b01c5e2006-12-19 18:02:03 -0700371/**
Brian2761cfc2007-12-20 09:05:37 -0700372 * Return size (in floats) of the given GLSL type.
373 * See also _slang_sizeof_type_specifier().
374 */
375static GLint
376sizeof_glsl_type(GLenum type)
377{
378 switch (type) {
379 case GL_BOOL:
380 case GL_FLOAT:
381 case GL_INT:
382 return 1;
383 case GL_BOOL_VEC2:
384 case GL_FLOAT_VEC2:
385 case GL_INT_VEC2:
386 return 2;
387 case GL_BOOL_VEC3:
388 case GL_FLOAT_VEC3:
389 case GL_INT_VEC3:
390 return 3;
391 case GL_BOOL_VEC4:
392 case GL_FLOAT_VEC4:
393 case GL_INT_VEC4:
394 return 4;
395 case GL_FLOAT_MAT2:
396 return 8; /* 2 rows of 4, actually */
397 case GL_FLOAT_MAT3:
398 return 12; /* 3 rows of 4, actually */
399 case GL_FLOAT_MAT4:
400 return 16;
401 case GL_FLOAT_MAT2x3:
Bruce Merryeeb03fa2007-12-21 14:41:45 +0200402 return 8; /* 2 rows of 4, actually */
Brian2761cfc2007-12-20 09:05:37 -0700403 case GL_FLOAT_MAT2x4:
404 return 8;
405 case GL_FLOAT_MAT3x2:
406 return 12; /* 3 rows of 4, actually */
407 case GL_FLOAT_MAT3x4:
408 return 12;
409 case GL_FLOAT_MAT4x2:
410 return 16; /* 4 rows of 4, actually */
411 case GL_FLOAT_MAT4x3:
Bruce Merryeeb03fa2007-12-21 14:41:45 +0200412 return 16; /* 4 rows of 4, actually */
Brian2761cfc2007-12-20 09:05:37 -0700413 default:
414 return 0; /* error */
415 }
416}
417
418
419/**
Brian5b01c5e2006-12-19 18:02:03 -0700420 * Called via ctx->Driver.AttachShader()
421 */
422void
423_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
424{
Brian65a18442006-12-19 18:46:56 -0700425 struct gl_shader_program *shProg
426 = _mesa_lookup_shader_program(ctx, program);
427 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
Brian237b9852007-08-07 21:48:31 +0100428 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700429 GLuint i;
430
Brian65a18442006-12-19 18:46:56 -0700431 if (!shProg || !sh) {
Brian43975832007-01-04 08:21:09 -0700432 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700433 "glAttachShader(bad program or shader name)");
434 return;
435 }
436
Brian237b9852007-08-07 21:48:31 +0100437 n = shProg->NumShaders;
438
Brian5b01c5e2006-12-19 18:02:03 -0700439 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700440 if (shProg->Shaders[i] == sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700441 /* already attached */
442 return;
Brian34ae99d2006-12-18 08:28:54 -0700443 }
444 }
Brian5b01c5e2006-12-19 18:02:03 -0700445
446 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700447 shProg->Shaders = (struct gl_shader **)
448 _mesa_realloc(shProg->Shaders,
449 n * sizeof(struct gl_shader *),
450 (n + 1) * sizeof(struct gl_shader *));
451 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700452 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
453 return;
454 }
455
456 /* append */
Brian3c008a02007-04-12 15:22:32 -0600457 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
458 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700459 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700460}
461
462
463void
464_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
465 const GLchar *name)
466{
Brian65a18442006-12-19 18:46:56 -0700467 struct gl_shader_program *shProg
468 = _mesa_lookup_shader_program(ctx, program);
Brianb7978af2007-01-09 19:17:17 -0700469 const GLint size = -1; /* unknown size */
470 GLint i, oldIndex;
Brian5b01c5e2006-12-19 18:02:03 -0700471
Brian65a18442006-12-19 18:46:56 -0700472 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700473 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700474 return;
475 }
476
Brian9e4bae92006-12-20 09:27:42 -0700477 if (!name)
478 return;
479
480 if (strncmp(name, "gl_", 3) == 0) {
481 _mesa_error(ctx, GL_INVALID_OPERATION,
482 "glBindAttribLocation(illegal name)");
483 return;
484 }
485
Brian9f660252007-04-11 09:00:56 -0600486 if (shProg->LinkStatus) {
487 /* get current index/location for the attribute */
488 oldIndex = _mesa_get_attrib_location(ctx, program, name);
489 }
490 else {
491 oldIndex = -1;
492 }
Brian3209c3e2007-01-09 17:49:24 -0700493
494 /* this will replace the current value if it's already in the list */
Brianb7978af2007-01-09 19:17:17 -0700495 i = _mesa_add_attribute(shProg->Attributes, name, size, index);
Brian3209c3e2007-01-09 17:49:24 -0700496 if (i < 0) {
497 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
498 }
499
Brian9f660252007-04-11 09:00:56 -0600500 if (shProg->VertexProgram && oldIndex >= 0 && oldIndex != index) {
501 /* If the index changed, need to search/replace references to that attribute
502 * in the vertex program.
503 */
Brian3209c3e2007-01-09 17:49:24 -0700504 _slang_remap_attribute(&shProg->VertexProgram->Base, oldIndex, index);
505 }
Brian34ae99d2006-12-18 08:28:54 -0700506}
507
508
Brian5b01c5e2006-12-19 18:02:03 -0700509GLuint
510_mesa_create_shader(GLcontext *ctx, GLenum type)
511{
Brian65a18442006-12-19 18:46:56 -0700512 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700513 GLuint name;
514
515 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
516
517 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700518 case GL_FRAGMENT_SHADER:
519 case GL_VERTEX_SHADER:
520 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700521 break;
522 default:
523 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
524 return 0;
525 }
526
Brian65a18442006-12-19 18:46:56 -0700527 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700528
529 return name;
530}
531
532
533GLuint
534_mesa_create_program(GLcontext *ctx)
535{
536 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700537 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700538
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800539 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
Brian65a18442006-12-19 18:46:56 -0700540 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700541
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800542 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700543
Brian3c008a02007-04-12 15:22:32 -0600544 assert(shProg->RefCount == 1);
545
Brian5b01c5e2006-12-19 18:02:03 -0700546 return name;
547}
548
549
Brian3c008a02007-04-12 15:22:32 -0600550/**
551 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
552 * DeleteProgramARB.
553 */
Brian5b01c5e2006-12-19 18:02:03 -0700554void
555_mesa_delete_program2(GLcontext *ctx, GLuint name)
556{
Brian3c008a02007-04-12 15:22:32 -0600557 /*
558 * NOTE: deleting shaders/programs works a bit differently than
559 * texture objects (and buffer objects, etc). Shader/program
560 * handles/IDs exist in the hash table until the object is really
561 * deleted (refcount==0). With texture objects, the handle/ID is
562 * removed from the hash table in glDeleteTextures() while the tex
563 * object itself might linger until its refcount goes to zero.
564 */
Brian65a18442006-12-19 18:46:56 -0700565 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700566
Brian65a18442006-12-19 18:46:56 -0700567 shProg = _mesa_lookup_shader_program(ctx, name);
568 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700569 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteProgram(name)");
Brian5b01c5e2006-12-19 18:02:03 -0700570 return;
571 }
572
Brian9e4bae92006-12-20 09:27:42 -0700573 shProg->DeletePending = GL_TRUE;
574
Brian3c008a02007-04-12 15:22:32 -0600575 /* effectively, decr shProg's refcount */
576 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700577}
578
579
580void
581_mesa_delete_shader(GLcontext *ctx, GLuint shader)
582{
Brian9e4bae92006-12-20 09:27:42 -0700583 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
584 if (!sh) {
585 return;
586 }
Brian5b01c5e2006-12-19 18:02:03 -0700587
Brian9e4bae92006-12-20 09:27:42 -0700588 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600589
590 /* effectively, decr sh's refcount */
591 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700592}
593
594
595void
596_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
597{
Brian65a18442006-12-19 18:46:56 -0700598 struct gl_shader_program *shProg
599 = _mesa_lookup_shader_program(ctx, program);
Brian237b9852007-08-07 21:48:31 +0100600 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700601 GLuint i, j;
602
Brian65a18442006-12-19 18:46:56 -0700603 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700604 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700605 "glDetachShader(bad program or shader name)");
606 return;
607 }
608
Brian237b9852007-08-07 21:48:31 +0100609 n = shProg->NumShaders;
610
Brian5b01c5e2006-12-19 18:02:03 -0700611 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700612 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700613 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600614 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700615
Brian3c008a02007-04-12 15:22:32 -0600616 /* derefernce */
617 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700618
Brian5b01c5e2006-12-19 18:02:03 -0700619 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700620 newList = (struct gl_shader **)
621 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700622 if (!newList) {
623 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
624 return;
625 }
626 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700627 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700628 }
629 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700630 newList[j++] = shProg->Shaders[i];
631 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700632
Brian65a18442006-12-19 18:46:56 -0700633 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600634 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600635
636#ifdef DEBUG
637 /* sanity check */
638 {
639 for (j = 0; j < shProg->NumShaders; j++) {
640 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
641 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
642 assert(shProg->Shaders[j]->RefCount > 0);
643 }
644 }
645#endif
646
Brian5b01c5e2006-12-19 18:02:03 -0700647 return;
648 }
649 }
650
651 /* not found */
Brian43975832007-01-04 08:21:09 -0700652 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700653 "glDetachShader(shader not found)");
654}
655
656
657void
658_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
659 GLsizei maxLength, GLsizei *length, GLint *size,
660 GLenum *type, GLchar *nameOut)
661{
662 static const GLenum vec_types[] = {
663 GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4
664 };
Brian65a18442006-12-19 18:46:56 -0700665 struct gl_shader_program *shProg
666 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700667 GLint sz;
668
Brian65a18442006-12-19 18:46:56 -0700669 if (!shProg) {
Brianaaa57412007-04-18 15:22:43 -0600670 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib");
Brian5b01c5e2006-12-19 18:02:03 -0700671 return;
672 }
673
Brian65a18442006-12-19 18:46:56 -0700674 if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600675 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700676 return;
677 }
678
679 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700680 shProg->Attributes->Parameters[index].Name);
681 sz = shProg->Attributes->Parameters[index].Size;
Brian5b01c5e2006-12-19 18:02:03 -0700682 if (size)
Bruce Merryeeb03fa2007-12-21 14:41:45 +0200683 *size = 1; /* attributes may not be arrays */
684 if (type && sz > 0 && sz <= 4) /* XXX this is a temporary hack */
685 *type = vec_types[sz - 1];
Brian5b01c5e2006-12-19 18:02:03 -0700686}
687
688
689/**
690 * Called via ctx->Driver.GetActiveUniform().
691 */
692void
693_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
694 GLsizei maxLength, GLsizei *length, GLint *size,
695 GLenum *type, GLchar *nameOut)
696{
Brian65a18442006-12-19 18:46:56 -0700697 struct gl_shader_program *shProg
698 = _mesa_lookup_shader_program(ctx, program);
Brian274ac7a2007-04-18 16:05:53 -0600699 GLuint ind, j;
Brian5b01c5e2006-12-19 18:02:03 -0700700
Brian65a18442006-12-19 18:46:56 -0700701 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700702 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform");
Brian5b01c5e2006-12-19 18:02:03 -0700703 return;
704 }
705
Brian65a18442006-12-19 18:46:56 -0700706 if (!shProg->Uniforms || index >= shProg->Uniforms->NumParameters) {
Brian5b01c5e2006-12-19 18:02:03 -0700707 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
708 return;
709 }
710
Brian274ac7a2007-04-18 16:05:53 -0600711 ind = 0;
712 for (j = 0; j < shProg->Uniforms->NumParameters; j++) {
713 if (shProg->Uniforms->Parameters[j].Type == PROGRAM_UNIFORM ||
714 shProg->Uniforms->Parameters[j].Type == PROGRAM_SAMPLER) {
715 if (ind == index) {
Brian2761cfc2007-12-20 09:05:37 -0700716 GLuint uSize = shProg->Uniforms->Parameters[j].Size;
717 GLenum uType = shProg->Uniforms->Parameters[j].DataType;
Brian274ac7a2007-04-18 16:05:53 -0600718 /* found it */
719 copy_string(nameOut, maxLength, length,
720 shProg->Uniforms->Parameters[j].Name);
Brian2761cfc2007-12-20 09:05:37 -0700721 if (size) {
722 /* convert from floats to 'type' (eg: sizeof(mat4x4)=1) */
723 *size = uSize / sizeof_glsl_type(uType);
724 }
Brian274ac7a2007-04-18 16:05:53 -0600725 if (type)
Brian2761cfc2007-12-20 09:05:37 -0700726 *type = uType;
Brian274ac7a2007-04-18 16:05:53 -0600727 return;
728 }
729 ind++;
730 }
731 }
732
733 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700734}
735
736
737/**
738 * Called via ctx->Driver.GetAttachedShaders().
739 */
740void
741_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
742 GLsizei *count, GLuint *obj)
743{
Brian65a18442006-12-19 18:46:56 -0700744 struct gl_shader_program *shProg
745 = _mesa_lookup_shader_program(ctx, program);
746 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700747 GLint i;
Brian65a18442006-12-19 18:46:56 -0700748 for (i = 0; i < maxCount && i < shProg->NumShaders; i++) {
749 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700750 }
751 if (count)
752 *count = i;
753 }
754 else {
Brian43975832007-01-04 08:21:09 -0700755 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttachedShaders");
Brian5b01c5e2006-12-19 18:02:03 -0700756 }
757}
758
759
760GLint
761_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
762 const GLchar *name)
763{
Brian65a18442006-12-19 18:46:56 -0700764 struct gl_shader_program *shProg
765 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700766
Brian65a18442006-12-19 18:46:56 -0700767 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700768 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttribLocation");
Brian5b01c5e2006-12-19 18:02:03 -0700769 return -1;
770 }
771
Brian65a18442006-12-19 18:46:56 -0700772 if (!shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -0700773 _mesa_error(ctx, GL_INVALID_OPERATION,
774 "glGetAttribLocation(program not linked)");
775 return -1;
776 }
777
778 if (!name)
779 return -1;
780
Brian65a18442006-12-19 18:46:56 -0700781 if (shProg->Attributes) {
Brian3209c3e2007-01-09 17:49:24 -0700782 GLint i = _mesa_lookup_parameter_index(shProg->Attributes, -1, name);
783 if (i >= 0) {
Brian01a91eb2007-01-09 19:26:22 -0700784 return shProg->Attributes->Parameters[i].StateIndexes[0];
Brian5b01c5e2006-12-19 18:02:03 -0700785 }
786 }
787 return -1;
788}
789
790
791GLuint
792_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700793{
794#if 0
795 GET_CURRENT_CONTEXT(ctx);
796
797 switch (pname) {
798 case GL_PROGRAM_OBJECT_ARB:
799 {
Brian5b01c5e2006-12-19 18:02:03 -0700800 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700801
802 if (pro != NULL)
803 return (**pro)._container._generic.
804 GetName((struct gl2_generic_intf **) (pro));
805 }
806 break;
807 default:
808 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
809 }
810#endif
811 return 0;
812}
813
814
Brian5b01c5e2006-12-19 18:02:03 -0700815void
816_mesa_get_programiv(GLcontext *ctx, GLuint program,
817 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700818{
Brian65a18442006-12-19 18:46:56 -0700819 struct gl_shader_program *shProg
820 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700821
Brian65a18442006-12-19 18:46:56 -0700822 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700823 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700824 return;
825 }
826
Brian5b01c5e2006-12-19 18:02:03 -0700827 switch (pname) {
828 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700829 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700830 break;
831 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700832 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700833 break;
Brian5b01c5e2006-12-19 18:02:03 -0700834 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700835 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700836 break;
837 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600838 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700839 break;
840 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700841 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700842 break;
843 case GL_ACTIVE_ATTRIBUTES:
Brian3209c3e2007-01-09 17:49:24 -0700844 *params = shProg->Attributes ? shProg->Attributes->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700845 break;
846 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600847 *params = _mesa_longest_parameter_name(shProg->Attributes,
848 PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700849 break;
850 case GL_ACTIVE_UNIFORMS:
Brian274ac7a2007-04-18 16:05:53 -0600851 *params
852 = _mesa_num_parameters_of_type(shProg->Uniforms, PROGRAM_UNIFORM)
853 + _mesa_num_parameters_of_type(shProg->Uniforms, PROGRAM_SAMPLER);
Brian5b01c5e2006-12-19 18:02:03 -0700854 break;
855 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600856 *params = MAX2(
857 _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_UNIFORM),
858 _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_SAMPLER));
859 if (*params > 0)
860 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700861 break;
862 default:
Brian5b01c5e2006-12-19 18:02:03 -0700863 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
864 return;
Brian34ae99d2006-12-18 08:28:54 -0700865 }
Brian5b01c5e2006-12-19 18:02:03 -0700866}
Brian34ae99d2006-12-18 08:28:54 -0700867
Brian34ae99d2006-12-18 08:28:54 -0700868
Brian5b01c5e2006-12-19 18:02:03 -0700869void
870_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
871{
Brian65a18442006-12-19 18:46:56 -0700872 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700873
874 if (!shader) {
875 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderiv(shader)");
876 return;
877 }
Brian65a18442006-12-19 18:46:56 -0700878
Brian5b01c5e2006-12-19 18:02:03 -0700879 switch (pname) {
880 case GL_SHADER_TYPE:
881 *params = shader->Type;
882 break;
883 case GL_DELETE_STATUS:
884 *params = shader->DeletePending;
885 break;
886 case GL_COMPILE_STATUS:
887 *params = shader->CompileStatus;
888 break;
889 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600890 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700891 break;
892 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600893 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700894 break;
895 default:
896 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
897 return;
898 }
899}
900
901
902void
903_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
904 GLsizei *length, GLchar *infoLog)
905{
Brian65a18442006-12-19 18:46:56 -0700906 struct gl_shader_program *shProg
907 = _mesa_lookup_shader_program(ctx, program);
908 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700909 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
910 return;
911 }
Brian65a18442006-12-19 18:46:56 -0700912 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700913}
914
915
916void
917_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
918 GLsizei *length, GLchar *infoLog)
919{
Brian65a18442006-12-19 18:46:56 -0700920 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
921 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700922 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
923 return;
924 }
Brian65a18442006-12-19 18:46:56 -0700925 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700926}
927
928
929/**
930 * Called via ctx->Driver.GetShaderSource().
931 */
932void
933_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
934 GLsizei *length, GLchar *sourceOut)
935{
Brian65a18442006-12-19 18:46:56 -0700936 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
937 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700938 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderSource(shader)");
939 return;
940 }
Brian65a18442006-12-19 18:46:56 -0700941 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -0700942}
943
944
945/**
946 * Called via ctx->Driver.GetUniformfv().
947 */
948void
949_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
950 GLfloat *params)
951{
Brian65a18442006-12-19 18:46:56 -0700952 struct gl_shader_program *shProg
953 = _mesa_lookup_shader_program(ctx, program);
954 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700955 GLint i;
Brian65a18442006-12-19 18:46:56 -0700956 if (location >= 0 && location < shProg->Uniforms->NumParameters) {
Bruce Merryeeb03fa2007-12-21 14:41:45 +0200957 GLuint uSize;
958 GLenum uType;
959 GLint rows = 0;
960 uType = shProg->Uniforms->Parameters[location].DataType;
961 uSize = sizeof_glsl_type(uType);
962 /* Matrix types need special handling, because they span several
963 * parameters, and may also not be fully packed.
964 */
965 switch (shProg->Uniforms->Parameters[location].DataType) {
966 case GL_FLOAT_MAT2:
967 case GL_FLOAT_MAT3x2:
968 case GL_FLOAT_MAT4x2:
969 rows = 2;
970 break;
971 case GL_FLOAT_MAT2x3:
972 case GL_FLOAT_MAT3:
973 case GL_FLOAT_MAT4x3:
974 rows = 3;
975 break;
976 case GL_FLOAT_MAT2x4:
977 case GL_FLOAT_MAT3x4:
978 case GL_FLOAT_MAT4:
979 rows = 4;
Brian5b01c5e2006-12-19 18:02:03 -0700980 }
Bruce Merryeeb03fa2007-12-21 14:41:45 +0200981 if (rows != 0) {
982 GLint r, c;
983 for (c = 0, i = 0; c * 4 < uSize; c++)
984 for (r = 0; r < rows; r++, i++)
985 params[i] = shProg->Uniforms->ParameterValues[location + c][r];
986 }
987 else
988 for (i = 0; i < uSize; i++) {
989 params[i] = shProg->Uniforms->ParameterValues[location][i];
990 }
Brian5b01c5e2006-12-19 18:02:03 -0700991 }
992 else {
993 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(location)");
994 }
995 }
996 else {
Brian43975832007-01-04 08:21:09 -0700997 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700998 }
999}
1000
1001
1002/**
1003 * Called via ctx->Driver.GetUniformLocation().
1004 */
1005GLint
1006_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
1007{
Brian71623982007-01-30 16:55:03 -07001008 struct gl_shader_program *shProg
1009 = _mesa_lookup_shader_program(ctx, program);
1010 if (shProg) {
Brian5b01c5e2006-12-19 18:02:03 -07001011 GLuint loc;
Brian65a18442006-12-19 18:46:56 -07001012 for (loc = 0; loc < shProg->Uniforms->NumParameters; loc++) {
Brian5b01c5e2006-12-19 18:02:03 -07001013 const struct gl_program_parameter *u
Brian65a18442006-12-19 18:46:56 -07001014 = shProg->Uniforms->Parameters + loc;
Brian29053852006-12-21 11:21:26 -07001015 /* XXX this is a temporary simplification / short-cut.
1016 * We need to handle things like "e.c[0].b" as seen in the
1017 * GLSL orange book, page 189.
1018 */
Brian5cf73262007-01-05 16:02:45 -07001019 if ((u->Type == PROGRAM_UNIFORM ||
1020 u->Type == PROGRAM_SAMPLER) && !strcmp(u->Name, name)) {
Brian5b01c5e2006-12-19 18:02:03 -07001021 return loc;
1022 }
1023 }
1024 }
1025 return -1;
1026
1027}
1028
1029
1030GLboolean
1031_mesa_is_program(GLcontext *ctx, GLuint name)
1032{
Brian65a18442006-12-19 18:46:56 -07001033 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
1034 return shProg ? GL_TRUE : GL_FALSE;
Brian5b01c5e2006-12-19 18:02:03 -07001035}
1036
1037
1038GLboolean
1039_mesa_is_shader(GLcontext *ctx, GLuint name)
1040{
Brian65a18442006-12-19 18:46:56 -07001041 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -07001042 return shader ? GL_TRUE : GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -07001043}
1044
1045
1046
Brian5b01c5e2006-12-19 18:02:03 -07001047/**
1048 * Called via ctx->Driver.ShaderSource()
1049 */
1050void
1051_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -07001052{
Brian65a18442006-12-19 18:46:56 -07001053 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
1054 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001055 _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSource(shaderObj)");
Brian34ae99d2006-12-18 08:28:54 -07001056 return;
1057 }
1058
Brian34ae99d2006-12-18 08:28:54 -07001059 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -07001060 if (sh->Source) {
1061 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -07001062 }
Brian65a18442006-12-19 18:46:56 -07001063 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -07001064 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -07001065}
1066
1067
Brian5b01c5e2006-12-19 18:02:03 -07001068/**
1069 * Called via ctx->Driver.CompileShader()
1070 */
1071void
1072_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -07001073{
Brian65a18442006-12-19 18:46:56 -07001074 struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj);
Brian34ae99d2006-12-18 08:28:54 -07001075
Brian65a18442006-12-19 18:46:56 -07001076 if (!sh) {
Brian34ae99d2006-12-18 08:28:54 -07001077 _mesa_error(ctx, GL_INVALID_VALUE, "glCompileShader(shaderObj)");
1078 return;
1079 }
1080
Brian43975832007-01-04 08:21:09 -07001081 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -07001082}
1083
1084
Brian5b01c5e2006-12-19 18:02:03 -07001085/**
1086 * Called via ctx->Driver.LinkProgram()
1087 */
1088void
1089_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001090{
Brian65a18442006-12-19 18:46:56 -07001091 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001092
Brian65a18442006-12-19 18:46:56 -07001093 shProg = _mesa_lookup_shader_program(ctx, program);
1094 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001095 _mesa_error(ctx, GL_INVALID_VALUE, "glLinkProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001096 return;
1097 }
1098
Briandf43fb62008-05-06 23:08:51 -06001099 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1100
Brianc1771912007-02-16 09:56:19 -07001101 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001102}
1103
1104
1105/**
Brian5b01c5e2006-12-19 18:02:03 -07001106 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001107 */
Brian5b01c5e2006-12-19 18:02:03 -07001108void
1109_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001110{
Brian3c008a02007-04-12 15:22:32 -06001111 struct gl_shader_program *shProg;
1112
Brian00d63aa2007-02-03 11:35:02 -07001113 if (ctx->Shader.CurrentProgram &&
1114 ctx->Shader.CurrentProgram->Name == program) {
1115 /* no-op */
1116 return;
1117 }
1118
1119 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1120
Brian5b01c5e2006-12-19 18:02:03 -07001121 if (program) {
Brian65a18442006-12-19 18:46:56 -07001122 shProg = _mesa_lookup_shader_program(ctx, program);
1123 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001124 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -07001125 "glUseProgramObjectARB(programObj)");
1126 return;
1127 }
Brian5b01c5e2006-12-19 18:02:03 -07001128 }
1129 else {
Brian3c008a02007-04-12 15:22:32 -06001130 shProg = NULL;
1131 }
1132
1133 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001134}
Brian34ae99d2006-12-18 08:28:54 -07001135
Brian5b01c5e2006-12-19 18:02:03 -07001136
1137/**
1138 * Called via ctx->Driver.Uniform().
1139 */
1140void
1141_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1142 const GLvoid *values, GLenum type)
1143{
Brian3a8e2772006-12-20 17:19:16 -07001144 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian98650bd2007-03-13 16:32:48 -06001145 GLint elems, i, k;
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001146 GLenum uType;
1147 GLsizei maxCount;
Brian3a8e2772006-12-20 17:19:16 -07001148
1149 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001150 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001151 return;
1152 }
1153
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001154 if (location == -1)
1155 return; /* The standard specifies this as a no-op */
1156
Bruce Merry89b80322007-12-21 15:20:17 +02001157 /* The spec says this is GL_INVALID_OPERATION, although it seems like it
1158 * ought to be GL_INVALID_VALUE
1159 */
Brian223d7cb2007-01-23 16:37:51 -07001160 if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) {
Bruce Merry89b80322007-12-21 15:20:17 +02001161 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(location)");
Brian3a8e2772006-12-20 17:19:16 -07001162 return;
1163 }
1164
1165 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1166
Bruce Merry89b80322007-12-21 15:20:17 +02001167 uType = shProg->Uniforms->Parameters[location].DataType;
Brianfee9bbe2007-02-02 18:05:43 -07001168 /*
1169 * If we're setting a sampler, we must use glUniformi1()!
1170 */
Bruce Merry89b80322007-12-21 15:20:17 +02001171 if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
Brian3e4302f2007-05-09 08:04:32 -06001172 GLint unit;
Brianfee9bbe2007-02-02 18:05:43 -07001173 if (type != GL_INT || count != 1) {
1174 _mesa_error(ctx, GL_INVALID_OPERATION,
1175 "glUniform(only glUniform1i can be used "
1176 "to set sampler uniforms)");
1177 return;
1178 }
Brian3e4302f2007-05-09 08:04:32 -06001179 /* check that the sampler (tex unit index) is legal */
1180 unit = ((GLint *) values)[0];
1181 if (unit >= ctx->Const.MaxTextureImageUnits) {
1182 _mesa_error(ctx, GL_INVALID_VALUE,
1183 "glUniform1(invalid sampler/tex unit index)");
1184 return;
1185 }
Brianfee9bbe2007-02-02 18:05:43 -07001186 }
1187
Brian52363952007-03-13 16:50:24 -06001188 if (count < 0) {
1189 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1190 return;
1191 }
1192
Brian98650bd2007-03-13 16:32:48 -06001193 switch (type) {
1194 case GL_FLOAT:
1195 case GL_INT:
1196 elems = 1;
1197 break;
1198 case GL_FLOAT_VEC2:
1199 case GL_INT_VEC2:
1200 elems = 2;
1201 break;
1202 case GL_FLOAT_VEC3:
1203 case GL_INT_VEC3:
1204 elems = 3;
1205 break;
1206 case GL_FLOAT_VEC4:
1207 case GL_INT_VEC4:
1208 elems = 4;
1209 break;
1210 default:
1211 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1212 return;
Brian89dc4852007-01-04 14:35:44 -07001213 }
Brian98650bd2007-03-13 16:32:48 -06001214
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001215 /* OpenGL requires types to match exactly, except that one can convert
1216 * float or int array to boolean array.
1217 */
1218 switch (uType)
1219 {
1220 case GL_BOOL:
1221 case GL_BOOL_VEC2:
1222 case GL_BOOL_VEC3:
1223 case GL_BOOL_VEC4:
Bruce Merry89b80322007-12-21 15:20:17 +02001224 if (elems != sizeof_glsl_type(uType)) {
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001225 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count mismatch)");
1226 }
1227 break;
1228 case PROGRAM_SAMPLER:
1229 break;
1230 default:
Bruce Merry89b80322007-12-21 15:20:17 +02001231 if (shProg->Uniforms->Parameters[location].Type != PROGRAM_SAMPLER
1232 && uType != type) {
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001233 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
1234 }
1235 break;
Brian98650bd2007-03-13 16:32:48 -06001236 }
1237
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001238 /* XXX if this is a base type, then count must equal 1. However, we
1239 * don't have enough information from the compiler to distinguish a
1240 * base type from a 1-element array of that type. The standard allows
1241 * count to overrun an array, in which case the overflow is ignored.
1242 */
1243 maxCount = shProg->Uniforms->Parameters[location].Size / elems;
1244 if (count > maxCount) count = maxCount;
1245
Brian98650bd2007-03-13 16:32:48 -06001246 for (k = 0; k < count; k++) {
1247 GLfloat *uniformVal = shProg->Uniforms->ParameterValues[location + k];
1248 if (type == GL_INT ||
1249 type == GL_INT_VEC2 ||
1250 type == GL_INT_VEC3 ||
1251 type == GL_INT_VEC4) {
Brian52363952007-03-13 16:50:24 -06001252 const GLint *iValues = ((const GLint *) values) + k * elems;
Brian98650bd2007-03-13 16:32:48 -06001253 for (i = 0; i < elems; i++) {
1254 uniformVal[i] = (GLfloat) iValues[i];
1255 }
1256 }
1257 else {
Brian52363952007-03-13 16:50:24 -06001258 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
Brian98650bd2007-03-13 16:32:48 -06001259 for (i = 0; i < elems; i++) {
1260 uniformVal[i] = fValues[i];
1261 }
Brian89dc4852007-01-04 14:35:44 -07001262 }
Bruce Merry2bf2a8c2007-12-21 23:18:40 +02001263 if (uType == GL_BOOL ||
1264 uType == GL_BOOL_VEC2 ||
1265 uType == GL_BOOL_VEC3 ||
1266 uType == GL_BOOL_VEC4) {
1267 for (i = 0; i < elems; i++)
1268 uniformVal[i] = uniformVal[i] ? 1.0f : 0.0f;
1269 }
Brian5b01c5e2006-12-19 18:02:03 -07001270 }
Brian5cf73262007-01-05 16:02:45 -07001271
1272 if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
Briancec81ee2007-03-07 08:04:06 -07001273 if (shProg->VertexProgram)
1274 _slang_resolve_samplers(shProg, &shProg->VertexProgram->Base);
1275 if (shProg->FragmentProgram)
1276 _slang_resolve_samplers(shProg, &shProg->FragmentProgram->Base);
Brian5cf73262007-01-05 16:02:45 -07001277 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1278 }
Brian34ae99d2006-12-18 08:28:54 -07001279}
1280
1281
1282/**
Brian5b01c5e2006-12-19 18:02:03 -07001283 * Called by ctx->Driver.UniformMatrix().
Brian34ae99d2006-12-18 08:28:54 -07001284 */
Brian5b01c5e2006-12-19 18:02:03 -07001285void
1286_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1287 GLenum matrixType, GLint location, GLsizei count,
1288 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001289{
Bruce Merry3f948022007-12-21 16:04:43 +02001290 GLsizei maxCount, i;
Brian3a8e2772006-12-20 17:19:16 -07001291 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
1292 if (!shProg || !shProg->LinkStatus) {
1293 _mesa_error(ctx, GL_INVALID_OPERATION,
1294 "glUniformMatrix(program not linked)");
1295 return;
1296 }
Bruce Merry89b80322007-12-21 15:20:17 +02001297 if (location == -1)
1298 return; /* The standard specifies this as a no-op */
1299 /* The spec says this is GL_INVALID_OPERATION, although it seems like it
1300 * ought to be GL_INVALID_VALUE
1301 */
1302 if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) {
1303 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(location)");
Brian3a8e2772006-12-20 17:19:16 -07001304 return;
1305 }
Brian34ae99d2006-12-18 08:28:54 -07001306 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001307 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001308 return;
1309 }
Bruce Merry3f948022007-12-21 16:04:43 +02001310 if (count < 0) {
1311 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(count < 0)");
1312 return;
1313 }
Brian34ae99d2006-12-18 08:28:54 -07001314
1315 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1316
Brian3a8e2772006-12-20 17:19:16 -07001317 /*
1318 * Note: the _columns_ of a matrix are stored in program registers, not
1319 * the rows.
1320 */
1321 /* XXXX need to test 3x3 and 2x2 matrices... */
Bruce Merry3f948022007-12-21 16:04:43 +02001322 maxCount = shProg->Uniforms->Parameters[location].Size / (4 * cols);
1323 if (count > maxCount)
1324 count = maxCount;
1325 for (i = 0; i < count; i++) {
1326 if (transpose) {
1327 GLuint row, col;
1328 for (col = 0; col < cols; col++) {
1329 GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
1330 for (row = 0; row < rows; row++) {
1331 v[row] = values[row * cols + col];
1332 }
Brian34ae99d2006-12-18 08:28:54 -07001333 }
Brian34ae99d2006-12-18 08:28:54 -07001334 }
Bruce Merry3f948022007-12-21 16:04:43 +02001335 else {
1336 GLuint row, col;
1337 for (col = 0; col < cols; col++) {
1338 GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
1339 for (row = 0; row < rows; row++) {
1340 v[row] = values[col * rows + row];
1341 }
Brian3a8e2772006-12-20 17:19:16 -07001342 }
1343 }
Bruce Merry3f948022007-12-21 16:04:43 +02001344 location += cols;
1345 values += rows * cols;
Brian34ae99d2006-12-18 08:28:54 -07001346 }
1347}
1348
1349
Brian5b01c5e2006-12-19 18:02:03 -07001350void
1351_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001352{
Brian65a18442006-12-19 18:46:56 -07001353 struct gl_shader_program *shProg;
1354 shProg = _mesa_lookup_shader_program(ctx, program);
1355 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001356 _mesa_error(ctx, GL_INVALID_VALUE, "glValidateProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001357 return;
1358 }
Brian5b01c5e2006-12-19 18:02:03 -07001359 /* XXX temporary */
Brian65a18442006-12-19 18:46:56 -07001360 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001361
Brian5b01c5e2006-12-19 18:02:03 -07001362 /* From the GL spec:
1363 any two active samplers in the current program object are of
1364 different types, but refer to the same texture image unit,
1365
1366 any active sampler in the current program object refers to a texture
1367 image unit where fixed-function fragment processing accesses a
1368 texture target that does not match the sampler type, or
1369
1370 the sum of the number of active samplers in the program and the
1371 number of texture image units enabled for fixed-function fragment
1372 processing exceeds the combined limit on the total number of texture
1373 image units allowed.
1374 */
Brian34ae99d2006-12-18 08:28:54 -07001375}