2
* Mesa 3-D graphics library
5
* Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
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:
14
* The above copyright notice and this permission notice shall be included
15
* in all copies or substantial portions of the Software.
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.
27
* Vertex/Fragment program optimizations and transformations for program
34
#include "main/glheader.h"
35
#include "main/context.h"
36
#include "prog_parameter.h"
37
#include "prog_statevars.h"
39
#include "programopt.h"
40
#include "prog_instruction.h"
44
* This function inserts instructions for coordinate modelview * projection
45
* into a vertex program.
46
* May be used to implement the position_invariant option.
49
_mesa_insert_mvp_dp4_code(GLcontext *ctx, struct gl_vertex_program *vprog)
51
struct prog_instruction *newInst;
52
const GLuint origLen = vprog->Base.NumInstructions;
53
const GLuint newLen = origLen + 4;
57
* Setup state references for the modelview/projection matrix.
58
* XXX we should check if these state vars are already declared.
60
static const gl_state_index mvpState[4][STATE_LENGTH] = {
61
{ STATE_MVP_MATRIX, 0, 0, 0, 0 }, /* state.matrix.mvp.row[0] */
62
{ STATE_MVP_MATRIX, 0, 1, 1, 0 }, /* state.matrix.mvp.row[1] */
63
{ STATE_MVP_MATRIX, 0, 2, 2, 0 }, /* state.matrix.mvp.row[2] */
64
{ STATE_MVP_MATRIX, 0, 3, 3, 0 }, /* state.matrix.mvp.row[3] */
68
for (i = 0; i < 4; i++) {
69
mvpRef[i] = _mesa_add_state_reference(vprog->Base.Parameters,
73
/* Alloc storage for new instructions */
74
newInst = _mesa_alloc_instructions(newLen);
76
_mesa_error(ctx, GL_OUT_OF_MEMORY,
77
"glProgramString(inserting position_invariant code)");
82
* Generated instructions:
83
* newInst[0] = DP4 result.position.x, mvp.row[0], vertex.position;
84
* newInst[1] = DP4 result.position.y, mvp.row[1], vertex.position;
85
* newInst[2] = DP4 result.position.z, mvp.row[2], vertex.position;
86
* newInst[3] = DP4 result.position.w, mvp.row[3], vertex.position;
88
_mesa_init_instructions(newInst, 4);
89
for (i = 0; i < 4; i++) {
90
newInst[i].Opcode = OPCODE_DP4;
91
newInst[i].DstReg.File = PROGRAM_OUTPUT;
92
newInst[i].DstReg.Index = VERT_RESULT_HPOS;
93
newInst[i].DstReg.WriteMask = (WRITEMASK_X << i);
94
newInst[i].SrcReg[0].File = PROGRAM_STATE_VAR;
95
newInst[i].SrcReg[0].Index = mvpRef[i];
96
newInst[i].SrcReg[0].Swizzle = SWIZZLE_NOOP;
97
newInst[i].SrcReg[1].File = PROGRAM_INPUT;
98
newInst[i].SrcReg[1].Index = VERT_ATTRIB_POS;
99
newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP;
102
/* Append original instructions after new instructions */
103
_mesa_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen);
105
/* free old instructions */
106
_mesa_free_instructions(vprog->Base.Instructions, origLen);
108
/* install new instructions */
109
vprog->Base.Instructions = newInst;
110
vprog->Base.NumInstructions = newLen;
111
vprog->Base.InputsRead |= VERT_BIT_POS;
112
vprog->Base.OutputsWritten |= BITFIELD64_BIT(VERT_RESULT_HPOS);
117
_mesa_insert_mvp_mad_code(GLcontext *ctx, struct gl_vertex_program *vprog)
119
struct prog_instruction *newInst;
120
const GLuint origLen = vprog->Base.NumInstructions;
121
const GLuint newLen = origLen + 4;
126
* Setup state references for the modelview/projection matrix.
127
* XXX we should check if these state vars are already declared.
129
static const gl_state_index mvpState[4][STATE_LENGTH] = {
130
{ STATE_MVP_MATRIX, 0, 0, 0, STATE_MATRIX_TRANSPOSE },
131
{ STATE_MVP_MATRIX, 0, 1, 1, STATE_MATRIX_TRANSPOSE },
132
{ STATE_MVP_MATRIX, 0, 2, 2, STATE_MATRIX_TRANSPOSE },
133
{ STATE_MVP_MATRIX, 0, 3, 3, STATE_MATRIX_TRANSPOSE },
137
for (i = 0; i < 4; i++) {
138
mvpRef[i] = _mesa_add_state_reference(vprog->Base.Parameters,
142
/* Alloc storage for new instructions */
143
newInst = _mesa_alloc_instructions(newLen);
145
_mesa_error(ctx, GL_OUT_OF_MEMORY,
146
"glProgramString(inserting position_invariant code)");
151
hposTemp = vprog->Base.NumTemporaries++;
154
* Generated instructions:
155
* emit_op2(p, OPCODE_MUL, tmp, 0, swizzle1(src,X), mat[0]);
156
* emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Y), mat[1], tmp);
157
* emit_op3(p, OPCODE_MAD, tmp, 0, swizzle1(src,Z), mat[2], tmp);
158
* emit_op3(p, OPCODE_MAD, dest, 0, swizzle1(src,W), mat[3], tmp);
160
_mesa_init_instructions(newInst, 4);
162
newInst[0].Opcode = OPCODE_MUL;
163
newInst[0].DstReg.File = PROGRAM_TEMPORARY;
164
newInst[0].DstReg.Index = hposTemp;
165
newInst[0].DstReg.WriteMask = WRITEMASK_XYZW;
166
newInst[0].SrcReg[0].File = PROGRAM_INPUT;
167
newInst[0].SrcReg[0].Index = VERT_ATTRIB_POS;
168
newInst[0].SrcReg[0].Swizzle = SWIZZLE_XXXX;
169
newInst[0].SrcReg[1].File = PROGRAM_STATE_VAR;
170
newInst[0].SrcReg[1].Index = mvpRef[0];
171
newInst[0].SrcReg[1].Swizzle = SWIZZLE_NOOP;
173
for (i = 1; i <= 2; i++) {
174
newInst[i].Opcode = OPCODE_MAD;
175
newInst[i].DstReg.File = PROGRAM_TEMPORARY;
176
newInst[i].DstReg.Index = hposTemp;
177
newInst[i].DstReg.WriteMask = WRITEMASK_XYZW;
178
newInst[i].SrcReg[0].File = PROGRAM_INPUT;
179
newInst[i].SrcReg[0].Index = VERT_ATTRIB_POS;
180
newInst[i].SrcReg[0].Swizzle = MAKE_SWIZZLE4(i,i,i,i);
181
newInst[i].SrcReg[1].File = PROGRAM_STATE_VAR;
182
newInst[i].SrcReg[1].Index = mvpRef[i];
183
newInst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP;
184
newInst[i].SrcReg[2].File = PROGRAM_TEMPORARY;
185
newInst[i].SrcReg[2].Index = hposTemp;
186
newInst[1].SrcReg[2].Swizzle = SWIZZLE_NOOP;
189
newInst[3].Opcode = OPCODE_MAD;
190
newInst[3].DstReg.File = PROGRAM_OUTPUT;
191
newInst[3].DstReg.Index = VERT_RESULT_HPOS;
192
newInst[3].DstReg.WriteMask = WRITEMASK_XYZW;
193
newInst[3].SrcReg[0].File = PROGRAM_INPUT;
194
newInst[3].SrcReg[0].Index = VERT_ATTRIB_POS;
195
newInst[3].SrcReg[0].Swizzle = SWIZZLE_WWWW;
196
newInst[3].SrcReg[1].File = PROGRAM_STATE_VAR;
197
newInst[3].SrcReg[1].Index = mvpRef[3];
198
newInst[3].SrcReg[1].Swizzle = SWIZZLE_NOOP;
199
newInst[3].SrcReg[2].File = PROGRAM_TEMPORARY;
200
newInst[3].SrcReg[2].Index = hposTemp;
201
newInst[3].SrcReg[2].Swizzle = SWIZZLE_NOOP;
204
/* Append original instructions after new instructions */
205
_mesa_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen);
207
/* free old instructions */
208
_mesa_free_instructions(vprog->Base.Instructions, origLen);
210
/* install new instructions */
211
vprog->Base.Instructions = newInst;
212
vprog->Base.NumInstructions = newLen;
213
vprog->Base.InputsRead |= VERT_BIT_POS;
214
vprog->Base.OutputsWritten |= BITFIELD64_BIT(VERT_RESULT_HPOS);
219
_mesa_insert_mvp_code(GLcontext *ctx, struct gl_vertex_program *vprog)
221
if (ctx->mvp_with_dp4)
222
_mesa_insert_mvp_dp4_code( ctx, vprog );
224
_mesa_insert_mvp_mad_code( ctx, vprog );
233
* Append extra instructions onto the given fragment program to implement
234
* the fog mode specified by fprog->FogOption.
235
* The fragment.fogcoord input is used to compute the fog blend factor.
237
* XXX with a little work, this function could be adapted to add fog code
238
* to vertex programs too.
241
_mesa_append_fog_code(GLcontext *ctx, struct gl_fragment_program *fprog)
243
static const gl_state_index fogPStateOpt[STATE_LENGTH]
244
= { STATE_INTERNAL, STATE_FOG_PARAMS_OPTIMIZED, 0, 0, 0 };
245
static const gl_state_index fogColorState[STATE_LENGTH]
246
= { STATE_FOG_COLOR, 0, 0, 0, 0};
247
struct prog_instruction *newInst, *inst;
248
const GLuint origLen = fprog->Base.NumInstructions;
249
const GLuint newLen = origLen + 5;
251
GLint fogPRefOpt, fogColorRef; /* state references */
252
GLuint colorTemp, fogFactorTemp; /* temporary registerss */
254
if (fprog->FogOption == GL_NONE) {
255
_mesa_problem(ctx, "_mesa_append_fog_code() called for fragment program"
256
" with FogOption == GL_NONE");
260
/* Alloc storage for new instructions */
261
newInst = _mesa_alloc_instructions(newLen);
263
_mesa_error(ctx, GL_OUT_OF_MEMORY,
264
"glProgramString(inserting fog_option code)");
268
/* Copy orig instructions into new instruction buffer */
269
_mesa_copy_instructions(newInst, fprog->Base.Instructions, origLen);
271
/* PARAM fogParamsRefOpt = internal optimized fog params; */
273
= _mesa_add_state_reference(fprog->Base.Parameters, fogPStateOpt);
274
/* PARAM fogColorRef = state.fog.color; */
276
= _mesa_add_state_reference(fprog->Base.Parameters, fogColorState);
278
/* TEMP colorTemp; */
279
colorTemp = fprog->Base.NumTemporaries++;
280
/* TEMP fogFactorTemp; */
281
fogFactorTemp = fprog->Base.NumTemporaries++;
283
/* Scan program to find where result.color is written */
285
for (i = 0; i < fprog->Base.NumInstructions; i++) {
286
if (inst->Opcode == OPCODE_END)
288
if (inst->DstReg.File == PROGRAM_OUTPUT &&
289
inst->DstReg.Index == FRAG_RESULT_COLOR) {
290
/* change the instruction to write to colorTemp w/ clamping */
291
inst->DstReg.File = PROGRAM_TEMPORARY;
292
inst->DstReg.Index = colorTemp;
293
inst->SaturateMode = SATURATE_ZERO_ONE;
294
/* don't break (may be several writes to result.color) */
298
assert(inst->Opcode == OPCODE_END); /* we'll overwrite this inst */
300
_mesa_init_instructions(inst, 5);
302
/* emit instructions to compute fog blending factor */
303
if (fprog->FogOption == GL_LINEAR) {
304
/* MAD fogFactorTemp.x, fragment.fogcoord.x, fogPRefOpt.x, fogPRefOpt.y; */
305
inst->Opcode = OPCODE_MAD;
306
inst->DstReg.File = PROGRAM_TEMPORARY;
307
inst->DstReg.Index = fogFactorTemp;
308
inst->DstReg.WriteMask = WRITEMASK_X;
309
inst->SrcReg[0].File = PROGRAM_INPUT;
310
inst->SrcReg[0].Index = FRAG_ATTRIB_FOGC;
311
inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
312
inst->SrcReg[1].File = PROGRAM_STATE_VAR;
313
inst->SrcReg[1].Index = fogPRefOpt;
314
inst->SrcReg[1].Swizzle = SWIZZLE_XXXX;
315
inst->SrcReg[2].File = PROGRAM_STATE_VAR;
316
inst->SrcReg[2].Index = fogPRefOpt;
317
inst->SrcReg[2].Swizzle = SWIZZLE_YYYY;
318
inst->SaturateMode = SATURATE_ZERO_ONE;
322
ASSERT(fprog->FogOption == GL_EXP || fprog->FogOption == GL_EXP2);
323
/* fogPRefOpt.z = d/ln(2), fogPRefOpt.w = d/sqrt(ln(2) */
324
/* EXP: MUL fogFactorTemp.x, fogPRefOpt.z, fragment.fogcoord.x; */
325
/* EXP2: MUL fogFactorTemp.x, fogPRefOpt.w, fragment.fogcoord.x; */
326
inst->Opcode = OPCODE_MUL;
327
inst->DstReg.File = PROGRAM_TEMPORARY;
328
inst->DstReg.Index = fogFactorTemp;
329
inst->DstReg.WriteMask = WRITEMASK_X;
330
inst->SrcReg[0].File = PROGRAM_STATE_VAR;
331
inst->SrcReg[0].Index = fogPRefOpt;
332
inst->SrcReg[0].Swizzle
333
= (fprog->FogOption == GL_EXP) ? SWIZZLE_ZZZZ : SWIZZLE_WWWW;
334
inst->SrcReg[1].File = PROGRAM_INPUT;
335
inst->SrcReg[1].Index = FRAG_ATTRIB_FOGC;
336
inst->SrcReg[1].Swizzle = SWIZZLE_XXXX;
338
if (fprog->FogOption == GL_EXP2) {
339
/* MUL fogFactorTemp.x, fogFactorTemp.x, fogFactorTemp.x; */
340
inst->Opcode = OPCODE_MUL;
341
inst->DstReg.File = PROGRAM_TEMPORARY;
342
inst->DstReg.Index = fogFactorTemp;
343
inst->DstReg.WriteMask = WRITEMASK_X;
344
inst->SrcReg[0].File = PROGRAM_TEMPORARY;
345
inst->SrcReg[0].Index = fogFactorTemp;
346
inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
347
inst->SrcReg[1].File = PROGRAM_TEMPORARY;
348
inst->SrcReg[1].Index = fogFactorTemp;
349
inst->SrcReg[1].Swizzle = SWIZZLE_XXXX;
352
/* EX2_SAT fogFactorTemp.x, -fogFactorTemp.x; */
353
inst->Opcode = OPCODE_EX2;
354
inst->DstReg.File = PROGRAM_TEMPORARY;
355
inst->DstReg.Index = fogFactorTemp;
356
inst->DstReg.WriteMask = WRITEMASK_X;
357
inst->SrcReg[0].File = PROGRAM_TEMPORARY;
358
inst->SrcReg[0].Index = fogFactorTemp;
359
inst->SrcReg[0].Negate = NEGATE_XYZW;
360
inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
361
inst->SaturateMode = SATURATE_ZERO_ONE;
364
/* LRP result.color.xyz, fogFactorTemp.xxxx, colorTemp, fogColorRef; */
365
inst->Opcode = OPCODE_LRP;
366
inst->DstReg.File = PROGRAM_OUTPUT;
367
inst->DstReg.Index = FRAG_RESULT_COLOR;
368
inst->DstReg.WriteMask = WRITEMASK_XYZ;
369
inst->SrcReg[0].File = PROGRAM_TEMPORARY;
370
inst->SrcReg[0].Index = fogFactorTemp;
371
inst->SrcReg[0].Swizzle = SWIZZLE_XXXX;
372
inst->SrcReg[1].File = PROGRAM_TEMPORARY;
373
inst->SrcReg[1].Index = colorTemp;
374
inst->SrcReg[1].Swizzle = SWIZZLE_NOOP;
375
inst->SrcReg[2].File = PROGRAM_STATE_VAR;
376
inst->SrcReg[2].Index = fogColorRef;
377
inst->SrcReg[2].Swizzle = SWIZZLE_NOOP;
379
/* MOV result.color.w, colorTemp.x; # copy alpha */
380
inst->Opcode = OPCODE_MOV;
381
inst->DstReg.File = PROGRAM_OUTPUT;
382
inst->DstReg.Index = FRAG_RESULT_COLOR;
383
inst->DstReg.WriteMask = WRITEMASK_W;
384
inst->SrcReg[0].File = PROGRAM_TEMPORARY;
385
inst->SrcReg[0].Index = colorTemp;
386
inst->SrcReg[0].Swizzle = SWIZZLE_NOOP;
389
inst->Opcode = OPCODE_END;
392
/* free old instructions */
393
_mesa_free_instructions(fprog->Base.Instructions, origLen);
395
/* install new instructions */
396
fprog->Base.Instructions = newInst;
397
fprog->Base.NumInstructions = inst - newInst;
398
fprog->Base.InputsRead |= FRAG_BIT_FOGC;
399
/* XXX do this? fprog->FogOption = GL_NONE; */
405
is_texture_instruction(const struct prog_instruction *inst)
407
switch (inst->Opcode) {
422
* Count the number of texure indirections in the given program.
423
* The program's NumTexIndirections field will be updated.
424
* See the GL_ARB_fragment_program spec (issue 24) for details.
425
* XXX we count texture indirections in texenvprogram.c (maybe use this code
426
* instead and elsewhere).
429
_mesa_count_texture_indirections(struct gl_program *prog)
431
GLuint indirections = 1;
432
GLbitfield tempsOutput = 0x0;
433
GLbitfield aluTemps = 0x0;
436
for (i = 0; i < prog->NumInstructions; i++) {
437
const struct prog_instruction *inst = prog->Instructions + i;
439
if (is_texture_instruction(inst)) {
440
if (((inst->SrcReg[0].File == PROGRAM_TEMPORARY) &&
441
(tempsOutput & (1 << inst->SrcReg[0].Index))) ||
442
((inst->Opcode != OPCODE_KIL) &&
443
(inst->DstReg.File == PROGRAM_TEMPORARY) &&
444
(aluTemps & (1 << inst->DstReg.Index))))
453
for (j = 0; j < 3; j++) {
454
if (inst->SrcReg[j].File == PROGRAM_TEMPORARY)
455
aluTemps |= (1 << inst->SrcReg[j].Index);
457
if (inst->DstReg.File == PROGRAM_TEMPORARY)
458
aluTemps |= (1 << inst->DstReg.Index);
461
if ((inst->Opcode != OPCODE_KIL) && (inst->DstReg.File == PROGRAM_TEMPORARY))
462
tempsOutput |= (1 << inst->DstReg.Index);
465
prog->NumTexIndirections = indirections;
470
* Count number of texture instructions in given program and update the
471
* program's NumTexInstructions field.
474
_mesa_count_texture_instructions(struct gl_program *prog)
477
prog->NumTexInstructions = 0;
478
for (i = 0; i < prog->NumInstructions; i++) {
479
prog->NumTexInstructions += is_texture_instruction(prog->Instructions + i);
485
* Scan/rewrite program to remove reads of custom (output) registers.
486
* The passed type has to be either PROGRAM_OUTPUT or PROGRAM_VARYING
487
* (for vertex shaders).
488
* In GLSL shaders, varying vars can be read and written.
489
* On some hardware, trying to read an output register causes trouble.
490
* So, rewrite the program to use a temporary register in this case.
493
_mesa_remove_output_reads(struct gl_program *prog, gl_register_file type)
496
GLint outputMap[VERT_RESULT_MAX];
497
GLuint numVaryingReads = 0;
498
GLboolean usedTemps[MAX_PROGRAM_TEMPS];
499
GLuint firstTemp = 0;
501
_mesa_find_used_registers(prog, PROGRAM_TEMPORARY,
502
usedTemps, MAX_PROGRAM_TEMPS);
504
assert(type == PROGRAM_VARYING || type == PROGRAM_OUTPUT);
505
assert(prog->Target == GL_VERTEX_PROGRAM_ARB || type != PROGRAM_VARYING);
507
for (i = 0; i < VERT_RESULT_MAX; i++)
510
/* look for instructions which read from varying vars */
511
for (i = 0; i < prog->NumInstructions; i++) {
512
struct prog_instruction *inst = prog->Instructions + i;
513
const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
515
for (j = 0; j < numSrc; j++) {
516
if (inst->SrcReg[j].File == type) {
517
/* replace the read with a temp reg */
518
const GLuint var = inst->SrcReg[j].Index;
519
if (outputMap[var] == -1) {
521
outputMap[var] = _mesa_find_free_register(usedTemps,
524
firstTemp = outputMap[var] + 1;
526
inst->SrcReg[j].File = PROGRAM_TEMPORARY;
527
inst->SrcReg[j].Index = outputMap[var];
532
if (numVaryingReads == 0)
533
return; /* nothing to be done */
535
/* look for instructions which write to the varying vars identified above */
536
for (i = 0; i < prog->NumInstructions; i++) {
537
struct prog_instruction *inst = prog->Instructions + i;
538
if (inst->DstReg.File == type &&
539
outputMap[inst->DstReg.Index] >= 0) {
540
/* change inst to write to the temp reg, instead of the varying */
541
inst->DstReg.File = PROGRAM_TEMPORARY;
542
inst->DstReg.Index = outputMap[inst->DstReg.Index];
546
/* insert new instructions to copy the temp vars to the varying vars */
548
struct prog_instruction *inst;
551
/* Look for END instruction and insert the new varying writes */
553
for (i = 0; i < prog->NumInstructions; i++) {
554
struct prog_instruction *inst = prog->Instructions + i;
555
if (inst->Opcode == OPCODE_END) {
557
_mesa_insert_instructions(prog, i, numVaryingReads);
564
/* insert new MOV instructions here */
565
inst = prog->Instructions + endPos;
566
for (var = 0; var < VERT_RESULT_MAX; var++) {
567
if (outputMap[var] >= 0) {
568
/* MOV VAR[var], TEMP[tmp]; */
569
inst->Opcode = OPCODE_MOV;
570
inst->DstReg.File = type;
571
inst->DstReg.Index = var;
572
inst->SrcReg[0].File = PROGRAM_TEMPORARY;
573
inst->SrcReg[0].Index = outputMap[var];
582
* Make the given fragment program into a "no-op" shader.
583
* Actually, just copy the incoming fragment color (or texcoord)
584
* to the output color.
585
* This is for debug/test purposes.
588
_mesa_nop_fragment_program(GLcontext *ctx, struct gl_fragment_program *prog)
590
struct prog_instruction *inst;
593
inst = _mesa_alloc_instructions(2);
595
_mesa_error(ctx, GL_OUT_OF_MEMORY, "_mesa_nop_fragment_program");
599
_mesa_init_instructions(inst, 2);
601
inst[0].Opcode = OPCODE_MOV;
602
inst[0].DstReg.File = PROGRAM_OUTPUT;
603
inst[0].DstReg.Index = FRAG_RESULT_COLOR;
604
inst[0].SrcReg[0].File = PROGRAM_INPUT;
605
if (prog->Base.InputsRead & FRAG_BIT_COL0)
606
inputAttr = FRAG_ATTRIB_COL0;
608
inputAttr = FRAG_ATTRIB_TEX0;
609
inst[0].SrcReg[0].Index = inputAttr;
611
inst[1].Opcode = OPCODE_END;
613
_mesa_free_instructions(prog->Base.Instructions,
614
prog->Base.NumInstructions);
616
prog->Base.Instructions = inst;
617
prog->Base.NumInstructions = 2;
618
prog->Base.InputsRead = 1 << inputAttr;
619
prog->Base.OutputsWritten = BITFIELD64_BIT(FRAG_RESULT_COLOR);
624
* \sa _mesa_nop_fragment_program
625
* Replace the given vertex program with a "no-op" program that just
626
* transforms vertex position and emits color.
629
_mesa_nop_vertex_program(GLcontext *ctx, struct gl_vertex_program *prog)
631
struct prog_instruction *inst;
635
* Start with a simple vertex program that emits color.
637
inst = _mesa_alloc_instructions(2);
639
_mesa_error(ctx, GL_OUT_OF_MEMORY, "_mesa_nop_vertex_program");
643
_mesa_init_instructions(inst, 2);
645
inst[0].Opcode = OPCODE_MOV;
646
inst[0].DstReg.File = PROGRAM_OUTPUT;
647
inst[0].DstReg.Index = VERT_RESULT_COL0;
648
inst[0].SrcReg[0].File = PROGRAM_INPUT;
649
if (prog->Base.InputsRead & VERT_BIT_COLOR0)
650
inputAttr = VERT_ATTRIB_COLOR0;
652
inputAttr = VERT_ATTRIB_TEX0;
653
inst[0].SrcReg[0].Index = inputAttr;
655
inst[1].Opcode = OPCODE_END;
657
_mesa_free_instructions(prog->Base.Instructions,
658
prog->Base.NumInstructions);
660
prog->Base.Instructions = inst;
661
prog->Base.NumInstructions = 2;
662
prog->Base.InputsRead = 1 << inputAttr;
663
prog->Base.OutputsWritten = BITFIELD64_BIT(VERT_RESULT_COL0);
666
* Now insert code to do standard modelview/projection transformation.
668
_mesa_insert_mvp_code(ctx, prog);