📄 t_vb_arbprogram.c
字号:
}
if (result == REG_RES) {
op = cvp_next_instruction(cp);
op->dword = fixup.dword;
}
break;
}
case VP_OPCODE_END:
break;
default:
result = cvp_choose_result( cp, &inst->DstReg, &fixup );
for (i = 0; i < info->nr_args; i++)
reg[i] = cvp_emit_arg( cp, &inst->SrcReg[i], REG_ARG0 + i );
op = cvp_next_instruction(cp);
op->alu.opcode = inst->Opcode;
op->alu.file0 = reg[0].file;
op->alu.idx0 = reg[0].idx;
op->alu.file1 = reg[1].file;
op->alu.idx1 = reg[1].idx;
op->alu.dst = result;
if (result == REG_RES) {
op = cvp_next_instruction(cp);
op->dword = fixup.dword;
}
break;
}
}
static void free_tnl_data( struct vertex_program *program )
{
struct tnl_compiled_program *p = program->TnlData;
if (p->compiled_func)
_mesa_free((void *)p->compiled_func);
_mesa_free(p);
program->TnlData = NULL;
}
static void compile_vertex_program( struct vertex_program *program,
GLboolean try_codegen )
{
struct compilation cp;
struct tnl_compiled_program *p = CALLOC_STRUCT(tnl_compiled_program);
GLuint i;
if (program->TnlData)
free_tnl_data( program );
program->TnlData = p;
/* Initialize cp. Note that ctx and VB aren't used in compilation
* so we don't have to worry about statechanges:
*/
memset(&cp, 0, sizeof(cp));
cp.csr = p->instructions;
/* Compile instructions:
*/
for (i = 0; i < program->Base.NumInstructions; i++) {
cvp_emit_inst(&cp, &program->Instructions[i]);
}
/* Finish up:
*/
p->nr_instructions = cp.csr - p->instructions;
/* Print/disassemble:
*/
if (DISASSEM) {
for (i = 0; i < p->nr_instructions; i++) {
_tnl_disassem_vba_insn(p->instructions[i]);
}
_mesa_printf("\n\n");
}
#ifdef USE_SSE_ASM
if (try_codegen)
_tnl_sse_codegen_vertex_program(p);
#endif
}
/* ----------------------------------------------------------------------
* Execution
*/
static void userclip( GLcontext *ctx,
GLvector4f *clip,
GLubyte *clipmask,
GLubyte *clipormask,
GLubyte *clipandmask )
{
GLuint p;
for (p = 0; p < ctx->Const.MaxClipPlanes; p++) {
if (ctx->Transform.ClipPlanesEnabled & (1 << p)) {
GLuint nr, i;
const GLfloat a = ctx->Transform._ClipUserPlane[p][0];
const GLfloat b = ctx->Transform._ClipUserPlane[p][1];
const GLfloat c = ctx->Transform._ClipUserPlane[p][2];
const GLfloat d = ctx->Transform._ClipUserPlane[p][3];
GLfloat *coord = (GLfloat *)clip->data;
GLuint stride = clip->stride;
GLuint count = clip->count;
for (nr = 0, i = 0 ; i < count ; i++) {
GLfloat dp = (coord[0] * a +
coord[1] * b +
coord[2] * c +
coord[3] * d);
if (dp < 0) {
nr++;
clipmask[i] |= CLIP_USER_BIT;
}
STRIDE_F(coord, stride);
}
if (nr > 0) {
*clipormask |= CLIP_USER_BIT;
if (nr == count) {
*clipandmask |= CLIP_USER_BIT;
return;
}
}
}
}
}
static GLboolean do_ndc_cliptest( struct arb_vp_machine *m )
{
GLcontext *ctx = m->ctx;
TNLcontext *tnl = TNL_CONTEXT(ctx);
struct vertex_buffer *VB = m->VB;
/* Cliptest and perspective divide. Clip functions must clear
* the clipmask.
*/
m->ormask = 0;
m->andmask = CLIP_ALL_BITS;
if (tnl->NeedNdcCoords) {
VB->NdcPtr =
_mesa_clip_tab[VB->ClipPtr->size]( VB->ClipPtr,
&m->ndcCoords,
m->clipmask,
&m->ormask,
&m->andmask );
}
else {
VB->NdcPtr = NULL;
_mesa_clip_np_tab[VB->ClipPtr->size]( VB->ClipPtr,
NULL,
m->clipmask,
&m->ormask,
&m->andmask );
}
if (m->andmask) {
/* All vertices are outside the frustum */
return GL_FALSE;
}
/* Test userclip planes. This contributes to VB->ClipMask.
*/
if (ctx->Transform.ClipPlanesEnabled && !ctx->VertexProgram._Enabled) {
userclip( ctx,
VB->ClipPtr,
m->clipmask,
&m->ormask,
&m->andmask );
if (m->andmask) {
return GL_FALSE;
}
}
VB->ClipAndMask = m->andmask;
VB->ClipOrMask = m->ormask;
VB->ClipMask = m->clipmask;
return GL_TRUE;
}
static INLINE void call_func( struct tnl_compiled_program *p,
struct arb_vp_machine *m )
{
p->compiled_func(m);
}
/**
* Execute the given vertex program.
*
* TODO: Integrate the t_vertex.c code here, to build machine vertices
* directly at this point.
*
* TODO: Eliminate the VB struct entirely and just use
* struct arb_vertex_machine.
*/
static GLboolean
run_arb_vertex_program(GLcontext *ctx, struct tnl_pipeline_stage *stage)
{
struct vertex_program *program = (ctx->VertexProgram._Enabled ?
ctx->VertexProgram.Current :
ctx->_TnlProgram);
struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
struct arb_vp_machine *m = ARB_VP_MACHINE(stage);
struct tnl_compiled_program *p;
GLuint i, j, outputs;
if (!program || program->IsNVProgram)
return GL_TRUE;
if (program->Parameters) {
_mesa_load_state_parameters(ctx, program->Parameters);
}
p = (struct tnl_compiled_program *)program->TnlData;
assert(p);
m->nr_inputs = m->nr_outputs = 0;
for (i = 0; i < _TNL_ATTRIB_MAX; i++) {
if (program->InputsRead & (1<<i)) {
GLuint j = m->nr_inputs++;
m->input[j].idx = i;
m->input[j].data = (GLfloat *)m->VB->AttribPtr[i]->data;
m->input[j].stride = m->VB->AttribPtr[i]->stride;
m->input[j].size = m->VB->AttribPtr[i]->size;
ASSIGN_4V(m->File[0][REG_IN0 + i], 0, 0, 0, 1);
}
}
for (i = 0; i < 15; i++) {
if (program->OutputsWritten & (1<<i)) {
GLuint j = m->nr_outputs++;
m->output[j].idx = i;
m->output[j].data = (GLfloat *)m->attribs[i].data;
}
}
/* Run the actual program:
*/
for (m->vtx_nr = 0; m->vtx_nr < VB->Count; m->vtx_nr++) {
for (j = 0; j < m->nr_inputs; j++) {
GLuint idx = REG_IN0 + m->input[j].idx;
switch (m->input[j].size) {
case 4: m->File[0][idx][3] = m->input[j].data[3];
case 3: m->File[0][idx][2] = m->input[j].data[2];
case 2: m->File[0][idx][1] = m->input[j].data[1];
case 1: m->File[0][idx][0] = m->input[j].data[0];
}
STRIDE_F(m->input[j].data, m->input[j].stride);
}
if (p->compiled_func) {
call_func( p, m );
}
else {
for (j = 0; j < p->nr_instructions; j++) {
union instruction inst = p->instructions[j];
opcode_func[inst.alu.opcode]( m, inst );
}
}
for (j = 0; j < m->nr_outputs; j++) {
GLuint idx = REG_OUT0 + m->output[j].idx;
m->output[j].data[0] = m->File[0][idx][0];
m->output[j].data[1] = m->File[0][idx][1];
m->output[j].data[2] = m->File[0][idx][2];
m->output[j].data[3] = m->File[0][idx][3];
m->output[j].data += 4;
}
}
/* Setup the VB pointers so that the next pipeline stages get
* their data from the right place (the program output arrays).
*
* TODO: 1) Have tnl use these RESULT values for outputs rather
* than trying to shoe-horn inputs and outputs into one set of
* values.
*
* TODO: 2) Integrate t_vertex.c so that we just go straight ahead
* and build machine vertices here.
*/
VB->ClipPtr = &m->attribs[VERT_RESULT_HPOS];
VB->ClipPtr->count = VB->Count;
outputs = program->OutputsWritten;
if (outputs & (1<<VERT_RESULT_COL0)) {
VB->ColorPtr[0] = &m->attribs[VERT_RESULT_COL0];
VB->AttribPtr[VERT_ATTRIB_COLOR0] = VB->ColorPtr[0];
}
if (outputs & (1<<VERT_RESULT_BFC0)) {
VB->ColorPtr[1] = &m->attribs[VERT_RESULT_BFC0];
}
if (outputs & (1<<VERT_RESULT_COL1)) {
VB->SecondaryColorPtr[0] = &m->attribs[VERT_RESULT_COL1];
VB->AttribPtr[VERT_ATTRIB_COLOR1] = VB->SecondaryColorPtr[0];
}
if (outputs & (1<<VERT_RESULT_BFC1)) {
VB->SecondaryColorPtr[1] = &m->attribs[VERT_RESULT_BFC1];
}
if (outputs & (1<<VERT_RESULT_FOGC)) {
VB->FogCoordPtr = &m->attribs[VERT_RESULT_FOGC];
VB->AttribPtr[VERT_ATTRIB_FOG] = VB->FogCoordPtr;
}
if (outputs & (1<<VERT_RESULT_PSIZ)) {
VB->PointSizePtr = &m->attribs[VERT_RESULT_PSIZ];
VB->AttribPtr[_TNL_ATTRIB_POINTSIZE] = &m->attribs[VERT_RESULT_PSIZ];
}
for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
if (outputs & (1<<(VERT_RESULT_TEX0+i))) {
VB->TexCoordPtr[i] = &m->attribs[VERT_RESULT_TEX0 + i];
VB->AttribPtr[VERT_ATTRIB_TEX0+i] = VB->TexCoordPtr[i];
}
}
#if 0
for (i = 0; i < VB->Count; i++) {
printf("Out %d: %f %f %f %f %f %f %f %f\n", i,
VEC_ELT(VB->ClipPtr, GLfloat, i)[0],
VEC_ELT(VB->ClipPtr, GLfloat, i)[1],
VEC_ELT(VB->ClipPtr, GLfloat, i)[2],
VEC_ELT(VB->ClipPtr, GLfloat, i)[3],
VEC_ELT(VB->TexCoordPtr[0], GLfloat, i)[0],
VEC_ELT(VB->TexCoordPtr[0], GLfloat, i)[1],
VEC_ELT(VB->TexCoordPtr[0], GLfloat, i)[2],
VEC_ELT(VB->TexCoordPtr[0], GLfloat, i)[3]);
}
#endif
/* Perform NDC and cliptest operations:
*/
return do_ndc_cliptest(m);
}
static void
validate_vertex_program( GLcontext *ctx, struct tnl_pipeline_stage *stage )
{
struct arb_vp_machine *m = ARB_VP_MACHINE(stage);
struct vertex_program *program =
(ctx->VertexProgram._Enabled ? ctx->VertexProgram.Current : 0);
if (!program && ctx->_MaintainTnlProgram) {
program = ctx->_TnlProgram;
}
if (program) {
if (!program->TnlData)
compile_vertex_program( program, m->try_codegen );
/* Grab the state GL state and put into registers:
*/
m->File[FILE_LOCAL_PARAM] = program->Base.LocalParams;
m->File[FILE_ENV_PARAM] = ctx->VertexProgram.Parameters;
/* GL_NV_vertex_programs can't reference GL state */
if (program->Parameters)
m->File[FILE_STATE_PARAM] = program->Parameters->ParameterValues;
else
m->File[FILE_STATE_PARAM] = NULL;
}
}
/**
* Called the first time stage->run is called. In effect, don't
* allocate data until the first time the stage is run.
*/
static GLboolean init_vertex_program( GLcontext *ctx,
struct tnl_pipeline_stage *stage )
{
TNLcontext *tnl = TNL_CONTEXT(ctx);
struct vertex_buffer *VB = &(tnl->vb);
struct arb_vp_machine *m;
const GLuint size = VB->Size;
GLuint i;
stage->privatePtr = _mesa_malloc(sizeof(*m));
m = ARB_VP_MACHINE(stage);
if (!m)
return GL_FALSE;
/* arb_vertex_machine struct should subsume the VB:
*/
m->VB = VB;
m->ctx = ctx;
m->File[0] = ALIGN_MALLOC(REG_MAX * sizeof(GLfloat) * 4, 16);
/* Initialize regs where necessary:
*/
ASSIGN_4V(m->File[0][REG_ID], 0, 0, 0, 1);
ASSIGN_4V(m->File[0][REG_ONES], 1, 1, 1, 1);
ASSIGN_4V(m->File[0][REG_SWZ], -1, 1, 0, 0);
ASSIGN_4V(m->File[0][REG_NEG], -1, -1, -1, -1);
ASSIGN_4V(m->File[0][REG_LIT], 1, 0, 0, 1);
ASSIGN_4V(m->File[0][REG_LIT2], 1, .5, .2, 1); /* debug value */
if (_mesa_getenv("MESA_EXPERIMENTAL"))
m->try_codegen = 1;
/* Allocate arrays of vertex output values */
for (i = 0; i < VERT_RESULT_MAX; i++) {
_mesa_vector4f_alloc( &m->attribs[i], 0, size, 32 );
m->attribs[i].size = 4;
}
/* a few other misc allocations */
_mesa_vector4f_alloc( &m->ndcCoords, 0, size, 32 );
m->clipmask = (GLubyte *) ALIGN_MALLOC(sizeof(GLubyte)*size, 32 );
if (ctx->_MaintainTnlProgram)
_mesa_allow_light_in_model( ctx, GL_FALSE );
m->fpucntl_rnd_neg = RND_NEG_FPU; /* const value */
m->fpucntl_restore = RESTORE_FPU; /* const value */
return GL_TRUE;
}
/**
* Destructor for this pipeline stage.
*/
static void dtr( struct tnl_pipeline_stage *stage )
{
struct arb_vp_machine *m = ARB_VP_MACHINE(stage);
if (m) {
GLuint i;
/* free the vertex program result arrays */
for (i = 0; i < VERT_RESULT_MAX; i++)
_mesa_vector4f_free( &m->attribs[i] );
/* free misc arrays */
_mesa_vector4f_free( &m->ndcCoords );
ALIGN_FREE( m->clipmask );
ALIGN_FREE( m->File[0] );
_mesa_free( m );
stage->privatePtr = NULL;
}
}
/**
* Public description of this pipeline stage.
*/
const struct tnl_pipeline_stage _tnl_arb_vertex_program_stage =
{
"vertex-program",
NULL, /* private_data */
init_vertex_program, /* create */
dtr, /* destroy */
validate_vertex_program, /* validate */
run_arb_vertex_program /* run */
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -