blob: c77d0c439731eca6accdfb1676ee427522d6b126 [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
Brian5b01c5e2006-12-19 18:02:03 -0700363/**
364 * Called via ctx->Driver.AttachShader()
365 */
Brian Paulfd59f192008-05-18 16:04:55 -0600366static void
Brian5b01c5e2006-12-19 18:02:03 -0700367_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
368{
Brian65a18442006-12-19 18:46:56 -0700369 struct gl_shader_program *shProg
370 = _mesa_lookup_shader_program(ctx, program);
371 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
Brian237b9852007-08-07 21:48:31 +0100372 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700373 GLuint i;
374
Brian65a18442006-12-19 18:46:56 -0700375 if (!shProg || !sh) {
Brian43975832007-01-04 08:21:09 -0700376 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700377 "glAttachShader(bad program or shader name)");
378 return;
379 }
380
Brian237b9852007-08-07 21:48:31 +0100381 n = shProg->NumShaders;
382
Brian5b01c5e2006-12-19 18:02:03 -0700383 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700384 if (shProg->Shaders[i] == sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700385 /* already attached */
386 return;
Brian34ae99d2006-12-18 08:28:54 -0700387 }
388 }
Brian5b01c5e2006-12-19 18:02:03 -0700389
390 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700391 shProg->Shaders = (struct gl_shader **)
392 _mesa_realloc(shProg->Shaders,
393 n * sizeof(struct gl_shader *),
394 (n + 1) * sizeof(struct gl_shader *));
395 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700396 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
397 return;
398 }
399
400 /* append */
Brian3c008a02007-04-12 15:22:32 -0600401 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
402 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700403 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700404}
405
406
Brian Paulfd59f192008-05-18 16:04:55 -0600407static GLint
Brian Paul896c0cc2008-05-16 15:47:55 -0600408_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
409 const GLchar *name)
410{
411 struct gl_shader_program *shProg
412 = _mesa_lookup_shader_program(ctx, program);
413
414 if (!shProg) {
415 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttribLocation");
416 return -1;
417 }
418
419 if (!shProg->LinkStatus) {
420 _mesa_error(ctx, GL_INVALID_OPERATION,
421 "glGetAttribLocation(program not linked)");
422 return -1;
423 }
424
425 if (!name)
426 return -1;
427
428 if (shProg->Attributes) {
429 GLint i = _mesa_lookup_parameter_index(shProg->Attributes, -1, name);
430 if (i >= 0) {
431 return shProg->Attributes->Parameters[i].StateIndexes[0];
432 }
433 }
434 return -1;
435}
436
437
Brian Paulfd59f192008-05-18 16:04:55 -0600438static void
Brian5b01c5e2006-12-19 18:02:03 -0700439_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
440 const GLchar *name)
441{
Brian65a18442006-12-19 18:46:56 -0700442 struct gl_shader_program *shProg
443 = _mesa_lookup_shader_program(ctx, program);
Brianb7978af2007-01-09 19:17:17 -0700444 const GLint size = -1; /* unknown size */
445 GLint i, oldIndex;
Brian5b01c5e2006-12-19 18:02:03 -0700446
Brian65a18442006-12-19 18:46:56 -0700447 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700448 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700449 return;
450 }
451
Brian9e4bae92006-12-20 09:27:42 -0700452 if (!name)
453 return;
454
455 if (strncmp(name, "gl_", 3) == 0) {
456 _mesa_error(ctx, GL_INVALID_OPERATION,
457 "glBindAttribLocation(illegal name)");
458 return;
459 }
460
Brian9f660252007-04-11 09:00:56 -0600461 if (shProg->LinkStatus) {
462 /* get current index/location for the attribute */
463 oldIndex = _mesa_get_attrib_location(ctx, program, name);
464 }
465 else {
466 oldIndex = -1;
467 }
Brian3209c3e2007-01-09 17:49:24 -0700468
469 /* this will replace the current value if it's already in the list */
Brianb7978af2007-01-09 19:17:17 -0700470 i = _mesa_add_attribute(shProg->Attributes, name, size, index);
Brian3209c3e2007-01-09 17:49:24 -0700471 if (i < 0) {
472 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
473 }
474
Brian9f660252007-04-11 09:00:56 -0600475 if (shProg->VertexProgram && oldIndex >= 0 && oldIndex != index) {
476 /* If the index changed, need to search/replace references to that attribute
477 * in the vertex program.
478 */
Brian3209c3e2007-01-09 17:49:24 -0700479 _slang_remap_attribute(&shProg->VertexProgram->Base, oldIndex, index);
480 }
Brian34ae99d2006-12-18 08:28:54 -0700481}
482
483
Brian Paulfd59f192008-05-18 16:04:55 -0600484static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700485_mesa_create_shader(GLcontext *ctx, GLenum type)
486{
Brian65a18442006-12-19 18:46:56 -0700487 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700488 GLuint name;
489
490 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
491
492 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700493 case GL_FRAGMENT_SHADER:
494 case GL_VERTEX_SHADER:
495 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700496 break;
497 default:
498 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
499 return 0;
500 }
501
Brian65a18442006-12-19 18:46:56 -0700502 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700503
504 return name;
505}
506
507
Brian Paulfd59f192008-05-18 16:04:55 -0600508static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700509_mesa_create_program(GLcontext *ctx)
510{
511 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700512 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700513
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800514 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
Brian65a18442006-12-19 18:46:56 -0700515 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700516
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800517 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700518
Brian3c008a02007-04-12 15:22:32 -0600519 assert(shProg->RefCount == 1);
520
Brian5b01c5e2006-12-19 18:02:03 -0700521 return name;
522}
523
524
Brian3c008a02007-04-12 15:22:32 -0600525/**
526 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
527 * DeleteProgramARB.
528 */
Brian Paulfd59f192008-05-18 16:04:55 -0600529static void
Brian5b01c5e2006-12-19 18:02:03 -0700530_mesa_delete_program2(GLcontext *ctx, GLuint name)
531{
Brian3c008a02007-04-12 15:22:32 -0600532 /*
533 * NOTE: deleting shaders/programs works a bit differently than
534 * texture objects (and buffer objects, etc). Shader/program
535 * handles/IDs exist in the hash table until the object is really
536 * deleted (refcount==0). With texture objects, the handle/ID is
537 * removed from the hash table in glDeleteTextures() while the tex
538 * object itself might linger until its refcount goes to zero.
539 */
Brian65a18442006-12-19 18:46:56 -0700540 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700541
Brian65a18442006-12-19 18:46:56 -0700542 shProg = _mesa_lookup_shader_program(ctx, name);
543 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700544 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteProgram(name)");
Brian5b01c5e2006-12-19 18:02:03 -0700545 return;
546 }
547
Brian9e4bae92006-12-20 09:27:42 -0700548 shProg->DeletePending = GL_TRUE;
549
Brian3c008a02007-04-12 15:22:32 -0600550 /* effectively, decr shProg's refcount */
551 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700552}
553
554
Brian Paulfd59f192008-05-18 16:04:55 -0600555static void
Brian5b01c5e2006-12-19 18:02:03 -0700556_mesa_delete_shader(GLcontext *ctx, GLuint shader)
557{
Brian9e4bae92006-12-20 09:27:42 -0700558 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
559 if (!sh) {
560 return;
561 }
Brian5b01c5e2006-12-19 18:02:03 -0700562
Brian9e4bae92006-12-20 09:27:42 -0700563 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600564
565 /* effectively, decr sh's refcount */
566 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700567}
568
569
Brian Paulfd59f192008-05-18 16:04:55 -0600570static void
Brian5b01c5e2006-12-19 18:02:03 -0700571_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
572{
Brian65a18442006-12-19 18:46:56 -0700573 struct gl_shader_program *shProg
574 = _mesa_lookup_shader_program(ctx, program);
Brian237b9852007-08-07 21:48:31 +0100575 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700576 GLuint i, j;
577
Brian65a18442006-12-19 18:46:56 -0700578 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700579 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700580 "glDetachShader(bad program or shader name)");
581 return;
582 }
583
Brian237b9852007-08-07 21:48:31 +0100584 n = shProg->NumShaders;
585
Brian5b01c5e2006-12-19 18:02:03 -0700586 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700587 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700588 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600589 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700590
Brian3c008a02007-04-12 15:22:32 -0600591 /* derefernce */
592 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700593
Brian5b01c5e2006-12-19 18:02:03 -0700594 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700595 newList = (struct gl_shader **)
596 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700597 if (!newList) {
598 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
599 return;
600 }
601 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700602 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700603 }
604 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700605 newList[j++] = shProg->Shaders[i];
606 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700607
Brian65a18442006-12-19 18:46:56 -0700608 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600609 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600610
611#ifdef DEBUG
612 /* sanity check */
613 {
614 for (j = 0; j < shProg->NumShaders; j++) {
615 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
616 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
617 assert(shProg->Shaders[j]->RefCount > 0);
618 }
619 }
620#endif
621
Brian5b01c5e2006-12-19 18:02:03 -0700622 return;
623 }
624 }
625
626 /* not found */
Brian43975832007-01-04 08:21:09 -0700627 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700628 "glDetachShader(shader not found)");
629}
630
631
Brian Paulfd59f192008-05-18 16:04:55 -0600632static void
Brian5b01c5e2006-12-19 18:02:03 -0700633_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
634 GLsizei maxLength, GLsizei *length, GLint *size,
635 GLenum *type, GLchar *nameOut)
636{
637 static const GLenum vec_types[] = {
638 GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4
639 };
Brian65a18442006-12-19 18:46:56 -0700640 struct gl_shader_program *shProg
641 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700642 GLint sz;
643
Brian65a18442006-12-19 18:46:56 -0700644 if (!shProg) {
Brianaaa57412007-04-18 15:22:43 -0600645 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib");
Brian5b01c5e2006-12-19 18:02:03 -0700646 return;
647 }
648
Brian65a18442006-12-19 18:46:56 -0700649 if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600650 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700651 return;
652 }
653
654 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700655 shProg->Attributes->Parameters[index].Name);
656 sz = shProg->Attributes->Parameters[index].Size;
Brian5b01c5e2006-12-19 18:02:03 -0700657 if (size)
Brian Paulade50832008-05-14 16:09:46 -0600658 *size = sz;
659 if (type)
660 *type = vec_types[sz]; /* XXX this is a temporary hack */
Brian5b01c5e2006-12-19 18:02:03 -0700661}
662
663
664/**
665 * Called via ctx->Driver.GetActiveUniform().
666 */
Brian Paulfd59f192008-05-18 16:04:55 -0600667static void
Brian5b01c5e2006-12-19 18:02:03 -0700668_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
669 GLsizei maxLength, GLsizei *length, GLint *size,
670 GLenum *type, GLchar *nameOut)
671{
Brian Paul896c0cc2008-05-16 15:47:55 -0600672 const struct gl_shader_program *shProg
Brian65a18442006-12-19 18:46:56 -0700673 = _mesa_lookup_shader_program(ctx, program);
Brian Paulade50832008-05-14 16:09:46 -0600674 const struct gl_program *prog;
675 GLint progPos;
Brian5b01c5e2006-12-19 18:02:03 -0700676
Brian65a18442006-12-19 18:46:56 -0700677 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700678 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform");
Brian5b01c5e2006-12-19 18:02:03 -0700679 return;
680 }
681
Brian Paulade50832008-05-14 16:09:46 -0600682 if (!shProg->Uniforms || index >= shProg->Uniforms->NumUniforms) {
Brian5b01c5e2006-12-19 18:02:03 -0700683 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
684 return;
685 }
686
Brian Paulade50832008-05-14 16:09:46 -0600687 progPos = shProg->Uniforms->Uniforms[index].VertPos;
688 if (progPos >= 0) {
689 prog = &shProg->VertexProgram->Base;
690 }
691 else {
692 progPos = shProg->Uniforms->Uniforms[index].FragPos;
693 if (progPos >= 0) {
694 prog = &shProg->FragmentProgram->Base;
Brian274ac7a2007-04-18 16:05:53 -0600695 }
696 }
697
Brian Paulade50832008-05-14 16:09:46 -0600698 if (!prog || progPos < 0)
699 return; /* should never happen */
700
701 if (nameOut)
702 copy_string(nameOut, maxLength, length,
703 prog->Parameters->Parameters[progPos].Name);
704 if (size)
705 *size = prog->Parameters->Parameters[progPos].Size;
706
707 if (type)
708 *type = prog->Parameters->Parameters[progPos].DataType;
Brian5b01c5e2006-12-19 18:02:03 -0700709}
710
711
712/**
713 * Called via ctx->Driver.GetAttachedShaders().
714 */
Brian Paulfd59f192008-05-18 16:04:55 -0600715static void
Brian5b01c5e2006-12-19 18:02:03 -0700716_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
717 GLsizei *count, GLuint *obj)
718{
Brian65a18442006-12-19 18:46:56 -0700719 struct gl_shader_program *shProg
720 = _mesa_lookup_shader_program(ctx, program);
721 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700722 GLint i;
Brian65a18442006-12-19 18:46:56 -0700723 for (i = 0; i < maxCount && i < shProg->NumShaders; i++) {
724 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700725 }
726 if (count)
727 *count = i;
728 }
729 else {
Brian43975832007-01-04 08:21:09 -0700730 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttachedShaders");
Brian5b01c5e2006-12-19 18:02:03 -0700731 }
732}
733
734
Brian Paulfd59f192008-05-18 16:04:55 -0600735static GLuint
Brian5b01c5e2006-12-19 18:02:03 -0700736_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700737{
738#if 0
739 GET_CURRENT_CONTEXT(ctx);
740
741 switch (pname) {
742 case GL_PROGRAM_OBJECT_ARB:
743 {
Brian5b01c5e2006-12-19 18:02:03 -0700744 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700745
746 if (pro != NULL)
747 return (**pro)._container._generic.
748 GetName((struct gl2_generic_intf **) (pro));
749 }
750 break;
751 default:
752 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
753 }
754#endif
755 return 0;
756}
757
758
Brian Paulfd59f192008-05-18 16:04:55 -0600759static void
Brian5b01c5e2006-12-19 18:02:03 -0700760_mesa_get_programiv(GLcontext *ctx, GLuint program,
761 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700762{
Brian65a18442006-12-19 18:46:56 -0700763 struct gl_shader_program *shProg
764 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700765
Brian65a18442006-12-19 18:46:56 -0700766 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700767 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700768 return;
769 }
770
Brian5b01c5e2006-12-19 18:02:03 -0700771 switch (pname) {
772 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700773 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700774 break;
775 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700776 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700777 break;
Brian5b01c5e2006-12-19 18:02:03 -0700778 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700779 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700780 break;
781 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600782 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700783 break;
784 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700785 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700786 break;
787 case GL_ACTIVE_ATTRIBUTES:
Brian3209c3e2007-01-09 17:49:24 -0700788 *params = shProg->Attributes ? shProg->Attributes->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700789 break;
790 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600791 *params = _mesa_longest_parameter_name(shProg->Attributes,
792 PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700793 break;
794 case GL_ACTIVE_UNIFORMS:
Brian Paulade50832008-05-14 16:09:46 -0600795 *params = shProg->Uniforms ? shProg->Uniforms->NumUniforms : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700796 break;
797 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian Paulade50832008-05-14 16:09:46 -0600798 *params = _mesa_longest_uniform_name(shProg->Uniforms);
Brian274ac7a2007-04-18 16:05:53 -0600799 if (*params > 0)
800 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700801 break;
802 default:
Brian5b01c5e2006-12-19 18:02:03 -0700803 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
804 return;
Brian34ae99d2006-12-18 08:28:54 -0700805 }
Brian5b01c5e2006-12-19 18:02:03 -0700806}
Brian34ae99d2006-12-18 08:28:54 -0700807
Brian34ae99d2006-12-18 08:28:54 -0700808
Brian Paulfd59f192008-05-18 16:04:55 -0600809static void
Brian5b01c5e2006-12-19 18:02:03 -0700810_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
811{
Brian65a18442006-12-19 18:46:56 -0700812 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700813
814 if (!shader) {
815 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderiv(shader)");
816 return;
817 }
Brian65a18442006-12-19 18:46:56 -0700818
Brian5b01c5e2006-12-19 18:02:03 -0700819 switch (pname) {
820 case GL_SHADER_TYPE:
821 *params = shader->Type;
822 break;
823 case GL_DELETE_STATUS:
824 *params = shader->DeletePending;
825 break;
826 case GL_COMPILE_STATUS:
827 *params = shader->CompileStatus;
828 break;
829 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600830 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700831 break;
832 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600833 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700834 break;
835 default:
836 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
837 return;
838 }
839}
840
841
Brian Paulfd59f192008-05-18 16:04:55 -0600842static void
Brian5b01c5e2006-12-19 18:02:03 -0700843_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
844 GLsizei *length, GLchar *infoLog)
845{
Brian65a18442006-12-19 18:46:56 -0700846 struct gl_shader_program *shProg
847 = _mesa_lookup_shader_program(ctx, program);
848 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700849 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
850 return;
851 }
Brian65a18442006-12-19 18:46:56 -0700852 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700853}
854
855
Brian Paulfd59f192008-05-18 16:04:55 -0600856static void
Brian5b01c5e2006-12-19 18:02:03 -0700857_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
858 GLsizei *length, GLchar *infoLog)
859{
Brian65a18442006-12-19 18:46:56 -0700860 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
861 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700862 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
863 return;
864 }
Brian65a18442006-12-19 18:46:56 -0700865 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700866}
867
868
869/**
870 * Called via ctx->Driver.GetShaderSource().
871 */
Brian Paulfd59f192008-05-18 16:04:55 -0600872static void
Brian5b01c5e2006-12-19 18:02:03 -0700873_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
874 GLsizei *length, GLchar *sourceOut)
875{
Brian65a18442006-12-19 18:46:56 -0700876 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
877 if (!sh) {
Brian Paul36a58262008-07-02 16:40:24 -0600878 GLenum err;
879 if (_mesa_lookup_shader_program(ctx, shader))
880 err = GL_INVALID_OPERATION;
881 else
882 err = GL_INVALID_VALUE;
883 _mesa_error(ctx, err, "glGetShaderSource(shader)");
Brian5b01c5e2006-12-19 18:02:03 -0700884 return;
885 }
Brian65a18442006-12-19 18:46:56 -0700886 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -0700887}
888
889
890/**
891 * Called via ctx->Driver.GetUniformfv().
892 */
Brian Paulfd59f192008-05-18 16:04:55 -0600893static void
Brian5b01c5e2006-12-19 18:02:03 -0700894_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
895 GLfloat *params)
896{
Brian65a18442006-12-19 18:46:56 -0700897 struct gl_shader_program *shProg
898 = _mesa_lookup_shader_program(ctx, program);
899 if (shProg) {
Brian Paul6cb12702008-06-28 16:48:31 -0600900 if (shProg->Uniforms &&
901 location >= 0 && location < shProg->Uniforms->NumUniforms) {
902 GLint progPos;
903 GLuint i;
Brian Paulf2632212008-05-16 10:49:44 -0600904 const struct gl_program *prog = NULL;
Brian Paulade50832008-05-14 16:09:46 -0600905
906 progPos = shProg->Uniforms->Uniforms[location].VertPos;
907 if (progPos >= 0) {
908 prog = &shProg->VertexProgram->Base;
Brian5b01c5e2006-12-19 18:02:03 -0700909 }
Brian Paulade50832008-05-14 16:09:46 -0600910 else {
911 progPos = shProg->Uniforms->Uniforms[location].FragPos;
912 if (progPos >= 0) {
913 prog = &shProg->FragmentProgram->Base;
Bruce Merryeeb03fa2007-12-21 14:41:45 +0200914 }
Brian Paulade50832008-05-14 16:09:46 -0600915 }
916
Brian Paulf2632212008-05-16 10:49:44 -0600917 ASSERT(prog);
918 if (prog) {
919 for (i = 0; i < prog->Parameters->Parameters[progPos].Size; i++) {
920 params[i] = prog->Parameters->ParameterValues[progPos][i];
921 }
Brian Paulade50832008-05-14 16:09:46 -0600922 }
Brian5b01c5e2006-12-19 18:02:03 -0700923 }
924 else {
Brian Paul6cb12702008-06-28 16:48:31 -0600925 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(location)");
Brian5b01c5e2006-12-19 18:02:03 -0700926 }
927 }
928 else {
Brian Paul6cb12702008-06-28 16:48:31 -0600929 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetUniformfv(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700930 }
931}
932
933
934/**
935 * Called via ctx->Driver.GetUniformLocation().
936 */
Brian Paulfd59f192008-05-18 16:04:55 -0600937static GLint
Brian5b01c5e2006-12-19 18:02:03 -0700938_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
939{
Brian71623982007-01-30 16:55:03 -0700940 struct gl_shader_program *shProg
941 = _mesa_lookup_shader_program(ctx, program);
Brian Paulade50832008-05-14 16:09:46 -0600942 if (!shProg)
943 return -1;
Brian5b01c5e2006-12-19 18:02:03 -0700944
Brian Paulade50832008-05-14 16:09:46 -0600945 return _mesa_lookup_uniform(shProg->Uniforms, name);
Brian5b01c5e2006-12-19 18:02:03 -0700946}
947
948
Brian Paulfd59f192008-05-18 16:04:55 -0600949static GLboolean
Brian5b01c5e2006-12-19 18:02:03 -0700950_mesa_is_program(GLcontext *ctx, GLuint name)
951{
Brian65a18442006-12-19 18:46:56 -0700952 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
953 return shProg ? GL_TRUE : GL_FALSE;
Brian5b01c5e2006-12-19 18:02:03 -0700954}
955
956
Brian Paulfd59f192008-05-18 16:04:55 -0600957static GLboolean
Brian5b01c5e2006-12-19 18:02:03 -0700958_mesa_is_shader(GLcontext *ctx, GLuint name)
959{
Brian65a18442006-12-19 18:46:56 -0700960 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700961 return shader ? GL_TRUE : GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700962}
963
964
965
Brian5b01c5e2006-12-19 18:02:03 -0700966/**
967 * Called via ctx->Driver.ShaderSource()
968 */
Brian Paulfd59f192008-05-18 16:04:55 -0600969static void
Brian5b01c5e2006-12-19 18:02:03 -0700970_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -0700971{
Brian65a18442006-12-19 18:46:56 -0700972 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
973 if (!sh) {
Brian Paul36a58262008-07-02 16:40:24 -0600974 GLenum err;
975 if (_mesa_lookup_shader_program(ctx, shader))
976 err = GL_INVALID_OPERATION;
977 else
978 err = GL_INVALID_VALUE;
979 _mesa_error(ctx, err, "glShaderSource(shaderObj)");
Brian34ae99d2006-12-18 08:28:54 -0700980 return;
981 }
982
Brian34ae99d2006-12-18 08:28:54 -0700983 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -0700984 if (sh->Source) {
985 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -0700986 }
Brian65a18442006-12-19 18:46:56 -0700987 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -0700988 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -0700989}
990
991
Brian5b01c5e2006-12-19 18:02:03 -0700992/**
993 * Called via ctx->Driver.CompileShader()
994 */
Brian Paulfd59f192008-05-18 16:04:55 -0600995static void
Brian5b01c5e2006-12-19 18:02:03 -0700996_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -0700997{
Brian65a18442006-12-19 18:46:56 -0700998 struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj);
Brian34ae99d2006-12-18 08:28:54 -0700999
Brian65a18442006-12-19 18:46:56 -07001000 if (!sh) {
Brian34ae99d2006-12-18 08:28:54 -07001001 _mesa_error(ctx, GL_INVALID_VALUE, "glCompileShader(shaderObj)");
1002 return;
1003 }
1004
Brian43975832007-01-04 08:21:09 -07001005 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -07001006}
1007
1008
Brian5b01c5e2006-12-19 18:02:03 -07001009/**
1010 * Called via ctx->Driver.LinkProgram()
1011 */
Brian Paulfd59f192008-05-18 16:04:55 -06001012static void
Brian5b01c5e2006-12-19 18:02:03 -07001013_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001014{
Brian65a18442006-12-19 18:46:56 -07001015 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001016
Brian65a18442006-12-19 18:46:56 -07001017 shProg = _mesa_lookup_shader_program(ctx, program);
1018 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001019 _mesa_error(ctx, GL_INVALID_VALUE, "glLinkProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001020 return;
1021 }
1022
Briandf43fb62008-05-06 23:08:51 -06001023 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1024
Brianc1771912007-02-16 09:56:19 -07001025 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001026}
1027
1028
1029/**
Brian5b01c5e2006-12-19 18:02:03 -07001030 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001031 */
Brian5b01c5e2006-12-19 18:02:03 -07001032void
1033_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001034{
Brian3c008a02007-04-12 15:22:32 -06001035 struct gl_shader_program *shProg;
1036
Brian00d63aa2007-02-03 11:35:02 -07001037 if (ctx->Shader.CurrentProgram &&
1038 ctx->Shader.CurrentProgram->Name == program) {
1039 /* no-op */
1040 return;
1041 }
1042
1043 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1044
Brian5b01c5e2006-12-19 18:02:03 -07001045 if (program) {
Brian65a18442006-12-19 18:46:56 -07001046 shProg = _mesa_lookup_shader_program(ctx, program);
1047 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001048 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -07001049 "glUseProgramObjectARB(programObj)");
1050 return;
1051 }
Brian5b01c5e2006-12-19 18:02:03 -07001052 }
1053 else {
Brian3c008a02007-04-12 15:22:32 -06001054 shProg = NULL;
1055 }
1056
1057 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001058}
Brian34ae99d2006-12-18 08:28:54 -07001059
Brian5b01c5e2006-12-19 18:02:03 -07001060
Brian Paulade50832008-05-14 16:09:46 -06001061
1062/**
1063 * Update the vertex and fragment program's TexturesUsed arrays.
1064 */
1065static void
1066update_textures_used(struct gl_program *prog)
1067{
1068 GLuint s;
1069
1070 memset(prog->TexturesUsed, 0, sizeof(prog->TexturesUsed));
1071
1072 for (s = 0; s < MAX_SAMPLERS; s++) {
1073 if (prog->SamplersUsed & (1 << s)) {
1074 GLuint u = prog->SamplerUnits[s];
1075 GLuint t = prog->SamplerTargets[s];
1076 assert(u < MAX_TEXTURE_IMAGE_UNITS);
1077 prog->TexturesUsed[u] |= (1 << t);
1078 }
1079 }
1080}
1081
1082
1083/**
1084 * Set the value of a program's uniform variable.
1085 * \param program the program whose uniform to update
1086 * \param location the location/index of the uniform
1087 * \param type the datatype of the uniform
1088 * \param count the number of uniforms to set
1089 * \param elems number of elements per uniform
1090 * \param values the new values
1091 */
1092static void
1093set_program_uniform(GLcontext *ctx, struct gl_program *program, GLint location,
1094 GLenum type, GLint count, GLint elems, const void *values)
1095{
1096 if (program->Parameters->Parameters[location].Type == PROGRAM_SAMPLER) {
1097 /* This controls which texture unit which is used by a sampler */
1098 GLuint texUnit, sampler;
1099
1100 /* data type for setting samplers must be int */
1101 if (type != GL_INT || count != 1) {
1102 _mesa_error(ctx, GL_INVALID_OPERATION,
1103 "glUniform(only glUniform1i can be used "
1104 "to set sampler uniforms)");
1105 return;
1106 }
1107
1108 sampler = (GLuint) program->Parameters->ParameterValues[location][0];
1109 texUnit = ((GLuint *) values)[0];
1110
1111 /* check that the sampler (tex unit index) is legal */
1112 if (texUnit >= ctx->Const.MaxTextureImageUnits) {
1113 _mesa_error(ctx, GL_INVALID_VALUE,
1114 "glUniform1(invalid sampler/tex unit index)");
1115 return;
1116 }
1117
1118 /* This maps a sampler to a texture unit: */
1119 program->SamplerUnits[sampler] = texUnit;
1120 update_textures_used(program);
1121
1122 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1123 }
1124 else {
1125 /* ordinary uniform variable */
1126 GLint k, i;
1127
1128 if (count * elems > program->Parameters->Parameters[location].Size) {
1129 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count too large)");
1130 return;
1131 }
1132
1133 for (k = 0; k < count; k++) {
1134 GLfloat *uniformVal = program->Parameters->ParameterValues[location + k];
1135 if (type == GL_INT ||
1136 type == GL_INT_VEC2 ||
1137 type == GL_INT_VEC3 ||
1138 type == GL_INT_VEC4) {
1139 const GLint *iValues = ((const GLint *) values) + k * elems;
1140 for (i = 0; i < elems; i++) {
1141 uniformVal[i] = (GLfloat) iValues[i];
1142 }
1143 }
1144 else {
1145 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
1146 for (i = 0; i < elems; i++) {
1147 uniformVal[i] = fValues[i];
1148 }
1149 }
1150 }
1151 }
1152}
1153
1154
Brian5b01c5e2006-12-19 18:02:03 -07001155/**
1156 * Called via ctx->Driver.Uniform().
1157 */
Brian Paulfd59f192008-05-18 16:04:55 -06001158static void
Brian5b01c5e2006-12-19 18:02:03 -07001159_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1160 const GLvoid *values, GLenum type)
1161{
Brian3a8e2772006-12-20 17:19:16 -07001162 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paulade50832008-05-14 16:09:46 -06001163 GLint elems;
Brian3a8e2772006-12-20 17:19:16 -07001164
1165 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001166 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001167 return;
1168 }
1169
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001170 if (location == -1)
1171 return; /* The standard specifies this as a no-op */
1172
Brian Paulade50832008-05-14 16:09:46 -06001173 if (location < 0 || location >= (GLint) shProg->Uniforms->NumUniforms) {
1174 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(location)");
Brian3a8e2772006-12-20 17:19:16 -07001175 return;
1176 }
1177
Brian52363952007-03-13 16:50:24 -06001178 if (count < 0) {
1179 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1180 return;
1181 }
1182
Brian98650bd2007-03-13 16:32:48 -06001183 switch (type) {
1184 case GL_FLOAT:
1185 case GL_INT:
1186 elems = 1;
1187 break;
1188 case GL_FLOAT_VEC2:
1189 case GL_INT_VEC2:
1190 elems = 2;
1191 break;
1192 case GL_FLOAT_VEC3:
1193 case GL_INT_VEC3:
1194 elems = 3;
1195 break;
1196 case GL_FLOAT_VEC4:
1197 case GL_INT_VEC4:
1198 elems = 4;
1199 break;
1200 default:
1201 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1202 return;
Brian89dc4852007-01-04 14:35:44 -07001203 }
Brian98650bd2007-03-13 16:32:48 -06001204
Brian Paulade50832008-05-14 16:09:46 -06001205 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
Brian98650bd2007-03-13 16:32:48 -06001206
Brian Paulade50832008-05-14 16:09:46 -06001207 /* A uniform var may be used by both a vertex shader and a fragment
1208 * shader. We may need to update one or both shader's uniform here:
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001209 */
Brian Paulade50832008-05-14 16:09:46 -06001210 if (shProg->VertexProgram) {
1211 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1212 if (loc >= 0) {
1213 set_program_uniform(ctx, &shProg->VertexProgram->Base,
1214 loc, type, count, elems, values);
Bruce Merry2bf2a8c2007-12-21 23:18:40 +02001215 }
Brian5b01c5e2006-12-19 18:02:03 -07001216 }
Brian5cf73262007-01-05 16:02:45 -07001217
Brian Paulade50832008-05-14 16:09:46 -06001218 if (shProg->FragmentProgram) {
1219 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1220 if (loc >= 0) {
1221 set_program_uniform(ctx, &shProg->FragmentProgram->Base,
1222 loc, type, count, elems, values);
1223 }
1224 }
1225}
1226
1227
1228static void
1229set_program_uniform_matrix(GLcontext *ctx, struct gl_program *program,
1230 GLuint location, GLuint rows, GLuint cols,
1231 GLboolean transpose, const GLfloat *values)
1232{
1233 /*
1234 * Note: the _columns_ of a matrix are stored in program registers, not
1235 * the rows.
1236 */
1237 /* XXXX need to test 3x3 and 2x2 matrices... */
1238 if (transpose) {
1239 GLuint row, col;
1240 for (col = 0; col < cols; col++) {
1241 GLfloat *v = program->Parameters->ParameterValues[location + col];
1242 for (row = 0; row < rows; row++) {
1243 v[row] = values[row * cols + col];
1244 }
1245 }
1246 }
1247 else {
1248 GLuint row, col;
1249 for (col = 0; col < cols; col++) {
1250 GLfloat *v = program->Parameters->ParameterValues[location + col];
1251 for (row = 0; row < rows; row++) {
1252 v[row] = values[col * rows + row];
1253 }
1254 }
Brian5cf73262007-01-05 16:02:45 -07001255 }
Brian34ae99d2006-12-18 08:28:54 -07001256}
1257
1258
1259/**
Brian5b01c5e2006-12-19 18:02:03 -07001260 * Called by ctx->Driver.UniformMatrix().
Brian34ae99d2006-12-18 08:28:54 -07001261 */
Brian Paulfd59f192008-05-18 16:04:55 -06001262static void
Brian5b01c5e2006-12-19 18:02:03 -07001263_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1264 GLenum matrixType, GLint location, GLsizei count,
1265 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001266{
Brian3a8e2772006-12-20 17:19:16 -07001267 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian Paulade50832008-05-14 16:09:46 -06001268
Brian3a8e2772006-12-20 17:19:16 -07001269 if (!shProg || !shProg->LinkStatus) {
1270 _mesa_error(ctx, GL_INVALID_OPERATION,
1271 "glUniformMatrix(program not linked)");
1272 return;
1273 }
Brian Paulade50832008-05-14 16:09:46 -06001274
Bruce Merry89b80322007-12-21 15:20:17 +02001275 if (location == -1)
1276 return; /* The standard specifies this as a no-op */
Brian Paulade50832008-05-14 16:09:46 -06001277
1278 if (location < 0 || location >= shProg->Uniforms->NumUniforms) {
1279 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(location)");
Brian3a8e2772006-12-20 17:19:16 -07001280 return;
1281 }
Brian34ae99d2006-12-18 08:28:54 -07001282 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001283 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001284 return;
1285 }
1286
1287 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1288
Brian Paulade50832008-05-14 16:09:46 -06001289 if (shProg->VertexProgram) {
1290 GLint loc = shProg->Uniforms->Uniforms[location].VertPos;
1291 if (loc >= 0) {
1292 set_program_uniform_matrix(ctx, &shProg->VertexProgram->Base,
1293 loc, rows, cols, transpose, values);
Brian34ae99d2006-12-18 08:28:54 -07001294 }
Brian Paulade50832008-05-14 16:09:46 -06001295 }
1296
1297 if (shProg->FragmentProgram) {
1298 GLint loc = shProg->Uniforms->Uniforms[location].FragPos;
1299 if (loc >= 0) {
1300 set_program_uniform_matrix(ctx, &shProg->FragmentProgram->Base,
1301 loc, rows, cols, transpose, values);
Brian3a8e2772006-12-20 17:19:16 -07001302 }
Brian34ae99d2006-12-18 08:28:54 -07001303 }
1304}
1305
1306
Brian Paulfd59f192008-05-18 16:04:55 -06001307static void
Brian5b01c5e2006-12-19 18:02:03 -07001308_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001309{
Brian65a18442006-12-19 18:46:56 -07001310 struct gl_shader_program *shProg;
1311 shProg = _mesa_lookup_shader_program(ctx, program);
1312 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001313 _mesa_error(ctx, GL_INVALID_VALUE, "glValidateProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001314 return;
1315 }
Brian5b01c5e2006-12-19 18:02:03 -07001316 /* XXX temporary */
Brian65a18442006-12-19 18:46:56 -07001317 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001318
Brian5b01c5e2006-12-19 18:02:03 -07001319 /* From the GL spec:
1320 any two active samplers in the current program object are of
1321 different types, but refer to the same texture image unit,
1322
1323 any active sampler in the current program object refers to a texture
1324 image unit where fixed-function fragment processing accesses a
1325 texture target that does not match the sampler type, or
1326
1327 the sum of the number of active samplers in the program and the
1328 number of texture image units enabled for fixed-function fragment
1329 processing exceeds the combined limit on the total number of texture
1330 image units allowed.
1331 */
Brian34ae99d2006-12-18 08:28:54 -07001332}
Brian Paulfd59f192008-05-18 16:04:55 -06001333
1334
1335/**
1336 * Plug in Mesa's GLSL functions into the device driver function table.
1337 */
1338void
1339_mesa_init_glsl_driver_functions(struct dd_function_table *driver)
1340{
1341 driver->AttachShader = _mesa_attach_shader;
1342 driver->BindAttribLocation = _mesa_bind_attrib_location;
1343 driver->CompileShader = _mesa_compile_shader;
1344 driver->CreateProgram = _mesa_create_program;
1345 driver->CreateShader = _mesa_create_shader;
1346 driver->DeleteProgram2 = _mesa_delete_program2;
1347 driver->DeleteShader = _mesa_delete_shader;
1348 driver->DetachShader = _mesa_detach_shader;
1349 driver->GetActiveAttrib = _mesa_get_active_attrib;
1350 driver->GetActiveUniform = _mesa_get_active_uniform;
1351 driver->GetAttachedShaders = _mesa_get_attached_shaders;
1352 driver->GetAttribLocation = _mesa_get_attrib_location;
1353 driver->GetHandle = _mesa_get_handle;
1354 driver->GetProgramiv = _mesa_get_programiv;
1355 driver->GetProgramInfoLog = _mesa_get_program_info_log;
1356 driver->GetShaderiv = _mesa_get_shaderiv;
1357 driver->GetShaderInfoLog = _mesa_get_shader_info_log;
1358 driver->GetShaderSource = _mesa_get_shader_source;
1359 driver->GetUniformfv = _mesa_get_uniformfv;
1360 driver->GetUniformLocation = _mesa_get_uniform_location;
1361 driver->IsProgram = _mesa_is_program;
1362 driver->IsShader = _mesa_is_shader;
1363 driver->LinkProgram = _mesa_link_program;
1364 driver->ShaderSource = _mesa_shader_source;
1365 driver->Uniform = _mesa_uniform;
1366 driver->UniformMatrix = _mesa_uniform_matrix;
1367 driver->UseProgram = _mesa_use_program;
1368 driver->ValidateProgram = _mesa_validate_program;
1369}