📄 nvvertexec.c
字号:
/* * Mesa 3-D graphics library * Version: 6.5 * * Copyright (C) 1999-2005 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *//** * \file nvvertexec.c * Code to execute vertex programs. * \author Brian Paul */#include "glheader.h"#include "context.h"#include "imports.h"#include "macros.h"#include "mtypes.h"#include "nvvertexec.h"#include "program_instruction.h"#include "program.h"#include "math/m_matrix.h"static const GLfloat ZeroVec[4] = { 0.0F, 0.0F, 0.0F, 0.0F };/** * Load/initialize the vertex program registers which need to be set * per-vertex. */void_mesa_init_vp_per_vertex_registers(GLcontext *ctx){ /* Input registers get initialized from the current vertex attribs */ MEMCPY(ctx->VertexProgram.Inputs, ctx->Current.Attrib, VERT_ATTRIB_MAX * 4 * sizeof(GLfloat)); if (ctx->VertexProgram.Current->IsNVProgram) { GLuint i; /* Output/result regs are initialized to [0,0,0,1] */ for (i = 0; i < MAX_NV_VERTEX_PROGRAM_OUTPUTS; i++) { ASSIGN_4V(ctx->VertexProgram.Outputs[i], 0.0F, 0.0F, 0.0F, 1.0F); } /* Temp regs are initialized to [0,0,0,0] */ for (i = 0; i < MAX_NV_VERTEX_PROGRAM_TEMPS; i++) { ASSIGN_4V(ctx->VertexProgram.Temporaries[i], 0.0F, 0.0F, 0.0F, 0.0F); } ASSIGN_4V(ctx->VertexProgram.AddressReg, 0, 0, 0, 0); }}/** * Copy the 16 elements of a matrix into four consecutive program * registers starting at 'pos'. */static voidload_matrix(GLfloat registers[][4], GLuint pos, const GLfloat mat[16]){ GLuint i; for (i = 0; i < 4; i++) { registers[pos + i][0] = mat[0 + i]; registers[pos + i][1] = mat[4 + i]; registers[pos + i][2] = mat[8 + i]; registers[pos + i][3] = mat[12 + i]; }}/** * As above, but transpose the matrix. */static voidload_transpose_matrix(GLfloat registers[][4], GLuint pos, const GLfloat mat[16]){ MEMCPY(registers[pos], mat, 16 * sizeof(GLfloat));}/** * Load program parameter registers with tracked matrices (if NV program) * or GL state values (if ARB program). * This needs to be done per glBegin/glEnd, not per-vertex. */void_mesa_init_vp_per_primitive_registers(GLcontext *ctx){ if (ctx->VertexProgram.Current->IsNVProgram) { GLuint i; for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS / 4; i++) { /* point 'mat' at source matrix */ GLmatrix *mat; if (ctx->VertexProgram.TrackMatrix[i] == GL_MODELVIEW) { mat = ctx->ModelviewMatrixStack.Top; } else if (ctx->VertexProgram.TrackMatrix[i] == GL_PROJECTION) { mat = ctx->ProjectionMatrixStack.Top; } else if (ctx->VertexProgram.TrackMatrix[i] == GL_TEXTURE) { mat = ctx->TextureMatrixStack[ctx->Texture.CurrentUnit].Top; } else if (ctx->VertexProgram.TrackMatrix[i] == GL_COLOR) { mat = ctx->ColorMatrixStack.Top; } else if (ctx->VertexProgram.TrackMatrix[i]==GL_MODELVIEW_PROJECTION_NV) { /* XXX verify the combined matrix is up to date */ mat = &ctx->_ModelProjectMatrix; } else if (ctx->VertexProgram.TrackMatrix[i] >= GL_MATRIX0_NV && ctx->VertexProgram.TrackMatrix[i] <= GL_MATRIX7_NV) { GLuint n = ctx->VertexProgram.TrackMatrix[i] - GL_MATRIX0_NV; ASSERT(n < MAX_PROGRAM_MATRICES); mat = ctx->ProgramMatrixStack[n].Top; } else { /* no matrix is tracked, but we leave the register values as-is */ assert(ctx->VertexProgram.TrackMatrix[i] == GL_NONE); continue; } /* load the matrix */ if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_IDENTITY_NV) { load_matrix(ctx->VertexProgram.Parameters, i*4, mat->m); } else if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_INVERSE_NV) { _math_matrix_analyse(mat); /* update the inverse */ ASSERT(!_math_matrix_is_dirty(mat)); load_matrix(ctx->VertexProgram.Parameters, i*4, mat->inv); } else if (ctx->VertexProgram.TrackMatrixTransform[i] == GL_TRANSPOSE_NV) { load_transpose_matrix(ctx->VertexProgram.Parameters, i*4, mat->m); } else { assert(ctx->VertexProgram.TrackMatrixTransform[i] == GL_INVERSE_TRANSPOSE_NV); _math_matrix_analyse(mat); /* update the inverse */ ASSERT(!_math_matrix_is_dirty(mat)); load_transpose_matrix(ctx->VertexProgram.Parameters, i*4, mat->inv); } } } else { /* Using and ARB vertex program */ if (ctx->VertexProgram.Current->Base.Parameters) { /* Grab the state GL state and put into registers */ _mesa_load_state_parameters(ctx, ctx->VertexProgram.Current->Base.Parameters); } }}/** * For debugging. Dump the current vertex program machine registers. */void_mesa_dump_vp_state( const struct gl_vertex_program_state *state ){ int i; _mesa_printf("VertexIn:\n"); for (i = 0; i < MAX_NV_VERTEX_PROGRAM_INPUTS; i++) { _mesa_printf("%d: %f %f %f %f ", i, state->Inputs[i][0], state->Inputs[i][1], state->Inputs[i][2], state->Inputs[i][3]); } _mesa_printf("\n"); _mesa_printf("VertexOut:\n"); for (i = 0; i < MAX_NV_VERTEX_PROGRAM_OUTPUTS; i++) { _mesa_printf("%d: %f %f %f %f ", i, state->Outputs[i][0], state->Outputs[i][1], state->Outputs[i][2], state->Outputs[i][3]); } _mesa_printf("\n"); _mesa_printf("Registers:\n"); for (i = 0; i < MAX_NV_VERTEX_PROGRAM_TEMPS; i++) { _mesa_printf("%d: %f %f %f %f ", i, state->Temporaries[i][0], state->Temporaries[i][1], state->Temporaries[i][2], state->Temporaries[i][3]); } _mesa_printf("\n"); _mesa_printf("Parameters:\n"); for (i = 0; i < MAX_NV_VERTEX_PROGRAM_PARAMS; i++) { _mesa_printf("%d: %f %f %f %f ", i, state->Parameters[i][0], state->Parameters[i][1], state->Parameters[i][2], state->Parameters[i][3]); } _mesa_printf("\n");}/** * Return a pointer to the 4-element float vector specified by the given * source register. */static INLINE const GLfloat *get_register_pointer( const struct prog_src_register *source, const struct gl_vertex_program_state *state ){ if (source->RelAddr) { const GLint reg = source->Index + state->AddressReg[0]; ASSERT( (source->File == PROGRAM_ENV_PARAM) || (source->File == PROGRAM_STATE_VAR) ); if (reg < 0 || reg > MAX_NV_VERTEX_PROGRAM_PARAMS) return ZeroVec; else if (source->File == PROGRAM_ENV_PARAM) return state->Parameters[reg]; else return state->Current->Base.Parameters->ParameterValues[reg]; } else { switch (source->File) { case PROGRAM_TEMPORARY: ASSERT(source->Index < MAX_NV_VERTEX_PROGRAM_TEMPS); return state->Temporaries[source->Index]; case PROGRAM_INPUT: ASSERT(source->Index < MAX_NV_VERTEX_PROGRAM_INPUTS); return state->Inputs[source->Index]; case PROGRAM_OUTPUT: /* This is only needed for the PRINT instruction */ ASSERT(source->Index < MAX_NV_VERTEX_PROGRAM_OUTPUTS); return state->Outputs[source->Index]; case PROGRAM_LOCAL_PARAM: ASSERT(source->Index < MAX_PROGRAM_LOCAL_PARAMS); return state->Current->Base.LocalParams[source->Index]; case PROGRAM_ENV_PARAM: ASSERT(source->Index < MAX_NV_VERTEX_PROGRAM_PARAMS); return state->Parameters[source->Index]; case PROGRAM_STATE_VAR: ASSERT(source->Index < state->Current->Base.Parameters->NumParameters); return state->Current->Base.Parameters->ParameterValues[source->Index]; default: _mesa_problem(NULL, "Bad source register file in get_register_pointer"); return NULL; } } return NULL;}/** * Fetch a 4-element float vector from the given source register. * Apply swizzling and negating as needed. */static INLINE voidfetch_vector4( const struct prog_src_register *source, const struct gl_vertex_program_state *state, GLfloat result[4] ){ const GLfloat *src = get_register_pointer(source, state); if (source->NegateBase) { result[0] = -src[GET_SWZ(source->Swizzle, 0)]; result[1] = -src[GET_SWZ(source->Swizzle, 1)]; result[2] = -src[GET_SWZ(source->Swizzle, 2)]; result[3] = -src[GET_SWZ(source->Swizzle, 3)]; } else { result[0] = src[GET_SWZ(source->Swizzle, 0)]; result[1] = src[GET_SWZ(source->Swizzle, 1)]; result[2] = src[GET_SWZ(source->Swizzle, 2)]; result[3] = src[GET_SWZ(source->Swizzle, 3)]; }}/** * As above, but only return result[0] element. */static INLINE voidfetch_vector1( const struct prog_src_register *source, const struct gl_vertex_program_state *state, GLfloat result[4] ){ const GLfloat *src = get_register_pointer(source, state); if (source->NegateBase) { result[0] = -src[GET_SWZ(source->Swizzle, 0)]; } else { result[0] = src[GET_SWZ(source->Swizzle, 0)]; }}/** * Store 4 floats into a register. */static voidstore_vector4( const struct prog_dst_register *dest, struct gl_vertex_program_state *state, const GLfloat value[4] ){ GLfloat *dst; switch (dest->File) { case PROGRAM_TEMPORARY: dst = state->Temporaries[dest->Index]; break; case PROGRAM_OUTPUT: dst = state->Outputs[dest->Index]; break; case PROGRAM_ENV_PARAM: { /* a slight hack */ GET_CURRENT_CONTEXT(ctx); dst = ctx->VertexProgram.Parameters[dest->Index]; } break; default: _mesa_problem(NULL, "Invalid register file in store_vector4(file=%d)", dest->File); return; } if (dest->WriteMask & WRITEMASK_X) dst[0] = value[0]; if (dest->WriteMask & WRITEMASK_Y) dst[1] = value[1]; if (dest->WriteMask & WRITEMASK_Z) dst[2] = value[2]; if (dest->WriteMask & WRITEMASK_W) dst[3] = value[3];}/** * Set x to positive or negative infinity. */#if defined(USE_IEEE) || defined(_WIN32)#define SET_POS_INFINITY(x) ( *((GLuint *) (void *)&x) = 0x7F800000 )#define SET_NEG_INFINITY(x) ( *((GLuint *) (void *)&x) = 0xFF800000 )#elif defined(VMS)#define SET_POS_INFINITY(x) x = __MAXFLOAT#define SET_NEG_INFINITY(x) x = -__MAXFLOAT#else#define SET_POS_INFINITY(x) x = (GLfloat) HUGE_VAL#define SET_NEG_INFINITY(x) x = (GLfloat) -HUGE_VAL#endif#define SET_FLOAT_BITS(x, bits) ((fi_type *) (void *) &(x))->i = bits/** * Execute the given vertex program */void_mesa_exec_vertex_program(GLcontext *ctx, const struct vertex_program *program){ struct gl_vertex_program_state *state = &ctx->VertexProgram; const struct prog_instruction *inst; ctx->_CurrentProgram = GL_VERTEX_PROGRAM_ARB; /* or NV, doesn't matter */ /* If the program is position invariant, multiply the input position * by the MVP matrix and store in the vertex position result register. */ if (ctx->VertexProgram.Current->IsPositionInvariant) { TRANSFORM_POINT( ctx->VertexProgram.Outputs[VERT_RESULT_HPOS], ctx->_ModelProjectMatrix.m, ctx->VertexProgram.Inputs[VERT_ATTRIB_POS]); /* XXX: This could go elsewhere */ ctx->VertexProgram.Current->Base.OutputsWritten |= VERT_BIT_POS; } for (inst = program->Base.Instructions; ; inst++) { if (ctx->VertexProgram.CallbackEnabled && ctx->VertexProgram.Callback) { ctx->VertexProgram.CurrentPosition = inst->StringPos; ctx->VertexProgram.Callback(program->Base.Target, ctx->VertexProgram.CallbackData); } switch (inst->Opcode) { case OPCODE_MOV: { GLfloat t[4]; fetch_vector4( &inst->SrcReg[0], state, t ); store_vector4( &inst->DstReg, state, t ); } break; case OPCODE_LIT: { const GLfloat epsilon = 1.0F / 256.0F; /* per NV spec */ GLfloat t[4], lit[4]; fetch_vector4( &inst->SrcReg[0], state, t ); t[0] = MAX2(t[0], 0.0F); t[1] = MAX2(t[1], 0.0F); t[3] = CLAMP(t[3], -(128.0F - epsilon), (128.0F - epsilon)); lit[0] = 1.0; lit[1] = t[0];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -