blob: 11450db6448edcec9dfc3a4b6ebb1aa7c6a16eff [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"
Brian Paulade50832008-05-14 16:09:46 -060046#include "prog_uniform.h"
Brianc223c6b2007-07-04 13:15:20 -060047#include "shader/shader_api.h"
48#include "shader/slang/slang_compile.h"
49#include "shader/slang/slang_link.h"
Brian34ae99d2006-12-18 08:28:54 -070050
51
52
Brianf2923612006-12-20 09:56:44 -070053/**
54 * Allocate a new gl_shader_program object, initialize it.
55 */
56struct gl_shader_program *
57_mesa_new_shader_program(GLcontext *ctx, GLuint name)
58{
59 struct gl_shader_program *shProg;
60 shProg = CALLOC_STRUCT(gl_shader_program);
61 if (shProg) {
Brianf3e8c322007-04-18 14:53:23 -060062 shProg->Type = GL_SHADER_PROGRAM_MESA;
Brianf2923612006-12-20 09:56:44 -070063 shProg->Name = name;
64 shProg->RefCount = 1;
Brian3209c3e2007-01-09 17:49:24 -070065 shProg->Attributes = _mesa_new_parameter_list();
Brianf2923612006-12-20 09:56:44 -070066 }
67 return shProg;
68}
69
70
Brianb9fbedd2007-03-26 09:23:44 -060071/**
Brian3c008a02007-04-12 15:22:32 -060072 * Clear (free) the shader program state that gets produced by linking.
Brianb9fbedd2007-03-26 09:23:44 -060073 */
Brianf2923612006-12-20 09:56:44 -070074void
Brian3c008a02007-04-12 15:22:32 -060075_mesa_clear_shader_program_data(GLcontext *ctx,
76 struct gl_shader_program *shProg)
Brianf2923612006-12-20 09:56:44 -070077{
Brianf2923612006-12-20 09:56:44 -070078 if (shProg->VertexProgram) {
Brian Paulade50832008-05-14 16:09:46 -060079 /* Set ptr to NULL since the param list is shared with the
80 * original/unlinked program.
81 */
82 shProg->VertexProgram->Base.Parameters = NULL;
Briandf43fb62008-05-06 23:08:51 -060083 _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL);
Brianf2923612006-12-20 09:56:44 -070084 }
85
86 if (shProg->FragmentProgram) {
Brian Paulade50832008-05-14 16:09:46 -060087 /* Set ptr to NULL since the param list is shared with the
88 * original/unlinked program.
89 */
90 shProg->FragmentProgram->Base.Parameters = NULL;
Briandf43fb62008-05-06 23:08:51 -060091 _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL);
Brianf2923612006-12-20 09:56:44 -070092 }
93
Brianf2923612006-12-20 09:56:44 -070094 if (shProg->Uniforms) {
Brian Paulade50832008-05-14 16:09:46 -060095 _mesa_free_uniform_list(shProg->Uniforms);
Brianf2923612006-12-20 09:56:44 -070096 shProg->Uniforms = NULL;
97 }
98
99 if (shProg->Varying) {
100 _mesa_free_parameter_list(shProg->Varying);
101 shProg->Varying = NULL;
102 }
103}
104
105
Brianb9fbedd2007-03-26 09:23:44 -0600106/**
Brian3c008a02007-04-12 15:22:32 -0600107 * Free all the data that hangs off a shader program object, but not the
108 * object itself.
109 */
110void
111_mesa_free_shader_program_data(GLcontext *ctx,
112 struct gl_shader_program *shProg)
113{
114 GLuint i;
115
Brianf3e8c322007-04-18 14:53:23 -0600116 assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
Brian3c008a02007-04-12 15:22:32 -0600117
118 _mesa_clear_shader_program_data(ctx, shProg);
119
Brian4b7c6fc2007-04-19 15:23:34 -0600120 if (shProg->Attributes) {
121 _mesa_free_parameter_list(shProg->Attributes);
122 shProg->Attributes = NULL;
123 }
124
Brian3c008a02007-04-12 15:22:32 -0600125 /* detach shaders */
126 for (i = 0; i < shProg->NumShaders; i++) {
127 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
128 }
Xiang, Haihao63d8a842008-03-31 17:02:47 +0800129 shProg->NumShaders = 0;
130
Brian3c008a02007-04-12 15:22:32 -0600131 if (shProg->Shaders) {
132 _mesa_free(shProg->Shaders);
133 shProg->Shaders = NULL;
134 }
Alan Hourihaneeec20c32008-04-22 20:29:42 +0100135
136 if (shProg->InfoLog) {
137 _mesa_free(shProg->InfoLog);
138 shProg->InfoLog = NULL;
139 }
Brian3c008a02007-04-12 15:22:32 -0600140}
141
142
143/**
Brianb9fbedd2007-03-26 09:23:44 -0600144 * Free/delete a shader program object.
145 */
Brianf2923612006-12-20 09:56:44 -0700146void
147_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg)
148{
149 _mesa_free_shader_program_data(ctx, shProg);
Alan Hourihaneeec20c32008-04-22 20:29:42 +0100150
Brianf2923612006-12-20 09:56:44 -0700151 _mesa_free(shProg);
152}
153
154
155/**
Brian3c008a02007-04-12 15:22:32 -0600156 * Set ptr to point to shProg.
157 * If ptr is pointing to another object, decrement its refcount (and delete
158 * if refcount hits zero).
159 * Then set ptr to point to shProg, incrementing its refcount.
160 */
161/* XXX this could be static */
162void
163_mesa_reference_shader_program(GLcontext *ctx,
164 struct gl_shader_program **ptr,
165 struct gl_shader_program *shProg)
166{
167 assert(ptr);
168 if (*ptr == shProg) {
169 /* no-op */
170 return;
171 }
172 if (*ptr) {
173 /* Unreference the old shader program */
174 GLboolean deleteFlag = GL_FALSE;
175 struct gl_shader_program *old = *ptr;
176
177 ASSERT(old->RefCount > 0);
178 old->RefCount--;
179 /*printf("SHPROG DECR %p (%d) to %d\n",
180 (void*) old, old->Name, old->RefCount);*/
181 deleteFlag = (old->RefCount == 0);
182
183 if (deleteFlag) {
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800184 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
Brian3c008a02007-04-12 15:22:32 -0600185 _mesa_free_shader_program(ctx, old);
186 }
187
188 *ptr = NULL;
189 }
190 assert(!*ptr);
191
192 if (shProg) {
193 shProg->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600194 /*printf("SHPROG INCR %p (%d) to %d\n",
195 (void*) shProg, shProg->Name, shProg->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600196 *ptr = shProg;
197 }
198}
199
200
201/**
Brianf2923612006-12-20 09:56:44 -0700202 * Lookup a GLSL program object.
203 */
204struct gl_shader_program *
205_mesa_lookup_shader_program(GLcontext *ctx, GLuint name)
206{
207 struct gl_shader_program *shProg;
208 if (name) {
209 shProg = (struct gl_shader_program *)
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800210 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
Brianf2923612006-12-20 09:56:44 -0700211 /* Note that both gl_shader and gl_shader_program objects are kept
212 * in the same hash table. Check the object's type to be sure it's
213 * what we're expecting.
214 */
Brianf3e8c322007-04-18 14:53:23 -0600215 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700216 return NULL;
217 }
218 return shProg;
219 }
220 return NULL;
221}
222
223
224/**
225 * Allocate a new gl_shader object, initialize it.
226 */
227struct gl_shader *
228_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
229{
230 struct gl_shader *shader;
231 assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
232 shader = CALLOC_STRUCT(gl_shader);
233 if (shader) {
234 shader->Type = type;
235 shader->Name = name;
236 shader->RefCount = 1;
237 }
238 return shader;
239}
240
241
242void
243_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh)
244{
245 GLuint i;
246 if (sh->Source)
247 _mesa_free((void *) sh->Source);
248 if (sh->InfoLog)
249 _mesa_free(sh->InfoLog);
Brian Paul57e222d2008-05-14 12:10:45 -0600250 for (i = 0; i < sh->NumPrograms; i++)
251 _mesa_reference_program(ctx, &sh->Programs[i], NULL);
Brianf2923612006-12-20 09:56:44 -0700252 if (sh->Programs)
253 _mesa_free(sh->Programs);
254 _mesa_free(sh);
255}
256
257
258/**
Brian3c008a02007-04-12 15:22:32 -0600259 * Set ptr to point to sh.
260 * If ptr is pointing to another shader, decrement its refcount (and delete
261 * if refcount hits zero).
262 * Then set ptr to point to sh, incrementing its refcount.
263 */
264/* XXX this could be static */
265void
266_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr,
267 struct gl_shader *sh)
268{
269 assert(ptr);
270 if (*ptr == sh) {
271 /* no-op */
272 return;
273 }
274 if (*ptr) {
275 /* Unreference the old shader */
276 GLboolean deleteFlag = GL_FALSE;
277 struct gl_shader *old = *ptr;
278
279 ASSERT(old->RefCount > 0);
280 old->RefCount--;
Brian99193e42007-04-12 15:45:02 -0600281 /*printf("SHADER DECR %p (%d) to %d\n",
282 (void*) old, old->Name, old->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600283 deleteFlag = (old->RefCount == 0);
284
285 if (deleteFlag) {
286 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
287 _mesa_free_shader(ctx, old);
288 }
289
290 *ptr = NULL;
291 }
292 assert(!*ptr);
293
294 if (sh) {
295 /* reference new */
296 sh->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600297 /*printf("SHADER INCR %p (%d) to %d\n",
298 (void*) sh, sh->Name, sh->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600299 *ptr = sh;
300 }
301}
302
303
304/**
Brianf2923612006-12-20 09:56:44 -0700305 * Lookup a GLSL shader object.
306 */
307struct gl_shader *
308_mesa_lookup_shader(GLcontext *ctx, GLuint name)
309{
310 if (name) {
311 struct gl_shader *sh = (struct gl_shader *)
312 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
313 /* Note that both gl_shader and gl_shader_program objects are kept
314 * in the same hash table. Check the object's type to be sure it's
315 * what we're expecting.
316 */
Brianf3e8c322007-04-18 14:53:23 -0600317 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700318 return NULL;
319 }
320 return sh;
321 }
322 return NULL;
323}
324
325
Brianfa4d0362007-02-26 18:33:50 -0700326/**
327 * Initialize context's shader state.
328 */
Brianf2923612006-12-20 09:56:44 -0700329void
330_mesa_init_shader_state(GLcontext * ctx)
331{
Brianfa4d0362007-02-26 18:33:50 -0700332 /* Device drivers may override these to control what kind of instructions
333 * are generated by the GLSL compiler.
334 */
335 ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
Brian63556fa2007-03-23 14:47:46 -0600336 ctx->Shader.EmitCondCodes = GL_TRUE; /* XXX probably want GL_FALSE... */
Brianfa4d0362007-02-26 18:33:50 -0700337 ctx->Shader.EmitComments = GL_FALSE;
Brianf2923612006-12-20 09:56:44 -0700338}
339
340
Brian5b01c5e2006-12-19 18:02:03 -0700341/**
Brian935f93f2007-03-24 16:20:02 -0600342 * Free the per-context shader-related state.
343 */
344void
345_mesa_free_shader_state(GLcontext *ctx)
346{
Brian3c008a02007-04-12 15:22:32 -0600347 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
Brian935f93f2007-03-24 16:20:02 -0600348}
349
350
351/**
Brian5b01c5e2006-12-19 18:02:03 -0700352 * Copy string from <src> to <dst>, up to maxLength characters, returning
353 * length of <dst> in <length>.
354 * \param src the strings source
355 * \param maxLength max chars to copy
356 * \param length returns number of chars copied
357 * \param dst the string destination
358 */
359static void
360copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
361{
362 GLsizei len;
363 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
364 dst[len] = src[len];
365 if (maxLength > 0)
366 dst[len] = 0;
367 if (length)
368 *length = len;
369}
370
371
Brian5b01c5e2006-12-19 18:02:03 -0700372/**
Brian2761cfc2007-12-20 09:05:37 -0700373 * Return size (in floats) of the given GLSL type.
374 * See also _slang_sizeof_type_specifier().
375 */
376static GLint
377sizeof_glsl_type(GLenum type)
378{
379 switch (type) {
380 case GL_BOOL:
381 case GL_FLOAT:
382 case GL_INT:
383 return 1;
384 case GL_BOOL_VEC2:
385 case GL_FLOAT_VEC2:
386 case GL_INT_VEC2:
387 return 2;
388 case GL_BOOL_VEC3:
389 case GL_FLOAT_VEC3:
390 case GL_INT_VEC3:
391 return 3;
392 case GL_BOOL_VEC4:
393 case GL_FLOAT_VEC4:
394 case GL_INT_VEC4:
395 return 4;
396 case GL_FLOAT_MAT2:
397 return 8; /* 2 rows of 4, actually */
398 case GL_FLOAT_MAT3:
399 return 12; /* 3 rows of 4, actually */
400 case GL_FLOAT_MAT4:
401 return 16;
402 case GL_FLOAT_MAT2x3:
Bruce Merryeeb03fa2007-12-21 14:41:45 +0200403 return 8; /* 2 rows of 4, actually */
Brian2761cfc2007-12-20 09:05:37 -0700404 case GL_FLOAT_MAT2x4:
405 return 8;
406 case GL_FLOAT_MAT3x2:
407 return 12; /* 3 rows of 4, actually */
408 case GL_FLOAT_MAT3x4:
409 return 12;
410 case GL_FLOAT_MAT4x2:
411 return 16; /* 4 rows of 4, actually */
412 case GL_FLOAT_MAT4x3:
Bruce Merryeeb03fa2007-12-21 14:41:45 +0200413 return 16; /* 4 rows of 4, actually */
Brian2761cfc2007-12-20 09:05:37 -0700414 default:
415 return 0; /* error */
416 }
417}
418
419
420/**
Brian5b01c5e2006-12-19 18:02:03 -0700421 * Called via ctx->Driver.AttachShader()
422 */
423void
424_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
425{
Brian65a18442006-12-19 18:46:56 -0700426 struct gl_shader_program *shProg
427 = _mesa_lookup_shader_program(ctx, program);
428 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
Brian237b9852007-08-07 21:48:31 +0100429 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700430 GLuint i;
431
Brian65a18442006-12-19 18:46:56 -0700432 if (!shProg || !sh) {
Brian43975832007-01-04 08:21:09 -0700433 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700434 "glAttachShader(bad program or shader name)");
435 return;
436 }
437
Brian237b9852007-08-07 21:48:31 +0100438 n = shProg->NumShaders;
439
Brian5b01c5e2006-12-19 18:02:03 -0700440 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700441 if (shProg->Shaders[i] == sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700442 /* already attached */
443 return;
Brian34ae99d2006-12-18 08:28:54 -0700444 }
445 }
Brian5b01c5e2006-12-19 18:02:03 -0700446
447 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700448 shProg->Shaders = (struct gl_shader **)
449 _mesa_realloc(shProg->Shaders,
450 n * sizeof(struct gl_shader *),
451 (n + 1) * sizeof(struct gl_shader *));
452 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700453 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
454 return;
455 }
456
457 /* append */
Brian3c008a02007-04-12 15:22:32 -0600458 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
459 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700460 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700461}
462
463
464void
465_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
466 const GLchar *name)
467{
Brian65a18442006-12-19 18:46:56 -0700468 struct gl_shader_program *shProg
469 = _mesa_lookup_shader_program(ctx, program);
Brianb7978af2007-01-09 19:17:17 -0700470 const GLint size = -1; /* unknown size */
471 GLint i, oldIndex;
Brian5b01c5e2006-12-19 18:02:03 -0700472
Brian65a18442006-12-19 18:46:56 -0700473 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700474 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700475 return;
476 }
477
Brian9e4bae92006-12-20 09:27:42 -0700478 if (!name)
479 return;
480
481 if (strncmp(name, "gl_", 3) == 0) {
482 _mesa_error(ctx, GL_INVALID_OPERATION,
483 "glBindAttribLocation(illegal name)");
484 return;
485 }
486
Brian9f660252007-04-11 09:00:56 -0600487 if (shProg->LinkStatus) {
488 /* get current index/location for the attribute */
489 oldIndex = _mesa_get_attrib_location(ctx, program, name);
490 }
491 else {
492 oldIndex = -1;
493 }
Brian3209c3e2007-01-09 17:49:24 -0700494
495 /* this will replace the current value if it's already in the list */
Brianb7978af2007-01-09 19:17:17 -0700496 i = _mesa_add_attribute(shProg->Attributes, name, size, index);
Brian3209c3e2007-01-09 17:49:24 -0700497 if (i < 0) {
498 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
499 }
500
Brian9f660252007-04-11 09:00:56 -0600501 if (shProg->VertexProgram && oldIndex >= 0 && oldIndex != index) {
502 /* If the index changed, need to search/replace references to that attribute
503 * in the vertex program.
504 */
Brian3209c3e2007-01-09 17:49:24 -0700505 _slang_remap_attribute(&shProg->VertexProgram->Base, oldIndex, index);
506 }
Brian34ae99d2006-12-18 08:28:54 -0700507}
508
509
Brian5b01c5e2006-12-19 18:02:03 -0700510GLuint
511_mesa_create_shader(GLcontext *ctx, GLenum type)
512{
Brian65a18442006-12-19 18:46:56 -0700513 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700514 GLuint name;
515
516 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
517
518 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700519 case GL_FRAGMENT_SHADER:
520 case GL_VERTEX_SHADER:
521 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700522 break;
523 default:
524 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
525 return 0;
526 }
527
Brian65a18442006-12-19 18:46:56 -0700528 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700529
530 return name;
531}
532
533
534GLuint
535_mesa_create_program(GLcontext *ctx)
536{
537 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700538 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700539
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800540 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
Brian65a18442006-12-19 18:46:56 -0700541 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700542
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800543 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700544
Brian3c008a02007-04-12 15:22:32 -0600545 assert(shProg->RefCount == 1);
546
Brian5b01c5e2006-12-19 18:02:03 -0700547 return name;
548}
549
550
Brian3c008a02007-04-12 15:22:32 -0600551/**
552 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
553 * DeleteProgramARB.
554 */
Brian5b01c5e2006-12-19 18:02:03 -0700555void
556_mesa_delete_program2(GLcontext *ctx, GLuint name)
557{
Brian3c008a02007-04-12 15:22:32 -0600558 /*
559 * NOTE: deleting shaders/programs works a bit differently than
560 * texture objects (and buffer objects, etc). Shader/program
561 * handles/IDs exist in the hash table until the object is really
562 * deleted (refcount==0). With texture objects, the handle/ID is
563 * removed from the hash table in glDeleteTextures() while the tex
564 * object itself might linger until its refcount goes to zero.
565 */
Brian65a18442006-12-19 18:46:56 -0700566 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700567
Brian65a18442006-12-19 18:46:56 -0700568 shProg = _mesa_lookup_shader_program(ctx, name);
569 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700570 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteProgram(name)");
Brian5b01c5e2006-12-19 18:02:03 -0700571 return;
572 }
573
Brian9e4bae92006-12-20 09:27:42 -0700574 shProg->DeletePending = GL_TRUE;
575
Brian3c008a02007-04-12 15:22:32 -0600576 /* effectively, decr shProg's refcount */
577 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700578}
579
580
581void
582_mesa_delete_shader(GLcontext *ctx, GLuint shader)
583{
Brian9e4bae92006-12-20 09:27:42 -0700584 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
585 if (!sh) {
586 return;
587 }
Brian5b01c5e2006-12-19 18:02:03 -0700588
Brian9e4bae92006-12-20 09:27:42 -0700589 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600590
591 /* effectively, decr sh's refcount */
592 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700593}
594
595
596void
597_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
598{
Brian65a18442006-12-19 18:46:56 -0700599 struct gl_shader_program *shProg
600 = _mesa_lookup_shader_program(ctx, program);
Brian237b9852007-08-07 21:48:31 +0100601 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700602 GLuint i, j;
603
Brian65a18442006-12-19 18:46:56 -0700604 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700605 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700606 "glDetachShader(bad program or shader name)");
607 return;
608 }
609
Brian237b9852007-08-07 21:48:31 +0100610 n = shProg->NumShaders;
611
Brian5b01c5e2006-12-19 18:02:03 -0700612 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700613 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700614 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600615 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700616
Brian3c008a02007-04-12 15:22:32 -0600617 /* derefernce */
618 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700619
Brian5b01c5e2006-12-19 18:02:03 -0700620 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700621 newList = (struct gl_shader **)
622 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700623 if (!newList) {
624 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
625 return;
626 }
627 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700628 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700629 }
630 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700631 newList[j++] = shProg->Shaders[i];
632 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700633
Brian65a18442006-12-19 18:46:56 -0700634 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600635 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600636
637#ifdef DEBUG
638 /* sanity check */
639 {
640 for (j = 0; j < shProg->NumShaders; j++) {
641 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
642 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
643 assert(shProg->Shaders[j]->RefCount > 0);
644 }
645 }
646#endif
647
Brian5b01c5e2006-12-19 18:02:03 -0700648 return;
649 }
650 }
651
652 /* not found */
Brian43975832007-01-04 08:21:09 -0700653 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700654 "glDetachShader(shader not found)");
655}
656
657
658void
659_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
660 GLsizei maxLength, GLsizei *length, GLint *size,
661 GLenum *type, GLchar *nameOut)
662{
663 static const GLenum vec_types[] = {
664 GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4
665 };
Brian65a18442006-12-19 18:46:56 -0700666 struct gl_shader_program *shProg
667 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700668 GLint sz;
669
Brian65a18442006-12-19 18:46:56 -0700670 if (!shProg) {
Brianaaa57412007-04-18 15:22:43 -0600671 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib");
Brian5b01c5e2006-12-19 18:02:03 -0700672 return;
673 }
674
Brian65a18442006-12-19 18:46:56 -0700675 if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600676 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700677 return;
678 }
679
680 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700681 shProg->Attributes->Parameters[index].Name);
682 sz = shProg->Attributes->Parameters[index].Size;
Brian5b01c5e2006-12-19 18:02:03 -0700683 if (size)
Brian Paulade50832008-05-14 16:09:46 -0600684 *size = sz;
685 if (type)
686 *type = vec_types[sz]; /* XXX this is a temporary hack */
Brian5b01c5e2006-12-19 18:02:03 -0700687}
688
689
690/**
691 * Called via ctx->Driver.GetActiveUniform().
692 */
693void
694_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
695 GLsizei maxLength, GLsizei *length, GLint *size,
696 GLenum *type, GLchar *nameOut)
697{
Brian65a18442006-12-19 18:46:56 -0700698 struct gl_shader_program *shProg
699 = _mesa_lookup_shader_program(ctx, program);
Brian Paulade50832008-05-14 16:09:46 -0600700 const struct gl_program *prog;
701 GLint progPos;
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
Brian Paulade50832008-05-14 16:09:46 -0600708 if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
Brian5b01c5e2006-12-19 18:02:03 -0700709 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
710 return;
711 }
712
Brian Paulade50832008-05-14 16:09:46 -0600713 progPos = shProg->Uniforms->Uniforms[index].VertPos;
714 if (progPos >= 0) {
715 prog = &shProg->VertexProgram->Base;
716 }
717 else {
718 progPos = shProg->Uniforms->Uniforms[index].FragPos;
719 if (progPos >= 0) {
720 prog = &shProg->FragmentProgram->Base;
Brian274ac7a2007-04-18 16:05:53 -0600721 }
722 }
723
Brian Paulade50832008-05-14 16:09:46 -0600724 if (!prog || progPos < 0)
725 return; /* should never happen */
726
727 if (nameOut)
728 copy_string(nameOut, maxLength, length,
729 prog->Parameters->Parameters[progPos].Name);
730 if (size)
731 *size = prog->Parameters->Parameters[progPos].Size;
732
733 if (type)
734 *type = prog->Parameters->Parameters[progPos].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700735}
736
737
738/**
739 * Called via ctx->Driver.GetAttachedShaders().
740 */
741void
742_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
743 GLsizei *count, GLuint *obj)
744{
Brian65a18442006-12-19 18:46:56 -0700745 struct gl_shader_program *shProg
746 = _mesa_lookup_shader_program(ctx, program);
747 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700748 GLint i;
Brian65a18442006-12-19 18:46:56 -0700749 for (i = 0; i < maxCount && i < shProg->NumShaders; i++) {
750 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700751 }
752 if (count)
753 *count = i;
754 }
755 else {
Brian43975832007-01-04 08:21:09 -0700756 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttachedShaders");
Brian5b01c5e2006-12-19 18:02:03 -0700757 }
758}
759
760
761GLint
762_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
763 const GLchar *name)
764{
Brian65a18442006-12-19 18:46:56 -0700765 struct gl_shader_program *shProg
766 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700767
Brian65a18442006-12-19 18:46:56 -0700768 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700769 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttribLocation");
Brian5b01c5e2006-12-19 18:02:03 -0700770 return -1;
771 }
772
Brian65a18442006-12-19 18:46:56 -0700773 if (!shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -0700774 _mesa_error(ctx, GL_INVALID_OPERATION,
775 "glGetAttribLocation(program not linked)");
776 return -1;
777 }
778
779 if (!name)
780 return -1;
781
Brian65a18442006-12-19 18:46:56 -0700782 if (shProg->Attributes) {
Brian3209c3e2007-01-09 17:49:24 -0700783 GLint i = _mesa_lookup_parameter_index(shProg->Attributes, -1, name);
784 if (i >= 0) {
Brian01a91eb2007-01-09 19:26:22 -0700785 return shProg->Attributes->Parameters[i].StateIndexes[0];
Brian5b01c5e2006-12-19 18:02:03 -0700786 }
787 }
788 return -1;
789}
790
791
792GLuint
793_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700794{
795#if 0
796 GET_CURRENT_CONTEXT(ctx);
797
798 switch (pname) {
799 case GL_PROGRAM_OBJECT_ARB:
800 {
Brian5b01c5e2006-12-19 18:02:03 -0700801 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700802
803 if (pro != NULL)
804 return (**pro)._container._generic.
805 GetName((struct gl2_generic_intf **) (pro));
806 }
807 break;
808 default:
809 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
810 }
811#endif
812 return 0;
813}
814
815
Brian5b01c5e2006-12-19 18:02:03 -0700816void
817_mesa_get_programiv(GLcontext *ctx, GLuint program,
818 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700819{
Brian65a18442006-12-19 18:46:56 -0700820 struct gl_shader_program *shProg
821 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700822
Brian65a18442006-12-19 18:46:56 -0700823 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700824 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700825 return;
826 }
827
Brian5b01c5e2006-12-19 18:02:03 -0700828 switch (pname) {
829 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700830 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700831 break;
832 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700833 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700834 break;
Brian5b01c5e2006-12-19 18:02:03 -0700835 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700836 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700837 break;
838 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600839 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700840 break;
841 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700842 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700843 break;
844 case GL_ACTIVE_ATTRIBUTES:
Brian3209c3e2007-01-09 17:49:24 -0700845 *params = shProg->Attributes ? shProg->Attributes->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700846 break;
847 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600848 *params = _mesa_longest_parameter_name(shProg->Attributes,
849 PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700850 break;
851 case GL_ACTIVE_UNIFORMS:
Brian Paulade50832008-05-14 16:09:46 -0600852 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700853 break;
854 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian Paulade50832008-05-14 16:09:46 -0600855 *params = _mesa_longest_uniform_name(shProg->Uniforms);
Brian274ac7a2007-04-18 16:05:53 -0600856 if (*params > 0)
857 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700858 break;
859 default:
Brian5b01c5e2006-12-19 18:02:03 -0700860 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
861 return;
Brian34ae99d2006-12-18 08:28:54 -0700862 }
Brian5b01c5e2006-12-19 18:02:03 -0700863}
Brian34ae99d2006-12-18 08:28:54 -0700864
Brian34ae99d2006-12-18 08:28:54 -0700865
Brian5b01c5e2006-12-19 18:02:03 -0700866void
867_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
868{
Brian65a18442006-12-19 18:46:56 -0700869 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700870
871 if (!shader) {
872 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderiv(shader)");
873 return;
874 }
Brian65a18442006-12-19 18:46:56 -0700875
Brian5b01c5e2006-12-19 18:02:03 -0700876 switch (pname) {
877 case GL_SHADER_TYPE:
878 *params = shader->Type;
879 break;
880 case GL_DELETE_STATUS:
881 *params = shader->DeletePending;
882 break;
883 case GL_COMPILE_STATUS:
884 *params = shader->CompileStatus;
885 break;
886 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600887 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700888 break;
889 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600890 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700891 break;
892 default:
893 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
894 return;
895 }
896}
897
898
899void
900_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
901 GLsizei *length, GLchar *infoLog)
902{
Brian65a18442006-12-19 18:46:56 -0700903 struct gl_shader_program *shProg
904 = _mesa_lookup_shader_program(ctx, program);
905 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700906 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
907 return;
908 }
Brian65a18442006-12-19 18:46:56 -0700909 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700910}
911
912
913void
914_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
915 GLsizei *length, GLchar *infoLog)
916{
Brian65a18442006-12-19 18:46:56 -0700917 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
918 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700919 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
920 return;
921 }
Brian65a18442006-12-19 18:46:56 -0700922 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700923}
924
925
926/**
927 * Called via ctx->Driver.GetShaderSource().
928 */
929void
930_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
931 GLsizei *length, GLchar *sourceOut)
932{
Brian65a18442006-12-19 18:46:56 -0700933 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
934 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700935 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderSource(shader)");
936 return;
937 }
Brian65a18442006-12-19 18:46:56 -0700938 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -0700939}
940
941
942/**
943 * Called via ctx->Driver.GetUniformfv().
944 */
945void
946_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
947 GLfloat *params)
948{
Brian65a18442006-12-19 18:46:56 -0700949 struct gl_shader_program *shProg
950 = _mesa_lookup_shader_program(ctx, program);
951 if (shProg) {
Brian Paulade50832008-05-14 16:09:46 -0600952 if (location < shProg->Uniforms->NumUniforms) {
953 GLint progPos, i;
954 const struct gl_program *prog;
955
956 progPos = shProg->Uniforms->Uniforms[location].VertPos;
957 if (progPos >= 0) {
958 prog = &shProg->VertexProgram->Base;
Brian5b01c5e2006-12-19 18:02:03 -0700959 }
Brian Paulade50832008-05-14 16:09:46 -0600960 else {
961 progPos = shProg->Uniforms->Uniforms[location].FragPos;
962 if (progPos >= 0) {
963 prog = &shProg->FragmentProgram->Base;
Bruce Merryeeb03fa2007-12-21 14:41:45 +0200964 }
Brian Paulade50832008-05-14 16:09:46 -0600965 }
966
967 for (i = 0; i < prog->Parameters->Parameters[progPos].Size; i++) {
968 params[i] = prog->Parameters->ParameterValues[progPos][i];
969 }
Brian5b01c5e2006-12-19 18:02:03 -0700970 }
971 else {
972 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(location)");
973 }
974 }
975 else {
Brian43975832007-01-04 08:21:09 -0700976 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700977 }
978}
979
980
981/**
982 * Called via ctx->Driver.GetUniformLocation().
983 */
984GLint
985_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
986{
Brian71623982007-01-30 16:55:03 -0700987 struct gl_shader_program *shProg
988 = _mesa_lookup_shader_program(ctx, program);
Brian Paulade50832008-05-14 16:09:46 -0600989 if (!shProg)
990 return -1;
Brian5b01c5e2006-12-19 18:02:03 -0700991
Brian Paulade50832008-05-14 16:09:46 -0600992 return _mesa_lookup_uniform(shProg->Uniforms, name);
Brian5b01c5e2006-12-19 18:02:03 -0700993}
994
995
996GLboolean
997_mesa_is_program(GLcontext *ctx, GLuint name)
998{
Brian65a18442006-12-19 18:46:56 -0700999 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
1000 return shProg ? GL_TRUE : GL_FALSE;
Brian5b01c5e2006-12-19 18:02:03 -07001001}
1002
1003
1004GLboolean
1005_mesa_is_shader(GLcontext *ctx, GLuint name)
1006{
Brian65a18442006-12-19 18:46:56 -07001007 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -07001008 return shader ? GL_TRUE : GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -07001009}
1010
1011
1012
Brian5b01c5e2006-12-19 18:02:03 -07001013/**
1014 * Called via ctx->Driver.ShaderSource()
1015 */
1016void
1017_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -07001018{
Brian65a18442006-12-19 18:46:56 -07001019 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
1020 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001021 _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSource(shaderObj)");
Brian34ae99d2006-12-18 08:28:54 -07001022 return;
1023 }
1024
Brian34ae99d2006-12-18 08:28:54 -07001025 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -07001026 if (sh->Source) {
1027 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -07001028 }
Brian65a18442006-12-19 18:46:56 -07001029 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -07001030 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -07001031}
1032
1033
Brian5b01c5e2006-12-19 18:02:03 -07001034/**
1035 * Called via ctx->Driver.CompileShader()
1036 */
1037void
1038_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -07001039{
Brian65a18442006-12-19 18:46:56 -07001040 struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj);
Brian34ae99d2006-12-18 08:28:54 -07001041
Brian65a18442006-12-19 18:46:56 -07001042 if (!sh) {
Brian34ae99d2006-12-18 08:28:54 -07001043 _mesa_error(ctx, GL_INVALID_VALUE, "glCompileShader(shaderObj)");
1044 return;
1045 }
1046
Brian43975832007-01-04 08:21:09 -07001047 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -07001048}
1049
1050
Brian5b01c5e2006-12-19 18:02:03 -07001051/**
1052 * Called via ctx->Driver.LinkProgram()
1053 */
1054void
1055_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001056{
Brian65a18442006-12-19 18:46:56 -07001057 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001058
Brian65a18442006-12-19 18:46:56 -07001059 shProg = _mesa_lookup_shader_program(ctx, program);
1060 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001061 _mesa_error(ctx, GL_INVALID_VALUE, "glLinkProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001062 return;
1063 }
1064
Briandf43fb62008-05-06 23:08:51 -06001065 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1066
Brianc1771912007-02-16 09:56:19 -07001067 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001068}
1069
1070
1071/**
Brian5b01c5e2006-12-19 18:02:03 -07001072 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001073 */
Brian5b01c5e2006-12-19 18:02:03 -07001074void
1075_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001076{
Brian3c008a02007-04-12 15:22:32 -06001077 struct gl_shader_program *shProg;
1078
Brian00d63aa2007-02-03 11:35:02 -07001079 if (ctx->Shader.CurrentProgram &&
1080 ctx->Shader.CurrentProgram->Name == program) {
1081 /* no-op */
1082 return;
1083 }
1084
1085 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1086
Brian5b01c5e2006-12-19 18:02:03 -07001087 if (program) {
Brian65a18442006-12-19 18:46:56 -07001088 shProg = _mesa_lookup_shader_program(ctx, program);
1089 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001090 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -07001091 "glUseProgramObjectARB(programObj)");
1092 return;
1093 }
Brian5b01c5e2006-12-19 18:02:03 -07001094 }
1095 else {
Brian3c008a02007-04-12 15:22:32 -06001096 shProg = NULL;
1097 }
1098
1099 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001100}
Brian34ae99d2006-12-18 08:28:54 -07001101
Brian5b01c5e2006-12-19 18:02:03 -07001102
Brian Paulade50832008-05-14 16:09:46 -06001103
1104/**
1105 * Update the vertex and fragment program's TexturesUsed arrays.
1106 */
1107static void
1108update_textures_used(struct gl_program *prog)
1109{
1110 GLuint s;
1111
1112 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1113
1114 for (s = 0; s < MAX_SAMPLERS; s++) {
1115 if (prog->SamplersUsed & (1 << s)) {
1116 GLuint u = prog->SamplerUnits[s];
1117 GLuint t = prog->SamplerTargets[s];
1118 assert(u < MAX_TEXTURE_IMAGE_UNITS);
1119 prog->TexturesUsed[u] |= (1 << t);
1120 }
1121 }
1122}
1123
1124
1125/**
1126 * Set the value of a program's uniform variable.
1127 * \param program the program whose uniform to update
1128 * \param location the location/index of the uniform
1129 * \param type the datatype of the uniform
1130 * \param count the number of uniforms to set
1131 * \param elems number of elements per uniform
1132 * \param values the new values
1133 */
1134static void
1135set_program_uniform(GLcontext *ctx, struct gl_program *program, GLint location,
1136 GLenum type, GLint count, GLint elems, const void *values)
1137{
1138 if (program->Parameters->Parameters[location].Type == PROGRAM_SAMPLER) {
1139 /* This controls which texture unit which is used by a sampler */
1140 GLuint texUnit, sampler;
1141
1142 /* data type for setting samplers must be int */
1143 if (type != GL_INT || count != 1) {
1144 _mesa_error(ctx, GL_INVALID_OPERATION,
1145 "glUniform(only glUniform1i can be used "
1146 "to set sampler uniforms)");
1147 return;
1148 }
1149
1150 sampler = (GLuint) program->Parameters->ParameterValues[location][0];
1151 texUnit = ((GLuint *) values)[0];
1152
1153 /* check that the sampler (tex unit index) is legal */
1154 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1155 _mesa_error(ctx, GL_INVALID_VALUE,
1156 "glUniform1(invalid sampler/tex unit index)");
1157 return;
1158 }
1159
1160 /* This maps a sampler to a texture unit: */
1161 program->SamplerUnits[sampler] = texUnit;
1162 update_textures_used(program);
1163
1164 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1165 }
1166 else {
1167 /* ordinary uniform variable */
1168 GLint k, i;
1169
1170 if (count * elems > program->Parameters->Parameters[location].Size) {
1171 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1172 return;
1173 }
1174
1175 for (k = 0; k < count; k++) {
1176 GLfloat *uniformVal = program->Parameters->ParameterValues[location + k];
1177 if (type == GL_INT ||
1178 type == GL_INT_VEC2 ||
1179 type == GL_INT_VEC3 ||
1180 type == GL_INT_VEC4) {
1181 const GLint *iValues = ((const GLint *) values) + k * elems;
1182 for (i = 0; i < elems; i++) {
1183 uniformVal[i] = (GLfloat) iValues[i];
1184 }
1185 }
1186 else {
1187 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1188 for (i = 0; i < elems; i++) {
1189 uniformVal[i] = fValues[i];
1190 }
1191 }
1192 }
1193 }
1194}
1195
1196
Brian5b01c5e2006-12-19 18:02:03 -07001197/**
1198 * Called via ctx->Driver.Uniform().
1199 */
1200void
1201_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1202 const GLvoid *values, GLenum type)
1203{
Brian3a8e2772006-12-20 17:19:16 -07001204 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paulade50832008-05-14 16:09:46 -06001205 GLint elems;
Brian3a8e2772006-12-20 17:19:16 -07001206
1207 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001208 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001209 return;
1210 }
1211
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001212 if (location == -1)
1213 return; /* The standard specifies this as a no-op */
1214
Brian Paulade50832008-05-14 16:09:46 -06001215 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
1216 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
Brian3a8e2772006-12-20 17:19:16 -07001217 return;
1218 }
1219
Brian52363952007-03-13 16:50:24 -06001220 if (count < 0) {
1221 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1222 return;
1223 }
1224
Brian98650bd2007-03-13 16:32:48 -06001225 switch (type) {
1226 case GL_FLOAT:
1227 case GL_INT:
1228 elems = 1;
1229 break;
1230 case GL_FLOAT_VEC2:
1231 case GL_INT_VEC2:
1232 elems = 2;
1233 break;
1234 case GL_FLOAT_VEC3:
1235 case GL_INT_VEC3:
1236 elems = 3;
1237 break;
1238 case GL_FLOAT_VEC4:
1239 case GL_INT_VEC4:
1240 elems = 4;
1241 break;
1242 default:
1243 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1244 return;
Brian89dc4852007-01-04 14:35:44 -07001245 }
Brian98650bd2007-03-13 16:32:48 -06001246
Brian Paulade50832008-05-14 16:09:46 -06001247 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
Brian98650bd2007-03-13 16:32:48 -06001248
Brian Paulade50832008-05-14 16:09:46 -06001249 /* A uniform var may be used by both a vertex shader and a fragment
1250 * shader. We may need to update one or both shader's uniform here:
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001251 */
Brian Paulade50832008-05-14 16:09:46 -06001252 if (shProg->VertexProgram) {
1253 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1254 if (loc >= 0) {
1255 set_program_uniform(ctx, &shProg->VertexProgram->Base,
1256 loc, type, count, elems, values);
Bruce Merry2bf2a8c2007-12-21 23:18:40 +02001257 }
Brian5b01c5e2006-12-19 18:02:03 -07001258 }
Brian5cf73262007-01-05 16:02:45 -07001259
Brian Paulade50832008-05-14 16:09:46 -06001260 if (shProg->FragmentProgram) {
1261 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1262 if (loc >= 0) {
1263 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
1264 loc, type, count, elems, values);
1265 }
1266 }
1267}
1268
1269
1270static void
1271set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
1272 GLuint location, GLuint rows, GLuint cols,
1273 GLboolean transpose, const GLfloat *values)
1274{
1275 /*
1276 * Note: the _columns_ of a matrix are stored in program registers, not
1277 * the rows.
1278 */
1279 /* XXXX need to test 3x3 and 2x2 matrices... */
1280 if (transpose) {
1281 GLuint row, col;
1282 for (col = 0; col < cols; col++) {
1283 GLfloat *v = program->Parameters->ParameterValues[location + col];
1284 for (row = 0; row < rows; row++) {
1285 v[row] = values[row * cols + col];
1286 }
1287 }
1288 }
1289 else {
1290 GLuint row, col;
1291 for (col = 0; col < cols; col++) {
1292 GLfloat *v = program->Parameters->ParameterValues[location + col];
1293 for (row = 0; row < rows; row++) {
1294 v[row] = values[col * rows + row];
1295 }
1296 }
Brian5cf73262007-01-05 16:02:45 -07001297 }
Brian34ae99d2006-12-18 08:28:54 -07001298}
1299
1300
1301/**
Brian5b01c5e2006-12-19 18:02:03 -07001302 * Called by ctx->Driver.UniformMatrix().
Brian34ae99d2006-12-18 08:28:54 -07001303 */
Brian5b01c5e2006-12-19 18:02:03 -07001304void
1305_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1306 GLenum matrixType, GLint location, GLsizei count,
1307 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001308{
Brian3a8e2772006-12-20 17:19:16 -07001309 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paulade50832008-05-14 16:09:46 -06001310
Brian3a8e2772006-12-20 17:19:16 -07001311 if (!shProg || !shProg->LinkStatus) {
1312 _mesa_error(ctx, GL_INVALID_OPERATION,
1313 "glUniformMatrix(program not linked)");
1314 return;
1315 }
Brian Paulade50832008-05-14 16:09:46 -06001316
Bruce Merry89b80322007-12-21 15:20:17 +02001317 if (location == -1)
1318 return; /* The standard specifies this as a no-op */
Brian Paulade50832008-05-14 16:09:46 -06001319
1320 if (location < 0 || location >= shProg->Uniforms->NumUniforms) {
1321 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
Brian3a8e2772006-12-20 17:19:16 -07001322 return;
1323 }
Brian34ae99d2006-12-18 08:28:54 -07001324 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001325 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001326 return;
1327 }
1328
1329 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1330
Brian Paulade50832008-05-14 16:09:46 -06001331 if (shProg->VertexProgram) {
1332 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1333 if (loc >= 0) {
1334 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
1335 loc, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07001336 }
Brian Paulade50832008-05-14 16:09:46 -06001337 }
1338
1339 if (shProg->FragmentProgram) {
1340 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1341 if (loc >= 0) {
1342 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
1343 loc, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07001344 }
Brian34ae99d2006-12-18 08:28:54 -07001345 }
1346}
1347
1348
Brian5b01c5e2006-12-19 18:02:03 -07001349void
1350_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001351{
Brian65a18442006-12-19 18:46:56 -07001352 struct gl_shader_program *shProg;
1353 shProg = _mesa_lookup_shader_program(ctx, program);
1354 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001355 _mesa_error(ctx, GL_INVALID_VALUE, "glValidateProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001356 return;
1357 }
Brian5b01c5e2006-12-19 18:02:03 -07001358 /* XXX temporary */
Brian65a18442006-12-19 18:46:56 -07001359 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001360
Brian5b01c5e2006-12-19 18:02:03 -07001361 /* From the GL spec:
1362 any two active samplers in the current program object are of
1363 different types, but refer to the same texture image unit,
1364
1365 any active sampler in the current program object refers to a texture
1366 image unit where fixed-function fragment processing accesses a
1367 texture target that does not match the sampler type, or
1368
1369 the sum of the number of active samplers in the program and the
1370 number of texture image units enabled for fixed-function fragment
1371 processing exceeds the combined limit on the total number of texture
1372 image units allowed.
1373 */
Brian34ae99d2006-12-18 08:28:54 -07001374}