mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2025-12-24 21:50:12 +01:00
mesa: new _mesa_remove_varying_reads() function
We'll apply this function to GLSL vertex programs. In GLSL it's legal to read and write varying (output) vars in a vertex shader. But reading from an output register isn't supported by all hardware. This routine examines the vertex program for that condition and rewrites it to use temporary registers where needed.
This commit is contained in:
parent
5d1e73028a
commit
48a25bdd36
2 changed files with 96 additions and 2 deletions
|
|
@ -35,6 +35,7 @@
|
|||
#include "context.h"
|
||||
#include "prog_parameter.h"
|
||||
#include "prog_statevars.h"
|
||||
#include "program.h"
|
||||
#include "programopt.h"
|
||||
#include "prog_instruction.h"
|
||||
|
||||
|
|
@ -102,7 +103,7 @@ _mesa_insert_mvp_code(GLcontext *ctx, struct gl_vertex_program *vprog)
|
|||
_mesa_copy_instructions (newInst + 4, vprog->Base.Instructions, origLen);
|
||||
|
||||
/* free old instructions */
|
||||
_mesa_free(vprog->Base.Instructions);
|
||||
_mesa_free_instructions(vprog->Base.Instructions, origLen);
|
||||
|
||||
/* install new instructions */
|
||||
vprog->Base.Instructions = newInst;
|
||||
|
|
@ -274,7 +275,7 @@ _mesa_append_fog_code(GLcontext *ctx, struct gl_fragment_program *fprog)
|
|||
inst++;
|
||||
|
||||
/* free old instructions */
|
||||
_mesa_free(fprog->Base.Instructions);
|
||||
_mesa_free_instructions(fprog->Base.Instructions, origLen);
|
||||
|
||||
/* install new instructions */
|
||||
fprog->Base.Instructions = newInst;
|
||||
|
|
@ -364,3 +365,94 @@ _mesa_count_texture_instructions(struct gl_program *prog)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scan/rewrite program to remove reads of varying (output) registers.
|
||||
* In GLSL vertex shaders, varying vars can be read and written.
|
||||
* Normally, vertex varying vars are implemented as output registers.
|
||||
* On some hardware, trying to read an output register causes trouble.
|
||||
* So, rewrite the program to use a temporary register in this case.
|
||||
*/
|
||||
void
|
||||
_mesa_remove_varying_reads(struct gl_program *prog)
|
||||
{
|
||||
GLuint i;
|
||||
GLint outputMap[VERT_RESULT_MAX];
|
||||
GLuint numVaryingReads = 0;
|
||||
|
||||
assert(prog->Target == GL_VERTEX_PROGRAM_ARB);
|
||||
|
||||
for (i = 0; i < VERT_RESULT_MAX; i++)
|
||||
outputMap[i] = -1;
|
||||
|
||||
/* look for instructions which read from varying vars */
|
||||
for (i = 0; i < prog->NumInstructions; i++) {
|
||||
struct prog_instruction *inst = prog->Instructions + i;
|
||||
const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
|
||||
GLuint j;
|
||||
for (j = 0; j < numSrc; j++) {
|
||||
if (inst->SrcReg[j].File == PROGRAM_VARYING) {
|
||||
/* replace the read with a temp reg */
|
||||
const GLuint var = inst->SrcReg[j].Index;
|
||||
if (outputMap[var] == -1) {
|
||||
numVaryingReads++;
|
||||
outputMap[var] = _mesa_find_free_register(prog,
|
||||
PROGRAM_TEMPORARY);
|
||||
}
|
||||
inst->SrcReg[j].File = PROGRAM_TEMPORARY;
|
||||
inst->SrcReg[j].Index = outputMap[var];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (numVaryingReads == 0)
|
||||
return; /* nothing to be done */
|
||||
|
||||
/* look for instructions which write to the varying vars identified above */
|
||||
for (i = 0; i < prog->NumInstructions; i++) {
|
||||
struct prog_instruction *inst = prog->Instructions + i;
|
||||
const GLuint numSrc = _mesa_num_inst_src_regs(inst->Opcode);
|
||||
GLuint j;
|
||||
for (j = 0; j < numSrc; j++) {
|
||||
if (inst->DstReg.File == PROGRAM_VARYING &&
|
||||
outputMap[inst->DstReg.Index] >= 0) {
|
||||
/* change inst to write to the temp reg, instead of the varying */
|
||||
inst->DstReg.File = PROGRAM_TEMPORARY;
|
||||
inst->DstReg.Index = outputMap[inst->DstReg.Index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* insert new instructions to copy the temp vars to the varying vars */
|
||||
{
|
||||
struct prog_instruction *inst;
|
||||
GLint endPos, var;
|
||||
|
||||
/* Look for END instruction and insert the new varying writes */
|
||||
endPos = -1;
|
||||
for (i = 0; i < prog->NumInstructions; i++) {
|
||||
struct prog_instruction *inst = prog->Instructions + i;
|
||||
if (inst->Opcode == OPCODE_END) {
|
||||
endPos = i;
|
||||
_mesa_insert_instructions(prog, i, numVaryingReads);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(endPos >= 0);
|
||||
|
||||
/* insert new MOV instructions here */
|
||||
inst = prog->Instructions + endPos;
|
||||
for (var = 0; var < VERT_RESULT_MAX; var++) {
|
||||
if (outputMap[var] >= 0) {
|
||||
/* MOV VAR[var], TEMP[tmp]; */
|
||||
inst->Opcode = OPCODE_MOV;
|
||||
inst->DstReg.File = PROGRAM_VARYING;
|
||||
inst->DstReg.Index = var;
|
||||
inst->SrcReg[0].File = PROGRAM_TEMPORARY;
|
||||
inst->SrcReg[0].Index = outputMap[var];
|
||||
inst++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,5 +39,7 @@ _mesa_count_texture_indirections(struct gl_program *prog);
|
|||
extern void
|
||||
_mesa_count_texture_instructions(struct gl_program *prog);
|
||||
|
||||
extern void
|
||||
_mesa_remove_varying_reads(struct gl_program *prog);
|
||||
|
||||
#endif /* PROGRAMOPT_H */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue