3cb26109508ea5d1b79cb6efe15c06cc4ad74e6b
[mesa.git] / src / mesa / shader / arbprogram.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.0
4 *
5 * Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
6 *
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 arbprogram.c
27 * ARB_vertex/fragment_program state management functions.
28 * \author Brian Paul
29 */
30
31
32 #include "main/glheader.h"
33 #include "main/context.h"
34 #include "main/hash.h"
35 #include "main/imports.h"
36 #include "main/macros.h"
37 #include "main/mtypes.h"
38 #include "arbprogram.h"
39 #include "arbprogparse.h"
40 #include "nvfragparse.h"
41 #include "nvvertparse.h"
42 #include "program.h"
43
44
45
46 /**
47 * Mixing ARB and NV vertex/fragment programs can be tricky.
48 * Note: GL_VERTEX_PROGRAM_ARB == GL_VERTEX_PROGRAM_NV
49 * but, GL_FRAGMENT_PROGRAM_ARB != GL_FRAGMENT_PROGRAM_NV
50 * The two different fragment program targets are supposed to be compatible
51 * to some extent (see GL_ARB_fragment_program spec).
52 * This function does the compatibility check.
53 */
54 static GLboolean
55 compatible_program_targets(GLenum t1, GLenum t2)
56 {
57 if (t1 == t2)
58 return GL_TRUE;
59 if (t1 == GL_FRAGMENT_PROGRAM_ARB && t2 == GL_FRAGMENT_PROGRAM_NV)
60 return GL_TRUE;
61 if (t1 == GL_FRAGMENT_PROGRAM_NV && t2 == GL_FRAGMENT_PROGRAM_ARB)
62 return GL_TRUE;
63 return GL_FALSE;
64 }
65
66
67 /**
68 * Bind a program (make it current)
69 * \note Called from the GL API dispatcher by both glBindProgramNV
70 * and glBindProgramARB.
71 */
72 void GLAPIENTRY
73 _mesa_BindProgram(GLenum target, GLuint id)
74 {
75 struct gl_program *curProg, *newProg;
76 GET_CURRENT_CONTEXT(ctx);
77 ASSERT_OUTSIDE_BEGIN_END(ctx);
78
79 /* Error-check target and get curProg */
80 if ((target == GL_VERTEX_PROGRAM_ARB) && /* == GL_VERTEX_PROGRAM_NV */
81 (ctx->Extensions.NV_vertex_program ||
82 ctx->Extensions.ARB_vertex_program)) {
83 curProg = &ctx->VertexProgram.Current->Base;
84 }
85 else if ((target == GL_FRAGMENT_PROGRAM_NV
86 && ctx->Extensions.NV_fragment_program) ||
87 (target == GL_FRAGMENT_PROGRAM_ARB
88 && ctx->Extensions.ARB_fragment_program)) {
89 curProg = &ctx->FragmentProgram.Current->Base;
90 }
91 else {
92 _mesa_error(ctx, GL_INVALID_ENUM, "glBindProgramNV/ARB(target)");
93 return;
94 }
95
96 /*
97 * Get pointer to new program to bind.
98 * NOTE: binding to a non-existant program is not an error.
99 * That's supposed to be caught in glBegin.
100 */
101 if (id == 0) {
102 /* Bind a default program */
103 newProg = NULL;
104 if (target == GL_VERTEX_PROGRAM_ARB) /* == GL_VERTEX_PROGRAM_NV */
105 newProg = &ctx->Shared->DefaultVertexProgram->Base;
106 else
107 newProg = &ctx->Shared->DefaultFragmentProgram->Base;
108 }
109 else {
110 /* Bind a user program */
111 newProg = _mesa_lookup_program(ctx, id);
112 if (!newProg || newProg == &_mesa_DummyProgram) {
113 /* allocate a new program now */
114 newProg = ctx->Driver.NewProgram(ctx, target, id);
115 if (!newProg) {
116 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glBindProgramNV/ARB");
117 return;
118 }
119 _mesa_HashInsert(ctx->Shared->Programs, id, newProg);
120 }
121 else if (!compatible_program_targets(newProg->Target, target)) {
122 _mesa_error(ctx, GL_INVALID_OPERATION,
123 "glBindProgramNV/ARB(target mismatch)");
124 return;
125 }
126 }
127
128 /** All error checking is complete now **/
129
130 if (curProg->Id == id) {
131 /* binding same program - no change */
132 return;
133 }
134
135 /* signal new program (and its new constants) */
136 FLUSH_VERTICES(ctx, _NEW_PROGRAM | _NEW_PROGRAM_CONSTANTS);
137
138 /* bind newProg */
139 if (target == GL_VERTEX_PROGRAM_ARB) { /* == GL_VERTEX_PROGRAM_NV */
140 _mesa_reference_vertprog(ctx, &ctx->VertexProgram.Current,
141 (struct gl_vertex_program *) newProg);
142 }
143 else if (target == GL_FRAGMENT_PROGRAM_NV ||
144 target == GL_FRAGMENT_PROGRAM_ARB) {
145 _mesa_reference_fragprog(ctx, &ctx->FragmentProgram.Current,
146 (struct gl_fragment_program *) newProg);
147 }
148
149 /* Never null pointers */
150 ASSERT(ctx->VertexProgram.Current);
151 ASSERT(ctx->FragmentProgram.Current);
152
153 if (ctx->Driver.BindProgram)
154 ctx->Driver.BindProgram(ctx, target, newProg);
155 }
156
157
158 /**
159 * Delete a list of programs.
160 * \note Not compiled into display lists.
161 * \note Called by both glDeleteProgramsNV and glDeleteProgramsARB.
162 */
163 void GLAPIENTRY
164 _mesa_DeletePrograms(GLsizei n, const GLuint *ids)
165 {
166 GLint i;
167 GET_CURRENT_CONTEXT(ctx);
168 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx);
169
170 if (n < 0) {
171 _mesa_error( ctx, GL_INVALID_VALUE, "glDeleteProgramsNV" );
172 return;
173 }
174
175 for (i = 0; i < n; i++) {
176 if (ids[i] != 0) {
177 struct gl_program *prog = _mesa_lookup_program(ctx, ids[i]);
178 if (prog == &_mesa_DummyProgram) {
179 _mesa_HashRemove(ctx->Shared->Programs, ids[i]);
180 }
181 else if (prog) {
182 /* Unbind program if necessary */
183 if (prog->Target == GL_VERTEX_PROGRAM_ARB || /* == GL_VERTEX_PROGRAM_NV */
184 prog->Target == GL_VERTEX_STATE_PROGRAM_NV) {
185 if (ctx->VertexProgram.Current &&
186 ctx->VertexProgram.Current->Base.Id == ids[i]) {
187 /* unbind this currently bound program */
188 _mesa_BindProgram(prog->Target, 0);
189 }
190 }
191 else if (prog->Target == GL_FRAGMENT_PROGRAM_NV ||
192 prog->Target == GL_FRAGMENT_PROGRAM_ARB) {
193 if (ctx->FragmentProgram.Current &&
194 ctx->FragmentProgram.Current->Base.Id == ids[i]) {
195 /* unbind this currently bound program */
196 _mesa_BindProgram(prog->Target, 0);
197 }
198 }
199 else {
200 _mesa_problem(ctx, "bad target in glDeleteProgramsNV");
201 return;
202 }
203 /* The ID is immediately available for re-use now */
204 _mesa_HashRemove(ctx->Shared->Programs, ids[i]);
205 _mesa_reference_program(ctx, &prog, NULL);
206 }
207 }
208 }
209 }
210
211
212 /**
213 * Generate a list of new program identifiers.
214 * \note Not compiled into display lists.
215 * \note Called by both glGenProgramsNV and glGenProgramsARB.
216 */
217 void GLAPIENTRY
218 _mesa_GenPrograms(GLsizei n, GLuint *ids)
219 {
220 GLuint first;
221 GLuint i;
222 GET_CURRENT_CONTEXT(ctx);
223 ASSERT_OUTSIDE_BEGIN_END(ctx);
224
225 if (n < 0) {
226 _mesa_error(ctx, GL_INVALID_VALUE, "glGenPrograms");
227 return;
228 }
229
230 if (!ids)
231 return;
232
233 first = _mesa_HashFindFreeKeyBlock(ctx->Shared->Programs, n);
234
235 /* Insert pointer to dummy program as placeholder */
236 for (i = 0; i < (GLuint) n; i++) {
237 _mesa_HashInsert(ctx->Shared->Programs, first + i, &_mesa_DummyProgram);
238 }
239
240 /* Return the program names */
241 for (i = 0; i < (GLuint) n; i++) {
242 ids[i] = first + i;
243 }
244 }
245
246
247 void GLAPIENTRY
248 _mesa_EnableVertexAttribArrayARB(GLuint index)
249 {
250 GET_CURRENT_CONTEXT(ctx);
251 ASSERT_OUTSIDE_BEGIN_END(ctx);
252
253 if (index >= ctx->Const.VertexProgram.MaxAttribs) {
254 _mesa_error(ctx, GL_INVALID_VALUE,
255 "glEnableVertexAttribArrayARB(index)");
256 return;
257 }
258
259 ASSERT(index < Elements(ctx->Array.ArrayObj->VertexAttrib));
260
261 FLUSH_VERTICES(ctx, _NEW_ARRAY);
262 ctx->Array.ArrayObj->VertexAttrib[index].Enabled = GL_TRUE;
263 ctx->Array.ArrayObj->_Enabled |= _NEW_ARRAY_ATTRIB(index);
264 ctx->Array.NewState |= _NEW_ARRAY_ATTRIB(index);
265 }
266
267
268 void GLAPIENTRY
269 _mesa_DisableVertexAttribArrayARB(GLuint index)
270 {
271 GET_CURRENT_CONTEXT(ctx);
272 ASSERT_OUTSIDE_BEGIN_END(ctx);
273
274 if (index >= ctx->Const.VertexProgram.MaxAttribs) {
275 _mesa_error(ctx, GL_INVALID_VALUE,
276 "glEnableVertexAttribArrayARB(index)");
277 return;
278 }
279
280 ASSERT(index < Elements(ctx->Array.ArrayObj->VertexAttrib));
281
282 FLUSH_VERTICES(ctx, _NEW_ARRAY);
283 ctx->Array.ArrayObj->VertexAttrib[index].Enabled = GL_FALSE;
284 ctx->Array.ArrayObj->_Enabled &= ~_NEW_ARRAY_ATTRIB(index);
285 ctx->Array.NewState |= _NEW_ARRAY_ATTRIB(index);
286 }
287
288
289 void GLAPIENTRY
290 _mesa_GetVertexAttribdvARB(GLuint index, GLenum pname, GLdouble *params)
291 {
292 GLfloat fparams[4];
293 GET_CURRENT_CONTEXT(ctx);
294 ASSERT_OUTSIDE_BEGIN_END(ctx);
295
296 _mesa_GetVertexAttribfvARB(index, pname, fparams);
297 if (ctx->ErrorValue == GL_NO_ERROR) {
298 if (pname == GL_CURRENT_VERTEX_ATTRIB_ARB) {
299 COPY_4V(params, fparams);
300 }
301 else {
302 params[0] = fparams[0];
303 }
304 }
305 }
306
307
308 /**
309 * Return info for a generic vertex attribute array (no alias with
310 * legacy vertex attributes (pos, normal, color, etc)).
311 */
312 void GLAPIENTRY
313 _mesa_GetVertexAttribfvARB(GLuint index, GLenum pname, GLfloat *params)
314 {
315 const struct gl_client_array *array;
316 GET_CURRENT_CONTEXT(ctx);
317 ASSERT_OUTSIDE_BEGIN_END(ctx);
318
319 if (index >= MAX_VERTEX_GENERIC_ATTRIBS) {
320 _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribfvARB(index)");
321 return;
322 }
323
324 ASSERT(index < Elements(ctx->Array.ArrayObj->VertexAttrib));
325
326 array = &ctx->Array.ArrayObj->VertexAttrib[index];
327
328 switch (pname) {
329 case GL_VERTEX_ATTRIB_ARRAY_ENABLED_ARB:
330 params[0] = (GLfloat) array->Enabled;
331 break;
332 case GL_VERTEX_ATTRIB_ARRAY_SIZE_ARB:
333 params[0] = (GLfloat) array->Size;
334 break;
335 case GL_VERTEX_ATTRIB_ARRAY_STRIDE_ARB:
336 params[0] = (GLfloat) array->Stride;
337 break;
338 case GL_VERTEX_ATTRIB_ARRAY_TYPE_ARB:
339 params[0] = (GLfloat) array->Type;
340 break;
341 case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED_ARB:
342 params[0] = array->Normalized;
343 break;
344 case GL_CURRENT_VERTEX_ATTRIB_ARB:
345 if (index == 0) {
346 _mesa_error(ctx, GL_INVALID_OPERATION,
347 "glGetVertexAttribfvARB(index==0)");
348 return;
349 }
350 FLUSH_CURRENT(ctx, 0);
351 COPY_4V(params, ctx->Current.Attrib[VERT_ATTRIB_GENERIC0 + index]);
352 break;
353 case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING_ARB:
354 params[0] = (GLfloat) array->BufferObj->Name;
355 break;
356 default:
357 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribfvARB(pname)");
358 return;
359 }
360 }
361
362
363 void GLAPIENTRY
364 _mesa_GetVertexAttribivARB(GLuint index, GLenum pname, GLint *params)
365 {
366 GLfloat fparams[4];
367 GET_CURRENT_CONTEXT(ctx);
368 ASSERT_OUTSIDE_BEGIN_END(ctx);
369
370 _mesa_GetVertexAttribfvARB(index, pname, fparams);
371 if (ctx->ErrorValue == GL_NO_ERROR) {
372 if (pname == GL_CURRENT_VERTEX_ATTRIB_ARB) {
373 COPY_4V_CAST(params, fparams, GLint); /* float to int */
374 }
375 else {
376 params[0] = (GLint) fparams[0];
377 }
378 }
379 }
380
381
382 void GLAPIENTRY
383 _mesa_GetVertexAttribPointervARB(GLuint index, GLenum pname, GLvoid **pointer)
384 {
385 GET_CURRENT_CONTEXT(ctx);
386 ASSERT_OUTSIDE_BEGIN_END(ctx);
387
388 if (index >= ctx->Const.VertexProgram.MaxAttribs) {
389 _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribPointerARB(index)");
390 return;
391 }
392
393 if (pname != GL_VERTEX_ATTRIB_ARRAY_POINTER_ARB) {
394 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribPointerARB(pname)");
395 return;
396 }
397
398 ASSERT(index < Elements(ctx->Array.ArrayObj->VertexAttrib));
399
400 *pointer = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[index].Ptr;
401 }
402
403
404 /**
405 * Determine if id names a vertex or fragment program.
406 * \note Not compiled into display lists.
407 * \note Called from both glIsProgramNV and glIsProgramARB.
408 * \param id is the program identifier
409 * \return GL_TRUE if id is a program, else GL_FALSE.
410 */
411 GLboolean GLAPIENTRY
412 _mesa_IsProgramARB(GLuint id)
413 {
414 struct gl_program *prog = NULL;
415 GET_CURRENT_CONTEXT(ctx);
416 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
417
418 if (id == 0)
419 return GL_FALSE;
420
421 prog = _mesa_lookup_program(ctx, id);
422 if (prog && (prog != &_mesa_DummyProgram))
423 return GL_TRUE;
424 else
425 return GL_FALSE;
426 }
427
428
429 void GLAPIENTRY
430 _mesa_ProgramStringARB(GLenum target, GLenum format, GLsizei len,
431 const GLvoid *string)
432 {
433 struct gl_program *base;
434 GET_CURRENT_CONTEXT(ctx);
435 ASSERT_OUTSIDE_BEGIN_END(ctx);
436
437 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
438
439 if (!ctx->Extensions.ARB_vertex_program
440 && !ctx->Extensions.ARB_fragment_program) {
441 _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramStringARB()");
442 return;
443 }
444
445 if (format != GL_PROGRAM_FORMAT_ASCII_ARB) {
446 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(format)");
447 return;
448 }
449
450 /* The first couple cases are complicated. The same enum value is used for
451 * ARB and NV vertex programs. If the target is a vertex program, parse it
452 * using the ARB grammar if the string starts with "!!ARB" or if
453 * NV_vertex_program is not supported.
454 */
455 if (target == GL_VERTEX_PROGRAM_ARB
456 && ctx->Extensions.ARB_vertex_program
457 && ((strncmp(string, "!!ARB", 5) == 0)
458 || !ctx->Extensions.NV_vertex_program)) {
459 struct gl_vertex_program *prog = ctx->VertexProgram.Current;
460 _mesa_parse_arb_vertex_program(ctx, target, string, len, prog);
461
462 base = & prog->Base;
463 }
464 else if ((target == GL_VERTEX_PROGRAM_ARB
465 || target == GL_VERTEX_STATE_PROGRAM_NV)
466 && ctx->Extensions.NV_vertex_program) {
467 struct gl_vertex_program *prog = ctx->VertexProgram.Current;
468 _mesa_parse_nv_vertex_program(ctx, target, string, len, prog);
469
470 base = & prog->Base;
471 }
472 else if (target == GL_FRAGMENT_PROGRAM_ARB
473 && ctx->Extensions.ARB_fragment_program) {
474 struct gl_fragment_program *prog = ctx->FragmentProgram.Current;
475 _mesa_parse_arb_fragment_program(ctx, target, string, len, prog);
476
477 base = & prog->Base;
478 }
479 else if (target == GL_FRAGMENT_PROGRAM_NV
480 && ctx->Extensions.NV_fragment_program) {
481 struct gl_fragment_program *prog = ctx->FragmentProgram.Current;
482 _mesa_parse_nv_fragment_program(ctx, target, string, len, prog);
483
484 base = & prog->Base;
485 }
486 else {
487 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramStringARB(target)");
488 return;
489 }
490
491 if (ctx->Program.ErrorPos == -1 && ctx->Driver.ProgramStringNotify)
492 ctx->Driver.ProgramStringNotify( ctx, target, base );
493 }
494
495
496 /**
497 * Set a program env parameter register.
498 * \note Called from the GL API dispatcher.
499 * Note, this function is also used by the GL_NV_vertex_program extension
500 * (alias to ProgramParameterdNV)
501 */
502 void GLAPIENTRY
503 _mesa_ProgramEnvParameter4dARB(GLenum target, GLuint index,
504 GLdouble x, GLdouble y, GLdouble z, GLdouble w)
505 {
506 _mesa_ProgramEnvParameter4fARB(target, index, (GLfloat) x, (GLfloat) y,
507 (GLfloat) z, (GLfloat) w);
508 }
509
510
511 /**
512 * Set a program env parameter register.
513 * \note Called from the GL API dispatcher.
514 * Note, this function is also used by the GL_NV_vertex_program extension
515 * (alias to ProgramParameterdvNV)
516 */
517 void GLAPIENTRY
518 _mesa_ProgramEnvParameter4dvARB(GLenum target, GLuint index,
519 const GLdouble *params)
520 {
521 _mesa_ProgramEnvParameter4fARB(target, index, (GLfloat) params[0],
522 (GLfloat) params[1], (GLfloat) params[2],
523 (GLfloat) params[3]);
524 }
525
526
527 /**
528 * Set a program env parameter register.
529 * \note Called from the GL API dispatcher.
530 * Note, this function is also used by the GL_NV_vertex_program extension
531 * (alias to ProgramParameterfNV)
532 */
533 void GLAPIENTRY
534 _mesa_ProgramEnvParameter4fARB(GLenum target, GLuint index,
535 GLfloat x, GLfloat y, GLfloat z, GLfloat w)
536 {
537 GET_CURRENT_CONTEXT(ctx);
538 ASSERT_OUTSIDE_BEGIN_END(ctx);
539
540 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
541
542 if (target == GL_FRAGMENT_PROGRAM_ARB
543 && ctx->Extensions.ARB_fragment_program) {
544 if (index >= ctx->Const.FragmentProgram.MaxEnvParams) {
545 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameter(index)");
546 return;
547 }
548 ASSIGN_4V(ctx->FragmentProgram.Parameters[index], x, y, z, w);
549 }
550 else if (target == GL_VERTEX_PROGRAM_ARB /* == GL_VERTEX_PROGRAM_NV */
551 && (ctx->Extensions.ARB_vertex_program || ctx->Extensions.NV_vertex_program)) {
552 if (index >= ctx->Const.VertexProgram.MaxEnvParams) {
553 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameter(index)");
554 return;
555 }
556 ASSIGN_4V(ctx->VertexProgram.Parameters[index], x, y, z, w);
557 }
558 else {
559 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramEnvParameter(target)");
560 return;
561 }
562 }
563
564
565
566 /**
567 * Set a program env parameter register.
568 * \note Called from the GL API dispatcher.
569 * Note, this function is also used by the GL_NV_vertex_program extension
570 * (alias to ProgramParameterfvNV)
571 */
572 void GLAPIENTRY
573 _mesa_ProgramEnvParameter4fvARB(GLenum target, GLuint index,
574 const GLfloat *params)
575 {
576 GET_CURRENT_CONTEXT(ctx);
577 ASSERT_OUTSIDE_BEGIN_END(ctx);
578
579 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
580
581 if (target == GL_FRAGMENT_PROGRAM_ARB
582 && ctx->Extensions.ARB_fragment_program) {
583 if (index >= ctx->Const.FragmentProgram.MaxEnvParams) {
584 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameter4fv(index)");
585 return;
586 }
587 memcpy(ctx->FragmentProgram.Parameters[index], params,
588 4 * sizeof(GLfloat));
589 }
590 else if (target == GL_VERTEX_PROGRAM_ARB /* == GL_VERTEX_PROGRAM_NV */
591 && (ctx->Extensions.ARB_vertex_program || ctx->Extensions.NV_vertex_program)) {
592 if (index >= ctx->Const.VertexProgram.MaxEnvParams) {
593 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameter4fv(index)");
594 return;
595 }
596 memcpy(ctx->VertexProgram.Parameters[index], params,
597 4 * sizeof(GLfloat));
598 }
599 else {
600 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramEnvParameter4fv(target)");
601 return;
602 }
603 }
604
605
606 void GLAPIENTRY
607 _mesa_ProgramEnvParameters4fvEXT(GLenum target, GLuint index, GLsizei count,
608 const GLfloat *params)
609 {
610 GET_CURRENT_CONTEXT(ctx);
611 GLint i;
612 GLfloat * dest;
613 ASSERT_OUTSIDE_BEGIN_END(ctx);
614
615 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
616
617 if (count <= 0) {
618 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(count)");
619 }
620
621 if (target == GL_FRAGMENT_PROGRAM_ARB
622 && ctx->Extensions.ARB_fragment_program) {
623 if ((index + count) > ctx->Const.FragmentProgram.MaxEnvParams) {
624 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(index + count)");
625 return;
626 }
627 dest = ctx->FragmentProgram.Parameters[index];
628 }
629 else if (target == GL_VERTEX_PROGRAM_ARB
630 && ctx->Extensions.ARB_vertex_program) {
631 if ((index + count) > ctx->Const.VertexProgram.MaxEnvParams) {
632 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramEnvParameters4fv(index + count)");
633 return;
634 }
635 dest = ctx->VertexProgram.Parameters[index];
636 }
637 else {
638 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramEnvParameters4fv(target)");
639 return;
640 }
641
642 for ( i = 0 ; i < count ; i++ ) {
643 COPY_4V(dest, params);
644 params += 4;
645 dest += 4;
646 }
647 }
648
649
650 void GLAPIENTRY
651 _mesa_GetProgramEnvParameterdvARB(GLenum target, GLuint index,
652 GLdouble *params)
653 {
654 GET_CURRENT_CONTEXT(ctx);
655 GLfloat fparams[4];
656
657 _mesa_GetProgramEnvParameterfvARB(target, index, fparams);
658 if (ctx->ErrorValue == GL_NO_ERROR) {
659 params[0] = fparams[0];
660 params[1] = fparams[1];
661 params[2] = fparams[2];
662 params[3] = fparams[3];
663 }
664 }
665
666
667 void GLAPIENTRY
668 _mesa_GetProgramEnvParameterfvARB(GLenum target, GLuint index,
669 GLfloat *params)
670 {
671 GET_CURRENT_CONTEXT(ctx);
672
673 ASSERT_OUTSIDE_BEGIN_END(ctx);
674
675 if (target == GL_FRAGMENT_PROGRAM_ARB
676 && ctx->Extensions.ARB_fragment_program) {
677 if (index >= ctx->Const.FragmentProgram.MaxEnvParams) {
678 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramEnvParameter(index)");
679 return;
680 }
681 COPY_4V(params, ctx->FragmentProgram.Parameters[index]);
682 }
683 else if (target == GL_VERTEX_PROGRAM_ARB
684 && ctx->Extensions.ARB_vertex_program) {
685 if (index >= ctx->Const.VertexProgram.MaxEnvParams) {
686 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramEnvParameter(index)");
687 return;
688 }
689 COPY_4V(params, ctx->VertexProgram.Parameters[index]);
690 }
691 else {
692 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramEnvParameter(target)");
693 return;
694 }
695 }
696
697
698 /**
699 * Note, this function is also used by the GL_NV_fragment_program extension.
700 */
701 void GLAPIENTRY
702 _mesa_ProgramLocalParameter4fARB(GLenum target, GLuint index,
703 GLfloat x, GLfloat y, GLfloat z, GLfloat w)
704 {
705 GET_CURRENT_CONTEXT(ctx);
706 struct gl_program *prog;
707 ASSERT_OUTSIDE_BEGIN_END(ctx);
708
709 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
710
711 if ((target == GL_FRAGMENT_PROGRAM_NV
712 && ctx->Extensions.NV_fragment_program) ||
713 (target == GL_FRAGMENT_PROGRAM_ARB
714 && ctx->Extensions.ARB_fragment_program)) {
715 if (index >= ctx->Const.FragmentProgram.MaxLocalParams) {
716 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameterARB");
717 return;
718 }
719 prog = &(ctx->FragmentProgram.Current->Base);
720 }
721 else if (target == GL_VERTEX_PROGRAM_ARB
722 && ctx->Extensions.ARB_vertex_program) {
723 if (index >= ctx->Const.VertexProgram.MaxLocalParams) {
724 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameterARB");
725 return;
726 }
727 prog = &(ctx->VertexProgram.Current->Base);
728 }
729 else {
730 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramLocalParameterARB");
731 return;
732 }
733
734 ASSERT(index < MAX_PROGRAM_LOCAL_PARAMS);
735 prog->LocalParams[index][0] = x;
736 prog->LocalParams[index][1] = y;
737 prog->LocalParams[index][2] = z;
738 prog->LocalParams[index][3] = w;
739 }
740
741
742 /**
743 * Note, this function is also used by the GL_NV_fragment_program extension.
744 */
745 void GLAPIENTRY
746 _mesa_ProgramLocalParameter4fvARB(GLenum target, GLuint index,
747 const GLfloat *params)
748 {
749 _mesa_ProgramLocalParameter4fARB(target, index, params[0], params[1],
750 params[2], params[3]);
751 }
752
753
754 void GLAPIENTRY
755 _mesa_ProgramLocalParameters4fvEXT(GLenum target, GLuint index, GLsizei count,
756 const GLfloat *params)
757 {
758 GET_CURRENT_CONTEXT(ctx);
759 struct gl_program *prog;
760 GLint i;
761 ASSERT_OUTSIDE_BEGIN_END(ctx);
762
763 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
764
765 if (count <= 0) {
766 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fv(count)");
767 }
768
769 if (target == GL_FRAGMENT_PROGRAM_ARB
770 && ctx->Extensions.ARB_fragment_program) {
771 if ((index + count) > ctx->Const.FragmentProgram.MaxLocalParams) {
772 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fvEXT(index + count)");
773 return;
774 }
775 prog = &(ctx->FragmentProgram.Current->Base);
776 }
777 else if (target == GL_VERTEX_PROGRAM_ARB
778 && ctx->Extensions.ARB_vertex_program) {
779 if ((index + count) > ctx->Const.VertexProgram.MaxLocalParams) {
780 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramLocalParameters4fvEXT(index + count)");
781 return;
782 }
783 prog = &(ctx->VertexProgram.Current->Base);
784 }
785 else {
786 _mesa_error(ctx, GL_INVALID_ENUM, "glProgramLocalParameters4fvEXT(target)");
787 return;
788 }
789
790 for (i = 0; i < count; i++) {
791 ASSERT((index + i) < MAX_PROGRAM_LOCAL_PARAMS);
792 COPY_4V(prog->LocalParams[index + i], params);
793 params += 4;
794 }
795 }
796
797
798 /**
799 * Note, this function is also used by the GL_NV_fragment_program extension.
800 */
801 void GLAPIENTRY
802 _mesa_ProgramLocalParameter4dARB(GLenum target, GLuint index,
803 GLdouble x, GLdouble y,
804 GLdouble z, GLdouble w)
805 {
806 _mesa_ProgramLocalParameter4fARB(target, index, (GLfloat) x, (GLfloat) y,
807 (GLfloat) z, (GLfloat) w);
808 }
809
810
811 /**
812 * Note, this function is also used by the GL_NV_fragment_program extension.
813 */
814 void GLAPIENTRY
815 _mesa_ProgramLocalParameter4dvARB(GLenum target, GLuint index,
816 const GLdouble *params)
817 {
818 _mesa_ProgramLocalParameter4fARB(target, index,
819 (GLfloat) params[0], (GLfloat) params[1],
820 (GLfloat) params[2], (GLfloat) params[3]);
821 }
822
823
824 /**
825 * Note, this function is also used by the GL_NV_fragment_program extension.
826 */
827 void GLAPIENTRY
828 _mesa_GetProgramLocalParameterfvARB(GLenum target, GLuint index,
829 GLfloat *params)
830 {
831 const struct gl_program *prog;
832 GLuint maxParams;
833 GET_CURRENT_CONTEXT(ctx);
834 ASSERT_OUTSIDE_BEGIN_END(ctx);
835
836 if (target == GL_VERTEX_PROGRAM_ARB
837 && ctx->Extensions.ARB_vertex_program) {
838 prog = &(ctx->VertexProgram.Current->Base);
839 maxParams = ctx->Const.VertexProgram.MaxLocalParams;
840 }
841 else if (target == GL_FRAGMENT_PROGRAM_ARB
842 && ctx->Extensions.ARB_fragment_program) {
843 prog = &(ctx->FragmentProgram.Current->Base);
844 maxParams = ctx->Const.FragmentProgram.MaxLocalParams;
845 }
846 else if (target == GL_FRAGMENT_PROGRAM_NV
847 && ctx->Extensions.NV_fragment_program) {
848 prog = &(ctx->FragmentProgram.Current->Base);
849 maxParams = MAX_NV_FRAGMENT_PROGRAM_PARAMS;
850 }
851 else {
852 _mesa_error(ctx, GL_INVALID_ENUM,
853 "glGetProgramLocalParameterARB(target)");
854 return;
855 }
856
857 if (index >= maxParams) {
858 _mesa_error(ctx, GL_INVALID_VALUE,
859 "glGetProgramLocalParameterARB(index)");
860 return;
861 }
862
863 ASSERT(prog);
864 ASSERT(index < MAX_PROGRAM_LOCAL_PARAMS);
865 COPY_4V(params, prog->LocalParams[index]);
866 }
867
868
869 /**
870 * Note, this function is also used by the GL_NV_fragment_program extension.
871 */
872 void GLAPIENTRY
873 _mesa_GetProgramLocalParameterdvARB(GLenum target, GLuint index,
874 GLdouble *params)
875 {
876 GET_CURRENT_CONTEXT(ctx);
877 GLfloat floatParams[4];
878 ASSIGN_4V(floatParams, 0.0F, 0.0F, 0.0F, 0.0F);
879 _mesa_GetProgramLocalParameterfvARB(target, index, floatParams);
880 if (ctx->ErrorValue == GL_NO_ERROR) {
881 COPY_4V(params, floatParams);
882 }
883 }
884
885
886 void GLAPIENTRY
887 _mesa_GetProgramivARB(GLenum target, GLenum pname, GLint *params)
888 {
889 const struct gl_program_constants *limits;
890 struct gl_program *prog;
891 GET_CURRENT_CONTEXT(ctx);
892
893 ASSERT_OUTSIDE_BEGIN_END(ctx);
894
895 if (target == GL_VERTEX_PROGRAM_ARB
896 && ctx->Extensions.ARB_vertex_program) {
897 prog = &(ctx->VertexProgram.Current->Base);
898 limits = &ctx->Const.VertexProgram;
899 }
900 else if (target == GL_FRAGMENT_PROGRAM_ARB
901 && ctx->Extensions.ARB_fragment_program) {
902 prog = &(ctx->FragmentProgram.Current->Base);
903 limits = &ctx->Const.FragmentProgram;
904 }
905 else {
906 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(target)");
907 return;
908 }
909
910 ASSERT(prog);
911 ASSERT(limits);
912
913 /* Queries supported for both vertex and fragment programs */
914 switch (pname) {
915 case GL_PROGRAM_LENGTH_ARB:
916 *params
917 = prog->String ? (GLint) _mesa_strlen((char *) prog->String) : 0;
918 return;
919 case GL_PROGRAM_FORMAT_ARB:
920 *params = prog->Format;
921 return;
922 case GL_PROGRAM_BINDING_ARB:
923 *params = prog->Id;
924 return;
925 case GL_PROGRAM_INSTRUCTIONS_ARB:
926 *params = prog->NumInstructions;
927 return;
928 case GL_MAX_PROGRAM_INSTRUCTIONS_ARB:
929 *params = limits->MaxInstructions;
930 return;
931 case GL_PROGRAM_NATIVE_INSTRUCTIONS_ARB:
932 *params = prog->NumNativeInstructions;
933 return;
934 case GL_MAX_PROGRAM_NATIVE_INSTRUCTIONS_ARB:
935 *params = limits->MaxNativeInstructions;
936 return;
937 case GL_PROGRAM_TEMPORARIES_ARB:
938 *params = prog->NumTemporaries;
939 return;
940 case GL_MAX_PROGRAM_TEMPORARIES_ARB:
941 *params = limits->MaxTemps;
942 return;
943 case GL_PROGRAM_NATIVE_TEMPORARIES_ARB:
944 *params = prog->NumNativeTemporaries;
945 return;
946 case GL_MAX_PROGRAM_NATIVE_TEMPORARIES_ARB:
947 *params = limits->MaxNativeTemps;
948 return;
949 case GL_PROGRAM_PARAMETERS_ARB:
950 *params = prog->NumParameters;
951 return;
952 case GL_MAX_PROGRAM_PARAMETERS_ARB:
953 *params = limits->MaxParameters;
954 return;
955 case GL_PROGRAM_NATIVE_PARAMETERS_ARB:
956 *params = prog->NumNativeParameters;
957 return;
958 case GL_MAX_PROGRAM_NATIVE_PARAMETERS_ARB:
959 *params = limits->MaxNativeParameters;
960 return;
961 case GL_PROGRAM_ATTRIBS_ARB:
962 *params = prog->NumAttributes;
963 return;
964 case GL_MAX_PROGRAM_ATTRIBS_ARB:
965 *params = limits->MaxAttribs;
966 return;
967 case GL_PROGRAM_NATIVE_ATTRIBS_ARB:
968 *params = prog->NumNativeAttributes;
969 return;
970 case GL_MAX_PROGRAM_NATIVE_ATTRIBS_ARB:
971 *params = limits->MaxNativeAttribs;
972 return;
973 case GL_PROGRAM_ADDRESS_REGISTERS_ARB:
974 *params = prog->NumAddressRegs;
975 return;
976 case GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB:
977 *params = limits->MaxAddressRegs;
978 return;
979 case GL_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB:
980 *params = prog->NumNativeAddressRegs;
981 return;
982 case GL_MAX_PROGRAM_NATIVE_ADDRESS_REGISTERS_ARB:
983 *params = limits->MaxNativeAddressRegs;
984 return;
985 case GL_MAX_PROGRAM_LOCAL_PARAMETERS_ARB:
986 *params = limits->MaxLocalParams;
987 return;
988 case GL_MAX_PROGRAM_ENV_PARAMETERS_ARB:
989 *params = limits->MaxEnvParams;
990 return;
991 case GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB:
992 /*
993 * XXX we may not really need a driver callback here.
994 * If the number of native instructions, registers, etc. used
995 * are all below the maximums, we could return true.
996 * The spec says that even if this query returns true, there's
997 * no guarantee that the program will run in hardware.
998 */
999 if (prog->Id == 0) {
1000 /* default/null program */
1001 *params = GL_FALSE;
1002 }
1003 else if (ctx->Driver.IsProgramNative) {
1004 /* ask the driver */
1005 *params = ctx->Driver.IsProgramNative( ctx, target, prog );
1006 }
1007 else {
1008 /* probably running in software */
1009 *params = GL_TRUE;
1010 }
1011 return;
1012 default:
1013 /* continue with fragment-program only queries below */
1014 break;
1015 }
1016
1017 /*
1018 * The following apply to fragment programs only (at this time)
1019 */
1020 if (target == GL_FRAGMENT_PROGRAM_ARB) {
1021 const struct gl_fragment_program *fp = ctx->FragmentProgram.Current;
1022 switch (pname) {
1023 case GL_PROGRAM_ALU_INSTRUCTIONS_ARB:
1024 *params = fp->Base.NumNativeAluInstructions;
1025 return;
1026 case GL_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB:
1027 *params = fp->Base.NumAluInstructions;
1028 return;
1029 case GL_PROGRAM_TEX_INSTRUCTIONS_ARB:
1030 *params = fp->Base.NumTexInstructions;
1031 return;
1032 case GL_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB:
1033 *params = fp->Base.NumNativeTexInstructions;
1034 return;
1035 case GL_PROGRAM_TEX_INDIRECTIONS_ARB:
1036 *params = fp->Base.NumTexIndirections;
1037 return;
1038 case GL_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB:
1039 *params = fp->Base.NumNativeTexIndirections;
1040 return;
1041 case GL_MAX_PROGRAM_ALU_INSTRUCTIONS_ARB:
1042 *params = limits->MaxAluInstructions;
1043 return;
1044 case GL_MAX_PROGRAM_NATIVE_ALU_INSTRUCTIONS_ARB:
1045 *params = limits->MaxNativeAluInstructions;
1046 return;
1047 case GL_MAX_PROGRAM_TEX_INSTRUCTIONS_ARB:
1048 *params = limits->MaxTexInstructions;
1049 return;
1050 case GL_MAX_PROGRAM_NATIVE_TEX_INSTRUCTIONS_ARB:
1051 *params = limits->MaxNativeTexInstructions;
1052 return;
1053 case GL_MAX_PROGRAM_TEX_INDIRECTIONS_ARB:
1054 *params = limits->MaxTexIndirections;
1055 return;
1056 case GL_MAX_PROGRAM_NATIVE_TEX_INDIRECTIONS_ARB:
1057 *params = limits->MaxNativeTexIndirections;
1058 return;
1059 default:
1060 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(pname)");
1061 return;
1062 }
1063 } else {
1064 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivARB(pname)");
1065 return;
1066 }
1067 }
1068
1069
1070 void GLAPIENTRY
1071 _mesa_GetProgramStringARB(GLenum target, GLenum pname, GLvoid *string)
1072 {
1073 const struct gl_program *prog;
1074 char *dst = (char *) string;
1075 GET_CURRENT_CONTEXT(ctx);
1076
1077 ASSERT_OUTSIDE_BEGIN_END(ctx);
1078
1079 if (target == GL_VERTEX_PROGRAM_ARB) {
1080 prog = &(ctx->VertexProgram.Current->Base);
1081 }
1082 else if (target == GL_FRAGMENT_PROGRAM_ARB) {
1083 prog = &(ctx->FragmentProgram.Current->Base);
1084 }
1085 else {
1086 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringARB(target)");
1087 return;
1088 }
1089
1090 ASSERT(prog);
1091
1092 if (pname != GL_PROGRAM_STRING_ARB) {
1093 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringARB(pname)");
1094 return;
1095 }
1096
1097 if (prog->String)
1098 _mesa_memcpy(dst, prog->String, _mesa_strlen((char *) prog->String));
1099 else
1100 *dst = '\0';
1101 }