mesa: Restore 78-column wrapping of license text in C-style comments.
[mesa.git] / src / mesa / program / programopt.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5.3
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 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26 /**
27 * \file programopt.c
28 * Vertex/Fragment program optimizations and transformations for program
29 * options, etc.
30 *
31 * \author Brian Paul
32 */
33
34
35 #include "main/glheader.h"
36 #include "main/context.h"
37 #include "prog_parameter.h"
38 #include "prog_statevars.h"
39 #include "program.h"
40 #include "programopt.h"
41 #include "prog_instruction.h"
42
43
44 /**
45 * This function inserts instructions for coordinate modelview * projection
46 * into a vertex program.
47 * May be used to implement the position_invariant option.
48 */
49 static void
50 _mesa_insert_mvp_dp4_code(struct gl_context *ctx, struct gl_vertex_program *vprog)
51 {
52 struct prog_instruction *newInst;
53 const GLuint origLen = vprog->Base.NumInstructions;
54 const GLuint newLen = origLen + 4;
55 GLuint i;
56
57 /*
58 * Setup state references for the modelview/projection matrix.
59 * XXX we should check if these state vars are already declared.
60 */
61 static const gl_state_index mvpState[4][STATE_LENGTH] = {
62 { STATE_MVP_MATRIX, 0, 0, 0, 0 }, /* state.matrix.mvp.row[0] */
63 { STATE_MVP_MATRIX, 0, 1, 1, 0 }, /* state.matrix.mvp.row[1] */
64 { STATE_MVP_MATRIX, 0, 2, 2, 0 }, /* state.matrix.mvp.row[2] */
65 { STATE_MVP_MATRIX, 0, 3, 3, 0 }, /* state.matrix.mvp.row[3] */
66 };
67 GLint mvpRef[4];
68
69 for (i = 0; i < 4; i++) {
70 mvpRef[i] = _mesa_add_state_reference(vprog->Base.Parameters,
71 mvpState[i]);
72 }
73
74 /* Alloc storage for new instructions */
75 newInst = _mesa_alloc_instructions(newLen);
76 if (!newInst) {
77 _mesa_error(ctx, GL_OUT_OF_MEMORY,
78 "glProgramString(inserting position_invariant code)");
79 return;
80 }
81
82 /*
83 * Generated instructions:
84 * newInst[0] = DP4 result.position.x, mvp.row[0], vertex.position;
85 * newInst[1] = DP4 result.position.y, mvp.row[1], vertex.position;
86 * newInst[2] = DP4 result.position.z, mvp.row[2], vertex.position;
87 * newInst[3] = DP4 result.position.w, mvp.row[3], vertex.position;
88 */
89 _mesa_init_instructions(newInst, 4);
90 for (i = 0; i < 4; i++) {
91 newInst[i].Opcode = OPCODE_DP4;
92 newInst[i].DstReg.File = PROGRAM_OUTPUT;
93 newInst[i].DstReg.Index = VARYING_SLOT_POS;
94 newInst[i].DstReg.WriteMask = (WRITEMASK_X << i);
95 newInst[i].SrcReg[0].File = PROGRAM_STATE_VAR;
96 newInst[i].SrcReg[0].Index = mvpRef[i];
97 newInst[i].SrcReg[0].Swizzle = SWIZZLE_NOOP;
98 newInst[i].SrcReg[1].File = PROGRAM_INPUT;
99 newInst[i].SrcReg[1].Index = VERT_ATTRIB_POS;
100 newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP;
101 }
102
103 /* Append original instructions after new instructions */
104 _mesa_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen);
105
106 /* free old instructions */
107 _mesa_free_instructions(vprog->Base.Instructions, origLen);
108
109 /* install new instructions */
110 vprog->Base.Instructions = newInst;
111 vprog->Base.NumInstructions = newLen;
112 vprog->Base.InputsRead |= VERT_BIT_POS;
113 vprog->Base.OutputsWritten |= BITFIELD64_BIT(VARYING_SLOT_POS);
114 }
115
116
117 static void
118 _mesa_insert_mvp_mad_code(struct gl_context *ctx, struct gl_vertex_program *vprog)
119 {
120 struct prog_instruction *newInst;
121 const GLuint origLen = vprog->Base.NumInstructions;
122 const GLuint newLen = origLen + 4;
123 GLuint hposTemp;
124 GLuint i;
125
126 /*
127 * Setup state references for the modelview/projection matrix.
128 * XXX we should check if these state vars are already declared.
129 */
130 static const gl_state_index mvpState[4][STATE_LENGTH] = {
131 { STATE_MVP_MATRIX, 0, 0, 0, STATE_MATRIX_TRANSPOSE },
132 { STATE_MVP_MATRIX, 0, 1, 1, STATE_MATRIX_TRANSPOSE },
133 { STATE_MVP_MATRIX, 0, 2, 2, STATE_MATRIX_TRANSPOSE },
134 { STATE_MVP_MATRIX, 0, 3, 3, STATE_MATRIX_TRANSPOSE },
135 };
136 GLint mvpRef[4];
137
138 for (i = 0; i < 4; i++) {
139 mvpRef[i] = _mesa_add_state_reference(vprog->Base.Parameters,
140 mvpState[i]);
141 }
142
143 /* Alloc storage for new instructions */
144 newInst = _mesa_alloc_instructions(newLen);
145 if (!newInst) {
146 _mesa_error(ctx, GL_OUT_OF_MEMORY,
147 "glProgramString(inserting position_invariant code)");
148 return;
149 }
150
151 /* TEMP hposTemp; */
152 hposTemp = vprog->Base.NumTemporaries++;
153
154 /*
155 * Generated instructions:
156 * emit_op2(p, OPCODE_MUL, tmp, 0, swizzle1(src,X), mat[0]);
157 * emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Y), mat[1], tmp);
158 * emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Z), mat[2], tmp);
159 * emit_op3(p, OPCODE_MAD, dest, 0, swizzle1(src,W), mat[3], tmp);
160 */
161 _mesa_init_instructions(newInst, 4);
162
163 newInst[0].Opcode = OPCODE_MUL;
164 newInst[0].DstReg.File = PROGRAM_TEMPORARY;
165 newInst[0].DstReg.Index = hposTemp;
166 newInst[0].DstReg.WriteMask = WRITEMASK_XYZW;
167 newInst[0].SrcReg[0].File = PROGRAM_INPUT;
168 newInst[0].SrcReg[0].Index = VERT_ATTRIB_POS;
169 newInst[0].SrcReg[0].Swizzle = SWIZZLE_XXXX;
170 newInst[0].SrcReg[1].File = PROGRAM_STATE_VAR;
171 newInst[0].SrcReg[1].Index = mvpRef[0];
172 newInst[0].SrcReg[1].Swizzle = SWIZZLE_NOOP;
173
174 for (i = 1; i <= 2; i++) {
175 newInst[i].Opcode = OPCODE_MAD;
176 newInst[i].DstReg.File = PROGRAM_TEMPORARY;
177 newInst[i].DstReg.Index = hposTemp;
178 newInst[i].DstReg.WriteMask = WRITEMASK_XYZW;
179 newInst[i].SrcReg[0].File = PROGRAM_INPUT;
180 newInst[i].SrcReg[0].Index = VERT_ATTRIB_POS;
181 newInst[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(i,i,i,i);
182 newInst[i].SrcReg[1].File = PROGRAM_STATE_VAR;
183 newInst[i].SrcReg[1].Index = mvpRef[i];
184 newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP;
185 newInst[i].SrcReg[2].File = PROGRAM_TEMPORARY;
186 newInst[i].SrcReg[2].Index = hposTemp;
187 newInst[1].SrcReg[2].Swizzle = SWIZZLE_NOOP;
188 }
189
190 newInst[3].Opcode = OPCODE_MAD;
191 newInst[3].DstReg.File = PROGRAM_OUTPUT;
192 newInst[3].DstReg.Index = VARYING_SLOT_POS;
193 newInst[3].DstReg.WriteMask = WRITEMASK_XYZW;
194 newInst[3].SrcReg[0].File = PROGRAM_INPUT;
195 newInst[3].SrcReg[0].Index = VERT_ATTRIB_POS;
196 newInst[3].SrcReg[0].Swizzle = SWIZZLE_WWWW;
197 newInst[3].SrcReg[1].File = PROGRAM_STATE_VAR;
198 newInst[3].SrcReg[1].Index = mvpRef[3];
199 newInst[3].SrcReg[1].Swizzle = SWIZZLE_NOOP;
200 newInst[3].SrcReg[2].File = PROGRAM_TEMPORARY;
201 newInst[3].SrcReg[2].Index = hposTemp;
202 newInst[3].SrcReg[2].Swizzle = SWIZZLE_NOOP;
203
204
205 /* Append original instructions after new instructions */
206 _mesa_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen);
207
208 /* free old instructions */
209 _mesa_free_instructions(vprog->Base.Instructions, origLen);
210
211 /* install new instructions */
212 vprog->Base.Instructions = newInst;
213 vprog->Base.NumInstructions = newLen;
214 vprog->Base.InputsRead |= VERT_BIT_POS;
215 vprog->Base.OutputsWritten |= BITFIELD64_BIT(VARYING_SLOT_POS);
216 }
217
218
219 void
220 _mesa_insert_mvp_code(struct gl_context *ctx, struct gl_vertex_program *vprog)
221 {
222 if (ctx->mvp_with_dp4)
223 _mesa_insert_mvp_dp4_code( ctx, vprog );
224 else
225 _mesa_insert_mvp_mad_code( ctx, vprog );
226 }
227
228
229
230
231
232
233 /**
234 * Append instructions to implement fog
235 *
236 * The \c fragment.fogcoord input is used to compute the fog blend factor.
237 *
238 * \param ctx The GL context
239 * \param fprog Fragment program that fog instructions will be appended to.
240 * \param fog_mode Fog mode. One of \c GL_EXP, \c GL_EXP2, or \c GL_LINEAR.
241 * \param saturate True if writes to color outputs should be clamped to [0, 1]
242 *
243 * \note
244 * This function sets \c VARYING_BIT_FOGC in \c fprog->Base.InputsRead.
245 *
246 * \todo With a little work, this function could be adapted to add fog code
247 * to vertex programs too.
248 */
249 void
250 _mesa_append_fog_code(struct gl_context *ctx,
251 struct gl_fragment_program *fprog, GLenum fog_mode,
252 GLboolean saturate)
253 {
254 static const gl_state_index fogPStateOpt[STATE_LENGTH]
255 = { STATE_INTERNAL, STATE_FOG_PARAMS_OPTIMIZED, 0, 0, 0 };
256 static const gl_state_index fogColorState[STATE_LENGTH]
257 = { STATE_FOG_COLOR, 0, 0, 0, 0};
258 struct prog_instruction *newInst, *inst;
259 const GLuint origLen = fprog->Base.NumInstructions;
260 const GLuint newLen = origLen + 5;
261 GLuint i;
262 GLint fogPRefOpt, fogColorRef; /* state references */
263 GLuint colorTemp, fogFactorTemp; /* temporary registerss */
264
265 if (fog_mode == GL_NONE) {
266 _mesa_problem(ctx, "_mesa_append_fog_code() called for fragment program"
267 " with fog_mode == GL_NONE");
268 return;
269 }
270
271 if (!(fprog->Base.OutputsWritten & (1 << FRAG_RESULT_COLOR))) {
272 /* program doesn't output color, so nothing to do */
273 return;
274 }
275
276 /* Alloc storage for new instructions */
277 newInst = _mesa_alloc_instructions(newLen);
278 if (!newInst) {
279 _mesa_error(ctx, GL_OUT_OF_MEMORY,
280 "glProgramString(inserting fog_option code)");
281 return;
282 }
283
284 /* Copy orig instructions into new instruction buffer */
285 _mesa_copy_instructions(newInst, fprog->Base.Instructions, origLen);
286
287 /* PARAM fogParamsRefOpt = internal optimized fog params; */
288 fogPRefOpt
289 = _mesa_add_state_reference(fprog->Base.Parameters, fogPStateOpt);
290 /* PARAM fogColorRef = state.fog.color; */
291 fogColorRef
292 = _mesa_add_state_reference(fprog->Base.Parameters, fogColorState);
293
294 /* TEMP colorTemp; */
295 colorTemp = fprog->Base.NumTemporaries++;
296 /* TEMP fogFactorTemp; */
297 fogFactorTemp = fprog->Base.NumTemporaries++;
298
299 /* Scan program to find where result.color is written */
300 inst = newInst;
301 for (i = 0; i < fprog->Base.NumInstructions; i++) {
302 if (inst->Opcode == OPCODE_END)
303 break;
304 if (inst->DstReg.File == PROGRAM_OUTPUT &&
305 inst->DstReg.Index == FRAG_RESULT_COLOR) {
306 /* change the instruction to write to colorTemp w/ clamping */
307 inst->DstReg.File = PROGRAM_TEMPORARY;
308 inst->DstReg.Index = colorTemp;
309 inst->SaturateMode = saturate;
310 /* don't break (may be several writes to result.color) */
311 }
312 inst++;
313 }
314 assert(inst->Opcode == OPCODE_END); /* we'll overwrite this inst */
315
316 _mesa_init_instructions(inst, 5);
317
318 /* emit instructions to compute fog blending factor */
319 /* this is always clamped to [0, 1] regardless of fragment clamping */
320 if (fog_mode == GL_LINEAR) {
321 /* MAD fogFactorTemp.x, fragment.fogcoord.x, fogPRefOpt.x, fogPRefOpt.y; */
322 inst->Opcode = OPCODE_MAD;
323 inst->DstReg.File = PROGRAM_TEMPORARY;
324 inst->DstReg.Index = fogFactorTemp;
325 inst->DstReg.WriteMask = WRITEMASK_X;
326 inst->SrcReg[0].File = PROGRAM_INPUT;
327 inst->SrcReg[0].Index = VARYING_SLOT_FOGC;
328 inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
329 inst->SrcReg[1].File = PROGRAM_STATE_VAR;
330 inst->SrcReg[1].Index = fogPRefOpt;
331 inst->SrcReg[1].Swizzle = SWIZZLE_XXXX;
332 inst->SrcReg[2].File = PROGRAM_STATE_VAR;
333 inst->SrcReg[2].Index = fogPRefOpt;
334 inst->SrcReg[2].Swizzle = SWIZZLE_YYYY;
335 inst->SaturateMode = SATURATE_ZERO_ONE;
336 inst++;
337 }
338 else {
339 ASSERT(fog_mode == GL_EXP || fog_mode == GL_EXP2);
340 /* fogPRefOpt.z = d/ln(2), fogPRefOpt.w = d/sqrt(ln(2) */
341 /* EXP: MUL fogFactorTemp.x, fogPRefOpt.z, fragment.fogcoord.x; */
342 /* EXP2: MUL fogFactorTemp.x, fogPRefOpt.w, fragment.fogcoord.x; */
343 inst->Opcode = OPCODE_MUL;
344 inst->DstReg.File = PROGRAM_TEMPORARY;
345 inst->DstReg.Index = fogFactorTemp;
346 inst->DstReg.WriteMask = WRITEMASK_X;
347 inst->SrcReg[0].File = PROGRAM_STATE_VAR;
348 inst->SrcReg[0].Index = fogPRefOpt;
349 inst->SrcReg[0].Swizzle
350 = (fog_mode == GL_EXP) ? SWIZZLE_ZZZZ : SWIZZLE_WWWW;
351 inst->SrcReg[1].File = PROGRAM_INPUT;
352 inst->SrcReg[1].Index = VARYING_SLOT_FOGC;
353 inst->SrcReg[1].Swizzle = SWIZZLE_XXXX;
354 inst++;
355 if (fog_mode == GL_EXP2) {
356 /* MUL fogFactorTemp.x, fogFactorTemp.x, fogFactorTemp.x; */
357 inst->Opcode = OPCODE_MUL;
358 inst->DstReg.File = PROGRAM_TEMPORARY;
359 inst->DstReg.Index = fogFactorTemp;
360 inst->DstReg.WriteMask = WRITEMASK_X;
361 inst->SrcReg[0].File = PROGRAM_TEMPORARY;
362 inst->SrcReg[0].Index = fogFactorTemp;
363 inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
364 inst->SrcReg[1].File = PROGRAM_TEMPORARY;
365 inst->SrcReg[1].Index = fogFactorTemp;
366 inst->SrcReg[1].Swizzle = SWIZZLE_XXXX;
367 inst++;
368 }
369 /* EX2_SAT fogFactorTemp.x, -fogFactorTemp.x; */
370 inst->Opcode = OPCODE_EX2;
371 inst->DstReg.File = PROGRAM_TEMPORARY;
372 inst->DstReg.Index = fogFactorTemp;
373 inst->DstReg.WriteMask = WRITEMASK_X;
374 inst->SrcReg[0].File = PROGRAM_TEMPORARY;
375 inst->SrcReg[0].Index = fogFactorTemp;
376 inst->SrcReg[0].Negate = NEGATE_XYZW;
377 inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
378 inst->SaturateMode = SATURATE_ZERO_ONE;
379 inst++;
380 }
381 /* LRP result.color.xyz, fogFactorTemp.xxxx, colorTemp, fogColorRef; */
382 inst->Opcode = OPCODE_LRP;
383 inst->DstReg.File = PROGRAM_OUTPUT;
384 inst->DstReg.Index = FRAG_RESULT_COLOR;
385 inst->DstReg.WriteMask = WRITEMASK_XYZ;
386 inst->SrcReg[0].File = PROGRAM_TEMPORARY;
387 inst->SrcReg[0].Index = fogFactorTemp;
388 inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
389 inst->SrcReg[1].File = PROGRAM_TEMPORARY;
390 inst->SrcReg[1].Index = colorTemp;
391 inst->SrcReg[1].Swizzle = SWIZZLE_NOOP;
392 inst->SrcReg[2].File = PROGRAM_STATE_VAR;
393 inst->SrcReg[2].Index = fogColorRef;
394 inst->SrcReg[2].Swizzle = SWIZZLE_NOOP;
395 inst++;
396 /* MOV result.color.w, colorTemp.x; # copy alpha */
397 inst->Opcode = OPCODE_MOV;
398 inst->DstReg.File = PROGRAM_OUTPUT;
399 inst->DstReg.Index = FRAG_RESULT_COLOR;
400 inst->DstReg.WriteMask = WRITEMASK_W;
401 inst->SrcReg[0].File = PROGRAM_TEMPORARY;
402 inst->SrcReg[0].Index = colorTemp;
403 inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
404 inst++;
405 /* END; */
406 inst->Opcode = OPCODE_END;
407 inst++;
408
409 /* free old instructions */
410 _mesa_free_instructions(fprog->Base.Instructions, origLen);
411
412 /* install new instructions */
413 fprog->Base.Instructions = newInst;
414 fprog->Base.NumInstructions = inst - newInst;
415 fprog->Base.InputsRead |= VARYING_BIT_FOGC;
416 assert(fprog->Base.OutputsWritten & (1 << FRAG_RESULT_COLOR));
417 }
418
419
420
421 static GLboolean
422 is_texture_instruction(const struct prog_instruction *inst)
423 {
424 switch (inst->Opcode) {
425 case OPCODE_TEX:
426 case OPCODE_TXB:
427 case OPCODE_TXD:
428 case OPCODE_TXL:
429 case OPCODE_TXP:
430 case OPCODE_TXP_NV:
431 return GL_TRUE;
432 default:
433 return GL_FALSE;
434 }
435 }
436
437
438 /**
439 * Count the number of texure indirections in the given program.
440 * The program's NumTexIndirections field will be updated.
441 * See the GL_ARB_fragment_program spec (issue 24) for details.
442 * XXX we count texture indirections in texenvprogram.c (maybe use this code
443 * instead and elsewhere).
444 */
445 void
446 _mesa_count_texture_indirections(struct gl_program *prog)
447 {
448 GLuint indirections = 1;
449 GLbitfield tempsOutput = 0x0;
450 GLbitfield aluTemps = 0x0;
451 GLuint i;
452
453 for (i = 0; i < prog->NumInstructions; i++) {
454 const struct prog_instruction *inst = prog->Instructions + i;
455
456 if (is_texture_instruction(inst)) {
457 if (((inst->SrcReg[0].File == PROGRAM_TEMPORARY) &&
458 (tempsOutput & (1 << inst->SrcReg[0].Index))) ||
459 ((inst->Opcode != OPCODE_KIL) &&
460 (inst->DstReg.File == PROGRAM_TEMPORARY) &&
461 (aluTemps & (1 << inst->DstReg.Index))))
462 {
463 indirections++;
464 tempsOutput = 0x0;
465 aluTemps = 0x0;
466 }
467 }
468 else {
469 GLuint j;
470 for (j = 0; j < 3; j++) {
471 if (inst->SrcReg[j].File == PROGRAM_TEMPORARY)
472 aluTemps |= (1 << inst->SrcReg[j].Index);
473 }
474 if (inst->DstReg.File == PROGRAM_TEMPORARY)
475 aluTemps |= (1 << inst->DstReg.Index);
476 }
477
478 if ((inst->Opcode != OPCODE_KIL) && (inst->DstReg.File == PROGRAM_TEMPORARY))
479 tempsOutput |= (1 << inst->DstReg.Index);
480 }
481
482 prog->NumTexIndirections = indirections;
483 }
484
485
486 /**
487 * Count number of texture instructions in given program and update the
488 * program's NumTexInstructions field.
489 */
490 void
491 _mesa_count_texture_instructions(struct gl_program *prog)
492 {
493 GLuint i;
494 prog->NumTexInstructions = 0;
495 for (i = 0; i < prog->NumInstructions; i++) {
496 prog->NumTexInstructions += is_texture_instruction(prog->Instructions + i);
497 }
498 }
499
500
501 /**
502 * Scan/rewrite program to remove reads of custom (output) registers.
503 * The passed type has to be PROGRAM_OUTPUT.
504 * On some hardware, trying to read an output register causes trouble.
505 * So, rewrite the program to use a temporary register in this case.
506 */
507 void
508 _mesa_remove_output_reads(struct gl_program *prog, gl_register_file type)
509 {
510 GLuint i;
511 GLint outputMap[VARYING_SLOT_MAX];
512 GLuint numVaryingReads = 0;
513 GLboolean usedTemps[MAX_PROGRAM_TEMPS];
514 GLuint firstTemp = 0;
515
516 _mesa_find_used_registers(prog, PROGRAM_TEMPORARY,
517 usedTemps, MAX_PROGRAM_TEMPS);
518
519 assert(type == PROGRAM_OUTPUT);
520
521 for (i = 0; i < VARYING_SLOT_MAX; i++)
522 outputMap[i] = -1;
523
524 /* look for instructions which read from varying vars */
525 for (i = 0; i < prog->NumInstructions; i++) {
526 struct prog_instruction *inst = prog->Instructions + i;
527 const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
528 GLuint j;
529 for (j = 0; j < numSrc; j++) {
530 if (inst->SrcReg[j].File == type) {
531 /* replace the read with a temp reg */
532 const GLuint var = inst->SrcReg[j].Index;
533 if (outputMap[var] == -1) {
534 numVaryingReads++;
535 outputMap[var] = _mesa_find_free_register(usedTemps,
536 MAX_PROGRAM_TEMPS,
537 firstTemp);
538 firstTemp = outputMap[var] + 1;
539 }
540 inst->SrcReg[j].File = PROGRAM_TEMPORARY;
541 inst->SrcReg[j].Index = outputMap[var];
542 }
543 }
544 }
545
546 if (numVaryingReads == 0)
547 return; /* nothing to be done */
548
549 /* look for instructions which write to the varying vars identified above */
550 for (i = 0; i < prog->NumInstructions; i++) {
551 struct prog_instruction *inst = prog->Instructions + i;
552 if (inst->DstReg.File == type &&
553 outputMap[inst->DstReg.Index] >= 0) {
554 /* change inst to write to the temp reg, instead of the varying */
555 inst->DstReg.File = PROGRAM_TEMPORARY;
556 inst->DstReg.Index = outputMap[inst->DstReg.Index];
557 }
558 }
559
560 /* insert new instructions to copy the temp vars to the varying vars */
561 {
562 struct prog_instruction *inst;
563 GLint endPos, var;
564
565 /* Look for END instruction and insert the new varying writes */
566 endPos = -1;
567 for (i = 0; i < prog->NumInstructions; i++) {
568 struct prog_instruction *inst = prog->Instructions + i;
569 if (inst->Opcode == OPCODE_END) {
570 endPos = i;
571 _mesa_insert_instructions(prog, i, numVaryingReads);
572 break;
573 }
574 }
575
576 assert(endPos >= 0);
577
578 /* insert new MOV instructions here */
579 inst = prog->Instructions + endPos;
580 for (var = 0; var < VARYING_SLOT_MAX; var++) {
581 if (outputMap[var] >= 0) {
582 /* MOV VAR[var], TEMP[tmp]; */
583 inst->Opcode = OPCODE_MOV;
584 inst->DstReg.File = type;
585 inst->DstReg.Index = var;
586 inst->SrcReg[0].File = PROGRAM_TEMPORARY;
587 inst->SrcReg[0].Index = outputMap[var];
588 inst++;
589 }
590 }
591 }
592 }
593
594
595 /**
596 * Make the given fragment program into a "no-op" shader.
597 * Actually, just copy the incoming fragment color (or texcoord)
598 * to the output color.
599 * This is for debug/test purposes.
600 */
601 void
602 _mesa_nop_fragment_program(struct gl_context *ctx, struct gl_fragment_program *prog)
603 {
604 struct prog_instruction *inst;
605 GLuint inputAttr;
606
607 inst = _mesa_alloc_instructions(2);
608 if (!inst) {
609 _mesa_error(ctx, GL_OUT_OF_MEMORY, "_mesa_nop_fragment_program");
610 return;
611 }
612
613 _mesa_init_instructions(inst, 2);
614
615 inst[0].Opcode = OPCODE_MOV;
616 inst[0].DstReg.File = PROGRAM_OUTPUT;
617 inst[0].DstReg.Index = FRAG_RESULT_COLOR;
618 inst[0].SrcReg[0].File = PROGRAM_INPUT;
619 if (prog->Base.InputsRead & VARYING_BIT_COL0)
620 inputAttr = VARYING_SLOT_COL0;
621 else
622 inputAttr = VARYING_SLOT_TEX0;
623 inst[0].SrcReg[0].Index = inputAttr;
624
625 inst[1].Opcode = OPCODE_END;
626
627 _mesa_free_instructions(prog->Base.Instructions,
628 prog->Base.NumInstructions);
629
630 prog->Base.Instructions = inst;
631 prog->Base.NumInstructions = 2;
632 prog->Base.InputsRead = BITFIELD64_BIT(inputAttr);
633 prog->Base.OutputsWritten = BITFIELD64_BIT(FRAG_RESULT_COLOR);
634 }
635
636
637 /**
638 * \sa _mesa_nop_fragment_program
639 * Replace the given vertex program with a "no-op" program that just
640 * transforms vertex position and emits color.
641 */
642 void
643 _mesa_nop_vertex_program(struct gl_context *ctx, struct gl_vertex_program *prog)
644 {
645 struct prog_instruction *inst;
646 GLuint inputAttr;
647
648 /*
649 * Start with a simple vertex program that emits color.
650 */
651 inst = _mesa_alloc_instructions(2);
652 if (!inst) {
653 _mesa_error(ctx, GL_OUT_OF_MEMORY, "_mesa_nop_vertex_program");
654 return;
655 }
656
657 _mesa_init_instructions(inst, 2);
658
659 inst[0].Opcode = OPCODE_MOV;
660 inst[0].DstReg.File = PROGRAM_OUTPUT;
661 inst[0].DstReg.Index = VARYING_SLOT_COL0;
662 inst[0].SrcReg[0].File = PROGRAM_INPUT;
663 if (prog->Base.InputsRead & VERT_BIT_COLOR0)
664 inputAttr = VERT_ATTRIB_COLOR0;
665 else
666 inputAttr = VERT_ATTRIB_TEX0;
667 inst[0].SrcReg[0].Index = inputAttr;
668
669 inst[1].Opcode = OPCODE_END;
670
671 _mesa_free_instructions(prog->Base.Instructions,
672 prog->Base.NumInstructions);
673
674 prog->Base.Instructions = inst;
675 prog->Base.NumInstructions = 2;
676 prog->Base.InputsRead = BITFIELD64_BIT(inputAttr);
677 prog->Base.OutputsWritten = BITFIELD64_BIT(VARYING_SLOT_COL0);
678
679 /*
680 * Now insert code to do standard modelview/projection transformation.
681 */
682 _mesa_insert_mvp_code(ctx, prog);
683 }