blob: eea44eb92a62a4ea4265692fde167b959e633589 [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 */
Brian Paulfd59f192008-05-18 16:04:55 -060056static struct gl_shader_program *
Brianf2923612006-12-20 09:56:44 -070057_mesa_new_shader_program(GLcontext *ctx, GLuint name)
58{
59 struct gl_shader_program *shProg;
60 shProg = CALLOC_STRUCT(gl_shader_program);
61 if (shProg) {
Brianf3e8c322007-04-18 14:53:23 -060062 shProg->Type = GL_SHADER_PROGRAM_MESA;
Brianf2923612006-12-20 09:56:44 -070063 shProg->Name = name;
64 shProg->RefCount = 1;
Brian3209c3e2007-01-09 17:49:24 -070065 shProg->Attributes = _mesa_new_parameter_list();
Brianf2923612006-12-20 09:56:44 -070066 }
67 return shProg;
68}
69
70
Brianb9fbedd2007-03-26 09:23:44 -060071/**
Brian3c008a02007-04-12 15:22:32 -060072 * Clear (free) the shader program state that gets produced by linking.
Brianb9fbedd2007-03-26 09:23:44 -060073 */
Brianf2923612006-12-20 09:56:44 -070074void
Brian3c008a02007-04-12 15:22:32 -060075_mesa_clear_shader_program_data(GLcontext *ctx,
76 struct gl_shader_program *shProg)
Brianf2923612006-12-20 09:56:44 -070077{
Brian Paul8bdf5b62008-05-16 09:56:59 -060078 _mesa_reference_vertprog(ctx, &shProg->VertexProgram, NULL);
79 _mesa_reference_fragprog(ctx, &shProg->FragmentProgram, NULL);
Brianf2923612006-12-20 09:56:44 -070080
Brianf2923612006-12-20 09:56:44 -070081 if (shProg->Uniforms) {
Brian Paulade50832008-05-14 16:09:46 -060082 _mesa_free_uniform_list(shProg->Uniforms);
Brianf2923612006-12-20 09:56:44 -070083 shProg->Uniforms = NULL;
84 }
85
86 if (shProg->Varying) {
87 _mesa_free_parameter_list(shProg->Varying);
88 shProg->Varying = NULL;
89 }
90}
91
92
Brianb9fbedd2007-03-26 09:23:44 -060093/**
Brian3c008a02007-04-12 15:22:32 -060094 * Free all the data that hangs off a shader program object, but not the
95 * object itself.
96 */
97void
98_mesa_free_shader_program_data(GLcontext *ctx,
99 struct gl_shader_program *shProg)
100{
101 GLuint i;
102
Brianf3e8c322007-04-18 14:53:23 -0600103 assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
Brian3c008a02007-04-12 15:22:32 -0600104
105 _mesa_clear_shader_program_data(ctx, shProg);
106
Brian4b7c6fc2007-04-19 15:23:34 -0600107 if (shProg->Attributes) {
108 _mesa_free_parameter_list(shProg->Attributes);
109 shProg->Attributes = NULL;
110 }
111
Brian3c008a02007-04-12 15:22:32 -0600112 /* detach shaders */
113 for (i = 0; i < shProg->NumShaders; i++) {
114 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
115 }
Xiang, Haihao63d8a842008-03-31 17:02:47 +0800116 shProg->NumShaders = 0;
117
Brian3c008a02007-04-12 15:22:32 -0600118 if (shProg->Shaders) {
119 _mesa_free(shProg->Shaders);
120 shProg->Shaders = NULL;
121 }
Alan Hourihaneeec20c32008-04-22 20:29:42 +0100122
123 if (shProg->InfoLog) {
124 _mesa_free(shProg->InfoLog);
125 shProg->InfoLog = NULL;
126 }
Brian3c008a02007-04-12 15:22:32 -0600127}
128
129
130/**
Brianb9fbedd2007-03-26 09:23:44 -0600131 * Free/delete a shader program object.
132 */
Brianf2923612006-12-20 09:56:44 -0700133void
134_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg)
135{
136 _mesa_free_shader_program_data(ctx, shProg);
Alan Hourihaneeec20c32008-04-22 20:29:42 +0100137
Brianf2923612006-12-20 09:56:44 -0700138 _mesa_free(shProg);
139}
140
141
142/**
Brian3c008a02007-04-12 15:22:32 -0600143 * Set ptr to point to shProg.
144 * If ptr is pointing to another object, decrement its refcount (and delete
145 * if refcount hits zero).
146 * Then set ptr to point to shProg, incrementing its refcount.
147 */
148/* XXX this could be static */
149void
150_mesa_reference_shader_program(GLcontext *ctx,
151 struct gl_shader_program **ptr,
152 struct gl_shader_program *shProg)
153{
154 assert(ptr);
155 if (*ptr == shProg) {
156 /* no-op */
157 return;
158 }
159 if (*ptr) {
160 /* Unreference the old shader program */
161 GLboolean deleteFlag = GL_FALSE;
162 struct gl_shader_program *old = *ptr;
163
164 ASSERT(old->RefCount > 0);
165 old->RefCount--;
Brian Paul8bdf5b62008-05-16 09:56:59 -0600166#if 0
167 printf("ShaderProgram %p ID=%u RefCount-- to %d\n",
168 (void *) old, old->Name, old->RefCount);
169#endif
Brian3c008a02007-04-12 15:22:32 -0600170 deleteFlag = (old->RefCount == 0);
171
172 if (deleteFlag) {
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800173 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
Brian3c008a02007-04-12 15:22:32 -0600174 _mesa_free_shader_program(ctx, old);
175 }
176
177 *ptr = NULL;
178 }
179 assert(!*ptr);
180
181 if (shProg) {
182 shProg->RefCount++;
Brian Paul8bdf5b62008-05-16 09:56:59 -0600183#if 0
184 printf("ShaderProgram %p ID=%u RefCount++ to %d\n",
185 (void *) shProg, shProg->Name, shProg->RefCount);
186#endif
Brian3c008a02007-04-12 15:22:32 -0600187 *ptr = shProg;
188 }
189}
190
191
192/**
Brianf2923612006-12-20 09:56:44 -0700193 * Lookup a GLSL program object.
194 */
195struct gl_shader_program *
196_mesa_lookup_shader_program(GLcontext *ctx, GLuint name)
197{
198 struct gl_shader_program *shProg;
199 if (name) {
200 shProg = (struct gl_shader_program *)
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800201 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
Brianf2923612006-12-20 09:56:44 -0700202 /* Note that both gl_shader and gl_shader_program objects are kept
203 * in the same hash table. Check the object's type to be sure it's
204 * what we're expecting.
205 */
Brianf3e8c322007-04-18 14:53:23 -0600206 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700207 return NULL;
208 }
209 return shProg;
210 }
211 return NULL;
212}
213
214
215/**
216 * Allocate a new gl_shader object, initialize it.
217 */
218struct gl_shader *
219_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
220{
221 struct gl_shader *shader;
222 assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
223 shader = CALLOC_STRUCT(gl_shader);
224 if (shader) {
225 shader->Type = type;
226 shader->Name = name;
227 shader->RefCount = 1;
228 }
229 return shader;
230}
231
232
233void
234_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh)
235{
236 GLuint i;
237 if (sh->Source)
238 _mesa_free((void *) sh->Source);
239 if (sh->InfoLog)
240 _mesa_free(sh->InfoLog);
Brian Paul57e222d2008-05-14 12:10:45 -0600241 for (i = 0; i < sh->NumPrograms; i++)
242 _mesa_reference_program(ctx, &sh->Programs[i], NULL);
Brianf2923612006-12-20 09:56:44 -0700243 if (sh->Programs)
244 _mesa_free(sh->Programs);
245 _mesa_free(sh);
246}
247
248
249/**
Brian3c008a02007-04-12 15:22:32 -0600250 * Set ptr to point to sh.
251 * If ptr is pointing to another shader, decrement its refcount (and delete
252 * if refcount hits zero).
253 * Then set ptr to point to sh, incrementing its refcount.
254 */
255/* XXX this could be static */
256void
257_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr,
258 struct gl_shader *sh)
259{
260 assert(ptr);
261 if (*ptr == sh) {
262 /* no-op */
263 return;
264 }
265 if (*ptr) {
266 /* Unreference the old shader */
267 GLboolean deleteFlag = GL_FALSE;
268 struct gl_shader *old = *ptr;
269
270 ASSERT(old->RefCount > 0);
271 old->RefCount--;
Brian99193e42007-04-12 15:45:02 -0600272 /*printf("SHADER DECR %p (%d) to %d\n",
273 (void*) old, old->Name, old->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600274 deleteFlag = (old->RefCount == 0);
275
276 if (deleteFlag) {
277 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
278 _mesa_free_shader(ctx, old);
279 }
280
281 *ptr = NULL;
282 }
283 assert(!*ptr);
284
285 if (sh) {
286 /* reference new */
287 sh->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600288 /*printf("SHADER INCR %p (%d) to %d\n",
289 (void*) sh, sh->Name, sh->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600290 *ptr = sh;
291 }
292}
293
294
295/**
Brianf2923612006-12-20 09:56:44 -0700296 * Lookup a GLSL shader object.
297 */
298struct gl_shader *
299_mesa_lookup_shader(GLcontext *ctx, GLuint name)
300{
301 if (name) {
302 struct gl_shader *sh = (struct gl_shader *)
303 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
304 /* Note that both gl_shader and gl_shader_program objects are kept
305 * in the same hash table. Check the object's type to be sure it's
306 * what we're expecting.
307 */
Brianf3e8c322007-04-18 14:53:23 -0600308 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700309 return NULL;
310 }
311 return sh;
312 }
313 return NULL;
314}
315
316
Brianfa4d0362007-02-26 18:33:50 -0700317/**
318 * Initialize context's shader state.
319 */
Brianf2923612006-12-20 09:56:44 -0700320void
321_mesa_init_shader_state(GLcontext * ctx)
322{
Brianfa4d0362007-02-26 18:33:50 -0700323 /* Device drivers may override these to control what kind of instructions
324 * are generated by the GLSL compiler.
325 */
326 ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
Brian63556fa2007-03-23 14:47:46 -0600327 ctx->Shader.EmitCondCodes = GL_TRUE; /* XXX probably want GL_FALSE... */
Brianfa4d0362007-02-26 18:33:50 -0700328 ctx->Shader.EmitComments = GL_FALSE;
Brianf2923612006-12-20 09:56:44 -0700329}
330
331
Brian5b01c5e2006-12-19 18:02:03 -0700332/**
Brian935f93f2007-03-24 16:20:02 -0600333 * Free the per-context shader-related state.
334 */
335void
336_mesa_free_shader_state(GLcontext *ctx)
337{
Brian3c008a02007-04-12 15:22:32 -0600338 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
Brian935f93f2007-03-24 16:20:02 -0600339}
340
341
342/**
Brian5b01c5e2006-12-19 18:02:03 -0700343 * Copy string from <src> to <dst>, up to maxLength characters, returning
344 * length of <dst> in <length>.
345 * \param src the strings source
346 * \param maxLength max chars to copy
347 * \param length returns number of chars copied
348 * \param dst the string destination
349 */
350static void
351copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
352{
353 GLsizei len;
354 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
355 dst[len] = src[len];
356 if (maxLength > 0)
357 dst[len] = 0;
358 if (length)
359 *length = len;
360}
361
362
Brian Paul7acb7c12008-07-03 13:49:48 -0600363static GLboolean
364_mesa_is_program(GLcontext *ctx, GLuint name)
365{
366 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
367 return shProg ? GL_TRUE : GL_FALSE;
368}
369
370
371static GLboolean
372_mesa_is_shader(GLcontext *ctx, GLuint name)
373{
374 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
375 return shader ? GL_TRUE : GL_FALSE;
376}
377
378
Brian5b01c5e2006-12-19 18:02:03 -0700379/**
380 * Called via ctx->Driver.AttachShader()
381 */
Brian Paulfd59f192008-05-18 16:04:55 -0600382static void
Brian5b01c5e2006-12-19 18:02:03 -0700383_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
384{
Brian65a18442006-12-19 18:46:56 -0700385 struct gl_shader_program *shProg
386 = _mesa_lookup_shader_program(ctx, program);
387 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
Brian237b9852007-08-07 21:48:31 +0100388 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700389 GLuint i;
390
Brian Paul7acb7c12008-07-03 13:49:48 -0600391 if (!shProg) {
392 GLenum err = _mesa_is_shader(ctx, program)
393 ? GL_INVALID_OPERATION : GL_INVALID_VALUE;
394 _mesa_error(ctx, err, "glAttachShader(bad program or shader name)");
Brian5b01c5e2006-12-19 18:02:03 -0700395 return;
396 }
397
Brian Paul7acb7c12008-07-03 13:49:48 -0600398 if (!sh) {
399 GLenum err = _mesa_is_program(ctx, shader)
400 ? GL_INVALID_OPERATION : GL_INVALID_VALUE;
401 _mesa_error(ctx, err, "glAttachShader(bad program or shader name)");
402 return;
403 }
404
405
Brian237b9852007-08-07 21:48:31 +0100406 n = shProg->NumShaders;
407
Brian5b01c5e2006-12-19 18:02:03 -0700408 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700409 if (shProg->Shaders[i] == sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700410 /* already attached */
411 return;
Brian34ae99d2006-12-18 08:28:54 -0700412 }
413 }
Brian5b01c5e2006-12-19 18:02:03 -0700414
415 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700416 shProg->Shaders = (struct gl_shader **)
417 _mesa_realloc(shProg->Shaders,
418 n * sizeof(struct gl_shader *),
419 (n + 1) * sizeof(struct gl_shader *));
420 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700421 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
422 return;
423 }
424
425 /* append */
Brian3c008a02007-04-12 15:22:32 -0600426 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
427 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700428 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700429}
430
431
Brian Paulfd59f192008-05-18 16:04:55 -0600432static GLint
Brian Paul896c0cc2008-05-16 15:47:55 -0600433_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
434 const GLchar *name)
435{
436 struct gl_shader_program *shProg
437 = _mesa_lookup_shader_program(ctx, program);
438
439 if (!shProg) {
440 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttribLocation");
441 return -1;
442 }
443
444 if (!shProg->LinkStatus) {
445 _mesa_error(ctx, GL_INVALID_OPERATION,
446 "glGetAttribLocation(program not linked)");
447 return -1;
448 }
449
450 if (!name)
451 return -1;
452
453 if (shProg->Attributes) {
454 GLint i = _mesa_lookup_parameter_index(shProg->Attributes, -1, name);
455 if (i >= 0) {
456 return shProg->Attributes->Parameters[i].StateIndexes[0];
457 }
458 }
459 return -1;
460}
461
462
Brian Paulfd59f192008-05-18 16:04:55 -0600463static void
Brian5b01c5e2006-12-19 18:02:03 -0700464_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
465 const GLchar *name)
466{
Brian65a18442006-12-19 18:46:56 -0700467 struct gl_shader_program *shProg
468 = _mesa_lookup_shader_program(ctx, program);
Brianb7978af2007-01-09 19:17:17 -0700469 const GLint size = -1; /* unknown size */
470 GLint i, oldIndex;
Brian5b01c5e2006-12-19 18:02:03 -0700471
Brian65a18442006-12-19 18:46:56 -0700472 if (!shProg) {
Brian Paul7acb7c12008-07-03 13:49:48 -0600473 GLenum err = _mesa_is_shader(ctx, program)
474 ? GL_INVALID_OPERATION : GL_INVALID_VALUE;
475 _mesa_error(ctx, err, "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
Brian Paul7acb7c12008-07-03 13:49:48 -0600488 if (index >= ctx->Const.VertexProgram.MaxAttribs) {
489 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(index)");
490 return;
491 }
492
Brian9f660252007-04-11 09:00:56 -0600493 if (shProg->LinkStatus) {
494 /* get current index/location for the attribute */
495 oldIndex = _mesa_get_attrib_location(ctx, program, name);
496 }
497 else {
498 oldIndex = -1;
499 }
Brian3209c3e2007-01-09 17:49:24 -0700500
501 /* this will replace the current value if it's already in the list */
Brianb7978af2007-01-09 19:17:17 -0700502 i = _mesa_add_attribute(shProg->Attributes, name, size, index);
Brian3209c3e2007-01-09 17:49:24 -0700503 if (i < 0) {
504 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
505 }
506
Brian9f660252007-04-11 09:00:56 -0600507 if (shProg->VertexProgram && oldIndex >= 0 && oldIndex != index) {
508 /* If the index changed, need to search/replace references to that attribute
509 * in the vertex program.
510 */
Brian3209c3e2007-01-09 17:49:24 -0700511 _slang_remap_attribute(&shProg->VertexProgram->Base, oldIndex, index);
512 }
Brian34ae99d2006-12-18 08:28:54 -0700513}
514
515
Brian Paulfd59f192008-05-18 16:04:55 -0600516static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700517_mesa_create_shader(GLcontext *ctx, GLenum type)
518{
Brian65a18442006-12-19 18:46:56 -0700519 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700520 GLuint name;
521
522 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
523
524 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700525 case GL_FRAGMENT_SHADER:
526 case GL_VERTEX_SHADER:
527 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700528 break;
529 default:
530 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
531 return 0;
532 }
533
Brian65a18442006-12-19 18:46:56 -0700534 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700535
536 return name;
537}
538
539
Brian Paulfd59f192008-05-18 16:04:55 -0600540static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700541_mesa_create_program(GLcontext *ctx)
542{
543 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700544 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700545
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800546 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
Brian65a18442006-12-19 18:46:56 -0700547 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700548
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800549 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700550
Brian3c008a02007-04-12 15:22:32 -0600551 assert(shProg->RefCount == 1);
552
Brian5b01c5e2006-12-19 18:02:03 -0700553 return name;
554}
555
556
Brian3c008a02007-04-12 15:22:32 -0600557/**
558 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
559 * DeleteProgramARB.
560 */
Brian Paulfd59f192008-05-18 16:04:55 -0600561static void
Brian5b01c5e2006-12-19 18:02:03 -0700562_mesa_delete_program2(GLcontext *ctx, GLuint name)
563{
Brian3c008a02007-04-12 15:22:32 -0600564 /*
565 * NOTE: deleting shaders/programs works a bit differently than
566 * texture objects (and buffer objects, etc). Shader/program
567 * handles/IDs exist in the hash table until the object is really
568 * deleted (refcount==0). With texture objects, the handle/ID is
569 * removed from the hash table in glDeleteTextures() while the tex
570 * object itself might linger until its refcount goes to zero.
571 */
Brian65a18442006-12-19 18:46:56 -0700572 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700573
Brian65a18442006-12-19 18:46:56 -0700574 shProg = _mesa_lookup_shader_program(ctx, name);
575 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700576 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteProgram(name)");
Brian5b01c5e2006-12-19 18:02:03 -0700577 return;
578 }
579
Brian9e4bae92006-12-20 09:27:42 -0700580 shProg->DeletePending = GL_TRUE;
581
Brian3c008a02007-04-12 15:22:32 -0600582 /* effectively, decr shProg's refcount */
583 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700584}
585
586
Brian Paulfd59f192008-05-18 16:04:55 -0600587static void
Brian5b01c5e2006-12-19 18:02:03 -0700588_mesa_delete_shader(GLcontext *ctx, GLuint shader)
589{
Brian9e4bae92006-12-20 09:27:42 -0700590 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
591 if (!sh) {
592 return;
593 }
Brian5b01c5e2006-12-19 18:02:03 -0700594
Brian9e4bae92006-12-20 09:27:42 -0700595 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600596
597 /* effectively, decr sh's refcount */
598 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700599}
600
601
Brian Paulfd59f192008-05-18 16:04:55 -0600602static void
Brian5b01c5e2006-12-19 18:02:03 -0700603_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
604{
Brian65a18442006-12-19 18:46:56 -0700605 struct gl_shader_program *shProg
606 = _mesa_lookup_shader_program(ctx, program);
Brian237b9852007-08-07 21:48:31 +0100607 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700608 GLuint i, j;
609
Brian65a18442006-12-19 18:46:56 -0700610 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700611 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700612 "glDetachShader(bad program or shader name)");
613 return;
614 }
615
Brian237b9852007-08-07 21:48:31 +0100616 n = shProg->NumShaders;
617
Brian5b01c5e2006-12-19 18:02:03 -0700618 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700619 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700620 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600621 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700622
Brian3c008a02007-04-12 15:22:32 -0600623 /* derefernce */
624 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700625
Brian5b01c5e2006-12-19 18:02:03 -0700626 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700627 newList = (struct gl_shader **)
628 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700629 if (!newList) {
630 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
631 return;
632 }
633 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700634 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700635 }
636 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700637 newList[j++] = shProg->Shaders[i];
638 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700639
Brian65a18442006-12-19 18:46:56 -0700640 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600641 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600642
643#ifdef DEBUG
644 /* sanity check */
645 {
646 for (j = 0; j < shProg->NumShaders; j++) {
647 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
648 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
649 assert(shProg->Shaders[j]->RefCount > 0);
650 }
651 }
652#endif
653
Brian5b01c5e2006-12-19 18:02:03 -0700654 return;
655 }
656 }
657
658 /* not found */
Brian43975832007-01-04 08:21:09 -0700659 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700660 "glDetachShader(shader not found)");
661}
662
663
Brian Paulfd59f192008-05-18 16:04:55 -0600664static void
Brian5b01c5e2006-12-19 18:02:03 -0700665_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
666 GLsizei maxLength, GLsizei *length, GLint *size,
667 GLenum *type, GLchar *nameOut)
668{
669 static const GLenum vec_types[] = {
670 GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4
671 };
Brian65a18442006-12-19 18:46:56 -0700672 struct gl_shader_program *shProg
673 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700674 GLint sz;
675
Brian65a18442006-12-19 18:46:56 -0700676 if (!shProg) {
Brianaaa57412007-04-18 15:22:43 -0600677 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib");
Brian5b01c5e2006-12-19 18:02:03 -0700678 return;
679 }
680
Brian65a18442006-12-19 18:46:56 -0700681 if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600682 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700683 return;
684 }
685
686 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700687 shProg->Attributes->Parameters[index].Name);
688 sz = shProg->Attributes->Parameters[index].Size;
Brian5b01c5e2006-12-19 18:02:03 -0700689 if (size)
Brian Paulade50832008-05-14 16:09:46 -0600690 *size = sz;
691 if (type)
692 *type = vec_types[sz]; /* XXX this is a temporary hack */
Brian5b01c5e2006-12-19 18:02:03 -0700693}
694
695
696/**
697 * Called via ctx->Driver.GetActiveUniform().
698 */
Brian Paulfd59f192008-05-18 16:04:55 -0600699static void
Brian5b01c5e2006-12-19 18:02:03 -0700700_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
701 GLsizei maxLength, GLsizei *length, GLint *size,
702 GLenum *type, GLchar *nameOut)
703{
Brian Paul896c0cc2008-05-16 15:47:55 -0600704 const struct gl_shader_program *shProg
Brian65a18442006-12-19 18:46:56 -0700705 = _mesa_lookup_shader_program(ctx, program);
Brian Paulade50832008-05-14 16:09:46 -0600706 const struct gl_program *prog;
707 GLint progPos;
Brian5b01c5e2006-12-19 18:02:03 -0700708
Brian65a18442006-12-19 18:46:56 -0700709 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700710 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform");
Brian5b01c5e2006-12-19 18:02:03 -0700711 return;
712 }
713
Brian Paulade50832008-05-14 16:09:46 -0600714 if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
Brian5b01c5e2006-12-19 18:02:03 -0700715 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
716 return;
717 }
718
Brian Paulade50832008-05-14 16:09:46 -0600719 progPos = shProg->Uniforms->Uniforms[index].VertPos;
720 if (progPos >= 0) {
721 prog = &shProg->VertexProgram->Base;
722 }
723 else {
724 progPos = shProg->Uniforms->Uniforms[index].FragPos;
725 if (progPos >= 0) {
726 prog = &shProg->FragmentProgram->Base;
Brian274ac7a2007-04-18 16:05:53 -0600727 }
728 }
729
Brian Paulade50832008-05-14 16:09:46 -0600730 if (!prog || progPos < 0)
731 return; /* should never happen */
732
733 if (nameOut)
734 copy_string(nameOut, maxLength, length,
735 prog->Parameters->Parameters[progPos].Name);
736 if (size)
737 *size = prog->Parameters->Parameters[progPos].Size;
738
739 if (type)
740 *type = prog->Parameters->Parameters[progPos].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700741}
742
743
744/**
745 * Called via ctx->Driver.GetAttachedShaders().
746 */
Brian Paulfd59f192008-05-18 16:04:55 -0600747static void
Brian5b01c5e2006-12-19 18:02:03 -0700748_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
749 GLsizei *count, GLuint *obj)
750{
Brian65a18442006-12-19 18:46:56 -0700751 struct gl_shader_program *shProg
752 = _mesa_lookup_shader_program(ctx, program);
753 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700754 GLint i;
Brian65a18442006-12-19 18:46:56 -0700755 for (i = 0; i < maxCount && i < shProg->NumShaders; i++) {
756 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700757 }
758 if (count)
759 *count = i;
760 }
761 else {
Brian43975832007-01-04 08:21:09 -0700762 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttachedShaders");
Brian5b01c5e2006-12-19 18:02:03 -0700763 }
764}
765
766
Brian Paulfd59f192008-05-18 16:04:55 -0600767static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700768_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700769{
770#if 0
771 GET_CURRENT_CONTEXT(ctx);
772
773 switch (pname) {
774 case GL_PROGRAM_OBJECT_ARB:
775 {
Brian5b01c5e2006-12-19 18:02:03 -0700776 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700777
778 if (pro != NULL)
779 return (**pro)._container._generic.
780 GetName((struct gl2_generic_intf **) (pro));
781 }
782 break;
783 default:
784 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
785 }
786#endif
787 return 0;
788}
789
790
Brian Paulfd59f192008-05-18 16:04:55 -0600791static void
Brian5b01c5e2006-12-19 18:02:03 -0700792_mesa_get_programiv(GLcontext *ctx, GLuint program,
793 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700794{
Brian65a18442006-12-19 18:46:56 -0700795 struct gl_shader_program *shProg
796 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700797
Brian65a18442006-12-19 18:46:56 -0700798 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700799 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700800 return;
801 }
802
Brian5b01c5e2006-12-19 18:02:03 -0700803 switch (pname) {
804 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700805 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700806 break;
807 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700808 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700809 break;
Brian5b01c5e2006-12-19 18:02:03 -0700810 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700811 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700812 break;
813 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600814 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700815 break;
816 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700817 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700818 break;
819 case GL_ACTIVE_ATTRIBUTES:
Brian3209c3e2007-01-09 17:49:24 -0700820 *params = shProg->Attributes ? shProg->Attributes->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700821 break;
822 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600823 *params = _mesa_longest_parameter_name(shProg->Attributes,
824 PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700825 break;
826 case GL_ACTIVE_UNIFORMS:
Brian Paulade50832008-05-14 16:09:46 -0600827 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700828 break;
829 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian Paulade50832008-05-14 16:09:46 -0600830 *params = _mesa_longest_uniform_name(shProg->Uniforms);
Brian274ac7a2007-04-18 16:05:53 -0600831 if (*params > 0)
832 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700833 break;
834 default:
Brian5b01c5e2006-12-19 18:02:03 -0700835 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
836 return;
Brian34ae99d2006-12-18 08:28:54 -0700837 }
Brian5b01c5e2006-12-19 18:02:03 -0700838}
Brian34ae99d2006-12-18 08:28:54 -0700839
Brian34ae99d2006-12-18 08:28:54 -0700840
Brian Paulfd59f192008-05-18 16:04:55 -0600841static void
Brian5b01c5e2006-12-19 18:02:03 -0700842_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
843{
Brian65a18442006-12-19 18:46:56 -0700844 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700845
846 if (!shader) {
847 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderiv(shader)");
848 return;
849 }
Brian65a18442006-12-19 18:46:56 -0700850
Brian5b01c5e2006-12-19 18:02:03 -0700851 switch (pname) {
852 case GL_SHADER_TYPE:
853 *params = shader->Type;
854 break;
855 case GL_DELETE_STATUS:
856 *params = shader->DeletePending;
857 break;
858 case GL_COMPILE_STATUS:
859 *params = shader->CompileStatus;
860 break;
861 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600862 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700863 break;
864 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600865 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700866 break;
867 default:
868 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
869 return;
870 }
871}
872
873
Brian Paulfd59f192008-05-18 16:04:55 -0600874static void
Brian5b01c5e2006-12-19 18:02:03 -0700875_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
876 GLsizei *length, GLchar *infoLog)
877{
Brian65a18442006-12-19 18:46:56 -0700878 struct gl_shader_program *shProg
879 = _mesa_lookup_shader_program(ctx, program);
880 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700881 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
882 return;
883 }
Brian65a18442006-12-19 18:46:56 -0700884 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700885}
886
887
Brian Paulfd59f192008-05-18 16:04:55 -0600888static void
Brian5b01c5e2006-12-19 18:02:03 -0700889_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
890 GLsizei *length, GLchar *infoLog)
891{
Brian65a18442006-12-19 18:46:56 -0700892 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
893 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700894 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
895 return;
896 }
Brian65a18442006-12-19 18:46:56 -0700897 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700898}
899
900
901/**
902 * Called via ctx->Driver.GetShaderSource().
903 */
Brian Paulfd59f192008-05-18 16:04:55 -0600904static void
Brian5b01c5e2006-12-19 18:02:03 -0700905_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
906 GLsizei *length, GLchar *sourceOut)
907{
Brian65a18442006-12-19 18:46:56 -0700908 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
909 if (!sh) {
Brian Paul36a58262008-07-02 16:40:24 -0600910 GLenum err;
911 if (_mesa_lookup_shader_program(ctx, shader))
912 err = GL_INVALID_OPERATION;
913 else
914 err = GL_INVALID_VALUE;
915 _mesa_error(ctx, err, "glGetShaderSource(shader)");
Brian5b01c5e2006-12-19 18:02:03 -0700916 return;
917 }
Brian65a18442006-12-19 18:46:56 -0700918 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -0700919}
920
921
922/**
923 * Called via ctx->Driver.GetUniformfv().
924 */
Brian Paulfd59f192008-05-18 16:04:55 -0600925static void
Brian5b01c5e2006-12-19 18:02:03 -0700926_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
927 GLfloat *params)
928{
Brian65a18442006-12-19 18:46:56 -0700929 struct gl_shader_program *shProg
930 = _mesa_lookup_shader_program(ctx, program);
931 if (shProg) {
Brian Paul6cb12702008-06-28 16:48:31 -0600932 if (shProg->Uniforms &&
933 location >= 0 && location < shProg->Uniforms->NumUniforms) {
934 GLint progPos;
935 GLuint i;
Brian Paulf2632212008-05-16 10:49:44 -0600936 const struct gl_program *prog = NULL;
Brian Paulade50832008-05-14 16:09:46 -0600937
938 progPos = shProg->Uniforms->Uniforms[location].VertPos;
939 if (progPos >= 0) {
940 prog = &shProg->VertexProgram->Base;
Brian5b01c5e2006-12-19 18:02:03 -0700941 }
Brian Paulade50832008-05-14 16:09:46 -0600942 else {
943 progPos = shProg->Uniforms->Uniforms[location].FragPos;
944 if (progPos >= 0) {
945 prog = &shProg->FragmentProgram->Base;
Bruce Merryeeb03fa2007-12-21 14:41:45 +0200946 }
Brian Paulade50832008-05-14 16:09:46 -0600947 }
948
Brian Paulf2632212008-05-16 10:49:44 -0600949 ASSERT(prog);
950 if (prog) {
951 for (i = 0; i < prog->Parameters->Parameters[progPos].Size; i++) {
952 params[i] = prog->Parameters->ParameterValues[progPos][i];
953 }
Brian Paulade50832008-05-14 16:09:46 -0600954 }
Brian5b01c5e2006-12-19 18:02:03 -0700955 }
956 else {
Brian Paul6cb12702008-06-28 16:48:31 -0600957 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
Brian5b01c5e2006-12-19 18:02:03 -0700958 }
959 }
960 else {
Brian Paul6cb12702008-06-28 16:48:31 -0600961 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700962 }
963}
964
965
966/**
967 * Called via ctx->Driver.GetUniformLocation().
968 */
Brian Paulfd59f192008-05-18 16:04:55 -0600969static GLint
Brian5b01c5e2006-12-19 18:02:03 -0700970_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
971{
Brian71623982007-01-30 16:55:03 -0700972 struct gl_shader_program *shProg
973 = _mesa_lookup_shader_program(ctx, program);
Brian Paulade50832008-05-14 16:09:46 -0600974 if (!shProg)
975 return -1;
Brian5b01c5e2006-12-19 18:02:03 -0700976
Brian Paulade50832008-05-14 16:09:46 -0600977 return _mesa_lookup_uniform(shProg->Uniforms, name);
Brian5b01c5e2006-12-19 18:02:03 -0700978}
979
980
Brian34ae99d2006-12-18 08:28:54 -0700981
Brian5b01c5e2006-12-19 18:02:03 -0700982/**
983 * Called via ctx->Driver.ShaderSource()
984 */
Brian Paulfd59f192008-05-18 16:04:55 -0600985static void
Brian5b01c5e2006-12-19 18:02:03 -0700986_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -0700987{
Brian65a18442006-12-19 18:46:56 -0700988 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
989 if (!sh) {
Brian Paul36a58262008-07-02 16:40:24 -0600990 GLenum err;
991 if (_mesa_lookup_shader_program(ctx, shader))
992 err = GL_INVALID_OPERATION;
993 else
994 err = GL_INVALID_VALUE;
995 _mesa_error(ctx, err, "glShaderSource(shaderObj)");
Brian34ae99d2006-12-18 08:28:54 -0700996 return;
997 }
998
Brian34ae99d2006-12-18 08:28:54 -0700999 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -07001000 if (sh->Source) {
1001 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -07001002 }
Brian65a18442006-12-19 18:46:56 -07001003 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -07001004 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -07001005}
1006
1007
Brian5b01c5e2006-12-19 18:02:03 -07001008/**
1009 * Called via ctx->Driver.CompileShader()
1010 */
Brian Paulfd59f192008-05-18 16:04:55 -06001011static void
Brian5b01c5e2006-12-19 18:02:03 -07001012_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -07001013{
Brian65a18442006-12-19 18:46:56 -07001014 struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj);
Brian34ae99d2006-12-18 08:28:54 -07001015
Brian65a18442006-12-19 18:46:56 -07001016 if (!sh) {
Brian34ae99d2006-12-18 08:28:54 -07001017 _mesa_error(ctx, GL_INVALID_VALUE, "glCompileShader(shaderObj)");
1018 return;
1019 }
1020
Brian43975832007-01-04 08:21:09 -07001021 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -07001022}
1023
1024
Brian5b01c5e2006-12-19 18:02:03 -07001025/**
1026 * Called via ctx->Driver.LinkProgram()
1027 */
Brian Paulfd59f192008-05-18 16:04:55 -06001028static void
Brian5b01c5e2006-12-19 18:02:03 -07001029_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001030{
Brian65a18442006-12-19 18:46:56 -07001031 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001032
Brian65a18442006-12-19 18:46:56 -07001033 shProg = _mesa_lookup_shader_program(ctx, program);
1034 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001035 _mesa_error(ctx, GL_INVALID_VALUE, "glLinkProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001036 return;
1037 }
1038
Briandf43fb62008-05-06 23:08:51 -06001039 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1040
Brianc1771912007-02-16 09:56:19 -07001041 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001042}
1043
1044
1045/**
Brian5b01c5e2006-12-19 18:02:03 -07001046 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001047 */
Brian5b01c5e2006-12-19 18:02:03 -07001048void
1049_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001050{
Brian3c008a02007-04-12 15:22:32 -06001051 struct gl_shader_program *shProg;
1052
Brian00d63aa2007-02-03 11:35:02 -07001053 if (ctx->Shader.CurrentProgram &&
1054 ctx->Shader.CurrentProgram->Name == program) {
1055 /* no-op */
1056 return;
1057 }
1058
1059 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1060
Brian5b01c5e2006-12-19 18:02:03 -07001061 if (program) {
Brian65a18442006-12-19 18:46:56 -07001062 shProg = _mesa_lookup_shader_program(ctx, program);
1063 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001064 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -07001065 "glUseProgramObjectARB(programObj)");
1066 return;
1067 }
Brian5b01c5e2006-12-19 18:02:03 -07001068 }
1069 else {
Brian3c008a02007-04-12 15:22:32 -06001070 shProg = NULL;
1071 }
1072
1073 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001074}
Brian34ae99d2006-12-18 08:28:54 -07001075
Brian5b01c5e2006-12-19 18:02:03 -07001076
Brian Paulade50832008-05-14 16:09:46 -06001077
1078/**
1079 * Update the vertex and fragment program's TexturesUsed arrays.
1080 */
1081static void
1082update_textures_used(struct gl_program *prog)
1083{
1084 GLuint s;
1085
1086 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1087
1088 for (s = 0; s < MAX_SAMPLERS; s++) {
1089 if (prog->SamplersUsed & (1 << s)) {
1090 GLuint u = prog->SamplerUnits[s];
1091 GLuint t = prog->SamplerTargets[s];
1092 assert(u < MAX_TEXTURE_IMAGE_UNITS);
1093 prog->TexturesUsed[u] |= (1 << t);
1094 }
1095 }
1096}
1097
1098
1099/**
1100 * Set the value of a program's uniform variable.
1101 * \param program the program whose uniform to update
1102 * \param location the location/index of the uniform
1103 * \param type the datatype of the uniform
1104 * \param count the number of uniforms to set
1105 * \param elems number of elements per uniform
1106 * \param values the new values
1107 */
1108static void
1109set_program_uniform(GLcontext *ctx, struct gl_program *program, GLint location,
1110 GLenum type, GLint count, GLint elems, const void *values)
1111{
1112 if (program->Parameters->Parameters[location].Type == PROGRAM_SAMPLER) {
1113 /* This controls which texture unit which is used by a sampler */
1114 GLuint texUnit, sampler;
1115
1116 /* data type for setting samplers must be int */
1117 if (type != GL_INT || count != 1) {
1118 _mesa_error(ctx, GL_INVALID_OPERATION,
1119 "glUniform(only glUniform1i can be used "
1120 "to set sampler uniforms)");
1121 return;
1122 }
1123
1124 sampler = (GLuint) program->Parameters->ParameterValues[location][0];
1125 texUnit = ((GLuint *) values)[0];
1126
1127 /* check that the sampler (tex unit index) is legal */
1128 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1129 _mesa_error(ctx, GL_INVALID_VALUE,
1130 "glUniform1(invalid sampler/tex unit index)");
1131 return;
1132 }
1133
1134 /* This maps a sampler to a texture unit: */
1135 program->SamplerUnits[sampler] = texUnit;
1136 update_textures_used(program);
1137
1138 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1139 }
1140 else {
1141 /* ordinary uniform variable */
1142 GLint k, i;
1143
1144 if (count * elems > program->Parameters->Parameters[location].Size) {
1145 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1146 return;
1147 }
1148
1149 for (k = 0; k < count; k++) {
1150 GLfloat *uniformVal = program->Parameters->ParameterValues[location + k];
1151 if (type == GL_INT ||
1152 type == GL_INT_VEC2 ||
1153 type == GL_INT_VEC3 ||
1154 type == GL_INT_VEC4) {
1155 const GLint *iValues = ((const GLint *) values) + k * elems;
1156 for (i = 0; i < elems; i++) {
1157 uniformVal[i] = (GLfloat) iValues[i];
1158 }
1159 }
1160 else {
1161 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1162 for (i = 0; i < elems; i++) {
1163 uniformVal[i] = fValues[i];
1164 }
1165 }
1166 }
1167 }
1168}
1169
1170
Brian5b01c5e2006-12-19 18:02:03 -07001171/**
1172 * Called via ctx->Driver.Uniform().
1173 */
Brian Paulfd59f192008-05-18 16:04:55 -06001174static void
Brian5b01c5e2006-12-19 18:02:03 -07001175_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1176 const GLvoid *values, GLenum type)
1177{
Brian3a8e2772006-12-20 17:19:16 -07001178 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paulade50832008-05-14 16:09:46 -06001179 GLint elems;
Brian3a8e2772006-12-20 17:19:16 -07001180
1181 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001182 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001183 return;
1184 }
1185
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001186 if (location == -1)
1187 return; /* The standard specifies this as a no-op */
1188
Brian Paulade50832008-05-14 16:09:46 -06001189 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
1190 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
Brian3a8e2772006-12-20 17:19:16 -07001191 return;
1192 }
1193
Brian52363952007-03-13 16:50:24 -06001194 if (count < 0) {
1195 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1196 return;
1197 }
1198
Brian98650bd2007-03-13 16:32:48 -06001199 switch (type) {
1200 case GL_FLOAT:
1201 case GL_INT:
1202 elems = 1;
1203 break;
1204 case GL_FLOAT_VEC2:
1205 case GL_INT_VEC2:
1206 elems = 2;
1207 break;
1208 case GL_FLOAT_VEC3:
1209 case GL_INT_VEC3:
1210 elems = 3;
1211 break;
1212 case GL_FLOAT_VEC4:
1213 case GL_INT_VEC4:
1214 elems = 4;
1215 break;
1216 default:
1217 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1218 return;
Brian89dc4852007-01-04 14:35:44 -07001219 }
Brian98650bd2007-03-13 16:32:48 -06001220
Brian Paulade50832008-05-14 16:09:46 -06001221 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
Brian98650bd2007-03-13 16:32:48 -06001222
Brian Paulade50832008-05-14 16:09:46 -06001223 /* A uniform var may be used by both a vertex shader and a fragment
1224 * shader. We may need to update one or both shader's uniform here:
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001225 */
Brian Paulade50832008-05-14 16:09:46 -06001226 if (shProg->VertexProgram) {
1227 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1228 if (loc >= 0) {
1229 set_program_uniform(ctx, &shProg->VertexProgram->Base,
1230 loc, type, count, elems, values);
Bruce Merry2bf2a8c2007-12-21 23:18:40 +02001231 }
Brian5b01c5e2006-12-19 18:02:03 -07001232 }
Brian5cf73262007-01-05 16:02:45 -07001233
Brian Paulade50832008-05-14 16:09:46 -06001234 if (shProg->FragmentProgram) {
1235 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1236 if (loc >= 0) {
1237 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
1238 loc, type, count, elems, values);
1239 }
1240 }
1241}
1242
1243
1244static void
1245set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
1246 GLuint location, GLuint rows, GLuint cols,
1247 GLboolean transpose, const GLfloat *values)
1248{
1249 /*
1250 * Note: the _columns_ of a matrix are stored in program registers, not
1251 * the rows.
1252 */
1253 /* XXXX need to test 3x3 and 2x2 matrices... */
1254 if (transpose) {
1255 GLuint row, col;
1256 for (col = 0; col < cols; col++) {
1257 GLfloat *v = program->Parameters->ParameterValues[location + col];
1258 for (row = 0; row < rows; row++) {
1259 v[row] = values[row * cols + col];
1260 }
1261 }
1262 }
1263 else {
1264 GLuint row, col;
1265 for (col = 0; col < cols; col++) {
1266 GLfloat *v = program->Parameters->ParameterValues[location + col];
1267 for (row = 0; row < rows; row++) {
1268 v[row] = values[col * rows + row];
1269 }
1270 }
Brian5cf73262007-01-05 16:02:45 -07001271 }
Brian34ae99d2006-12-18 08:28:54 -07001272}
1273
1274
1275/**
Brian5b01c5e2006-12-19 18:02:03 -07001276 * Called by ctx->Driver.UniformMatrix().
Brian34ae99d2006-12-18 08:28:54 -07001277 */
Brian Paulfd59f192008-05-18 16:04:55 -06001278static void
Brian5b01c5e2006-12-19 18:02:03 -07001279_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1280 GLenum matrixType, GLint location, GLsizei count,
1281 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001282{
Brian3a8e2772006-12-20 17:19:16 -07001283 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paulade50832008-05-14 16:09:46 -06001284
Brian3a8e2772006-12-20 17:19:16 -07001285 if (!shProg || !shProg->LinkStatus) {
1286 _mesa_error(ctx, GL_INVALID_OPERATION,
1287 "glUniformMatrix(program not linked)");
1288 return;
1289 }
Brian Paulade50832008-05-14 16:09:46 -06001290
Bruce Merry89b80322007-12-21 15:20:17 +02001291 if (location == -1)
1292 return; /* The standard specifies this as a no-op */
Brian Paulade50832008-05-14 16:09:46 -06001293
1294 if (location < 0 || location >= shProg->Uniforms->NumUniforms) {
1295 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
Brian3a8e2772006-12-20 17:19:16 -07001296 return;
1297 }
Brian34ae99d2006-12-18 08:28:54 -07001298 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001299 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001300 return;
1301 }
1302
1303 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1304
Brian Paulade50832008-05-14 16:09:46 -06001305 if (shProg->VertexProgram) {
1306 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1307 if (loc >= 0) {
1308 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
1309 loc, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07001310 }
Brian Paulade50832008-05-14 16:09:46 -06001311 }
1312
1313 if (shProg->FragmentProgram) {
1314 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1315 if (loc >= 0) {
1316 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
1317 loc, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07001318 }
Brian34ae99d2006-12-18 08:28:54 -07001319 }
1320}
1321
1322
Brian Paulfd59f192008-05-18 16:04:55 -06001323static void
Brian5b01c5e2006-12-19 18:02:03 -07001324_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001325{
Brian65a18442006-12-19 18:46:56 -07001326 struct gl_shader_program *shProg;
1327 shProg = _mesa_lookup_shader_program(ctx, program);
1328 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001329 _mesa_error(ctx, GL_INVALID_VALUE, "glValidateProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001330 return;
1331 }
Brian5b01c5e2006-12-19 18:02:03 -07001332 /* XXX temporary */
Brian65a18442006-12-19 18:46:56 -07001333 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001334
Brian5b01c5e2006-12-19 18:02:03 -07001335 /* From the GL spec:
1336 any two active samplers in the current program object are of
1337 different types, but refer to the same texture image unit,
1338
1339 any active sampler in the current program object refers to a texture
1340 image unit where fixed-function fragment processing accesses a
1341 texture target that does not match the sampler type, or
1342
1343 the sum of the number of active samplers in the program and the
1344 number of texture image units enabled for fixed-function fragment
1345 processing exceeds the combined limit on the total number of texture
1346 image units allowed.
1347 */
Brian34ae99d2006-12-18 08:28:54 -07001348}
Brian Paulfd59f192008-05-18 16:04:55 -06001349
1350
1351/**
1352 * Plug in Mesa's GLSL functions into the device driver function table.
1353 */
1354void
1355_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
1356{
1357 driver->AttachShader = _mesa_attach_shader;
1358 driver->BindAttribLocation = _mesa_bind_attrib_location;
1359 driver->CompileShader = _mesa_compile_shader;
1360 driver->CreateProgram = _mesa_create_program;
1361 driver->CreateShader = _mesa_create_shader;
1362 driver->DeleteProgram2 = _mesa_delete_program2;
1363 driver->DeleteShader = _mesa_delete_shader;
1364 driver->DetachShader = _mesa_detach_shader;
1365 driver->GetActiveAttrib = _mesa_get_active_attrib;
1366 driver->GetActiveUniform = _mesa_get_active_uniform;
1367 driver->GetAttachedShaders = _mesa_get_attached_shaders;
1368 driver->GetAttribLocation = _mesa_get_attrib_location;
1369 driver->GetHandle = _mesa_get_handle;
1370 driver->GetProgramiv = _mesa_get_programiv;
1371 driver->GetProgramInfoLog = _mesa_get_program_info_log;
1372 driver->GetShaderiv = _mesa_get_shaderiv;
1373 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
1374 driver->GetShaderSource = _mesa_get_shader_source;
1375 driver->GetUniformfv = _mesa_get_uniformfv;
1376 driver->GetUniformLocation = _mesa_get_uniform_location;
1377 driver->IsProgram = _mesa_is_program;
1378 driver->IsShader = _mesa_is_shader;
1379 driver->LinkProgram = _mesa_link_program;
1380 driver->ShaderSource = _mesa_shader_source;
1381 driver->Uniform = _mesa_uniform;
1382 driver->UniformMatrix = _mesa_uniform_matrix;
1383 driver->UseProgram = _mesa_use_program;
1384 driver->ValidateProgram = _mesa_validate_program;
1385}