#include "nouveau_context.h"
#include "nouveau_shader.h"
+#include "nouveau_msg.h"
static nvsFixedReg _tx_mesa_vp_dst_reg[VERT_RESULT_MAX] = {
NVS_FR_POSITION, NVS_FR_COL0, NVS_FR_COL1, NVS_FR_FOGCOORD,
#define W NVS_SWZ_W
static void
-pass0_append_fragment(nouveauShader *nvs, nvsFragmentHeader *fragment)
+pass0_append_fragment(nvsFragmentHeader *parent,
+ nvsFragmentHeader *fragment,
+ int pos)
{
- nvsFragmentList *list = calloc(1, sizeof(nvsFragmentList));
- if (!list)
- return;
-
- list->fragment = fragment;
- list->prev = nvs->list_tail;
- if ( nvs->list_tail)
- nvs->list_tail->next = list;
- if (!nvs->list_head)
- nvs->list_head = list;
- nvs->list_tail = list;
-
- nvs->inst_count++;
+ nvsFragmentHeader **head, **tail;
+ assert(parent && fragment);
+
+ switch (parent->type) {
+ case NVS_BRANCH:
+ if (pos == 0) {
+ head = &((nvsBranch *)parent)->target_head;
+ tail = &((nvsBranch *)parent)->target_tail;
+ } else {
+ head = &((nvsBranch *)parent)->else_head;
+ tail = &((nvsBranch *)parent)->else_tail;
+ }
+ break;
+ case NVS_LOOP:
+ head = &((nvsLoop *)parent)->insn_head;
+ tail = &((nvsLoop *)parent)->insn_tail;
+ break;
+ case NVS_SUBROUTINE:
+ head = &((nvsSubroutine *)parent)->insn_head;
+ tail = &((nvsSubroutine *)parent)->insn_tail;
+ break;
+ default:
+ assert(0);
+ break;
+ }
+
+ fragment->parent = parent;
+ fragment->prev = *tail;
+ fragment->next = NULL;
+ if (!(*head))
+ *head = fragment;
+ else
+ (*tail)->next = fragment;
+ *tail = fragment;
+
+}
+
+static nvsSubroutine *
+pass0_create_subroutine(nouveauShader *nvs, const char *label)
+{
+ nvsSubroutine *sub;
+
+ sub = CALLOC_STRUCT(nvs_subroutine);
+ if (sub) {
+ sub->header.type = NVS_SUBROUTINE;
+ sub->label = strdup(label);
+ if (!nvs->program_tree)
+ nvs->program_tree = &sub->header;
+ else
+ pass0_append_fragment(nvs->program_tree, &sub->header, 0);
+ }
+
+ return sub;
}
static void
}
static nvsInstruction *
-pass0_emit(nouveauShader *nvs, nvsOpcode op, nvsRegister dst,
- unsigned int mask, int saturate,
+pass0_emit(nouveauShader *nvs, nvsFragmentHeader *parent, int fpos,
+ nvsOpcode op, nvsRegister dst,
+ unsigned int mask, int saturate,
nvsRegister src0, nvsRegister src1, nvsRegister src2)
{
- struct pass0_rec *rec = nvs->pass_rec;
- nvsInstruction *sif = NULL;
-
- /* Seems mesa doesn't explicitly 0 this.. */
- if (nvs->mesa.vp.Base.Target == GL_VERTEX_PROGRAM_ARB)
- saturate = 0;
-
- sif = calloc(1, sizeof(nvsInstruction));
- if (sif) {
- sif->header.type = NVS_INSTRUCTION;
- sif->header.position = rec->nvs_ipos++;
- sif->op = op;
- sif->saturate = saturate;
- sif->dest = dst;
- sif->mask = mask;
- sif->src[0] = src0;
- sif->src[1] = src1;
- sif->src[2] = src2;
- sif->cond = COND_TR;
- sif->cond_reg = 0;
- sif->cond_test = 0;
- sif->cond_update = 0;
- pass0_make_swizzle(sif->cond_swizzle, SWIZZLE_NOOP);
- pass0_append_fragment(nvs, (nvsFragmentHeader *)sif);
- }
-
- return sif;
+ nvsInstruction *sif;
+
+ sif = CALLOC_STRUCT(nvs_instruction);
+ if (!sif)
+ return NULL;
+
+ /* Seems mesa doesn't explicitly 0 this.. */
+ if (nvs->mesa.vp.Base.Target == GL_VERTEX_PROGRAM_ARB)
+ saturate = 0;
+
+ sif->op = op;
+ sif->saturate = saturate;
+ sif->dest = dst;
+ sif->mask = mask;
+ sif->src[0] = src0;
+ sif->src[1] = src1;
+ sif->src[2] = src2;
+ sif->cond = COND_TR;
+ sif->cond_reg = 0;
+ sif->cond_test = 0;
+ sif->cond_update= 0;
+ pass0_make_swizzle(sif->cond_swizzle, SWIZZLE_NOOP);
+ pass0_append_fragment(parent, &sif->header, fpos);
+
+ return sif;
}
static void
-pass0_fixup_swizzle(nvsPtr nvs,
+pass0_fixup_swizzle(nvsPtr nvs, nvsFragmentHeader *parent, int fpos,
struct prog_src_register *src,
unsigned int sm1,
unsigned int sm2)
*/
pass0_make_reg(nvs, &dr, NVS_FILE_TEMP, -1);
pass0_make_src_reg(nvs, &sr, src);
- pass0_emit(nvs, NVS_OP_MOV, dr, SMASK_ALL, 0, sr, nvr_unused, nvr_unused);
+ pass0_emit(nvs, parent, fpos, NVS_OP_MOV, dr, SMASK_ALL, 0, sr, nvr_unused, nvr_unused);
pass0_make_reg(nvs, &sr, NVS_FILE_TEMP, dr.index);
} else {
if (fixup_1)
/* Any combination with SWIZZLE_ONE */
pass0_make_reg(nvs, &sm2const, NVS_FILE_CONST, rec->swzconst_id);
pass0_make_swizzle(sm2const.swizzle, sm2);
- pass0_emit(nvs, NVS_OP_MAD, dr, SMASK_ALL, 0, sr, sm1const, sm2const);
+ pass0_emit(nvs, parent, fpos, NVS_OP_MAD, dr, SMASK_ALL, 0, sr, sm1const, sm2const);
} else {
/* SWIZZLE_ZERO || arbitrary negate */
- pass0_emit(nvs, NVS_OP_MUL, dr, SMASK_ALL, 0, sr, sm1const, nvr_unused);
+ pass0_emit(nvs, parent, fpos, NVS_OP_MUL, dr, SMASK_ALL, 0, sr, sm1const, nvr_unused);
}
src->File = PROGRAM_TEMPORARY;
#define SET_SWZ(fs, cp, c) fs = (fs & ~(0x7<<(cp*3))) | (c<<(cp*3))
static void
-pass0_check_sources(nvsPtr nvs, struct prog_instruction *inst)
+pass0_check_sources(nvsPtr nvs, nvsFragmentHeader *parent, int fpos,
+ struct prog_instruction *inst)
{
unsigned int insrc = -1, constsrc = -1;
int i;
*/
if ((sm_1 != MAKE_SWIZZLE4(0,0,0,0) && sm_1 != MAKE_SWIZZLE4(2,2,2,2)) ||
sm_2 != MAKE_SWIZZLE4(1,1,1,1)) {
- pass0_fixup_swizzle(nvs, src, sm_1, sm_2);
+ pass0_fixup_swizzle(nvs, parent, fpos, src, sm_1, sm_2);
/* The source is definitely in a temp now, so don't bother checking
* for multiple ATTRIB/CONST regs.
*/
if (do_mov) {
pass0_make_src_reg(nvs, &sr, src);
pass0_make_reg(nvs, &dr, NVS_FILE_TEMP, -1);
- pass0_emit(nvs, NVS_OP_MOV, dr, SMASK_ALL, 0,
+ pass0_emit(nvs, parent, fpos, NVS_OP_MOV, dr, SMASK_ALL, 0,
sr, nvr_unused, nvr_unused);
src->File = PROGRAM_TEMPORARY;
}
static GLboolean
-pass0_emulate_instruction(nouveauShader *nvs, struct prog_instruction *inst)
+pass0_emulate_instruction(nouveauShader *nvs,
+ nvsFragmentHeader *parent, int fpos,
+ struct prog_instruction *inst)
{
nvsFunc *shader = nvs->func;
nvsRegister src[3], dest, temp;
switch (inst->Opcode) {
case OPCODE_ABS:
if (shader->caps & SCAP_SRC_ABS)
- pass0_emit(nvs, NVS_OP_MOV, dest, mask, sat,
+ pass0_emit(nvs, parent, fpos, NVS_OP_MOV, dest, mask, sat,
nvsAbs(src[0]), nvr_unused, nvr_unused);
else
- pass0_emit(nvs, NVS_OP_MAX, dest, mask, sat,
+ pass0_emit(nvs, parent, fpos, NVS_OP_MAX, dest, mask, sat,
src[0], nvsNegate(src[0]), nvr_unused);
break;
case OPCODE_KIL:
*/
/* MOVC0 temp, src */
pass0_make_reg(nvs, &temp, NVS_FILE_TEMP, -1);
- nvsinst = pass0_emit(nvs, NVS_OP_MOV, temp, SMASK_ALL, 0,
+ nvsinst = pass0_emit(nvs, parent, fpos, NVS_OP_MOV, temp, SMASK_ALL, 0,
src[0], nvr_unused, nvr_unused);
nvsinst->cond_update = 1;
nvsinst->cond_reg = 0;
/* KIL_NV (LT0.xyzw) temp */
- nvsinst = pass0_emit(nvs, NVS_OP_KIL, nvr_unused, 0, 0,
+ nvsinst = pass0_emit(nvs, parent, fpos, NVS_OP_KIL, nvr_unused, 0, 0,
nvr_unused, nvr_unused, nvr_unused);
nvsinst->cond = COND_LT;
nvsinst->cond_reg = 0;
break;
case OPCODE_LRP:
pass0_make_reg(nvs, &temp, NVS_FILE_TEMP, -1);
- pass0_emit(nvs, NVS_OP_MAD, temp, mask, 0,
+ pass0_emit(nvs, parent, fpos, NVS_OP_MAD, temp, mask, 0,
nvsNegate(src[0]), src[2], src[2]);
- pass0_emit(nvs, NVS_OP_MAD, dest, mask, sat,
+ pass0_emit(nvs, parent, fpos, NVS_OP_MAD, dest, mask, sat,
src[0], src[1], temp);
break;
case OPCODE_POW:
shader->SupportsOpcode(shader, NVS_OP_EX2)) {
pass0_make_reg(nvs, &temp, NVS_FILE_TEMP, -1);
/* LG2 temp.x, src0.c */
- pass0_emit(nvs, NVS_OP_LG2, temp, SMASK_X, 0,
+ pass0_emit(nvs, parent, fpos, NVS_OP_LG2, temp, SMASK_X, 0,
nvsSwizzle(src[0], X, X, X, X),
nvr_unused,
nvr_unused);
/* MUL temp.x, temp.x, src1.c */
- pass0_emit(nvs, NVS_OP_MUL, temp, SMASK_X, 0,
+ pass0_emit(nvs, parent, fpos, NVS_OP_MUL, temp, SMASK_X, 0,
nvsSwizzle(temp, X, X, X, X),
nvsSwizzle(src[1], X, X, X, X),
nvr_unused);
/* EX2 dest, temp.x */
- pass0_emit(nvs, NVS_OP_EX2, dest, mask, sat,
+ pass0_emit(nvs, parent, fpos, NVS_OP_EX2, dest, mask, sat,
nvsSwizzle(temp, X, X, X, X),
nvr_unused,
nvr_unused);
COPY_4V(nvs->params[rec->const_half.index].val, const_half);
}
pass0_make_reg(nvs, &temp, NVS_FILE_TEMP, -1);
- pass0_emit(nvs, NVS_OP_LG2, temp, SMASK_X, 0,
+ pass0_emit(nvs, parent, fpos, NVS_OP_LG2, temp, SMASK_X, 0,
nvsAbs(nvsSwizzle(src[0], X, X, X, X)),
nvr_unused,
nvr_unused);
- pass0_emit(nvs, NVS_OP_MUL, temp, SMASK_X, 0,
+ pass0_emit(nvs, parent, fpos, NVS_OP_MUL, temp, SMASK_X, 0,
nvsSwizzle(temp, X, X, X, X),
nvsNegate(rec->const_half),
nvr_unused);
- pass0_emit(nvs, NVS_OP_EX2, dest, mask, sat,
+ pass0_emit(nvs, parent, fpos, NVS_OP_EX2, dest, mask, sat,
nvsSwizzle(temp, X, X, X, X),
nvr_unused,
nvr_unused);
break;
case OPCODE_SCS:
if (mask & SMASK_X)
- pass0_emit(nvs, NVS_OP_COS, dest, SMASK_X, sat,
+ pass0_emit(nvs, parent, fpos, NVS_OP_COS, dest, SMASK_X, sat,
nvsSwizzle(src[0], X, X, X, X),
nvr_unused,
nvr_unused);
if (mask & SMASK_Y)
- pass0_emit(nvs, NVS_OP_SIN, dest, SMASK_Y, sat,
+ pass0_emit(nvs, parent, fpos, NVS_OP_SIN, dest, SMASK_Y, sat,
nvsSwizzle(src[0], X, X, X, X),
nvr_unused,
nvr_unused);
break;
case OPCODE_SUB:
- pass0_emit(nvs, NVS_OP_ADD, dest, mask, sat,
+ pass0_emit(nvs, parent, fpos, NVS_OP_ADD, dest, mask, sat,
src[0], nvsNegate(src[1]), nvr_unused);
break;
case OPCODE_XPD:
pass0_make_reg(nvs, &temp, NVS_FILE_TEMP, -1);
- pass0_emit(nvs, NVS_OP_MUL, temp, SMASK_ALL, 0,
+ pass0_emit(nvs, parent, fpos, NVS_OP_MUL, temp, SMASK_ALL, 0,
nvsSwizzle(src[0], Z, X, Y, Y),
nvsSwizzle(src[1], Y, Z, X, X),
nvr_unused);
- pass0_emit(nvs, NVS_OP_MAD, dest, (mask & ~SMASK_W), sat,
+ pass0_emit(nvs, parent, fpos, NVS_OP_MAD, dest, (mask & ~SMASK_W), sat,
nvsSwizzle(src[0], Y, Z, X, X),
nvsSwizzle(src[1], Z, X, Y, Y),
nvsNegate(temp));
}
static GLboolean
-pass0_translate_instructions(nouveauShader *nvs)
+pass0_translate_arith(nouveauShader *nvs, struct gl_program *prog,
+ int ipos, int fpos,
+ nvsFragmentHeader *parent)
{
- struct gl_program *prog = (struct gl_program *)&nvs->mesa.vp;
- nvsFunc *shader = nvs->func;
- int ipos;
-
- for (ipos=0; ipos<prog->NumInstructions; ipos++) {
- struct prog_instruction *inst = &prog->Instructions[ipos];
-
- if (inst->Opcode == OPCODE_END)
- break;
-
- /* Deal with multiple ATTRIB/PARAM in a single instruction */
- pass0_check_sources(nvs, inst);
-
- /* Now it's safe to do the prog_instruction->nvsInstruction conversion */
- if (shader->SupportsOpcode(shader, pass0_make_opcode(inst->Opcode))) {
- nvsInstruction *nvsinst;
- nvsRegister src[3], dest;
- int i;
-
- for (i=0; i<_mesa_num_inst_src_regs(inst->Opcode); i++)
- pass0_make_src_reg(nvs, &src[i], &inst->SrcReg[i]);
- pass0_make_dst_reg(nvs, &dest, &inst->DstReg);
-
- nvsinst = pass0_emit(nvs,
- pass0_make_opcode(inst->Opcode),
- dest,
- pass0_make_mask(inst->DstReg.WriteMask),
- (inst->SaturateMode != SATURATE_OFF),
- src[0], src[1], src[2]);
- nvsinst->tex_unit = inst->TexSrcUnit;
- nvsinst->tex_target = pass0_make_tex_target(inst->TexSrcTarget);
- /* TODO when NV_fp/vp is implemented */
- nvsinst->cond = COND_TR;
- } else {
- if (!pass0_emulate_instruction(nvs, inst))
- return GL_FALSE;
- }
- }
+ struct prog_instruction *inst = &prog->Instructions[ipos];
+ nvsFunc *shader = nvs->func;
+ nvsInstruction *nvsinst;
+ GLboolean ret;
+
+ /* Deal with multiple ATTRIB/PARAM in a single instruction */
+ pass0_check_sources(nvs, parent, fpos, inst);
+
+ /* Now it's safe to do the prog_instruction->nvsInstruction
+ * conversion
+ */
+ if (shader->SupportsOpcode(shader,
+ pass0_make_opcode(inst->Opcode))) {
+ nvsRegister src[3], dest;
+ int i;
+
+ for (i=0; i<_mesa_num_inst_src_regs(inst->Opcode); i++)
+ pass0_make_src_reg(nvs, &src[i], &inst->SrcReg[i]);
+ pass0_make_dst_reg(nvs, &dest, &inst->DstReg);
+
+ nvsinst = pass0_emit(nvs, parent, fpos,
+ pass0_make_opcode(inst->Opcode),
+ dest,
+ pass0_make_mask(inst->DstReg.WriteMask),
+ (inst->SaturateMode != SATURATE_OFF),
+ src[0], src[1], src[2]);
+ nvsinst->tex_unit = inst->TexSrcUnit;
+ nvsinst->tex_target = pass0_make_tex_target(inst->TexSrcTarget);
+ /* TODO when NV_fp/vp is implemented */
+ nvsinst->cond = COND_TR;
+
+ ret = GL_TRUE;
+ } else
+ ret = pass0_emulate_instruction(nvs, parent, fpos, inst);
+
+ return ret;
+}
- return GL_TRUE;
+static GLboolean
+pass0_translate_instructions(nouveauShader *nvs, int ipos, int fpos,
+ nvsFragmentHeader *parent)
+{
+ struct gl_program *prog = (struct gl_program *)&nvs->mesa.vp;
+
+ while (1) {
+ struct prog_instruction *inst = &prog->Instructions[ipos];
+
+ switch (inst->Opcode) {
+ case OPCODE_END:
+ return GL_TRUE;
+ case OPCODE_BRA:
+ case OPCODE_CAL:
+ //case OPCDOE_RET:
+ //case OPCODE_LOOP:
+ //case OPCODE_ENDLOOP:
+ //case OPCODE_IF:
+ //case OPCODE_ELSE:
+ //case OPCODE_ENDIF:
+ WARN_ONCE("branch ops unimplemented\n");
+ return GL_FALSE;
+ break;
+ default:
+ if (!pass0_translate_arith(nvs, prog,
+ ipos, fpos, parent))
+ return GL_FALSE;
+ break;
+ }
+
+ ipos++;
+ }
+
+ return GL_TRUE;
}
GLboolean
nouveau_shader_pass0(GLcontext *ctx, nouveauShader *nvs)
{
- nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
- struct gl_program *prog = (struct gl_program*)nvs;
- struct gl_vertex_program *vp = (struct gl_vertex_program *)prog;
- struct gl_fragment_program *fp = (struct gl_fragment_program *)prog;
- struct pass0_rec *rec;
- int ret;
-
- switch (prog->Target) {
- case GL_VERTEX_PROGRAM_ARB:
- nvs->func = &nmesa->VPfunc;
- if (vp->IsPositionInvariant)
- _mesa_insert_mvp_code(ctx, vp);
+ nouveauContextPtr nmesa = NOUVEAU_CONTEXT(ctx);
+ struct gl_program *prog = (struct gl_program*)nvs;
+ struct gl_vertex_program *vp = (struct gl_vertex_program *)prog;
+ struct gl_fragment_program *fp = (struct gl_fragment_program *)prog;
+ struct pass0_rec *rec;
+ int ret = GL_FALSE;
+
+ switch (prog->Target) {
+ case GL_VERTEX_PROGRAM_ARB:
+ nvs->func = &nmesa->VPfunc;
+
+ if (vp->IsPositionInvariant)
+ _mesa_insert_mvp_code(ctx, vp);
#if 0
- if (IS_FIXEDFUNCTION_PROG && CLIP_PLANES_USED)
- pass0_insert_ff_clip_planes();
+ if (IS_FIXEDFUNCTION_PROG && CLIP_PLANES_USED)
+ pass0_insert_ff_clip_planes();
#endif
- break;
- case GL_FRAGMENT_PROGRAM_ARB:
- nvs->func = &nmesa->FPfunc;
- if (fp->FogOption != GL_NONE)
- _mesa_append_fog_code(ctx, fp);
- break;
- default:
- fprintf(stderr, "Unknown program type %d", prog->Target);
- return GL_FALSE;
- }
-
- rec = calloc(1, sizeof(struct pass0_rec));
- rec->next_temp = prog->NumTemporaries;
- nvs->pass_rec = rec;
-
- ret = pass0_translate_instructions(nvs);
- if (!ret) {
- /* DESTROY list */
- }
-
- free(nvs->pass_rec);
- return ret;
+ break;
+ case GL_FRAGMENT_PROGRAM_ARB:
+ nvs->func = &nmesa->FPfunc;
+
+ if (fp->FogOption != GL_NONE)
+ _mesa_append_fog_code(ctx, fp);
+ break;
+ default:
+ fprintf(stderr, "Unknown program type %d", prog->Target);
+ return GL_FALSE;
+ }
+
+ rec = CALLOC_STRUCT(pass0_rec);
+ if (rec) {
+ rec->next_temp = prog->NumTemporaries;
+ nvs->pass_rec = rec;
+
+ nvs->program_tree = (nvsFragmentHeader*)
+ pass0_create_subroutine(nvs, "program body");
+ if (nvs->program_tree) {
+ ret = pass0_translate_instructions(nvs,
+ 0, 0,
+ nvs->program_tree);
+ /*XXX: if (!ret) DESTROY TREE!!! */
+ }
+ FREE(rec);
+ }
+
+ return ret;
}