blob: b0f79c29c1ed63485ca713e7719a56e293514ca4 [file] [log] [blame]
Brian34ae99d2006-12-18 08:28:54 -07001/*
2 * Mesa 3-D graphics library
Brian3e4302f2007-05-09 08:04:32 -06003 * Version: 7.0
Brian34ae99d2006-12-18 08:28:54 -07004 *
Brian5b01c5e2006-12-19 18:02:03 -07005 * Copyright (C) 2004-2007 Brian Paul All Rights Reserved.
Brian34ae99d2006-12-18 08:28:54 -07006 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25/**
26 * \file shader_api.c
Brian5b01c5e2006-12-19 18:02:03 -070027 * Implementation of GLSL-related API functions
Brian34ae99d2006-12-18 08:28:54 -070028 * \author Brian Paul
29 */
30
31/**
32 * XXX things to do:
33 * 1. Check that the right error code is generated for all _mesa_error() calls.
Brian5b01c5e2006-12-19 18:02:03 -070034 * 2. Insert FLUSH_VERTICES calls in various places
Brian34ae99d2006-12-18 08:28:54 -070035 */
36
37
38#include "glheader.h"
39#include "context.h"
40#include "hash.h"
Brian274ac7a2007-04-18 16:05:53 -060041#include "macros.h"
Brian34ae99d2006-12-18 08:28:54 -070042#include "program.h"
43#include "prog_parameter.h"
Brian3209c3e2007-01-09 17:49:24 -070044#include "prog_print.h"
45#include "prog_statevars.h"
Brianc223c6b2007-07-04 13:15:20 -060046#include "shader/shader_api.h"
47#include "shader/slang/slang_compile.h"
48#include "shader/slang/slang_link.h"
Brian34ae99d2006-12-18 08:28:54 -070049
50
51
Brianf2923612006-12-20 09:56:44 -070052/**
53 * Allocate a new gl_shader_program object, initialize it.
54 */
55struct gl_shader_program *
56_mesa_new_shader_program(GLcontext *ctx, GLuint name)
57{
58 struct gl_shader_program *shProg;
59 shProg = CALLOC_STRUCT(gl_shader_program);
60 if (shProg) {
Brianf3e8c322007-04-18 14:53:23 -060061 shProg->Type = GL_SHADER_PROGRAM_MESA;
Brianf2923612006-12-20 09:56:44 -070062 shProg->Name = name;
63 shProg->RefCount = 1;
Brian3209c3e2007-01-09 17:49:24 -070064 shProg->Attributes = _mesa_new_parameter_list();
Brianf2923612006-12-20 09:56:44 -070065 }
66 return shProg;
67}
68
69
Brianb9fbedd2007-03-26 09:23:44 -060070/**
Brian3c008a02007-04-12 15:22:32 -060071 * Clear (free) the shader program state that gets produced by linking.
Brianb9fbedd2007-03-26 09:23:44 -060072 */
Brianf2923612006-12-20 09:56:44 -070073void
Brian3c008a02007-04-12 15:22:32 -060074_mesa_clear_shader_program_data(GLcontext *ctx,
75 struct gl_shader_program *shProg)
Brianf2923612006-12-20 09:56:44 -070076{
Brianf2923612006-12-20 09:56:44 -070077 if (shProg->VertexProgram) {
78 if (shProg->VertexProgram->Base.Parameters == shProg->Uniforms) {
79 /* to prevent a double-free in the next call */
80 shProg->VertexProgram->Base.Parameters = NULL;
81 }
Briandc6fab92008-03-22 10:27:03 -060082 ctx->Driver.DeleteProgram(ctx, &shProg->VertexProgram->Base);
Brianf2923612006-12-20 09:56:44 -070083 shProg->VertexProgram = NULL;
84 }
85
86 if (shProg->FragmentProgram) {
87 if (shProg->FragmentProgram->Base.Parameters == shProg->Uniforms) {
88 /* to prevent a double-free in the next call */
89 shProg->FragmentProgram->Base.Parameters = NULL;
90 }
Briandc6fab92008-03-22 10:27:03 -060091 ctx->Driver.DeleteProgram(ctx, &shProg->FragmentProgram->Base);
Brianf2923612006-12-20 09:56:44 -070092 shProg->FragmentProgram = NULL;
93 }
94
Brianf2923612006-12-20 09:56:44 -070095 if (shProg->Uniforms) {
96 _mesa_free_parameter_list(shProg->Uniforms);
97 shProg->Uniforms = NULL;
98 }
99
100 if (shProg->Varying) {
101 _mesa_free_parameter_list(shProg->Varying);
102 shProg->Varying = NULL;
103 }
104}
105
106
Brianb9fbedd2007-03-26 09:23:44 -0600107/**
Brian3c008a02007-04-12 15:22:32 -0600108 * Free all the data that hangs off a shader program object, but not the
109 * object itself.
110 */
111void
112_mesa_free_shader_program_data(GLcontext *ctx,
113 struct gl_shader_program *shProg)
114{
115 GLuint i;
116
Brianf3e8c322007-04-18 14:53:23 -0600117 assert(shProg->Type == GL_SHADER_PROGRAM_MESA);
Brian3c008a02007-04-12 15:22:32 -0600118
119 _mesa_clear_shader_program_data(ctx, shProg);
120
Brian4b7c6fc2007-04-19 15:23:34 -0600121 if (shProg->Attributes) {
122 _mesa_free_parameter_list(shProg->Attributes);
123 shProg->Attributes = NULL;
124 }
125
Brian3c008a02007-04-12 15:22:32 -0600126 /* detach shaders */
127 for (i = 0; i < shProg->NumShaders; i++) {
128 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
129 }
Xiang, Haihao63d8a842008-03-31 17:02:47 +0800130 shProg->NumShaders = 0;
131
Brian3c008a02007-04-12 15:22:32 -0600132 if (shProg->Shaders) {
133 _mesa_free(shProg->Shaders);
134 shProg->Shaders = NULL;
135 }
Alan Hourihaneeec20c32008-04-22 20:29:42 +0100136
137 if (shProg->InfoLog) {
138 _mesa_free(shProg->InfoLog);
139 shProg->InfoLog = NULL;
140 }
Brian3c008a02007-04-12 15:22:32 -0600141}
142
143
144/**
Brianb9fbedd2007-03-26 09:23:44 -0600145 * Free/delete a shader program object.
146 */
Brianf2923612006-12-20 09:56:44 -0700147void
148_mesa_free_shader_program(GLcontext *ctx, struct gl_shader_program *shProg)
149{
150 _mesa_free_shader_program_data(ctx, shProg);
Alan Hourihaneeec20c32008-04-22 20:29:42 +0100151
Brianf2923612006-12-20 09:56:44 -0700152 _mesa_free(shProg);
153}
154
155
156/**
Brian3c008a02007-04-12 15:22:32 -0600157 * Set ptr to point to shProg.
158 * If ptr is pointing to another object, decrement its refcount (and delete
159 * if refcount hits zero).
160 * Then set ptr to point to shProg, incrementing its refcount.
161 */
162/* XXX this could be static */
163void
164_mesa_reference_shader_program(GLcontext *ctx,
165 struct gl_shader_program **ptr,
166 struct gl_shader_program *shProg)
167{
168 assert(ptr);
169 if (*ptr == shProg) {
170 /* no-op */
171 return;
172 }
173 if (*ptr) {
174 /* Unreference the old shader program */
175 GLboolean deleteFlag = GL_FALSE;
176 struct gl_shader_program *old = *ptr;
177
178 ASSERT(old->RefCount > 0);
179 old->RefCount--;
180 /*printf("SHPROG DECR %p (%d) to %d\n",
181 (void*) old, old->Name, old->RefCount);*/
182 deleteFlag = (old->RefCount == 0);
183
184 if (deleteFlag) {
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800185 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
Brian3c008a02007-04-12 15:22:32 -0600186 _mesa_free_shader_program(ctx, old);
187 }
188
189 *ptr = NULL;
190 }
191 assert(!*ptr);
192
193 if (shProg) {
194 shProg->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600195 /*printf("SHPROG INCR %p (%d) to %d\n",
196 (void*) shProg, shProg->Name, shProg->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600197 *ptr = shProg;
198 }
199}
200
201
202/**
Brianf2923612006-12-20 09:56:44 -0700203 * Lookup a GLSL program object.
204 */
205struct gl_shader_program *
206_mesa_lookup_shader_program(GLcontext *ctx, GLuint name)
207{
208 struct gl_shader_program *shProg;
209 if (name) {
210 shProg = (struct gl_shader_program *)
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800211 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
Brianf2923612006-12-20 09:56:44 -0700212 /* Note that both gl_shader and gl_shader_program objects are kept
213 * in the same hash table. Check the object's type to be sure it's
214 * what we're expecting.
215 */
Brianf3e8c322007-04-18 14:53:23 -0600216 if (shProg && shProg->Type != GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700217 return NULL;
218 }
219 return shProg;
220 }
221 return NULL;
222}
223
224
225/**
226 * Allocate a new gl_shader object, initialize it.
227 */
228struct gl_shader *
229_mesa_new_shader(GLcontext *ctx, GLuint name, GLenum type)
230{
231 struct gl_shader *shader;
232 assert(type == GL_FRAGMENT_SHADER || type == GL_VERTEX_SHADER);
233 shader = CALLOC_STRUCT(gl_shader);
234 if (shader) {
235 shader->Type = type;
236 shader->Name = name;
237 shader->RefCount = 1;
238 }
239 return shader;
240}
241
242
243void
244_mesa_free_shader(GLcontext *ctx, struct gl_shader *sh)
245{
246 GLuint i;
247 if (sh->Source)
248 _mesa_free((void *) sh->Source);
249 if (sh->InfoLog)
250 _mesa_free(sh->InfoLog);
251 for (i = 0; i < sh->NumPrograms; i++) {
252 assert(sh->Programs[i]);
Briandc6fab92008-03-22 10:27:03 -0600253 ctx->Driver.DeleteProgram(ctx, sh->Programs[i]);
Brianf2923612006-12-20 09:56:44 -0700254 }
255 if (sh->Programs)
256 _mesa_free(sh->Programs);
257 _mesa_free(sh);
258}
259
260
261/**
Brian3c008a02007-04-12 15:22:32 -0600262 * Set ptr to point to sh.
263 * If ptr is pointing to another shader, decrement its refcount (and delete
264 * if refcount hits zero).
265 * Then set ptr to point to sh, incrementing its refcount.
266 */
267/* XXX this could be static */
268void
269_mesa_reference_shader(GLcontext *ctx, struct gl_shader **ptr,
270 struct gl_shader *sh)
271{
272 assert(ptr);
273 if (*ptr == sh) {
274 /* no-op */
275 return;
276 }
277 if (*ptr) {
278 /* Unreference the old shader */
279 GLboolean deleteFlag = GL_FALSE;
280 struct gl_shader *old = *ptr;
281
282 ASSERT(old->RefCount > 0);
283 old->RefCount--;
Brian99193e42007-04-12 15:45:02 -0600284 /*printf("SHADER DECR %p (%d) to %d\n",
285 (void*) old, old->Name, old->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600286 deleteFlag = (old->RefCount == 0);
287
288 if (deleteFlag) {
289 _mesa_HashRemove(ctx->Shared->ShaderObjects, old->Name);
290 _mesa_free_shader(ctx, old);
291 }
292
293 *ptr = NULL;
294 }
295 assert(!*ptr);
296
297 if (sh) {
298 /* reference new */
299 sh->RefCount++;
Brian99193e42007-04-12 15:45:02 -0600300 /*printf("SHADER INCR %p (%d) to %d\n",
301 (void*) sh, sh->Name, sh->RefCount);*/
Brian3c008a02007-04-12 15:22:32 -0600302 *ptr = sh;
303 }
304}
305
306
307/**
Brianf2923612006-12-20 09:56:44 -0700308 * Lookup a GLSL shader object.
309 */
310struct gl_shader *
311_mesa_lookup_shader(GLcontext *ctx, GLuint name)
312{
313 if (name) {
314 struct gl_shader *sh = (struct gl_shader *)
315 _mesa_HashLookup(ctx->Shared->ShaderObjects, name);
316 /* Note that both gl_shader and gl_shader_program objects are kept
317 * in the same hash table. Check the object's type to be sure it's
318 * what we're expecting.
319 */
Brianf3e8c322007-04-18 14:53:23 -0600320 if (sh && sh->Type == GL_SHADER_PROGRAM_MESA) {
Brianf2923612006-12-20 09:56:44 -0700321 return NULL;
322 }
323 return sh;
324 }
325 return NULL;
326}
327
328
Brianfa4d0362007-02-26 18:33:50 -0700329/**
330 * Initialize context's shader state.
331 */
Brianf2923612006-12-20 09:56:44 -0700332void
333_mesa_init_shader_state(GLcontext * ctx)
334{
Brianfa4d0362007-02-26 18:33:50 -0700335 /* Device drivers may override these to control what kind of instructions
336 * are generated by the GLSL compiler.
337 */
338 ctx->Shader.EmitHighLevelInstructions = GL_TRUE;
Brian63556fa2007-03-23 14:47:46 -0600339 ctx->Shader.EmitCondCodes = GL_TRUE; /* XXX probably want GL_FALSE... */
Brianfa4d0362007-02-26 18:33:50 -0700340 ctx->Shader.EmitComments = GL_FALSE;
Brianf2923612006-12-20 09:56:44 -0700341}
342
343
Brian5b01c5e2006-12-19 18:02:03 -0700344/**
Brian935f93f2007-03-24 16:20:02 -0600345 * Free the per-context shader-related state.
346 */
347void
348_mesa_free_shader_state(GLcontext *ctx)
349{
Brian3c008a02007-04-12 15:22:32 -0600350 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, NULL);
Brian935f93f2007-03-24 16:20:02 -0600351}
352
353
354/**
Brian5b01c5e2006-12-19 18:02:03 -0700355 * Copy string from <src> to <dst>, up to maxLength characters, returning
356 * length of <dst> in <length>.
357 * \param src the strings source
358 * \param maxLength max chars to copy
359 * \param length returns number of chars copied
360 * \param dst the string destination
361 */
362static void
363copy_string(GLchar *dst, GLsizei maxLength, GLsizei *length, const GLchar *src)
364{
365 GLsizei len;
366 for (len = 0; len < maxLength - 1 && src && src[len]; len++)
367 dst[len] = src[len];
368 if (maxLength > 0)
369 dst[len] = 0;
370 if (length)
371 *length = len;
372}
373
374
Brian5b01c5e2006-12-19 18:02:03 -0700375/**
Brian2761cfc2007-12-20 09:05:37 -0700376 * Return size (in floats) of the given GLSL type.
377 * See also _slang_sizeof_type_specifier().
378 */
379static GLint
380sizeof_glsl_type(GLenum type)
381{
382 switch (type) {
383 case GL_BOOL:
384 case GL_FLOAT:
385 case GL_INT:
386 return 1;
387 case GL_BOOL_VEC2:
388 case GL_FLOAT_VEC2:
389 case GL_INT_VEC2:
390 return 2;
391 case GL_BOOL_VEC3:
392 case GL_FLOAT_VEC3:
393 case GL_INT_VEC3:
394 return 3;
395 case GL_BOOL_VEC4:
396 case GL_FLOAT_VEC4:
397 case GL_INT_VEC4:
398 return 4;
399 case GL_FLOAT_MAT2:
400 return 8; /* 2 rows of 4, actually */
401 case GL_FLOAT_MAT3:
402 return 12; /* 3 rows of 4, actually */
403 case GL_FLOAT_MAT4:
404 return 16;
405 case GL_FLOAT_MAT2x3:
Bruce Merryeeb03fa2007-12-21 14:41:45 +0200406 return 8; /* 2 rows of 4, actually */
Brian2761cfc2007-12-20 09:05:37 -0700407 case GL_FLOAT_MAT2x4:
408 return 8;
409 case GL_FLOAT_MAT3x2:
410 return 12; /* 3 rows of 4, actually */
411 case GL_FLOAT_MAT3x4:
412 return 12;
413 case GL_FLOAT_MAT4x2:
414 return 16; /* 4 rows of 4, actually */
415 case GL_FLOAT_MAT4x3:
Bruce Merryeeb03fa2007-12-21 14:41:45 +0200416 return 16; /* 4 rows of 4, actually */
Brian2761cfc2007-12-20 09:05:37 -0700417 default:
418 return 0; /* error */
419 }
420}
421
422
423/**
Brian5b01c5e2006-12-19 18:02:03 -0700424 * Called via ctx->Driver.AttachShader()
425 */
426void
427_mesa_attach_shader(GLcontext *ctx, GLuint program, GLuint shader)
428{
Brian65a18442006-12-19 18:46:56 -0700429 struct gl_shader_program *shProg
430 = _mesa_lookup_shader_program(ctx, program);
431 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
Brian237b9852007-08-07 21:48:31 +0100432 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700433 GLuint i;
434
Brian65a18442006-12-19 18:46:56 -0700435 if (!shProg || !sh) {
Brian43975832007-01-04 08:21:09 -0700436 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700437 "glAttachShader(bad program or shader name)");
438 return;
439 }
440
Brian237b9852007-08-07 21:48:31 +0100441 n = shProg->NumShaders;
442
Brian5b01c5e2006-12-19 18:02:03 -0700443 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700444 if (shProg->Shaders[i] == sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700445 /* already attached */
446 return;
Brian34ae99d2006-12-18 08:28:54 -0700447 }
448 }
Brian5b01c5e2006-12-19 18:02:03 -0700449
450 /* grow list */
Brian65a18442006-12-19 18:46:56 -0700451 shProg->Shaders = (struct gl_shader **)
452 _mesa_realloc(shProg->Shaders,
453 n * sizeof(struct gl_shader *),
454 (n + 1) * sizeof(struct gl_shader *));
455 if (!shProg->Shaders) {
Brian5b01c5e2006-12-19 18:02:03 -0700456 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glAttachShader");
457 return;
458 }
459
460 /* append */
Brian3c008a02007-04-12 15:22:32 -0600461 shProg->Shaders[n] = NULL; /* since realloc() didn't zero the new space */
462 _mesa_reference_shader(ctx, &shProg->Shaders[n], sh);
Brian65a18442006-12-19 18:46:56 -0700463 shProg->NumShaders++;
Brian5b01c5e2006-12-19 18:02:03 -0700464}
465
466
467void
468_mesa_bind_attrib_location(GLcontext *ctx, GLuint program, GLuint index,
469 const GLchar *name)
470{
Brian65a18442006-12-19 18:46:56 -0700471 struct gl_shader_program *shProg
472 = _mesa_lookup_shader_program(ctx, program);
Brianb7978af2007-01-09 19:17:17 -0700473 const GLint size = -1; /* unknown size */
474 GLint i, oldIndex;
Brian5b01c5e2006-12-19 18:02:03 -0700475
Brian65a18442006-12-19 18:46:56 -0700476 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700477 _mesa_error(ctx, GL_INVALID_VALUE, "glBindAttribLocation(program)");
Brian5b01c5e2006-12-19 18:02:03 -0700478 return;
479 }
480
Brian9e4bae92006-12-20 09:27:42 -0700481 if (!name)
482 return;
483
484 if (strncmp(name, "gl_", 3) == 0) {
485 _mesa_error(ctx, GL_INVALID_OPERATION,
486 "glBindAttribLocation(illegal name)");
487 return;
488 }
489
Brian9f660252007-04-11 09:00:56 -0600490 if (shProg->LinkStatus) {
491 /* get current index/location for the attribute */
492 oldIndex = _mesa_get_attrib_location(ctx, program, name);
493 }
494 else {
495 oldIndex = -1;
496 }
Brian3209c3e2007-01-09 17:49:24 -0700497
498 /* this will replace the current value if it's already in the list */
Brianb7978af2007-01-09 19:17:17 -0700499 i = _mesa_add_attribute(shProg->Attributes, name, size, index);
Brian3209c3e2007-01-09 17:49:24 -0700500 if (i < 0) {
501 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindAttribLocation");
502 }
503
Brian9f660252007-04-11 09:00:56 -0600504 if (shProg->VertexProgram && oldIndex >= 0 && oldIndex != index) {
505 /* If the index changed, need to search/replace references to that attribute
506 * in the vertex program.
507 */
Brian3209c3e2007-01-09 17:49:24 -0700508 _slang_remap_attribute(&shProg->VertexProgram->Base, oldIndex, index);
509 }
Brian34ae99d2006-12-18 08:28:54 -0700510}
511
512
Brian5b01c5e2006-12-19 18:02:03 -0700513GLuint
514_mesa_create_shader(GLcontext *ctx, GLenum type)
515{
Brian65a18442006-12-19 18:46:56 -0700516 struct gl_shader *sh;
Brian5b01c5e2006-12-19 18:02:03 -0700517 GLuint name;
518
519 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
520
521 switch (type) {
Brian65a18442006-12-19 18:46:56 -0700522 case GL_FRAGMENT_SHADER:
523 case GL_VERTEX_SHADER:
524 sh = _mesa_new_shader(ctx, name, type);
Brian5b01c5e2006-12-19 18:02:03 -0700525 break;
526 default:
527 _mesa_error(ctx, GL_INVALID_ENUM, "CreateShader(type)");
528 return 0;
529 }
530
Brian65a18442006-12-19 18:46:56 -0700531 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, sh);
Brian5b01c5e2006-12-19 18:02:03 -0700532
533 return name;
534}
535
536
537GLuint
538_mesa_create_program(GLcontext *ctx)
539{
540 GLuint name;
Brian65a18442006-12-19 18:46:56 -0700541 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700542
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800543 name = _mesa_HashFindFreeKeyBlock(ctx->Shared->ShaderObjects, 1);
Brian65a18442006-12-19 18:46:56 -0700544 shProg = _mesa_new_shader_program(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700545
Xiang, Haihaoaef47c42008-03-31 16:27:47 +0800546 _mesa_HashInsert(ctx->Shared->ShaderObjects, name, shProg);
Brian5b01c5e2006-12-19 18:02:03 -0700547
Brian3c008a02007-04-12 15:22:32 -0600548 assert(shProg->RefCount == 1);
549
Brian5b01c5e2006-12-19 18:02:03 -0700550 return name;
551}
552
553
Brian3c008a02007-04-12 15:22:32 -0600554/**
555 * Named w/ "2" to indicate OpenGL 2.x vs GL_ARB_fragment_programs's
556 * DeleteProgramARB.
557 */
Brian5b01c5e2006-12-19 18:02:03 -0700558void
559_mesa_delete_program2(GLcontext *ctx, GLuint name)
560{
Brian3c008a02007-04-12 15:22:32 -0600561 /*
562 * NOTE: deleting shaders/programs works a bit differently than
563 * texture objects (and buffer objects, etc). Shader/program
564 * handles/IDs exist in the hash table until the object is really
565 * deleted (refcount==0). With texture objects, the handle/ID is
566 * removed from the hash table in glDeleteTextures() while the tex
567 * object itself might linger until its refcount goes to zero.
568 */
Brian65a18442006-12-19 18:46:56 -0700569 struct gl_shader_program *shProg;
Brian5b01c5e2006-12-19 18:02:03 -0700570
Brian65a18442006-12-19 18:46:56 -0700571 shProg = _mesa_lookup_shader_program(ctx, name);
572 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700573 _mesa_error(ctx, GL_INVALID_VALUE, "glDeleteProgram(name)");
Brian5b01c5e2006-12-19 18:02:03 -0700574 return;
575 }
576
Brian9e4bae92006-12-20 09:27:42 -0700577 shProg->DeletePending = GL_TRUE;
578
Brian3c008a02007-04-12 15:22:32 -0600579 /* effectively, decr shProg's refcount */
580 _mesa_reference_shader_program(ctx, &shProg, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700581}
582
583
584void
585_mesa_delete_shader(GLcontext *ctx, GLuint shader)
586{
Brian9e4bae92006-12-20 09:27:42 -0700587 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
588 if (!sh) {
589 return;
590 }
Brian5b01c5e2006-12-19 18:02:03 -0700591
Brian9e4bae92006-12-20 09:27:42 -0700592 sh->DeletePending = GL_TRUE;
Brian3c008a02007-04-12 15:22:32 -0600593
594 /* effectively, decr sh's refcount */
595 _mesa_reference_shader(ctx, &sh, NULL);
Brian5b01c5e2006-12-19 18:02:03 -0700596}
597
598
599void
600_mesa_detach_shader(GLcontext *ctx, GLuint program, GLuint shader)
601{
Brian65a18442006-12-19 18:46:56 -0700602 struct gl_shader_program *shProg
603 = _mesa_lookup_shader_program(ctx, program);
Brian237b9852007-08-07 21:48:31 +0100604 GLuint n;
Brian5b01c5e2006-12-19 18:02:03 -0700605 GLuint i, j;
606
Brian65a18442006-12-19 18:46:56 -0700607 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700608 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700609 "glDetachShader(bad program or shader name)");
610 return;
611 }
612
Brian237b9852007-08-07 21:48:31 +0100613 n = shProg->NumShaders;
614
Brian5b01c5e2006-12-19 18:02:03 -0700615 for (i = 0; i < n; i++) {
Brian65a18442006-12-19 18:46:56 -0700616 if (shProg->Shaders[i]->Name == shader) {
Brian5b01c5e2006-12-19 18:02:03 -0700617 /* found it */
Brian3c008a02007-04-12 15:22:32 -0600618 struct gl_shader **newList;
Brian9e4bae92006-12-20 09:27:42 -0700619
Brian3c008a02007-04-12 15:22:32 -0600620 /* derefernce */
621 _mesa_reference_shader(ctx, &shProg->Shaders[i], NULL);
Brian9e4bae92006-12-20 09:27:42 -0700622
Brian5b01c5e2006-12-19 18:02:03 -0700623 /* alloc new, smaller array */
Brian65a18442006-12-19 18:46:56 -0700624 newList = (struct gl_shader **)
625 _mesa_malloc((n - 1) * sizeof(struct gl_shader *));
Brian5b01c5e2006-12-19 18:02:03 -0700626 if (!newList) {
627 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glDetachShader");
628 return;
629 }
630 for (j = 0; j < i; j++) {
Brian65a18442006-12-19 18:46:56 -0700631 newList[j] = shProg->Shaders[j];
Brian5b01c5e2006-12-19 18:02:03 -0700632 }
633 while (++i < n)
Brian65a18442006-12-19 18:46:56 -0700634 newList[j++] = shProg->Shaders[i];
635 _mesa_free(shProg->Shaders);
Brian5b01c5e2006-12-19 18:02:03 -0700636
Brian65a18442006-12-19 18:46:56 -0700637 shProg->Shaders = newList;
Brianbac15c82007-04-18 14:55:18 -0600638 shProg->NumShaders = n - 1;
Brianaaa57412007-04-18 15:22:43 -0600639
640#ifdef DEBUG
641 /* sanity check */
642 {
643 for (j = 0; j < shProg->NumShaders; j++) {
644 assert(shProg->Shaders[j]->Type == GL_VERTEX_SHADER ||
645 shProg->Shaders[j]->Type == GL_FRAGMENT_SHADER);
646 assert(shProg->Shaders[j]->RefCount > 0);
647 }
648 }
649#endif
650
Brian5b01c5e2006-12-19 18:02:03 -0700651 return;
652 }
653 }
654
655 /* not found */
Brian43975832007-01-04 08:21:09 -0700656 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -0700657 "glDetachShader(shader not found)");
658}
659
660
661void
662_mesa_get_active_attrib(GLcontext *ctx, GLuint program, GLuint index,
663 GLsizei maxLength, GLsizei *length, GLint *size,
664 GLenum *type, GLchar *nameOut)
665{
666 static const GLenum vec_types[] = {
667 GL_FLOAT, GL_FLOAT_VEC2, GL_FLOAT_VEC3, GL_FLOAT_VEC4
668 };
Brian65a18442006-12-19 18:46:56 -0700669 struct gl_shader_program *shProg
670 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700671 GLint sz;
672
Brian65a18442006-12-19 18:46:56 -0700673 if (!shProg) {
Brianaaa57412007-04-18 15:22:43 -0600674 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib");
Brian5b01c5e2006-12-19 18:02:03 -0700675 return;
676 }
677
Brian65a18442006-12-19 18:46:56 -0700678 if (!shProg->Attributes || index >= shProg->Attributes->NumParameters) {
Brianaaa57412007-04-18 15:22:43 -0600679 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveAttrib(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700680 return;
681 }
682
683 copy_string(nameOut, maxLength, length,
Brian65a18442006-12-19 18:46:56 -0700684 shProg->Attributes->Parameters[index].Name);
685 sz = shProg->Attributes->Parameters[index].Size;
Brian5b01c5e2006-12-19 18:02:03 -0700686 if (size)
Bruce Merryeeb03fa2007-12-21 14:41:45 +0200687 *size = 1; /* attributes may not be arrays */
688 if (type && sz > 0 && sz <= 4) /* XXX this is a temporary hack */
689 *type = vec_types[sz - 1];
Brian5b01c5e2006-12-19 18:02:03 -0700690}
691
692
693/**
694 * Called via ctx->Driver.GetActiveUniform().
695 */
696void
697_mesa_get_active_uniform(GLcontext *ctx, GLuint program, GLuint index,
698 GLsizei maxLength, GLsizei *length, GLint *size,
699 GLenum *type, GLchar *nameOut)
700{
Brian65a18442006-12-19 18:46:56 -0700701 struct gl_shader_program *shProg
702 = _mesa_lookup_shader_program(ctx, program);
Brian274ac7a2007-04-18 16:05:53 -0600703 GLuint ind, j;
Brian5b01c5e2006-12-19 18:02:03 -0700704
Brian65a18442006-12-19 18:46:56 -0700705 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700706 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform");
Brian5b01c5e2006-12-19 18:02:03 -0700707 return;
708 }
709
Brian65a18442006-12-19 18:46:56 -0700710 if (!shProg->Uniforms || index >= shProg->Uniforms->NumParameters) {
Brian5b01c5e2006-12-19 18:02:03 -0700711 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
712 return;
713 }
714
Brian274ac7a2007-04-18 16:05:53 -0600715 ind = 0;
716 for (j = 0; j < shProg->Uniforms->NumParameters; j++) {
717 if (shProg->Uniforms->Parameters[j].Type == PROGRAM_UNIFORM ||
718 shProg->Uniforms->Parameters[j].Type == PROGRAM_SAMPLER) {
719 if (ind == index) {
Brian2761cfc2007-12-20 09:05:37 -0700720 GLuint uSize = shProg->Uniforms->Parameters[j].Size;
721 GLenum uType = shProg->Uniforms->Parameters[j].DataType;
Brian274ac7a2007-04-18 16:05:53 -0600722 /* found it */
723 copy_string(nameOut, maxLength, length,
724 shProg->Uniforms->Parameters[j].Name);
Brian2761cfc2007-12-20 09:05:37 -0700725 if (size) {
726 /* convert from floats to 'type' (eg: sizeof(mat4x4)=1) */
727 *size = uSize / sizeof_glsl_type(uType);
728 }
Brian274ac7a2007-04-18 16:05:53 -0600729 if (type)
Brian2761cfc2007-12-20 09:05:37 -0700730 *type = uType;
Brian274ac7a2007-04-18 16:05:53 -0600731 return;
732 }
733 ind++;
734 }
735 }
736
737 _mesa_error(ctx, GL_INVALID_VALUE, "glGetActiveUniform(index)");
Brian5b01c5e2006-12-19 18:02:03 -0700738}
739
740
741/**
742 * Called via ctx->Driver.GetAttachedShaders().
743 */
744void
745_mesa_get_attached_shaders(GLcontext *ctx, GLuint program, GLsizei maxCount,
746 GLsizei *count, GLuint *obj)
747{
Brian65a18442006-12-19 18:46:56 -0700748 struct gl_shader_program *shProg
749 = _mesa_lookup_shader_program(ctx, program);
750 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700751 GLint i;
Brian65a18442006-12-19 18:46:56 -0700752 for (i = 0; i < maxCount && i < shProg->NumShaders; i++) {
753 obj[i] = shProg->Shaders[i]->Name;
Brian5b01c5e2006-12-19 18:02:03 -0700754 }
755 if (count)
756 *count = i;
757 }
758 else {
Brian43975832007-01-04 08:21:09 -0700759 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttachedShaders");
Brian5b01c5e2006-12-19 18:02:03 -0700760 }
761}
762
763
764GLint
765_mesa_get_attrib_location(GLcontext *ctx, GLuint program,
766 const GLchar *name)
767{
Brian65a18442006-12-19 18:46:56 -0700768 struct gl_shader_program *shProg
769 = _mesa_lookup_shader_program(ctx, program);
Brian5b01c5e2006-12-19 18:02:03 -0700770
Brian65a18442006-12-19 18:46:56 -0700771 if (!shProg) {
Brian43975832007-01-04 08:21:09 -0700772 _mesa_error(ctx, GL_INVALID_VALUE, "glGetAttribLocation");
Brian5b01c5e2006-12-19 18:02:03 -0700773 return -1;
774 }
775
Brian65a18442006-12-19 18:46:56 -0700776 if (!shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -0700777 _mesa_error(ctx, GL_INVALID_OPERATION,
778 "glGetAttribLocation(program not linked)");
779 return -1;
780 }
781
782 if (!name)
783 return -1;
784
Brian65a18442006-12-19 18:46:56 -0700785 if (shProg->Attributes) {
Brian3209c3e2007-01-09 17:49:24 -0700786 GLint i = _mesa_lookup_parameter_index(shProg->Attributes, -1, name);
787 if (i >= 0) {
Brian01a91eb2007-01-09 19:26:22 -0700788 return shProg->Attributes->Parameters[i].StateIndexes[0];
Brian5b01c5e2006-12-19 18:02:03 -0700789 }
790 }
791 return -1;
792}
793
794
795GLuint
796_mesa_get_handle(GLcontext *ctx, GLenum pname)
Brian34ae99d2006-12-18 08:28:54 -0700797{
798#if 0
799 GET_CURRENT_CONTEXT(ctx);
800
801 switch (pname) {
802 case GL_PROGRAM_OBJECT_ARB:
803 {
Brian5b01c5e2006-12-19 18:02:03 -0700804 struct gl2_program_intf **pro = ctx->Shader.CurrentProgram;
Brian34ae99d2006-12-18 08:28:54 -0700805
806 if (pro != NULL)
807 return (**pro)._container._generic.
808 GetName((struct gl2_generic_intf **) (pro));
809 }
810 break;
811 default:
812 _mesa_error(ctx, GL_INVALID_ENUM, "glGetHandleARB");
813 }
814#endif
815 return 0;
816}
817
818
Brian5b01c5e2006-12-19 18:02:03 -0700819void
820_mesa_get_programiv(GLcontext *ctx, GLuint program,
821 GLenum pname, GLint *params)
Brian34ae99d2006-12-18 08:28:54 -0700822{
Brian65a18442006-12-19 18:46:56 -0700823 struct gl_shader_program *shProg
824 = _mesa_lookup_shader_program(ctx, program);
Brian34ae99d2006-12-18 08:28:54 -0700825
Brian65a18442006-12-19 18:46:56 -0700826 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700827 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramiv(program)");
Brian34ae99d2006-12-18 08:28:54 -0700828 return;
829 }
830
Brian5b01c5e2006-12-19 18:02:03 -0700831 switch (pname) {
832 case GL_DELETE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700833 *params = shProg->DeletePending;
Brian5b01c5e2006-12-19 18:02:03 -0700834 break;
835 case GL_LINK_STATUS:
Brian65a18442006-12-19 18:46:56 -0700836 *params = shProg->LinkStatus;
Brian34ae99d2006-12-18 08:28:54 -0700837 break;
Brian5b01c5e2006-12-19 18:02:03 -0700838 case GL_VALIDATE_STATUS:
Brian65a18442006-12-19 18:46:56 -0700839 *params = shProg->Validated;
Brian5b01c5e2006-12-19 18:02:03 -0700840 break;
841 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600842 *params = shProg->InfoLog ? strlen(shProg->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700843 break;
844 case GL_ATTACHED_SHADERS:
Brian65a18442006-12-19 18:46:56 -0700845 *params = shProg->NumShaders;
Brian5b01c5e2006-12-19 18:02:03 -0700846 break;
847 case GL_ACTIVE_ATTRIBUTES:
Brian3209c3e2007-01-09 17:49:24 -0700848 *params = shProg->Attributes ? shProg->Attributes->NumParameters : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700849 break;
850 case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600851 *params = _mesa_longest_parameter_name(shProg->Attributes,
852 PROGRAM_INPUT) + 1;
Brian5b01c5e2006-12-19 18:02:03 -0700853 break;
854 case GL_ACTIVE_UNIFORMS:
Brian274ac7a2007-04-18 16:05:53 -0600855 *params
856 = _mesa_num_parameters_of_type(shProg->Uniforms, PROGRAM_UNIFORM)
857 + _mesa_num_parameters_of_type(shProg->Uniforms, PROGRAM_SAMPLER);
Brian5b01c5e2006-12-19 18:02:03 -0700858 break;
859 case GL_ACTIVE_UNIFORM_MAX_LENGTH:
Brian274ac7a2007-04-18 16:05:53 -0600860 *params = MAX2(
861 _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_UNIFORM),
862 _mesa_longest_parameter_name(shProg->Uniforms, PROGRAM_SAMPLER));
863 if (*params > 0)
864 (*params)++; /* add one for terminating zero */
Brian34ae99d2006-12-18 08:28:54 -0700865 break;
866 default:
Brian5b01c5e2006-12-19 18:02:03 -0700867 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramiv(pname)");
868 return;
Brian34ae99d2006-12-18 08:28:54 -0700869 }
Brian5b01c5e2006-12-19 18:02:03 -0700870}
Brian34ae99d2006-12-18 08:28:54 -0700871
Brian34ae99d2006-12-18 08:28:54 -0700872
Brian5b01c5e2006-12-19 18:02:03 -0700873void
874_mesa_get_shaderiv(GLcontext *ctx, GLuint name, GLenum pname, GLint *params)
875{
Brian65a18442006-12-19 18:46:56 -0700876 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -0700877
878 if (!shader) {
879 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderiv(shader)");
880 return;
881 }
Brian65a18442006-12-19 18:46:56 -0700882
Brian5b01c5e2006-12-19 18:02:03 -0700883 switch (pname) {
884 case GL_SHADER_TYPE:
885 *params = shader->Type;
886 break;
887 case GL_DELETE_STATUS:
888 *params = shader->DeletePending;
889 break;
890 case GL_COMPILE_STATUS:
891 *params = shader->CompileStatus;
892 break;
893 case GL_INFO_LOG_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600894 *params = shader->InfoLog ? strlen(shader->InfoLog) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700895 break;
896 case GL_SHADER_SOURCE_LENGTH:
Jan Dvorak5a0f02a2007-07-13 16:36:00 -0600897 *params = shader->Source ? strlen((char *) shader->Source) + 1 : 0;
Brian5b01c5e2006-12-19 18:02:03 -0700898 break;
899 default:
900 _mesa_error(ctx, GL_INVALID_ENUM, "glGetShaderiv(pname)");
901 return;
902 }
903}
904
905
906void
907_mesa_get_program_info_log(GLcontext *ctx, GLuint program, GLsizei bufSize,
908 GLsizei *length, GLchar *infoLog)
909{
Brian65a18442006-12-19 18:46:56 -0700910 struct gl_shader_program *shProg
911 = _mesa_lookup_shader_program(ctx, program);
912 if (!shProg) {
Brian5b01c5e2006-12-19 18:02:03 -0700913 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramInfoLog(program)");
914 return;
915 }
Brian65a18442006-12-19 18:46:56 -0700916 copy_string(infoLog, bufSize, length, shProg->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700917}
918
919
920void
921_mesa_get_shader_info_log(GLcontext *ctx, GLuint shader, GLsizei bufSize,
922 GLsizei *length, GLchar *infoLog)
923{
Brian65a18442006-12-19 18:46:56 -0700924 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
925 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700926 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderInfoLog(shader)");
927 return;
928 }
Brian65a18442006-12-19 18:46:56 -0700929 copy_string(infoLog, bufSize, length, sh->InfoLog);
Brian5b01c5e2006-12-19 18:02:03 -0700930}
931
932
933/**
934 * Called via ctx->Driver.GetShaderSource().
935 */
936void
937_mesa_get_shader_source(GLcontext *ctx, GLuint shader, GLsizei maxLength,
938 GLsizei *length, GLchar *sourceOut)
939{
Brian65a18442006-12-19 18:46:56 -0700940 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
941 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -0700942 _mesa_error(ctx, GL_INVALID_VALUE, "glGetShaderSource(shader)");
943 return;
944 }
Brian65a18442006-12-19 18:46:56 -0700945 copy_string(sourceOut, maxLength, length, sh->Source);
Brian5b01c5e2006-12-19 18:02:03 -0700946}
947
948
949/**
950 * Called via ctx->Driver.GetUniformfv().
951 */
952void
953_mesa_get_uniformfv(GLcontext *ctx, GLuint program, GLint location,
954 GLfloat *params)
955{
Brian65a18442006-12-19 18:46:56 -0700956 struct gl_shader_program *shProg
957 = _mesa_lookup_shader_program(ctx, program);
958 if (shProg) {
Brian223d7cb2007-01-23 16:37:51 -0700959 GLint i;
Brian65a18442006-12-19 18:46:56 -0700960 if (location >= 0 && location < shProg->Uniforms->NumParameters) {
Bruce Merryeeb03fa2007-12-21 14:41:45 +0200961 GLuint uSize;
962 GLenum uType;
963 GLint rows = 0;
964 uType = shProg->Uniforms->Parameters[location].DataType;
965 uSize = sizeof_glsl_type(uType);
966 /* Matrix types need special handling, because they span several
967 * parameters, and may also not be fully packed.
968 */
969 switch (shProg->Uniforms->Parameters[location].DataType) {
970 case GL_FLOAT_MAT2:
971 case GL_FLOAT_MAT3x2:
972 case GL_FLOAT_MAT4x2:
973 rows = 2;
974 break;
975 case GL_FLOAT_MAT2x3:
976 case GL_FLOAT_MAT3:
977 case GL_FLOAT_MAT4x3:
978 rows = 3;
979 break;
980 case GL_FLOAT_MAT2x4:
981 case GL_FLOAT_MAT3x4:
982 case GL_FLOAT_MAT4:
983 rows = 4;
Brian5b01c5e2006-12-19 18:02:03 -0700984 }
Bruce Merryeeb03fa2007-12-21 14:41:45 +0200985 if (rows != 0) {
986 GLint r, c;
987 for (c = 0, i = 0; c * 4 < uSize; c++)
988 for (r = 0; r < rows; r++, i++)
989 params[i] = shProg->Uniforms->ParameterValues[location + c][r];
990 }
991 else
992 for (i = 0; i < uSize; i++) {
993 params[i] = shProg->Uniforms->ParameterValues[location][i];
994 }
Brian5b01c5e2006-12-19 18:02:03 -0700995 }
996 else {
997 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(location)");
998 }
999 }
1000 else {
Brian43975832007-01-04 08:21:09 -07001001 _mesa_error(ctx, GL_INVALID_VALUE, "glGetUniformfv(program)");
Brian5b01c5e2006-12-19 18:02:03 -07001002 }
1003}
1004
1005
1006/**
1007 * Called via ctx->Driver.GetUniformLocation().
1008 */
1009GLint
1010_mesa_get_uniform_location(GLcontext *ctx, GLuint program, const GLchar *name)
1011{
Brian71623982007-01-30 16:55:03 -07001012 struct gl_shader_program *shProg
1013 = _mesa_lookup_shader_program(ctx, program);
1014 if (shProg) {
Brian5b01c5e2006-12-19 18:02:03 -07001015 GLuint loc;
Brian65a18442006-12-19 18:46:56 -07001016 for (loc = 0; loc < shProg->Uniforms->NumParameters; loc++) {
Brian5b01c5e2006-12-19 18:02:03 -07001017 const struct gl_program_parameter *u
Brian65a18442006-12-19 18:46:56 -07001018 = shProg->Uniforms->Parameters + loc;
Brian29053852006-12-21 11:21:26 -07001019 /* XXX this is a temporary simplification / short-cut.
1020 * We need to handle things like "e.c[0].b" as seen in the
1021 * GLSL orange book, page 189.
1022 */
Brian5cf73262007-01-05 16:02:45 -07001023 if ((u->Type == PROGRAM_UNIFORM ||
1024 u->Type == PROGRAM_SAMPLER) && !strcmp(u->Name, name)) {
Brian5b01c5e2006-12-19 18:02:03 -07001025 return loc;
1026 }
1027 }
1028 }
1029 return -1;
1030
1031}
1032
1033
1034GLboolean
1035_mesa_is_program(GLcontext *ctx, GLuint name)
1036{
Brian65a18442006-12-19 18:46:56 -07001037 struct gl_shader_program *shProg = _mesa_lookup_shader_program(ctx, name);
1038 return shProg ? GL_TRUE : GL_FALSE;
Brian5b01c5e2006-12-19 18:02:03 -07001039}
1040
1041
1042GLboolean
1043_mesa_is_shader(GLcontext *ctx, GLuint name)
1044{
Brian65a18442006-12-19 18:46:56 -07001045 struct gl_shader *shader = _mesa_lookup_shader(ctx, name);
Brian5b01c5e2006-12-19 18:02:03 -07001046 return shader ? GL_TRUE : GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -07001047}
1048
1049
1050
Brian5b01c5e2006-12-19 18:02:03 -07001051/**
1052 * Called via ctx->Driver.ShaderSource()
1053 */
1054void
1055_mesa_shader_source(GLcontext *ctx, GLuint shader, const GLchar *source)
Brian34ae99d2006-12-18 08:28:54 -07001056{
Brian65a18442006-12-19 18:46:56 -07001057 struct gl_shader *sh = _mesa_lookup_shader(ctx, shader);
1058 if (!sh) {
Brian5b01c5e2006-12-19 18:02:03 -07001059 _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSource(shaderObj)");
Brian34ae99d2006-12-18 08:28:54 -07001060 return;
1061 }
1062
Brian34ae99d2006-12-18 08:28:54 -07001063 /* free old shader source string and install new one */
Brian65a18442006-12-19 18:46:56 -07001064 if (sh->Source) {
1065 _mesa_free((void *) sh->Source);
Brian34ae99d2006-12-18 08:28:54 -07001066 }
Brian65a18442006-12-19 18:46:56 -07001067 sh->Source = source;
Brian9e4bae92006-12-20 09:27:42 -07001068 sh->CompileStatus = GL_FALSE;
Brian34ae99d2006-12-18 08:28:54 -07001069}
1070
1071
Brian5b01c5e2006-12-19 18:02:03 -07001072/**
1073 * Called via ctx->Driver.CompileShader()
1074 */
1075void
1076_mesa_compile_shader(GLcontext *ctx, GLuint shaderObj)
Brian34ae99d2006-12-18 08:28:54 -07001077{
Brian65a18442006-12-19 18:46:56 -07001078 struct gl_shader *sh = _mesa_lookup_shader(ctx, shaderObj);
Brian34ae99d2006-12-18 08:28:54 -07001079
Brian65a18442006-12-19 18:46:56 -07001080 if (!sh) {
Brian34ae99d2006-12-18 08:28:54 -07001081 _mesa_error(ctx, GL_INVALID_VALUE, "glCompileShader(shaderObj)");
1082 return;
1083 }
1084
Brian43975832007-01-04 08:21:09 -07001085 sh->CompileStatus = _slang_compile(ctx, sh);
Brian34ae99d2006-12-18 08:28:54 -07001086}
1087
1088
Brian5b01c5e2006-12-19 18:02:03 -07001089/**
1090 * Called via ctx->Driver.LinkProgram()
1091 */
1092void
1093_mesa_link_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001094{
Brian65a18442006-12-19 18:46:56 -07001095 struct gl_shader_program *shProg;
Brian34ae99d2006-12-18 08:28:54 -07001096
Brian65a18442006-12-19 18:46:56 -07001097 shProg = _mesa_lookup_shader_program(ctx, program);
1098 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001099 _mesa_error(ctx, GL_INVALID_VALUE, "glLinkProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001100 return;
1101 }
1102
Brianc1771912007-02-16 09:56:19 -07001103 _slang_link(ctx, program, shProg);
Brian34ae99d2006-12-18 08:28:54 -07001104}
1105
1106
1107/**
Brian5b01c5e2006-12-19 18:02:03 -07001108 * Called via ctx->Driver.UseProgram()
Brian34ae99d2006-12-18 08:28:54 -07001109 */
Brian5b01c5e2006-12-19 18:02:03 -07001110void
1111_mesa_use_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001112{
Brian3c008a02007-04-12 15:22:32 -06001113 struct gl_shader_program *shProg;
1114
Brian00d63aa2007-02-03 11:35:02 -07001115 if (ctx->Shader.CurrentProgram &&
1116 ctx->Shader.CurrentProgram->Name == program) {
1117 /* no-op */
1118 return;
1119 }
1120
1121 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1122
Brian5b01c5e2006-12-19 18:02:03 -07001123 if (program) {
Brian65a18442006-12-19 18:46:56 -07001124 shProg = _mesa_lookup_shader_program(ctx, program);
1125 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001126 _mesa_error(ctx, GL_INVALID_VALUE,
Brian5b01c5e2006-12-19 18:02:03 -07001127 "glUseProgramObjectARB(programObj)");
1128 return;
1129 }
Brian5b01c5e2006-12-19 18:02:03 -07001130 }
1131 else {
Brian3c008a02007-04-12 15:22:32 -06001132 shProg = NULL;
1133 }
1134
1135 _mesa_reference_shader_program(ctx, &ctx->Shader.CurrentProgram, shProg);
Brian5b01c5e2006-12-19 18:02:03 -07001136}
Brian34ae99d2006-12-18 08:28:54 -07001137
Brian5b01c5e2006-12-19 18:02:03 -07001138
1139/**
1140 * Called via ctx->Driver.Uniform().
1141 */
1142void
1143_mesa_uniform(GLcontext *ctx, GLint location, GLsizei count,
1144 const GLvoid *values, GLenum type)
1145{
Brian3a8e2772006-12-20 17:19:16 -07001146 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
Brian98650bd2007-03-13 16:32:48 -06001147 GLint elems, i, k;
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001148 GLenum uType;
1149 GLsizei maxCount;
Brian3a8e2772006-12-20 17:19:16 -07001150
1151 if (!shProg || !shProg->LinkStatus) {
Brian5b01c5e2006-12-19 18:02:03 -07001152 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(program not linked)");
Brian3a8e2772006-12-20 17:19:16 -07001153 return;
1154 }
1155
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001156 if (location == -1)
1157 return; /* The standard specifies this as a no-op */
1158
Bruce Merry89b80322007-12-21 15:20:17 +02001159 /* The spec says this is GL_INVALID_OPERATION, although it seems like it
1160 * ought to be GL_INVALID_VALUE
1161 */
Brian223d7cb2007-01-23 16:37:51 -07001162 if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) {
Bruce Merry89b80322007-12-21 15:20:17 +02001163 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(location)");
Brian3a8e2772006-12-20 17:19:16 -07001164 return;
1165 }
1166
1167 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1168
Bruce Merry89b80322007-12-21 15:20:17 +02001169 uType = shProg->Uniforms->Parameters[location].DataType;
Brianfee9bbe2007-02-02 18:05:43 -07001170 /*
1171 * If we're setting a sampler, we must use glUniformi1()!
1172 */
Bruce Merry89b80322007-12-21 15:20:17 +02001173 if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
Brian3e4302f2007-05-09 08:04:32 -06001174 GLint unit;
Brianfee9bbe2007-02-02 18:05:43 -07001175 if (type != GL_INT || count != 1) {
1176 _mesa_error(ctx, GL_INVALID_OPERATION,
1177 "glUniform(only glUniform1i can be used "
1178 "to set sampler uniforms)");
1179 return;
1180 }
Brian3e4302f2007-05-09 08:04:32 -06001181 /* check that the sampler (tex unit index) is legal */
1182 unit = ((GLint *) values)[0];
1183 if (unit >= ctx->Const.MaxTextureImageUnits) {
1184 _mesa_error(ctx, GL_INVALID_VALUE,
1185 "glUniform1(invalid sampler/tex unit index)");
1186 return;
1187 }
Brianfee9bbe2007-02-02 18:05:43 -07001188 }
1189
Brian52363952007-03-13 16:50:24 -06001190 if (count < 0) {
1191 _mesa_error(ctx, GL_INVALID_VALUE, "glUniform(count < 0)");
1192 return;
1193 }
1194
Brian98650bd2007-03-13 16:32:48 -06001195 switch (type) {
1196 case GL_FLOAT:
1197 case GL_INT:
1198 elems = 1;
1199 break;
1200 case GL_FLOAT_VEC2:
1201 case GL_INT_VEC2:
1202 elems = 2;
1203 break;
1204 case GL_FLOAT_VEC3:
1205 case GL_INT_VEC3:
1206 elems = 3;
1207 break;
1208 case GL_FLOAT_VEC4:
1209 case GL_INT_VEC4:
1210 elems = 4;
1211 break;
1212 default:
1213 _mesa_problem(ctx, "Invalid type in _mesa_uniform");
1214 return;
Brian89dc4852007-01-04 14:35:44 -07001215 }
Brian98650bd2007-03-13 16:32:48 -06001216
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001217 /* OpenGL requires types to match exactly, except that one can convert
1218 * float or int array to boolean array.
1219 */
1220 switch (uType)
1221 {
1222 case GL_BOOL:
1223 case GL_BOOL_VEC2:
1224 case GL_BOOL_VEC3:
1225 case GL_BOOL_VEC4:
Bruce Merry89b80322007-12-21 15:20:17 +02001226 if (elems != sizeof_glsl_type(uType)) {
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001227 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(count mismatch)");
1228 }
1229 break;
1230 case PROGRAM_SAMPLER:
1231 break;
1232 default:
Bruce Merry89b80322007-12-21 15:20:17 +02001233 if (shProg->Uniforms->Parameters[location].Type != PROGRAM_SAMPLER
1234 && uType != type) {
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001235 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniform(type mismatch)");
1236 }
1237 break;
Brian98650bd2007-03-13 16:32:48 -06001238 }
1239
Bruce Merryeeb03fa2007-12-21 14:41:45 +02001240 /* XXX if this is a base type, then count must equal 1. However, we
1241 * don't have enough information from the compiler to distinguish a
1242 * base type from a 1-element array of that type. The standard allows
1243 * count to overrun an array, in which case the overflow is ignored.
1244 */
1245 maxCount = shProg->Uniforms->Parameters[location].Size / elems;
1246 if (count > maxCount) count = maxCount;
1247
Brian98650bd2007-03-13 16:32:48 -06001248 for (k = 0; k < count; k++) {
1249 GLfloat *uniformVal = shProg->Uniforms->ParameterValues[location + k];
1250 if (type == GL_INT ||
1251 type == GL_INT_VEC2 ||
1252 type == GL_INT_VEC3 ||
1253 type == GL_INT_VEC4) {
Brian52363952007-03-13 16:50:24 -06001254 const GLint *iValues = ((const GLint *) values) + k * elems;
Brian98650bd2007-03-13 16:32:48 -06001255 for (i = 0; i < elems; i++) {
1256 uniformVal[i] = (GLfloat) iValues[i];
1257 }
1258 }
1259 else {
Brian52363952007-03-13 16:50:24 -06001260 const GLfloat *fValues = ((const GLfloat *) values) + k * elems;
Brian98650bd2007-03-13 16:32:48 -06001261 for (i = 0; i < elems; i++) {
1262 uniformVal[i] = fValues[i];
1263 }
Brian89dc4852007-01-04 14:35:44 -07001264 }
Bruce Merry2bf2a8c2007-12-21 23:18:40 +02001265 if (uType == GL_BOOL ||
1266 uType == GL_BOOL_VEC2 ||
1267 uType == GL_BOOL_VEC3 ||
1268 uType == GL_BOOL_VEC4) {
1269 for (i = 0; i < elems; i++)
1270 uniformVal[i] = uniformVal[i] ? 1.0f : 0.0f;
1271 }
Brian5b01c5e2006-12-19 18:02:03 -07001272 }
Brian5cf73262007-01-05 16:02:45 -07001273
1274 if (shProg->Uniforms->Parameters[location].Type == PROGRAM_SAMPLER) {
Briancec81ee2007-03-07 08:04:06 -07001275 if (shProg->VertexProgram)
1276 _slang_resolve_samplers(shProg, &shProg->VertexProgram->Base);
1277 if (shProg->FragmentProgram)
1278 _slang_resolve_samplers(shProg, &shProg->FragmentProgram->Base);
Brian5cf73262007-01-05 16:02:45 -07001279 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
1280 }
Brian34ae99d2006-12-18 08:28:54 -07001281}
1282
1283
1284/**
Brian5b01c5e2006-12-19 18:02:03 -07001285 * Called by ctx->Driver.UniformMatrix().
Brian34ae99d2006-12-18 08:28:54 -07001286 */
Brian5b01c5e2006-12-19 18:02:03 -07001287void
1288_mesa_uniform_matrix(GLcontext *ctx, GLint cols, GLint rows,
1289 GLenum matrixType, GLint location, GLsizei count,
1290 GLboolean transpose, const GLfloat *values)
Brian34ae99d2006-12-18 08:28:54 -07001291{
Bruce Merry3f948022007-12-21 16:04:43 +02001292 GLsizei maxCount, i;
Brian3a8e2772006-12-20 17:19:16 -07001293 struct gl_shader_program *shProg = ctx->Shader.CurrentProgram;
1294 if (!shProg || !shProg->LinkStatus) {
1295 _mesa_error(ctx, GL_INVALID_OPERATION,
1296 "glUniformMatrix(program not linked)");
1297 return;
1298 }
Bruce Merry89b80322007-12-21 15:20:17 +02001299 if (location == -1)
1300 return; /* The standard specifies this as a no-op */
1301 /* The spec says this is GL_INVALID_OPERATION, although it seems like it
1302 * ought to be GL_INVALID_VALUE
1303 */
1304 if (location < 0 || location >= (GLint) shProg->Uniforms->NumParameters) {
1305 _mesa_error(ctx, GL_INVALID_OPERATION, "glUniformMatrix(location)");
Brian3a8e2772006-12-20 17:19:16 -07001306 return;
1307 }
Brian34ae99d2006-12-18 08:28:54 -07001308 if (values == NULL) {
Brian3a8e2772006-12-20 17:19:16 -07001309 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix");
Brian34ae99d2006-12-18 08:28:54 -07001310 return;
1311 }
Bruce Merry3f948022007-12-21 16:04:43 +02001312 if (count < 0) {
1313 _mesa_error(ctx, GL_INVALID_VALUE, "glUniformMatrix(count < 0)");
1314 return;
1315 }
Brian34ae99d2006-12-18 08:28:54 -07001316
1317 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
1318
Brian3a8e2772006-12-20 17:19:16 -07001319 /*
1320 * Note: the _columns_ of a matrix are stored in program registers, not
1321 * the rows.
1322 */
1323 /* XXXX need to test 3x3 and 2x2 matrices... */
Bruce Merry3f948022007-12-21 16:04:43 +02001324 maxCount = shProg->Uniforms->Parameters[location].Size / (4 * cols);
1325 if (count > maxCount)
1326 count = maxCount;
1327 for (i = 0; i < count; i++) {
1328 if (transpose) {
1329 GLuint row, col;
1330 for (col = 0; col < cols; col++) {
1331 GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
1332 for (row = 0; row < rows; row++) {
1333 v[row] = values[row * cols + col];
1334 }
Brian34ae99d2006-12-18 08:28:54 -07001335 }
Brian34ae99d2006-12-18 08:28:54 -07001336 }
Bruce Merry3f948022007-12-21 16:04:43 +02001337 else {
1338 GLuint row, col;
1339 for (col = 0; col < cols; col++) {
1340 GLfloat *v = shProg->Uniforms->ParameterValues[location + col];
1341 for (row = 0; row < rows; row++) {
1342 v[row] = values[col * rows + row];
1343 }
Brian3a8e2772006-12-20 17:19:16 -07001344 }
1345 }
Bruce Merry3f948022007-12-21 16:04:43 +02001346 location += cols;
1347 values += rows * cols;
Brian34ae99d2006-12-18 08:28:54 -07001348 }
1349}
1350
1351
Brian5b01c5e2006-12-19 18:02:03 -07001352void
1353_mesa_validate_program(GLcontext *ctx, GLuint program)
Brian34ae99d2006-12-18 08:28:54 -07001354{
Brian65a18442006-12-19 18:46:56 -07001355 struct gl_shader_program *shProg;
1356 shProg = _mesa_lookup_shader_program(ctx, program);
1357 if (!shProg) {
Brian43975832007-01-04 08:21:09 -07001358 _mesa_error(ctx, GL_INVALID_VALUE, "glValidateProgram(program)");
Brian34ae99d2006-12-18 08:28:54 -07001359 return;
1360 }
Brian5b01c5e2006-12-19 18:02:03 -07001361 /* XXX temporary */
Brian65a18442006-12-19 18:46:56 -07001362 shProg->Validated = GL_TRUE;
Brian34ae99d2006-12-18 08:28:54 -07001363
Brian5b01c5e2006-12-19 18:02:03 -07001364 /* From the GL spec:
1365 any two active samplers in the current program object are of
1366 different types, but refer to the same texture image unit,
1367
1368 any active sampler in the current program object refers to a texture
1369 image unit where fixed-function fragment processing accesses a
1370 texture target that does not match the sampler type, or
1371
1372 the sum of the number of active samplers in the program and the
1373 number of texture image units enabled for fixed-function fragment
1374 processing exceeds the combined limit on the total number of texture
1375 image units allowed.
1376 */
Brian34ae99d2006-12-18 08:28:54 -07001377}