blob: c319cef10a5026ef48fbf9a585002bd6e59c4ba7 [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);
249 for (i = 0; i < sh->NumPrograms; i++) {
250 assert(sh->Programs[i]);
Briandc6fab92008-03-22 10:27:03 -0600251 ctx->Driver.DeleteProgram(ctx, sh->Programs[i]);
Brianf2923612006-12-20 09:56:44 -0700252 }
253 if (sh->Programs)
254 _mesa_free(sh->Programs);
255 _mesa_free(sh);
256}
257
258
259/**
Brian3c008a02007-04-12 15:22:32 -0600260 * Set ptr to point to sh.
261 * If ptr is pointing to another shader, decrement its refcount (and delete
262 * if refcount hits zero).
263 * Then set ptr to point to sh, incrementing its refcount.
264 */
265/* XXX this could be static */
266void
267_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr,
268 struct gl_shader *sh)
269{
270 assert(ptr);
271 if (*ptr == sh) {
272 /* no-op */
273 return;
274 }
275 if (*ptr) {
276 /* Unreference the old shader */
277 GLboolean deleteFlag = GL_FALSE;
278 struct gl_shader *old = *ptr;
279
280 ASSERT(old->RefCount > 0);
281 old->RefCount--;
Brian99193e42007-04-12 15:45:02 -0600282 /*printf("SHADER DECR %p (%d) to %d\n",
283 (void*) old, old->Name, old->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600284 deleteFlag = (old->RefCount == 0);
285
286 if (deleteFlag) {
287 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
288 _mesa_free_shader(ctx, old);
289 }
290
291 *ptr = NULL;
292 }
293 assert(!*ptr);
294
295 if (sh) {
296 /* reference new */
297 sh->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600298 /*printf("SHADER INCR %p (%d) to %d\n",
299 (void*) sh, sh->Name, sh->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600300 *ptr = sh;
301 }
302}
303
304
305/**
Brianf2923612006-12-20 09:56:44 -0700306 * Lookup a GLSL shader object.
307 */
308struct gl_shader *
309_mesa_lookup_shader(GLcontext *ctx, GLuint name)
310{
311 if (name) {
312 struct gl_shader *sh = (struct gl_shader *)
313 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
314 /* Note that both gl_shader and gl_shader_program objects are kept
315 * in the same hash table. Check the object's type to be sure it's
316 * what we're expecting.
317 */
Brianf3e8c322007-04-18 14:53:23 -0600318 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700319 return NULL;
320 }
321 return sh;
322 }
323 return NULL;
324}
325
326
Brianfa4d0362007-02-26 18:33:50 -0700327/**
328 * Initialize context's shader state.
329 */
Brianf2923612006-12-20 09:56:44 -0700330void
331_mesa_init_shader_state(GLcontext * ctx)
332{
Brianfa4d0362007-02-26 18:33:50 -0700333 /* Device drivers may override these to control what kind of instructions
334 * are generated by the GLSL compiler.
335 */
336 ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
Brian63556fa2007-03-23 14:47:46 -0600337 ctx->Shader.EmitCondCodes = GL_TRUE; /* XXX probably want GL_FALSE... */
Brianfa4d0362007-02-26 18:33:50 -0700338 ctx->Shader.EmitComments = GL_FALSE;
Brianf2923612006-12-20 09:56:44 -0700339}
340
341
Brian5b01c5e2006-12-19 18:02:03 -0700342/**
Brian935f93f2007-03-24 16:20:02 -0600343 * Free the per-context shader-related state.
344 */
345void
346_mesa_free_shader_state(GLcontext *ctx)
347{
Brian3c008a02007-04-12 15:22:32 -0600348 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
Brian935f93f2007-03-24 16:20:02 -0600349}
350
351
352/**
Brian5b01c5e2006-12-19 18:02:03 -0700353 * Copy string from <src> to <dst>, up to maxLength characters, returning
354 * length of <dst> in <length>.
355 * \param src the strings source
356 * \param maxLength max chars to copy
357 * \param length returns number of chars copied
358 * \param dst the string destination
359 */
360static void
361copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
362{
363 GLsizei len;
364 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
365 dst[len] = src[len];
366 if (maxLength > 0)
367 dst[len] = 0;
368 if (length)
369 *length = len;
370}
371
372
Brian5b01c5e2006-12-19 18:02:03 -0700373/**
Brian2761cfc2007-12-20 09:05:37 -0700374 * Return size (in floats) of the given GLSL type.
375 * See also _slang_sizeof_type_specifier().
376 */
377static GLint
378sizeof_glsl_type(GLenum type)
379{
380 switch (type) {
381 case GL_BOOL:
382 case GL_FLOAT:
383 case GL_INT:
384 return 1;
385 case GL_BOOL_VEC2:
386 case GL_FLOAT_VEC2:
387 case GL_INT_VEC2:
388 return 2;
389 case GL_BOOL_VEC3:
390 case GL_FLOAT_VEC3:
391 case GL_INT_VEC3:
392 return 3;
393 case GL_BOOL_VEC4:
394 case GL_FLOAT_VEC4:
395 case GL_INT_VEC4:
396 return 4;
397 case GL_FLOAT_MAT2:
398 return 8; /* 2 rows of 4, actually */
399 case GL_FLOAT_MAT3:
400 return 12; /* 3 rows of 4, actually */
401 case GL_FLOAT_MAT4:
402 return 16;
403 case GL_FLOAT_MAT2x3:
Bruce Merryeeb03fa2007-12-21 14:41:45 +0200404 return 8; /* 2 rows of 4, actually */
Brian2761cfc2007-12-20 09:05:37 -0700405 case GL_FLOAT_MAT2x4:
406 return 8;
407 case GL_FLOAT_MAT3x2:
408 return 12; /* 3 rows of 4, actually */
409 case GL_FLOAT_MAT3x4:
410 return 12;
411 case GL_FLOAT_MAT4x2:
412 return 16; /* 4 rows of 4, actually */
413 case GL_FLOAT_MAT4x3:
Bruce Merryeeb03fa2007-12-21 14:41:45 +0200414 return 16; /* 4 rows of 4, actually */
Brian2761cfc2007-12-20 09:05:37 -0700415 default:
416 return 0; /* error */
417 }
418}
419
420
421/**
Brian5b01c5e2006-12-19 18:02:03 -0700422 * Called via ctx->Driver.AttachShader()
423 */
424void
425_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
426{
Brian65a18442006-12-19 18:46:56 -0700427 struct gl_shader_program *shProg
428 = _mesa_lookup_shader_program(ctx, program);
429 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
Brian237b9852007-08-07 21:48:31 +0100430 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700431 GLuint i;
432
Brian65a18442006-12-19 18:46:56 -0700433 if (!shProg || !sh) {
Brian43975832007-01-04 08:21:09 -0700434 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700435 "glAttachShader(bad program or shader name)");
436 return;
437 }
438
Brian237b9852007-08-07 21:48:31 +0100439 n = shProg->NumShaders;
440
Brian5b01c5e2006-12-19 18:02:03 -0700441 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700442 if (shProg->Shaders[i] == sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700443 /* already attached */
444 return;
Brian34ae99d2006-12-18 08:28:54 -0700445 }
446 }
Brian5b01c5e2006-12-19 18:02:03 -0700447
448 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700449 shProg->Shaders = (struct gl_shader **)
450 _mesa_realloc(shProg->Shaders,
451 n * sizeof(struct gl_shader *),
452 (n + 1) * sizeof(struct gl_shader *));
453 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700454 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
455 return;
456 }
457
458 /* append */
Brian3c008a02007-04-12 15:22:32 -0600459 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
460 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700461 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700462}
463
464
465void
466_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
467 const GLchar *name)
468{
Brian65a18442006-12-19 18:46:56 -0700469 struct gl_shader_program *shProg
470 = _mesa_lookup_shader_program(ctx, program);
Brianb7978af2007-01-09 19:17:17 -0700471 const GLint size = -1; /* unknown size */
472 GLint i, oldIndex;
Brian5b01c5e2006-12-19 18:02:03 -0700473
Brian65a18442006-12-19 18:46:56 -0700474 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700475 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700476 return;
477 }
478
Brian9e4bae92006-12-20 09:27:42 -0700479 if (!name)
480 return;
481
482 if (strncmp(name, "gl_", 3) == 0) {
483 _mesa_error(ctx, GL_INVALID_OPERATION,
484 "glBindAttribLocation(illegal name)");
485 return;
486 }
487
Brian9f660252007-04-11 09:00:56 -0600488 if (shProg->LinkStatus) {
489 /* get current index/location for the attribute */
490 oldIndex = _mesa_get_attrib_location(ctx, program, name);
491 }
492 else {
493 oldIndex = -1;
494 }
Brian3209c3e2007-01-09 17:49:24 -0700495
496 /* this will replace the current value if it's already in the list */
Brianb7978af2007-01-09 19:17:17 -0700497 i = _mesa_add_attribute(shProg->Attributes, name, size, index);
Brian3209c3e2007-01-09 17:49:24 -0700498 if (i < 0) {
499 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
500 }
501
Brian9f660252007-04-11 09:00:56 -0600502 if (shProg->VertexProgram && oldIndex >= 0 && oldIndex != index) {
503 /* If the index changed, need to search/replace references to that attribute
504 * in the vertex program.
505 */
Brian3209c3e2007-01-09 17:49:24 -0700506 _slang_remap_attribute(&shProg->VertexProgram->Base, oldIndex, index);
507 }
Brian34ae99d2006-12-18 08:28:54 -0700508}
509
510
Brian5b01c5e2006-12-19 18:02:03 -0700511GLuint
512_mesa_create_shader(GLcontext *ctx, GLenum type)
513{
Brian65a18442006-12-19 18:46:56 -0700514 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700515 GLuint name;
516
517 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
518
519 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700520 case GL_FRAGMENT_SHADER:
521 case GL_VERTEX_SHADER:
522 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700523 break;
524 default:
525 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
526 return 0;
527 }
528
Brian65a18442006-12-19 18:46:56 -0700529 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700530
531 return name;
532}
533
534
535GLuint
536_mesa_create_program(GLcontext *ctx)
537{
538 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700539 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700540
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800541 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
Brian65a18442006-12-19 18:46:56 -0700542 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700543
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800544 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700545
Brian3c008a02007-04-12 15:22:32 -0600546 assert(shProg->RefCount == 1);
547
Brian5b01c5e2006-12-19 18:02:03 -0700548 return name;
549}
550
551
Brian3c008a02007-04-12 15:22:32 -0600552/**
553 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
554 * DeleteProgramARB.
555 */
Brian5b01c5e2006-12-19 18:02:03 -0700556void
557_mesa_delete_program2(GLcontext *ctx, GLuint name)
558{
Brian3c008a02007-04-12 15:22:32 -0600559 /*
560 * NOTE: deleting shaders/programs works a bit differently than
561 * texture objects (and buffer objects, etc). Shader/program
562 * handles/IDs exist in the hash table until the object is really
563 * deleted (refcount==0). With texture objects, the handle/ID is
564 * removed from the hash table in glDeleteTextures() while the tex
565 * object itself might linger until its refcount goes to zero.
566 */
Brian65a18442006-12-19 18:46:56 -0700567 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700568
Brian65a18442006-12-19 18:46:56 -0700569 shProg = _mesa_lookup_shader_program(ctx, name);
570 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700571 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteProgram(name)");
Brian5b01c5e2006-12-19 18:02:03 -0700572 return;
573 }
574
Brian9e4bae92006-12-20 09:27:42 -0700575 shProg->DeletePending = GL_TRUE;
576
Brian3c008a02007-04-12 15:22:32 -0600577 /* effectively, decr shProg's refcount */
578 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700579}
580
581
582void
583_mesa_delete_shader(GLcontext *ctx, GLuint shader)
584{
Brian9e4bae92006-12-20 09:27:42 -0700585 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
586 if (!sh) {
587 return;
588 }
Brian5b01c5e2006-12-19 18:02:03 -0700589
Brian9e4bae92006-12-20 09:27:42 -0700590 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600591
592 /* effectively, decr sh's refcount */
593 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700594}
595
596
597void
598_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
599{
Brian65a18442006-12-19 18:46:56 -0700600 struct gl_shader_program *shProg
601 = _mesa_lookup_shader_program(ctx, program);
Brian237b9852007-08-07 21:48:31 +0100602 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700603 GLuint i, j;
604
Brian65a18442006-12-19 18:46:56 -0700605 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700606 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700607 "glDetachShader(bad program or shader name)");
608 return;
609 }
610
Brian237b9852007-08-07 21:48:31 +0100611 n = shProg->NumShaders;
612
Brian5b01c5e2006-12-19 18:02:03 -0700613 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700614 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700615 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600616 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700617
Brian3c008a02007-04-12 15:22:32 -0600618 /* derefernce */
619 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700620
Brian5b01c5e2006-12-19 18:02:03 -0700621 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700622 newList = (struct gl_shader **)
623 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700624 if (!newList) {
625 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
626 return;
627 }
628 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700629 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700630 }
631 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700632 newList[j++] = shProg->Shaders[i];
633 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700634
Brian65a18442006-12-19 18:46:56 -0700635 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600636 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600637
638#ifdef DEBUG
639 /* sanity check */
640 {
641 for (j = 0; j < shProg->NumShaders; j++) {
642 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
643 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
644 assert(shProg->Shaders[j]->RefCount > 0);
645 }
646 }
647#endif
648
Brian5b01c5e2006-12-19 18:02:03 -0700649 return;
650 }
651 }
652
653 /* not found */
Brian43975832007-01-04 08:21:09 -0700654 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700655 "glDetachShader(shader not found)");
656}
657
658
659void
660_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
661 GLsizei maxLength, GLsizei *length, GLint *size,
662 GLenum *type, GLchar *nameOut)
663{
664 static const GLenum vec_types[] = {
665 GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4
666 };
Brian65a18442006-12-19 18:46:56 -0700667 struct gl_shader_program *shProg
668 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700669 GLint sz;
670
Brian65a18442006-12-19 18:46:56 -0700671 if (!shProg) {
Brianaaa57412007-04-18 15:22:43 -0600672 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib");
Brian5b01c5e2006-12-19 18:02:03 -0700673 return;
674 }
675
Brian65a18442006-12-19 18:46:56 -0700676 if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600677 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700678 return;
679 }
680
681 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700682 shProg->Attributes->Parameters[index].Name);
683 sz = shProg->Attributes->Parameters[index].Size;
Brian5b01c5e2006-12-19 18:02:03 -0700684 if (size)
Bruce Merryeeb03fa2007-12-21 14:41:45 +0200685 *size = 1; /* attributes may not be arrays */
686 if (type && sz > 0 && sz <= 4) /* XXX this is a temporary hack */
687 *type = vec_types[sz - 1];
Brian5b01c5e2006-12-19 18:02:03 -0700688}
689
690
691/**
692 * Called via ctx->Driver.GetActiveUniform().
693 */
694void
695_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
696 GLsizei maxLength, GLsizei *length, GLint *size,
697 GLenum *type, GLchar *nameOut)
698{
Brian65a18442006-12-19 18:46:56 -0700699 struct gl_shader_program *shProg
700 = _mesa_lookup_shader_program(ctx, program);
Brian274ac7a2007-04-18 16:05:53 -0600701 GLuint ind, j;
Brian5b01c5e2006-12-19 18:02:03 -0700702
Brian65a18442006-12-19 18:46:56 -0700703 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700704 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform");
Brian5b01c5e2006-12-19 18:02:03 -0700705 return;
706 }
707
Brian65a18442006-12-19 18:46:56 -0700708 if (!shProg->Uniforms || index >= shProg->Uniforms->NumParameters) {
Brian5b01c5e2006-12-19 18:02:03 -0700709 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
710 return;
711 }
712
Brian274ac7a2007-04-18 16:05:53 -0600713 ind = 0;
714 for (j = 0; j < shProg->Uniforms->NumParameters; j++) {
715 if (shProg->Uniforms->Parameters[j].Type == PROGRAM_UNIFORM ||
716 shProg->Uniforms->Parameters[j].Type == PROGRAM_SAMPLER) {
717 if (ind == index) {
Brian2761cfc2007-12-20 09:05:37 -0700718 GLuint uSize = shProg->Uniforms->Parameters[j].Size;
719 GLenum uType = shProg->Uniforms->Parameters[j].DataType;
Brian274ac7a2007-04-18 16:05:53 -0600720 /* found it */
721 copy_string(nameOut, maxLength, length,
722 shProg->Uniforms->Parameters[j].Name);
Brian2761cfc2007-12-20 09:05:37 -0700723 if (size) {
724 /* convert from floats to 'type' (eg: sizeof(mat4x4)=1) */
725 *size = uSize / sizeof_glsl_type(uType);
726 }
Brian274ac7a2007-04-18 16:05:53 -0600727 if (type)
Brian2761cfc2007-12-20 09:05:37 -0700728 *type = uType;
Brian274ac7a2007-04-18 16:05:53 -0600729 return;
730 }
731 ind++;
732 }
733 }
734
735 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700736}
737
738
739/**
740 * Called via ctx->Driver.GetAttachedShaders().
741 */
742void
743_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
744 GLsizei *count, GLuint *obj)
745{
Brian65a18442006-12-19 18:46:56 -0700746 struct gl_shader_program *shProg
747 = _mesa_lookup_shader_program(ctx, program);
748 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700749 GLint i;
Brian65a18442006-12-19 18:46:56 -0700750 for (i = 0; i < maxCount && i < shProg->NumShaders; i++) {
751 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700752 }
753 if (count)
754 *count = i;
755 }
756 else {
Brian43975832007-01-04 08:21:09 -0700757 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttachedShaders");
Brian5b01c5e2006-12-19 18:02:03 -0700758 }
759}
760
761
762GLint
763_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
764 const GLchar *name)
765{
Brian65a18442006-12-19 18:46:56 -0700766 struct gl_shader_program *shProg
767 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700768
Brian65a18442006-12-19 18:46:56 -0700769 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700770 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttribLocation");
Brian5b01c5e2006-12-19 18:02:03 -0700771 return -1;
772 }
773
Brian65a18442006-12-19 18:46:56 -0700774 if (!shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -0700775 _mesa_error(ctx, GL_INVALID_OPERATION,
776 "glGetAttribLocation(program not linked)");
777 return -1;
778 }
779
780 if (!name)
781 return -1;
782
Brian65a18442006-12-19 18:46:56 -0700783 if (shProg->Attributes) {
Brian3209c3e2007-01-09 17:49:24 -0700784 GLint i = _mesa_lookup_parameter_index(shProg->Attributes, -1, name);
785 if (i >= 0) {
Brian01a91eb2007-01-09 19:26:22 -0700786 return shProg->Attributes->Parameters[i].StateIndexes[0];
Brian5b01c5e2006-12-19 18:02:03 -0700787 }
788 }
789 return -1;
790}
791
792
793GLuint
794_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700795{
796#if 0
797 GET_CURRENT_CONTEXT(ctx);
798
799 switch (pname) {
800 case GL_PROGRAM_OBJECT_ARB:
801 {
Brian5b01c5e2006-12-19 18:02:03 -0700802 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700803
804 if (pro != NULL)
805 return (**pro)._container._generic.
806 GetName((struct gl2_generic_intf **) (pro));
807 }
808 break;
809 default:
810 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
811 }
812#endif
813 return 0;
814}
815
816
Brian5b01c5e2006-12-19 18:02:03 -0700817void
818_mesa_get_programiv(GLcontext *ctx, GLuint program,
819 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700820{
Brian65a18442006-12-19 18:46:56 -0700821 struct gl_shader_program *shProg
822 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700823
Brian65a18442006-12-19 18:46:56 -0700824 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700825 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700826 return;
827 }
828
Brian5b01c5e2006-12-19 18:02:03 -0700829 switch (pname) {
830 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700831 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700832 break;
833 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700834 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700835 break;
Brian5b01c5e2006-12-19 18:02:03 -0700836 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700837 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700838 break;
839 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600840 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700841 break;
842 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700843 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700844 break;
845 case GL_ACTIVE_ATTRIBUTES:
Brian3209c3e2007-01-09 17:49:24 -0700846 *params = shProg->Attributes ? shProg->Attributes->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700847 break;
848 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600849 *params = _mesa_longest_parameter_name(shProg->Attributes,
850 PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700851 break;
852 case GL_ACTIVE_UNIFORMS:
Brian274ac7a2007-04-18 16:05:53 -0600853 *params
854 = _mesa_num_parameters_of_type(shProg->Uniforms, PROGRAM_UNIFORM)
855 + _mesa_num_parameters_of_type(shProg->Uniforms, PROGRAM_SAMPLER);
Brian5b01c5e2006-12-19 18:02:03 -0700856 break;
857 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600858 *params = MAX2(
859 _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_UNIFORM),
860 _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_SAMPLER));
861 if (*params > 0)
862 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700863 break;
864 default:
Brian5b01c5e2006-12-19 18:02:03 -0700865 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
866 return;
Brian34ae99d2006-12-18 08:28:54 -0700867 }
Brian5b01c5e2006-12-19 18:02:03 -0700868}
Brian34ae99d2006-12-18 08:28:54 -0700869
Brian34ae99d2006-12-18 08:28:54 -0700870
Brian5b01c5e2006-12-19 18:02:03 -0700871void
872_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
873{
Brian65a18442006-12-19 18:46:56 -0700874 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700875
876 if (!shader) {
877 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderiv(shader)");
878 return;
879 }
Brian65a18442006-12-19 18:46:56 -0700880
Brian5b01c5e2006-12-19 18:02:03 -0700881 switch (pname) {
882 case GL_SHADER_TYPE:
883 *params = shader->Type;
884 break;
885 case GL_DELETE_STATUS:
886 *params = shader->DeletePending;
887 break;
888 case GL_COMPILE_STATUS:
889 *params = shader->CompileStatus;
890 break;
891 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600892 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700893 break;
894 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600895 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700896 break;
897 default:
898 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
899 return;
900 }
901}
902
903
904void
905_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
906 GLsizei *length, GLchar *infoLog)
907{
Brian65a18442006-12-19 18:46:56 -0700908 struct gl_shader_program *shProg
909 = _mesa_lookup_shader_program(ctx, program);
910 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700911 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
912 return;
913 }
Brian65a18442006-12-19 18:46:56 -0700914 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700915}
916
917
918void
919_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
920 GLsizei *length, GLchar *infoLog)
921{
Brian65a18442006-12-19 18:46:56 -0700922 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
923 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700924 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
925 return;
926 }
Brian65a18442006-12-19 18:46:56 -0700927 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700928}
929
930
931/**
932 * Called via ctx->Driver.GetShaderSource().
933 */
934void
935_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
936 GLsizei *length, GLchar *sourceOut)
937{
Brian65a18442006-12-19 18:46:56 -0700938 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
939 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700940 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderSource(shader)");
941 return;
942 }
Brian65a18442006-12-19 18:46:56 -0700943 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -0700944}
945
946
947/**
948 * Called via ctx->Driver.GetUniformfv().
949 */
950void
951_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
952 GLfloat *params)
953{
Brian65a18442006-12-19 18:46:56 -0700954 struct gl_shader_program *shProg
955 = _mesa_lookup_shader_program(ctx, program);
956 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700957 GLint i;
Brian65a18442006-12-19 18:46:56 -0700958 if (location >= 0 && location < shProg->Uniforms->NumParameters) {
Bruce Merryeeb03fa2007-12-21 14:41:45 +0200959 GLuint uSize;
960 GLenum uType;
961 GLint rows = 0;
962 uType = shProg->Uniforms->Parameters[location].DataType;
963 uSize = sizeof_glsl_type(uType);
964 /* Matrix types need special handling, because they span several
965 * parameters, and may also not be fully packed.
966 */
967 switch (shProg->Uniforms->Parameters[location].DataType) {
968 case GL_FLOAT_MAT2:
969 case GL_FLOAT_MAT3x2:
970 case GL_FLOAT_MAT4x2:
971 rows = 2;
972 break;
973 case GL_FLOAT_MAT2x3:
974 case GL_FLOAT_MAT3:
975 case GL_FLOAT_MAT4x3:
976 rows = 3;
977 break;
978 case GL_FLOAT_MAT2x4:
979 case GL_FLOAT_MAT3x4:
980 case GL_FLOAT_MAT4:
981 rows = 4;
Brian5b01c5e2006-12-19 18:02:03 -0700982 }
Bruce Merryeeb03fa2007-12-21 14:41:45 +0200983 if (rows != 0) {
984 GLint r, c;
985 for (c = 0, i = 0; c * 4 < uSize; c++)
986 for (r = 0; r < rows; r++, i++)
987 params[i] = shProg->Uniforms->ParameterValues[location + c][r];
988 }
989 else
990 for (i = 0; i < uSize; i++) {
991 params[i] = shProg->Uniforms->ParameterValues[location][i];
992 }
Brian5b01c5e2006-12-19 18:02:03 -0700993 }
994 else {
995 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(location)");
996 }
997 }
998 else {
Brian43975832007-01-04 08:21:09 -0700999 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(program)");
Brian5b01c5e2006-12-19 18:02:03 -07001000 }
1001}
1002
1003
1004/**
1005 * Called via ctx->Driver.GetUniformLocation().
1006 */
1007GLint
1008_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
1009{
Brian71623982007-01-30 16:55:03 -07001010 struct gl_shader_program *shProg
1011 = _mesa_lookup_shader_program(ctx, program);
1012 if (shProg) {
Brian5b01c5e2006-12-19 18:02:03 -07001013 GLuint loc;
Brian65a18442006-12-19 18:46:56 -07001014 for (loc = 0; loc < shProg->Uniforms->NumParameters; loc++) {
Brian5b01c5e2006-12-19 18:02:03 -07001015 const struct gl_program_parameter *u
Brian65a18442006-12-19 18:46:56 -07001016 = shProg->Uniforms->Parameters + loc;
Brian29053852006-12-21 11:21:26 -07001017 /* XXX this is a temporary simplification / short-cut.
1018 * We need to handle things like "e.c[0].b" as seen in the
1019 * GLSL orange book, page 189.
1020 */
Brian5cf73262007-01-05 16:02:45 -07001021 if ((u->Type == PROGRAM_UNIFORM ||
1022 u->Type == PROGRAM_SAMPLER) && !strcmp(u->Name, name)) {
Brian5b01c5e2006-12-19 18:02:03 -07001023 return loc;
1024 }
1025 }
1026 }
1027 return -1;
1028
1029}
1030
1031
1032GLboolean
1033_mesa_is_program(GLcontext *ctx, GLuint name)
1034{
Brian65a18442006-12-19 18:46:56 -07001035 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
1036 return shProg ? GL_TRUE : GL_FALSE;
Brian5b01c5e2006-12-19 18:02:03 -07001037}
1038
1039
1040GLboolean
1041_mesa_is_shader(GLcontext *ctx, GLuint name)
1042{
Brian65a18442006-12-19 18:46:56 -07001043 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -07001044 return shader ? GL_TRUE : GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -07001045}
1046
1047
1048
Brian5b01c5e2006-12-19 18:02:03 -07001049/**
1050 * Called via ctx->Driver.ShaderSource()
1051 */
1052void
1053_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -07001054{
Brian65a18442006-12-19 18:46:56 -07001055 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
1056 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001057 _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSource(shaderObj)");
Brian34ae99d2006-12-18 08:28:54 -07001058 return;
1059 }
1060
Brian34ae99d2006-12-18 08:28:54 -07001061 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -07001062 if (sh->Source) {
1063 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -07001064 }
Brian65a18442006-12-19 18:46:56 -07001065 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -07001066 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -07001067}
1068
1069
Brian5b01c5e2006-12-19 18:02:03 -07001070/**
1071 * Called via ctx->Driver.CompileShader()
1072 */
1073void
1074_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -07001075{
Brian65a18442006-12-19 18:46:56 -07001076 struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj);
Brian34ae99d2006-12-18 08:28:54 -07001077
Brian65a18442006-12-19 18:46:56 -07001078 if (!sh) {
Brian34ae99d2006-12-18 08:28:54 -07001079 _mesa_error(ctx, GL_INVALID_VALUE, "glCompileShader(shaderObj)");
1080 return;
1081 }
1082
Brian43975832007-01-04 08:21:09 -07001083 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -07001084}
1085
1086
Brian5b01c5e2006-12-19 18:02:03 -07001087/**
1088 * Called via ctx->Driver.LinkProgram()
1089 */
1090void
1091_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001092{
Brian65a18442006-12-19 18:46:56 -07001093 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001094
Brian65a18442006-12-19 18:46:56 -07001095 shProg = _mesa_lookup_shader_program(ctx, program);
1096 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001097 _mesa_error(ctx, GL_INVALID_VALUE, "glLinkProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001098 return;
1099 }
1100
Briandf43fb62008-05-06 23:08:51 -06001101 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1102
Brianc1771912007-02-16 09:56:19 -07001103 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001104}
1105
1106
1107/**
Brian5b01c5e2006-12-19 18:02:03 -07001108 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001109 */
Brian5b01c5e2006-12-19 18:02:03 -07001110void
1111_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001112{
Brian3c008a02007-04-12 15:22:32 -06001113 struct gl_shader_program *shProg;
1114
Brian00d63aa2007-02-03 11:35:02 -07001115 if (ctx->Shader.CurrentProgram &&
1116 ctx->Shader.CurrentProgram->Name == program) {
1117 /* no-op */
1118 return;
1119 }
1120
1121 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1122
Brian5b01c5e2006-12-19 18:02:03 -07001123 if (program) {
Brian65a18442006-12-19 18:46:56 -07001124 shProg = _mesa_lookup_shader_program(ctx, program);
1125 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001126 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -07001127 "glUseProgramObjectARB(programObj)");
1128 return;
1129 }
Brian5b01c5e2006-12-19 18:02:03 -07001130 }
1131 else {
Brian3c008a02007-04-12 15:22:32 -06001132 shProg = NULL;
1133 }
1134
1135 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001136}
Brian34ae99d2006-12-18 08:28:54 -07001137
Brian5b01c5e2006-12-19 18:02:03 -07001138
1139/**
1140 * Called via ctx->Driver.Uniform().
1141 */
1142void
1143_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1144 const GLvoid *values, GLenum type)
1145{
Brian3a8e2772006-12-20 17:19:16 -07001146 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian98650bd2007-03-13 16:32:48 -06001147 GLint elems, i, k;
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001148 GLenum uType;
1149 GLsizei maxCount;
Brian3a8e2772006-12-20 17:19:16 -07001150
1151 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001152 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001153 return;
1154 }
1155
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001156 if (location == -1)
1157 return; /* The standard specifies this as a no-op */
1158
Bruce Merry89b80322007-12-21 15:20:17 +02001159 /* The spec says this is GL_INVALID_OPERATION, although it seems like it
1160 * ought to be GL_INVALID_VALUE
1161 */
Brian223d7cb2007-01-23 16:37:51 -07001162 if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) {
Bruce Merry89b80322007-12-21 15:20:17 +02001163 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(location)");
Brian3a8e2772006-12-20 17:19:16 -07001164 return;
1165 }
1166
1167 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1168
Bruce Merry89b80322007-12-21 15:20:17 +02001169 uType = shProg->Uniforms->Parameters[location].DataType;
Brianfee9bbe2007-02-02 18:05:43 -07001170 /*
1171 * If we're setting a sampler, we must use glUniformi1()!
1172 */
Bruce Merry89b80322007-12-21 15:20:17 +02001173 if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
Brian3e4302f2007-05-09 08:04:32 -06001174 GLint unit;
Brianfee9bbe2007-02-02 18:05:43 -07001175 if (type != GL_INT || count != 1) {
1176 _mesa_error(ctx, GL_INVALID_OPERATION,
1177 "glUniform(only glUniform1i can be used "
1178 "to set sampler uniforms)");
1179 return;
1180 }
Brian3e4302f2007-05-09 08:04:32 -06001181 /* check that the sampler (tex unit index) is legal */
1182 unit = ((GLint *) values)[0];
1183 if (unit >= ctx->Const.MaxTextureImageUnits) {
1184 _mesa_error(ctx, GL_INVALID_VALUE,
1185 "glUniform1(invalid sampler/tex unit index)");
1186 return;
1187 }
Brianfee9bbe2007-02-02 18:05:43 -07001188 }
1189
Brian52363952007-03-13 16:50:24 -06001190 if (count < 0) {
1191 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1192 return;
1193 }
1194
Brian98650bd2007-03-13 16:32:48 -06001195 switch (type) {
1196 case GL_FLOAT:
1197 case GL_INT:
1198 elems = 1;
1199 break;
1200 case GL_FLOAT_VEC2:
1201 case GL_INT_VEC2:
1202 elems = 2;
1203 break;
1204 case GL_FLOAT_VEC3:
1205 case GL_INT_VEC3:
1206 elems = 3;
1207 break;
1208 case GL_FLOAT_VEC4:
1209 case GL_INT_VEC4:
1210 elems = 4;
1211 break;
1212 default:
1213 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1214 return;
Brian89dc4852007-01-04 14:35:44 -07001215 }
Brian98650bd2007-03-13 16:32:48 -06001216
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001217 /* OpenGL requires types to match exactly, except that one can convert
1218 * float or int array to boolean array.
1219 */
1220 switch (uType)
1221 {
1222 case GL_BOOL:
1223 case GL_BOOL_VEC2:
1224 case GL_BOOL_VEC3:
1225 case GL_BOOL_VEC4:
Bruce Merry89b80322007-12-21 15:20:17 +02001226 if (elems != sizeof_glsl_type(uType)) {
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001227 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count mismatch)");
1228 }
1229 break;
1230 case PROGRAM_SAMPLER:
1231 break;
1232 default:
Bruce Merry89b80322007-12-21 15:20:17 +02001233 if (shProg->Uniforms->Parameters[location].Type != PROGRAM_SAMPLER
1234 && uType != type) {
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001235 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
1236 }
1237 break;
Brian98650bd2007-03-13 16:32:48 -06001238 }
1239
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001240 /* XXX if this is a base type, then count must equal 1. However, we
1241 * don't have enough information from the compiler to distinguish a
1242 * base type from a 1-element array of that type. The standard allows
1243 * count to overrun an array, in which case the overflow is ignored.
1244 */
1245 maxCount = shProg->Uniforms->Parameters[location].Size / elems;
1246 if (count > maxCount) count = maxCount;
1247
Brian98650bd2007-03-13 16:32:48 -06001248 for (k = 0; k < count; k++) {
1249 GLfloat *uniformVal = shProg->Uniforms->ParameterValues[location + k];
1250 if (type == GL_INT ||
1251 type == GL_INT_VEC2 ||
1252 type == GL_INT_VEC3 ||
1253 type == GL_INT_VEC4) {
Brian52363952007-03-13 16:50:24 -06001254 const GLint *iValues = ((const GLint *) values) + k * elems;
Brian98650bd2007-03-13 16:32:48 -06001255 for (i = 0; i < elems; i++) {
1256 uniformVal[i] = (GLfloat) iValues[i];
1257 }
1258 }
1259 else {
Brian52363952007-03-13 16:50:24 -06001260 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
Brian98650bd2007-03-13 16:32:48 -06001261 for (i = 0; i < elems; i++) {
1262 uniformVal[i] = fValues[i];
1263 }
Brian89dc4852007-01-04 14:35:44 -07001264 }
Bruce Merry2bf2a8c2007-12-21 23:18:40 +02001265 if (uType == GL_BOOL ||
1266 uType == GL_BOOL_VEC2 ||
1267 uType == GL_BOOL_VEC3 ||
1268 uType == GL_BOOL_VEC4) {
1269 for (i = 0; i < elems; i++)
1270 uniformVal[i] = uniformVal[i] ? 1.0f : 0.0f;
1271 }
Brian5b01c5e2006-12-19 18:02:03 -07001272 }
Brian5cf73262007-01-05 16:02:45 -07001273
1274 if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
Briancec81ee2007-03-07 08:04:06 -07001275 if (shProg->VertexProgram)
1276 _slang_resolve_samplers(shProg, &shProg->VertexProgram->Base);
1277 if (shProg->FragmentProgram)
1278 _slang_resolve_samplers(shProg, &shProg->FragmentProgram->Base);
Brian5cf73262007-01-05 16:02:45 -07001279 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1280 }
Brian34ae99d2006-12-18 08:28:54 -07001281}
1282
1283
1284/**
Brian5b01c5e2006-12-19 18:02:03 -07001285 * Called by ctx->Driver.UniformMatrix().
Brian34ae99d2006-12-18 08:28:54 -07001286 */
Brian5b01c5e2006-12-19 18:02:03 -07001287void
1288_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1289 GLenum matrixType, GLint location, GLsizei count,
1290 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001291{
Bruce Merry3f948022007-12-21 16:04:43 +02001292 GLsizei maxCount, i;
Brian3a8e2772006-12-20 17:19:16 -07001293 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
1294 if (!shProg || !shProg->LinkStatus) {
1295 _mesa_error(ctx, GL_INVALID_OPERATION,
1296 "glUniformMatrix(program not linked)");
1297 return;
1298 }
Bruce Merry89b80322007-12-21 15:20:17 +02001299 if (location == -1)
1300 return; /* The standard specifies this as a no-op */
1301 /* The spec says this is GL_INVALID_OPERATION, although it seems like it
1302 * ought to be GL_INVALID_VALUE
1303 */
1304 if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) {
1305 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(location)");
Brian3a8e2772006-12-20 17:19:16 -07001306 return;
1307 }
Brian34ae99d2006-12-18 08:28:54 -07001308 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001309 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001310 return;
1311 }
Bruce Merry3f948022007-12-21 16:04:43 +02001312 if (count < 0) {
1313 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(count < 0)");
1314 return;
1315 }
Brian34ae99d2006-12-18 08:28:54 -07001316
1317 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1318
Brian3a8e2772006-12-20 17:19:16 -07001319 /*
1320 * Note: the _columns_ of a matrix are stored in program registers, not
1321 * the rows.
1322 */
1323 /* XXXX need to test 3x3 and 2x2 matrices... */
Bruce Merry3f948022007-12-21 16:04:43 +02001324 maxCount = shProg->Uniforms->Parameters[location].Size / (4 * cols);
1325 if (count > maxCount)
1326 count = maxCount;
1327 for (i = 0; i < count; i++) {
1328 if (transpose) {
1329 GLuint row, col;
1330 for (col = 0; col < cols; col++) {
1331 GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
1332 for (row = 0; row < rows; row++) {
1333 v[row] = values[row * cols + col];
1334 }
Brian34ae99d2006-12-18 08:28:54 -07001335 }
Brian34ae99d2006-12-18 08:28:54 -07001336 }
Bruce Merry3f948022007-12-21 16:04:43 +02001337 else {
1338 GLuint row, col;
1339 for (col = 0; col < cols; col++) {
1340 GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
1341 for (row = 0; row < rows; row++) {
1342 v[row] = values[col * rows + row];
1343 }
Brian3a8e2772006-12-20 17:19:16 -07001344 }
1345 }
Bruce Merry3f948022007-12-21 16:04:43 +02001346 location += cols;
1347 values += rows * cols;
Brian34ae99d2006-12-18 08:28:54 -07001348 }
1349}
1350
1351
Brian5b01c5e2006-12-19 18:02:03 -07001352void
1353_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001354{
Brian65a18442006-12-19 18:46:56 -07001355 struct gl_shader_program *shProg;
1356 shProg = _mesa_lookup_shader_program(ctx, program);
1357 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001358 _mesa_error(ctx, GL_INVALID_VALUE, "glValidateProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001359 return;
1360 }
Brian5b01c5e2006-12-19 18:02:03 -07001361 /* XXX temporary */
Brian65a18442006-12-19 18:46:56 -07001362 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001363
Brian5b01c5e2006-12-19 18:02:03 -07001364 /* From the GL spec:
1365 any two active samplers in the current program object are of
1366 different types, but refer to the same texture image unit,
1367
1368 any active sampler in the current program object refers to a texture
1369 image unit where fixed-function fragment processing accesses a
1370 texture target that does not match the sampler type, or
1371
1372 the sum of the number of active samplers in the program and the
1373 number of texture image units enabled for fixed-function fragment
1374 processing exceeds the combined limit on the total number of texture
1375 image units allowed.
1376 */
Brian34ae99d2006-12-18 08:28:54 -07001377}