4b24dde39c6a4a6dba91a3501f565a21c55d8972
[mesa.git] / src / mesa / main / nvprogram.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.2
4 *
5 * Copyright (C) 1999-2006 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 nvprogram.c
27 * NVIDIA vertex/fragment program state management functions.
28 * \author Brian Paul
29 */
30
31 /*
32 * Regarding GL_NV_fragment_program:
33 *
34 * Portions of this software may use or implement intellectual
35 * property owned and licensed by NVIDIA Corporation. NVIDIA disclaims
36 * any and all warranties with respect to such intellectual property,
37 * including any use thereof or modifications thereto.
38 */
39
40 #include "main/glheader.h"
41 #include "main/context.h"
42 #include "main/hash.h"
43 #include "main/imports.h"
44 #include "main/macros.h"
45 #include "main/mtypes.h"
46 #include "main/nvprogram.h"
47 #include "program/arbprogparse.h"
48 #include "program/nvfragparse.h"
49 #include "program/program.h"
50 #include "program/prog_instruction.h"
51 #include "program/prog_parameter.h"
52
53
54 /**
55 * Determine if a set of programs is resident in hardware.
56 * \note Not compiled into display lists.
57 * \note Called from the GL API dispatcher.
58 */
59 GLboolean GLAPIENTRY
60 _mesa_AreProgramsResidentNV(GLsizei n, const GLuint *ids,
61 GLboolean *residences)
62 {
63 GLint i, j;
64 GLboolean allResident = GL_TRUE;
65 GET_CURRENT_CONTEXT(ctx);
66 ASSERT_OUTSIDE_BEGIN_END_WITH_RETVAL(ctx, GL_FALSE);
67
68 if (n < 0) {
69 _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV(n)");
70 return GL_FALSE;
71 }
72
73 for (i = 0; i < n; i++) {
74 const struct gl_program *prog;
75 if (ids[i] == 0) {
76 _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV");
77 return GL_FALSE;
78 }
79 prog = _mesa_lookup_program(ctx, ids[i]);
80 if (!prog) {
81 _mesa_error(ctx, GL_INVALID_VALUE, "glAreProgramsResidentNV");
82 return GL_FALSE;
83 }
84 if (prog->Resident) {
85 if (!allResident)
86 residences[i] = GL_TRUE;
87 }
88 else {
89 if (allResident) {
90 allResident = GL_FALSE;
91 for (j = 0; j < i; j++)
92 residences[j] = GL_TRUE;
93 }
94 residences[i] = GL_FALSE;
95 }
96 }
97
98 return allResident;
99 }
100
101
102 /**
103 * Request that a set of programs be resident in hardware.
104 * \note Called from the GL API dispatcher.
105 */
106 void GLAPIENTRY
107 _mesa_RequestResidentProgramsNV(GLsizei n, const GLuint *ids)
108 {
109 GLint i;
110 GET_CURRENT_CONTEXT(ctx);
111 ASSERT_OUTSIDE_BEGIN_END(ctx);
112
113 if (n < 0) {
114 _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(n)");
115 return;
116 }
117
118 /* just error checking for now */
119 for (i = 0; i < n; i++) {
120 struct gl_program *prog;
121
122 if (ids[i] == 0) {
123 _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)");
124 return;
125 }
126
127 prog = _mesa_lookup_program(ctx, ids[i]);
128 if (!prog) {
129 _mesa_error(ctx, GL_INVALID_VALUE, "glRequestResidentProgramsNV(id)");
130 return;
131 }
132
133 /* XXX this is really a hardware thing we should hook out */
134 prog->Resident = GL_TRUE;
135 }
136 }
137
138 /**
139 * Get a program attribute.
140 * \note Not compiled into display lists.
141 * \note Called from the GL API dispatcher.
142 */
143 void GLAPIENTRY
144 _mesa_GetProgramivNV(GLuint id, GLenum pname, GLint *params)
145 {
146 struct gl_program *prog;
147 GET_CURRENT_CONTEXT(ctx);
148
149 ASSERT_OUTSIDE_BEGIN_END(ctx);
150
151 prog = _mesa_lookup_program(ctx, id);
152 if (!prog) {
153 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramivNV");
154 return;
155 }
156
157 switch (pname) {
158 case GL_PROGRAM_TARGET_NV:
159 *params = prog->Target;
160 return;
161 case GL_PROGRAM_LENGTH_NV:
162 *params = prog->String ?(GLint) strlen((char *) prog->String) : 0;
163 return;
164 case GL_PROGRAM_RESIDENT_NV:
165 *params = prog->Resident;
166 return;
167 default:
168 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramivNV(pname)");
169 return;
170 }
171 }
172
173
174 /**
175 * Get the program source code.
176 * \note Not compiled into display lists.
177 * \note Called from the GL API dispatcher.
178 */
179 void GLAPIENTRY
180 _mesa_GetProgramStringNV(GLuint id, GLenum pname, GLubyte *program)
181 {
182 struct gl_program *prog;
183 GET_CURRENT_CONTEXT(ctx);
184
185 ASSERT_OUTSIDE_BEGIN_END(ctx);
186
187 if (pname != GL_PROGRAM_STRING_NV) {
188 _mesa_error(ctx, GL_INVALID_ENUM, "glGetProgramStringNV(pname)");
189 return;
190 }
191
192 prog = _mesa_lookup_program(ctx, id);
193 if (!prog) {
194 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramStringNV");
195 return;
196 }
197
198 if (prog->String) {
199 memcpy(program, prog->String, strlen((char *) prog->String));
200 }
201 else {
202 program[0] = 0;
203 }
204 }
205
206 /**
207 * Get a vertex array attribute pointer.
208 *
209 * While the function first appeared in GL_NV_vertex_program, it's
210 * aliased for use by GL_ARB_vertex_program.
211 *
212 * \note Not compiled into display lists.
213 * \note Called from the GL API dispatcher.
214 */
215 void GLAPIENTRY
216 _mesa_GetVertexAttribPointervNV(GLuint index, GLenum pname, GLvoid **pointer)
217 {
218 GET_CURRENT_CONTEXT(ctx);
219 ASSERT_OUTSIDE_BEGIN_END(ctx);
220
221 if (index >= MAX_NV_VERTEX_PROGRAM_INPUTS) {
222 _mesa_error(ctx, GL_INVALID_VALUE, "glGetVertexAttribPointerNV(index)");
223 return;
224 }
225
226 if (pname != GL_ATTRIB_ARRAY_POINTER_NV) {
227 _mesa_error(ctx, GL_INVALID_ENUM, "glGetVertexAttribPointerNV(pname)");
228 return;
229 }
230
231 *pointer = (GLvoid *) ctx->Array.ArrayObj->VertexAttrib[VERT_ATTRIB_GENERIC(index)].Ptr;
232 }
233
234 void
235 _mesa_emit_nv_temp_initialization(struct gl_context *ctx,
236 struct gl_program *program)
237 {
238 struct prog_instruction *inst;
239 GLuint i;
240 struct gl_shader_compiler_options* options =
241 &ctx->ShaderCompilerOptions[_mesa_program_target_to_index(program->Target)];
242
243 if (!options->EmitNVTempInitialization)
244 return;
245
246 /* We'll swizzle up a zero temporary so we can use it for the
247 * ARL.
248 */
249 if (program->NumTemporaries == 0)
250 program->NumTemporaries = 1;
251
252 _mesa_insert_instructions(program, 0, program->NumTemporaries + 1);
253
254 for (i = 0; i < program->NumTemporaries; i++) {
255 struct prog_instruction *inst = &program->Instructions[i];
256
257 inst->Opcode = OPCODE_SWZ;
258 inst->DstReg.File = PROGRAM_TEMPORARY;
259 inst->DstReg.Index = i;
260 inst->DstReg.WriteMask = WRITEMASK_XYZW;
261 inst->SrcReg[0].File = PROGRAM_TEMPORARY;
262 inst->SrcReg[0].Index = 0;
263 inst->SrcReg[0].Swizzle = MAKE_SWIZZLE4(SWIZZLE_ZERO,
264 SWIZZLE_ZERO,
265 SWIZZLE_ZERO,
266 SWIZZLE_ZERO);
267 }
268
269 inst = &program->Instructions[i];
270 inst->Opcode = OPCODE_ARL;
271 inst->DstReg.File = PROGRAM_ADDRESS;
272 inst->DstReg.Index = 0;
273 inst->DstReg.WriteMask = WRITEMASK_XYZW;
274 inst->SrcReg[0].File = PROGRAM_TEMPORARY;
275 inst->SrcReg[0].Index = 0;
276 inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
277
278 if (program->NumAddressRegs == 0)
279 program->NumAddressRegs = 1;
280 }
281
282 void
283 _mesa_setup_nv_temporary_count(struct gl_program *program)
284 {
285 GLuint i;
286
287 program->NumTemporaries = 0;
288 for (i = 0; i < program->NumInstructions; i++) {
289 struct prog_instruction *inst = &program->Instructions[i];
290
291 if (inst->DstReg.File == PROGRAM_TEMPORARY) {
292 program->NumTemporaries = MAX2(program->NumTemporaries,
293 inst->DstReg.Index + 1);
294 }
295 if (inst->SrcReg[0].File == PROGRAM_TEMPORARY) {
296 program->NumTemporaries = MAX2((GLint)program->NumTemporaries,
297 inst->SrcReg[0].Index + 1);
298 }
299 if (inst->SrcReg[1].File == PROGRAM_TEMPORARY) {
300 program->NumTemporaries = MAX2((GLint)program->NumTemporaries,
301 inst->SrcReg[1].Index + 1);
302 }
303 if (inst->SrcReg[2].File == PROGRAM_TEMPORARY) {
304 program->NumTemporaries = MAX2((GLint)program->NumTemporaries,
305 inst->SrcReg[2].Index + 1);
306 }
307 }
308 }
309
310 /**
311 * Load/parse/compile a program.
312 * \note Called from the GL API dispatcher.
313 */
314 void GLAPIENTRY
315 _mesa_LoadProgramNV(GLenum target, GLuint id, GLsizei len,
316 const GLubyte *program)
317 {
318 struct gl_program *prog;
319 GET_CURRENT_CONTEXT(ctx);
320 ASSERT_OUTSIDE_BEGIN_END(ctx);
321
322 if (!ctx->Extensions.NV_fragment_program) {
323 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV()");
324 return;
325 }
326
327 if (id == 0) {
328 _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(id)");
329 return;
330 }
331
332 if (len < 0) {
333 _mesa_error(ctx, GL_INVALID_VALUE, "glLoadProgramNV(len)");
334 return;
335 }
336
337 FLUSH_VERTICES(ctx, _NEW_PROGRAM);
338
339 prog = _mesa_lookup_program(ctx, id);
340
341 if (prog && prog->Target != 0 && prog->Target != target) {
342 _mesa_error(ctx, GL_INVALID_OPERATION, "glLoadProgramNV(target)");
343 return;
344 }
345
346 if (target == GL_FRAGMENT_PROGRAM_NV
347 && ctx->Extensions.NV_fragment_program) {
348 struct gl_fragment_program *fprog = gl_fragment_program(prog);
349 if (!fprog || prog == &_mesa_DummyProgram) {
350 fprog = gl_fragment_program(ctx->Driver.NewProgram(ctx, target, id));
351 if (!fprog) {
352 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
353 return;
354 }
355 _mesa_HashInsert(ctx->Shared->Programs, id, fprog);
356 }
357 _mesa_parse_nv_fragment_program(ctx, target, program, len, fprog);
358 }
359 else if (target == GL_FRAGMENT_PROGRAM_ARB
360 && ctx->Extensions.ARB_fragment_program) {
361 struct gl_fragment_program *fprog = gl_fragment_program(prog);
362 if (!fprog || prog == &_mesa_DummyProgram) {
363 fprog = gl_fragment_program(ctx->Driver.NewProgram(ctx, target, id));
364 if (!fprog) {
365 _mesa_error(ctx, GL_OUT_OF_MEMORY, "glLoadProgramNV");
366 return;
367 }
368 _mesa_HashInsert(ctx->Shared->Programs, id, fprog);
369 }
370 _mesa_parse_arb_fragment_program(ctx, target, program, len, fprog);
371 }
372 else {
373 _mesa_error(ctx, GL_INVALID_ENUM, "glLoadProgramNV(target)");
374 }
375 }
376
377
378 void GLAPIENTRY
379 _mesa_ProgramNamedParameter4fNV(GLuint id, GLsizei len, const GLubyte *name,
380 GLfloat x, GLfloat y, GLfloat z, GLfloat w)
381 {
382 struct gl_program *prog;
383 struct gl_fragment_program *fragProg;
384 gl_constant_value *v;
385
386 GET_CURRENT_CONTEXT(ctx);
387 ASSERT_OUTSIDE_BEGIN_END(ctx);
388
389 FLUSH_VERTICES(ctx, _NEW_PROGRAM_CONSTANTS);
390
391 prog = _mesa_lookup_program(ctx, id);
392 if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) {
393 _mesa_error(ctx, GL_INVALID_OPERATION, "glProgramNamedParameterNV");
394 return;
395 }
396
397 if (len <= 0) {
398 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV(len)");
399 return;
400 }
401
402 fragProg = gl_fragment_program(prog);
403 v = _mesa_lookup_parameter_value(fragProg->Base.Parameters, len,
404 (char *) name);
405 if (v) {
406 v[0].f = x;
407 v[1].f = y;
408 v[2].f = z;
409 v[3].f = w;
410 return;
411 }
412
413 _mesa_error(ctx, GL_INVALID_VALUE, "glProgramNamedParameterNV(name)");
414 }
415
416
417 void GLAPIENTRY
418 _mesa_ProgramNamedParameter4fvNV(GLuint id, GLsizei len, const GLubyte *name,
419 const float v[])
420 {
421 _mesa_ProgramNamedParameter4fNV(id, len, name, v[0], v[1], v[2], v[3]);
422 }
423
424
425 void GLAPIENTRY
426 _mesa_ProgramNamedParameter4dNV(GLuint id, GLsizei len, const GLubyte *name,
427 GLdouble x, GLdouble y, GLdouble z, GLdouble w)
428 {
429 _mesa_ProgramNamedParameter4fNV(id, len, name, (GLfloat)x, (GLfloat)y,
430 (GLfloat)z, (GLfloat)w);
431 }
432
433
434 void GLAPIENTRY
435 _mesa_ProgramNamedParameter4dvNV(GLuint id, GLsizei len, const GLubyte *name,
436 const double v[])
437 {
438 _mesa_ProgramNamedParameter4fNV(id, len, name,
439 (GLfloat)v[0], (GLfloat)v[1],
440 (GLfloat)v[2], (GLfloat)v[3]);
441 }
442
443
444 void GLAPIENTRY
445 _mesa_GetProgramNamedParameterfvNV(GLuint id, GLsizei len, const GLubyte *name,
446 GLfloat *params)
447 {
448 struct gl_program *prog;
449 struct gl_fragment_program *fragProg;
450 const gl_constant_value *v;
451
452 GET_CURRENT_CONTEXT(ctx);
453
454 ASSERT_OUTSIDE_BEGIN_END(ctx);
455
456 prog = _mesa_lookup_program(ctx, id);
457 if (!prog || prog->Target != GL_FRAGMENT_PROGRAM_NV) {
458 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetProgramNamedParameterNV");
459 return;
460 }
461
462 if (len <= 0) {
463 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV");
464 return;
465 }
466
467 fragProg = gl_fragment_program(prog);
468 v = _mesa_lookup_parameter_value(fragProg->Base.Parameters,
469 len, (char *) name);
470 if (v) {
471 params[0] = v[0].f;
472 params[1] = v[1].f;
473 params[2] = v[2].f;
474 params[3] = v[3].f;
475 return;
476 }
477
478 _mesa_error(ctx, GL_INVALID_VALUE, "glGetProgramNamedParameterNV");
479 }
480
481
482 void GLAPIENTRY
483 _mesa_GetProgramNamedParameterdvNV(GLuint id, GLsizei len, const GLubyte *name,
484 GLdouble *params)
485 {
486 GLfloat floatParams[4];
487 _mesa_GetProgramNamedParameterfvNV(id, len, name, floatParams);
488 COPY_4V(params, floatParams);
489 }