a2670fda32a586c32f79a9e1dfd9c377c4e72aea
[mesa.git] / src / mesa / main / shaders.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 7.1
4 *
5 * Copyright (C) 2004-2008 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 #include "glheader.h"
27 #include "context.h"
28 #include "shaders.h"
29
30
31 /**
32 * These are basically just wrappers/adaptors for calling the
33 * ctx->Driver.foobar() GLSL-related functions.
34 *
35 * Things are biased toward the OpenGL 2.0 functions rather than the
36 * ARB extensions (i.e. the ARB functions are layered on the 2.0 functions).
37 *
38 * The general idea here is to allow enough modularity such that a
39 * completely different GLSL implemenation can be plugged in and co-exist
40 * with Mesa's native GLSL code.
41 */
42
43
44
45 void GLAPIENTRY
46 _mesa_AttachObjectARB(GLhandleARB program, GLhandleARB shader)
47 {
48 GET_CURRENT_CONTEXT(ctx);
49 ctx->Driver.AttachShader(ctx, program, shader);
50 }
51
52
53 void GLAPIENTRY
54 _mesa_AttachShader(GLuint program, GLuint shader)
55 {
56 GET_CURRENT_CONTEXT(ctx);
57 ctx->Driver.AttachShader(ctx, program, shader);
58 }
59
60
61 void GLAPIENTRY
62 _mesa_BindAttribLocationARB(GLhandleARB program, GLuint index,
63 const GLcharARB *name)
64 {
65 GET_CURRENT_CONTEXT(ctx);
66 ctx->Driver.BindAttribLocation(ctx, program, index, name);
67 }
68
69
70 void GLAPIENTRY
71 _mesa_CompileShaderARB(GLhandleARB shaderObj)
72 {
73 GET_CURRENT_CONTEXT(ctx);
74 ctx->Driver.CompileShader(ctx, shaderObj);
75 }
76
77
78 GLuint GLAPIENTRY
79 _mesa_CreateShader(GLenum type)
80 {
81 GET_CURRENT_CONTEXT(ctx);
82 return ctx->Driver.CreateShader(ctx, type);
83 }
84
85
86 GLhandleARB GLAPIENTRY
87 _mesa_CreateShaderObjectARB(GLenum type)
88 {
89 GET_CURRENT_CONTEXT(ctx);
90 return ctx->Driver.CreateShader(ctx, type);
91 }
92
93
94 GLuint GLAPIENTRY
95 _mesa_CreateProgram(void)
96 {
97 GET_CURRENT_CONTEXT(ctx);
98 return ctx->Driver.CreateProgram(ctx);
99 }
100
101
102 GLhandleARB GLAPIENTRY
103 _mesa_CreateProgramObjectARB(void)
104 {
105 GET_CURRENT_CONTEXT(ctx);
106 return ctx->Driver.CreateProgram(ctx);
107 }
108
109
110 void GLAPIENTRY
111 _mesa_DeleteObjectARB(GLhandleARB obj)
112 {
113 if (obj) {
114 GET_CURRENT_CONTEXT(ctx);
115 if (ctx->Driver.IsProgram(ctx, obj)) {
116 ctx->Driver.DeleteProgram2(ctx, obj);
117 }
118 else if (ctx->Driver.IsShader(ctx, obj)) {
119 ctx->Driver.DeleteShader(ctx, obj);
120 }
121 else {
122 /* error? */
123 }
124 }
125 }
126
127
128 void GLAPIENTRY
129 _mesa_DeleteProgram(GLuint name)
130 {
131 printf("%s name=%u\n", __FUNCTION__, name);
132 if (name) {
133 GET_CURRENT_CONTEXT(ctx);
134 ctx->Driver.DeleteProgram2(ctx, name);
135 }
136 }
137
138
139 void GLAPIENTRY
140 _mesa_DeleteShader(GLuint name)
141 {
142 if (name) {
143 GET_CURRENT_CONTEXT(ctx);
144 ctx->Driver.DeleteShader(ctx, name);
145 }
146 }
147
148
149 void GLAPIENTRY
150 _mesa_DetachObjectARB(GLhandleARB program, GLhandleARB shader)
151 {
152 GET_CURRENT_CONTEXT(ctx);
153 ctx->Driver.DetachShader(ctx, program, shader);
154 }
155
156
157 void GLAPIENTRY
158 _mesa_DetachShader(GLuint program, GLuint shader)
159 {
160 GET_CURRENT_CONTEXT(ctx);
161 ctx->Driver.DetachShader(ctx, program, shader);
162 }
163
164
165 void GLAPIENTRY
166 _mesa_GetActiveAttribARB(GLhandleARB program, GLuint index,
167 GLsizei maxLength, GLsizei * length, GLint * size,
168 GLenum * type, GLcharARB * name)
169 {
170 GET_CURRENT_CONTEXT(ctx);
171 ctx->Driver.GetActiveAttrib(ctx, program, index, maxLength, length, size,
172 type, name);
173 }
174
175
176 void GLAPIENTRY
177 _mesa_GetActiveUniformARB(GLhandleARB program, GLuint index,
178 GLsizei maxLength, GLsizei * length, GLint * size,
179 GLenum * type, GLcharARB * name)
180 {
181 GET_CURRENT_CONTEXT(ctx);
182 ctx->Driver.GetActiveUniform(ctx, program, index, maxLength, length, size,
183 type, name);
184 }
185
186
187 void GLAPIENTRY
188 _mesa_GetAttachedObjectsARB(GLhandleARB container, GLsizei maxCount,
189 GLsizei * count, GLhandleARB * obj)
190 {
191 GET_CURRENT_CONTEXT(ctx);
192 ctx->Driver.GetAttachedShaders(ctx, container, maxCount, count, obj);
193 }
194
195
196 void GLAPIENTRY
197 _mesa_GetAttachedShaders(GLuint program, GLsizei maxCount,
198 GLsizei *count, GLuint *obj)
199 {
200 GET_CURRENT_CONTEXT(ctx);
201 ctx->Driver.GetAttachedShaders(ctx, program, maxCount, count, obj);
202 }
203
204
205 GLint GLAPIENTRY
206 _mesa_GetAttribLocationARB(GLhandleARB program, const GLcharARB * name)
207 {
208 GET_CURRENT_CONTEXT(ctx);
209 return ctx->Driver.GetAttribLocation(ctx, program, name);
210 }
211
212
213 void GLAPIENTRY
214 _mesa_GetInfoLogARB(GLhandleARB object, GLsizei maxLength, GLsizei * length,
215 GLcharARB * infoLog)
216 {
217 GET_CURRENT_CONTEXT(ctx);
218 /* Implement in terms of GetProgramInfoLog, GetShaderInfoLog */
219 if (ctx->Driver.IsProgram(ctx, object)) {
220 ctx->Driver.GetProgramInfoLog(ctx, object, maxLength, length, infoLog);
221 }
222 else if (ctx->Driver.IsShader(ctx, object)) {
223 ctx->Driver.GetShaderInfoLog(ctx, object, maxLength, length, infoLog);
224 }
225 else {
226 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetInfoLogARB");
227 }
228 }
229
230
231 void GLAPIENTRY
232 _mesa_GetObjectParameterivARB(GLhandleARB object, GLenum pname, GLint *params)
233 {
234 GET_CURRENT_CONTEXT(ctx);
235 /* Implement in terms of GetProgramiv, GetShaderiv */
236 if (ctx->Driver.IsProgram(ctx, object)) {
237 ctx->Driver.GetProgramiv(ctx, object, pname, params);
238 }
239 else if (ctx->Driver.IsShader(ctx, object)) {
240 ctx->Driver.GetShaderiv(ctx, object, pname, params);
241 }
242 else {
243 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetObjectParameterivARB");
244 }
245 }
246
247
248 void GLAPIENTRY
249 _mesa_GetObjectParameterfvARB(GLhandleARB object, GLenum pname,
250 GLfloat *params)
251 {
252 GLint iparams[1]; /* XXX is one element enough? */
253 _mesa_GetObjectParameterivARB(object, pname, iparams);
254 params[0] = (GLfloat) iparams[0];
255 }
256
257
258 void GLAPIENTRY
259 _mesa_GetProgramiv(GLuint program, GLenum pname, GLint *params)
260 {
261 GET_CURRENT_CONTEXT(ctx);
262 ctx->Driver.GetProgramiv(ctx, program, pname, params);
263 }
264
265
266 void GLAPIENTRY
267 _mesa_GetShaderiv(GLuint shader, GLenum pname, GLint *params)
268 {
269 GET_CURRENT_CONTEXT(ctx);
270 ctx->Driver.GetShaderiv(ctx, shader, pname, params);
271 }
272
273
274 void GLAPIENTRY
275 _mesa_GetProgramInfoLog(GLuint program, GLsizei bufSize,
276 GLsizei *length, GLchar *infoLog)
277 {
278 GET_CURRENT_CONTEXT(ctx);
279 ctx->Driver.GetProgramInfoLog(ctx, program, bufSize, length, infoLog);
280 }
281
282
283 void GLAPIENTRY
284 _mesa_GetShaderInfoLog(GLuint shader, GLsizei bufSize,
285 GLsizei *length, GLchar *infoLog)
286 {
287 GET_CURRENT_CONTEXT(ctx);
288 ctx->Driver.GetShaderInfoLog(ctx, shader, bufSize, length, infoLog);
289 }
290
291
292 void GLAPIENTRY
293 _mesa_GetShaderSourceARB(GLhandleARB shader, GLsizei maxLength,
294 GLsizei *length, GLcharARB *sourceOut)
295 {
296 GET_CURRENT_CONTEXT(ctx);
297 ctx->Driver.GetShaderSource(ctx, shader, maxLength, length, sourceOut);
298 }
299
300
301 void GLAPIENTRY
302 _mesa_GetUniformfvARB(GLhandleARB program, GLint location, GLfloat * params)
303 {
304 GET_CURRENT_CONTEXT(ctx);
305 ctx->Driver.GetUniformfv(ctx, program, location, params);
306 }
307
308
309 void GLAPIENTRY
310 _mesa_GetUniformivARB(GLhandleARB program, GLint location, GLint * params)
311 {
312 GET_CURRENT_CONTEXT(ctx);
313 ctx->Driver.GetUniformiv(ctx, program, location, params);
314 }
315
316
317
318 #if 0
319 GLint GLAPIENTRY
320 _mesa_GetUniformLocation(GLuint program, const GLcharARB *name)
321 {
322 GET_CURRENT_CONTEXT(ctx);
323 return ctx->Driver.GetUniformLocation(ctx, program, name);
324 }
325 #endif
326
327
328 GLhandleARB GLAPIENTRY
329 _mesa_GetHandleARB(GLenum pname)
330 {
331 GET_CURRENT_CONTEXT(ctx);
332 return ctx->Driver.GetHandle(ctx, pname);
333 }
334
335
336 GLint GLAPIENTRY
337 _mesa_GetUniformLocationARB(GLhandleARB programObj, const GLcharARB *name)
338 {
339 GET_CURRENT_CONTEXT(ctx);
340 return ctx->Driver.GetUniformLocation(ctx, programObj, name);
341 }
342
343
344 GLboolean GLAPIENTRY
345 _mesa_IsProgram(GLuint name)
346 {
347 GET_CURRENT_CONTEXT(ctx);
348 return ctx->Driver.IsProgram(ctx, name);
349 }
350
351
352 GLboolean GLAPIENTRY
353 _mesa_IsShader(GLuint name)
354 {
355 GET_CURRENT_CONTEXT(ctx);
356 return ctx->Driver.IsShader(ctx, name);
357 }
358
359
360 void GLAPIENTRY
361 _mesa_LinkProgramARB(GLhandleARB programObj)
362 {
363 GET_CURRENT_CONTEXT(ctx);
364 ctx->Driver.LinkProgram(ctx, programObj);
365 }
366
367
368 /**
369 * Called via glShaderSource() and glShaderSourceARB() API functions.
370 * Basically, concatenate the source code strings into one long string
371 * and pass it to ctx->Driver.ShaderSource().
372 */
373 void GLAPIENTRY
374 _mesa_ShaderSourceARB(GLhandleARB shaderObj, GLsizei count,
375 const GLcharARB ** string, const GLint * length)
376 {
377 GET_CURRENT_CONTEXT(ctx);
378 GLint *offsets;
379 GLsizei i, totalLength;
380 GLcharARB *source;
381
382 if (!shaderObj || string == NULL) {
383 _mesa_error(ctx, GL_INVALID_VALUE, "glShaderSourceARB");
384 return;
385 }
386
387 /*
388 * This array holds offsets of where the appropriate string ends, thus the
389 * last element will be set to the total length of the source code.
390 */
391 offsets = (GLint *) _mesa_malloc(count * sizeof(GLint));
392 if (offsets == NULL) {
393 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderSourceARB");
394 return;
395 }
396
397 for (i = 0; i < count; i++) {
398 if (string[i] == NULL) {
399 _mesa_free((GLvoid *) offsets);
400 _mesa_error(ctx, GL_INVALID_OPERATION, "glShaderSourceARB(null string)");
401 return;
402 }
403 if (length == NULL || length[i] < 0)
404 offsets[i] = _mesa_strlen(string[i]);
405 else
406 offsets[i] = length[i];
407 /* accumulate string lengths */
408 if (i > 0)
409 offsets[i] += offsets[i - 1];
410 }
411
412 /* Total length of source string is sum off all strings plus two.
413 * One extra byte for terminating zero, another extra byte to silence
414 * valgrind warnings in the parser/grammer code.
415 */
416 totalLength = offsets[count - 1] + 2;
417 source = (GLcharARB *) _mesa_malloc(totalLength * sizeof(GLcharARB));
418 if (source == NULL) {
419 _mesa_free((GLvoid *) offsets);
420 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glShaderSourceARB");
421 return;
422 }
423
424 for (i = 0; i < count; i++) {
425 GLint start = (i > 0) ? offsets[i - 1] : 0;
426 _mesa_memcpy(source + start, string[i],
427 (offsets[i] - start) * sizeof(GLcharARB));
428 }
429 source[totalLength - 1] = '\0';
430 source[totalLength - 2] = '\0';
431
432 ctx->Driver.ShaderSource(ctx, shaderObj, source);
433
434 _mesa_free(offsets);
435 }
436
437
438 void GLAPIENTRY
439 _mesa_Uniform1fARB(GLint location, GLfloat v0)
440 {
441 GET_CURRENT_CONTEXT(ctx);
442 ctx->Driver.Uniform(ctx, location, 1, &v0, GL_FLOAT);
443 }
444
445 void GLAPIENTRY
446 _mesa_Uniform2fARB(GLint location, GLfloat v0, GLfloat v1)
447 {
448 GET_CURRENT_CONTEXT(ctx);
449 GLfloat v[2];
450 v[0] = v0;
451 v[1] = v1;
452 ctx->Driver.Uniform(ctx, location, 1, v, GL_FLOAT_VEC2);
453 }
454
455 void GLAPIENTRY
456 _mesa_Uniform3fARB(GLint location, GLfloat v0, GLfloat v1, GLfloat v2)
457 {
458 GET_CURRENT_CONTEXT(ctx);
459 GLfloat v[3];
460 v[0] = v0;
461 v[1] = v1;
462 v[2] = v2;
463 ctx->Driver.Uniform(ctx, location, 1, v, GL_FLOAT_VEC3);
464 }
465
466 void GLAPIENTRY
467 _mesa_Uniform4fARB(GLint location, GLfloat v0, GLfloat v1, GLfloat v2,
468 GLfloat v3)
469 {
470 GET_CURRENT_CONTEXT(ctx);
471 GLfloat v[4];
472 v[0] = v0;
473 v[1] = v1;
474 v[2] = v2;
475 v[3] = v3;
476 ctx->Driver.Uniform(ctx, location, 1, v, GL_FLOAT_VEC4);
477 }
478
479 void GLAPIENTRY
480 _mesa_Uniform1iARB(GLint location, GLint v0)
481 {
482 GET_CURRENT_CONTEXT(ctx);
483 ctx->Driver.Uniform(ctx, location, 1, &v0, GL_INT);
484 }
485
486 void GLAPIENTRY
487 _mesa_Uniform2iARB(GLint location, GLint v0, GLint v1)
488 {
489 GET_CURRENT_CONTEXT(ctx);
490 GLint v[2];
491 v[0] = v0;
492 v[1] = v1;
493 ctx->Driver.Uniform(ctx, location, 1, v, GL_INT_VEC2);
494 }
495
496 void GLAPIENTRY
497 _mesa_Uniform3iARB(GLint location, GLint v0, GLint v1, GLint v2)
498 {
499 GET_CURRENT_CONTEXT(ctx);
500 GLint v[3];
501 v[0] = v0;
502 v[1] = v1;
503 v[2] = v2;
504 ctx->Driver.Uniform(ctx, location, 1, v, GL_INT_VEC3);
505 }
506
507 void GLAPIENTRY
508 _mesa_Uniform4iARB(GLint location, GLint v0, GLint v1, GLint v2, GLint v3)
509 {
510 GET_CURRENT_CONTEXT(ctx);
511 GLint v[4];
512 v[0] = v0;
513 v[1] = v1;
514 v[2] = v2;
515 v[3] = v3;
516 ctx->Driver.Uniform(ctx, location, 1, v, GL_INT_VEC4);
517 }
518
519 void GLAPIENTRY
520 _mesa_Uniform1fvARB(GLint location, GLsizei count, const GLfloat * value)
521 {
522 GET_CURRENT_CONTEXT(ctx);
523 ctx->Driver.Uniform(ctx, location, count, value, GL_FLOAT);
524 }
525
526 void GLAPIENTRY
527 _mesa_Uniform2fvARB(GLint location, GLsizei count, const GLfloat * value)
528 {
529 GET_CURRENT_CONTEXT(ctx);
530 ctx->Driver.Uniform(ctx, location, count, value, GL_FLOAT_VEC2);
531 }
532
533 void GLAPIENTRY
534 _mesa_Uniform3fvARB(GLint location, GLsizei count, const GLfloat * value)
535 {
536 GET_CURRENT_CONTEXT(ctx);
537 ctx->Driver.Uniform(ctx, location, count, value, GL_FLOAT_VEC3);
538 }
539
540 void GLAPIENTRY
541 _mesa_Uniform4fvARB(GLint location, GLsizei count, const GLfloat * value)
542 {
543 GET_CURRENT_CONTEXT(ctx);
544 ctx->Driver.Uniform(ctx, location, count, value, GL_FLOAT_VEC4);
545 }
546
547 void GLAPIENTRY
548 _mesa_Uniform1ivARB(GLint location, GLsizei count, const GLint * value)
549 {
550 GET_CURRENT_CONTEXT(ctx);
551 ctx->Driver.Uniform(ctx, location, count, value, GL_INT);
552 }
553
554 void GLAPIENTRY
555 _mesa_Uniform2ivARB(GLint location, GLsizei count, const GLint * value)
556 {
557 GET_CURRENT_CONTEXT(ctx);
558 ctx->Driver.Uniform(ctx, location, count, value, GL_INT_VEC2);
559 }
560
561 void GLAPIENTRY
562 _mesa_Uniform3ivARB(GLint location, GLsizei count, const GLint * value)
563 {
564 GET_CURRENT_CONTEXT(ctx);
565 ctx->Driver.Uniform(ctx, location, count, value, GL_INT_VEC3);
566 }
567
568 void GLAPIENTRY
569 _mesa_Uniform4ivARB(GLint location, GLsizei count, const GLint * value)
570 {
571 GET_CURRENT_CONTEXT(ctx);
572 ctx->Driver.Uniform(ctx, location, count, value, GL_INT_VEC4);
573 }
574
575
576 void GLAPIENTRY
577 _mesa_UniformMatrix2fvARB(GLint location, GLsizei count, GLboolean transpose,
578 const GLfloat * value)
579 {
580 GET_CURRENT_CONTEXT(ctx);
581 ctx->Driver.UniformMatrix(ctx, 2, 2, GL_FLOAT_MAT2,
582 location, count, transpose, value);
583 }
584
585 void GLAPIENTRY
586 _mesa_UniformMatrix3fvARB(GLint location, GLsizei count, GLboolean transpose,
587 const GLfloat * value)
588 {
589 GET_CURRENT_CONTEXT(ctx);
590 ctx->Driver.UniformMatrix(ctx, 3, 3, GL_FLOAT_MAT3,
591 location, count, transpose, value);
592 }
593
594 void GLAPIENTRY
595 _mesa_UniformMatrix4fvARB(GLint location, GLsizei count, GLboolean transpose,
596 const GLfloat * value)
597 {
598 GET_CURRENT_CONTEXT(ctx);
599 ctx->Driver.UniformMatrix(ctx, 4, 4, GL_FLOAT_MAT4,
600 location, count, transpose, value);
601 }
602
603
604 /**
605 * Non-square UniformMatrix are OpenGL 2.1
606 */
607 void GLAPIENTRY
608 _mesa_UniformMatrix2x3fv(GLint location, GLsizei count, GLboolean transpose,
609 const GLfloat *value)
610 {
611 GET_CURRENT_CONTEXT(ctx);
612 ctx->Driver.UniformMatrix(ctx, 2, 3, GL_FLOAT_MAT2x3,
613 location, count, transpose, value);
614 }
615
616 void GLAPIENTRY
617 _mesa_UniformMatrix3x2fv(GLint location, GLsizei count, GLboolean transpose,
618 const GLfloat *value)
619 {
620 GET_CURRENT_CONTEXT(ctx);
621 ctx->Driver.UniformMatrix(ctx, 3, 2, GL_FLOAT_MAT3x2,
622 location, count, transpose, value);
623 }
624
625 void GLAPIENTRY
626 _mesa_UniformMatrix2x4fv(GLint location, GLsizei count, GLboolean transpose,
627 const GLfloat *value)
628 {
629 GET_CURRENT_CONTEXT(ctx);
630 ctx->Driver.UniformMatrix(ctx, 2, 4, GL_FLOAT_MAT2x4,
631 location, count, transpose, value);
632 }
633
634 void GLAPIENTRY
635 _mesa_UniformMatrix4x2fv(GLint location, GLsizei count, GLboolean transpose,
636 const GLfloat *value)
637 {
638 GET_CURRENT_CONTEXT(ctx);
639 ctx->Driver.UniformMatrix(ctx, 4, 2, GL_FLOAT_MAT4x2,
640 location, count, transpose, value);
641 }
642
643 void GLAPIENTRY
644 _mesa_UniformMatrix3x4fv(GLint location, GLsizei count, GLboolean transpose,
645 const GLfloat *value)
646 {
647 GET_CURRENT_CONTEXT(ctx);
648 ctx->Driver.UniformMatrix(ctx, 3, 4, GL_FLOAT_MAT3x4,
649 location, count, transpose, value);
650 }
651
652 void GLAPIENTRY
653 _mesa_UniformMatrix4x3fv(GLint location, GLsizei count, GLboolean transpose,
654 const GLfloat *value)
655 {
656 GET_CURRENT_CONTEXT(ctx);
657 ctx->Driver.UniformMatrix(ctx, 4, 3, GL_FLOAT_MAT4x3,
658 location, count, transpose, value);
659 }
660
661
662 void GLAPIENTRY
663 _mesa_UseProgramObjectARB(GLhandleARB program)
664 {
665 GET_CURRENT_CONTEXT(ctx);
666 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
667 ctx->Driver.UseProgram(ctx, program);
668 }
669
670
671 void GLAPIENTRY
672 _mesa_ValidateProgramARB(GLhandleARB program)
673 {
674 GET_CURRENT_CONTEXT(ctx);
675 ctx->Driver.ValidateProgram(ctx, program);
676 }
677