
v2: Remove dead positive() function, caught by Matt. Reviewed-by: Brian Paul <brianp@vmware.com> (v1)
346 lines
10 KiB
C
346 lines
10 KiB
C
/*
|
|
* Mesa 3-D graphics library
|
|
* Version: 7.3
|
|
*
|
|
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
|
|
* Copyright (C) 1999-2009 VMware, Inc. 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.
|
|
*/
|
|
|
|
|
|
#include "main/glheader.h"
|
|
#include "main/imports.h"
|
|
#include "main/mtypes.h"
|
|
#include "prog_instruction.h"
|
|
|
|
|
|
/**
|
|
* Initialize program instruction fields to defaults.
|
|
* \param inst first instruction to initialize
|
|
* \param count number of instructions to initialize
|
|
*/
|
|
void
|
|
_mesa_init_instructions(struct prog_instruction *inst, GLuint count)
|
|
{
|
|
GLuint i;
|
|
|
|
memset(inst, 0, count * sizeof(struct prog_instruction));
|
|
|
|
for (i = 0; i < count; i++) {
|
|
inst[i].SrcReg[0].File = PROGRAM_UNDEFINED;
|
|
inst[i].SrcReg[0].Swizzle = SWIZZLE_NOOP;
|
|
inst[i].SrcReg[1].File = PROGRAM_UNDEFINED;
|
|
inst[i].SrcReg[1].Swizzle = SWIZZLE_NOOP;
|
|
inst[i].SrcReg[2].File = PROGRAM_UNDEFINED;
|
|
inst[i].SrcReg[2].Swizzle = SWIZZLE_NOOP;
|
|
|
|
inst[i].DstReg.File = PROGRAM_UNDEFINED;
|
|
inst[i].DstReg.WriteMask = WRITEMASK_XYZW;
|
|
inst[i].DstReg.CondMask = COND_TR;
|
|
inst[i].DstReg.CondSwizzle = SWIZZLE_NOOP;
|
|
|
|
inst[i].SaturateMode = SATURATE_OFF;
|
|
inst[i].Precision = FLOAT32;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Allocate an array of program instructions.
|
|
* \param numInst number of instructions
|
|
* \return pointer to instruction memory
|
|
*/
|
|
struct prog_instruction *
|
|
_mesa_alloc_instructions(GLuint numInst)
|
|
{
|
|
return
|
|
calloc(1, numInst * sizeof(struct prog_instruction));
|
|
}
|
|
|
|
|
|
/**
|
|
* Reallocate memory storing an array of program instructions.
|
|
* This is used when we need to append additional instructions onto an
|
|
* program.
|
|
* \param oldInst pointer to first of old/src instructions
|
|
* \param numOldInst number of instructions at <oldInst>
|
|
* \param numNewInst desired size of new instruction array.
|
|
* \return pointer to start of new instruction array.
|
|
*/
|
|
struct prog_instruction *
|
|
_mesa_realloc_instructions(struct prog_instruction *oldInst,
|
|
GLuint numOldInst, GLuint numNewInst)
|
|
{
|
|
struct prog_instruction *newInst;
|
|
|
|
newInst = (struct prog_instruction *)
|
|
_mesa_realloc(oldInst,
|
|
numOldInst * sizeof(struct prog_instruction),
|
|
numNewInst * sizeof(struct prog_instruction));
|
|
|
|
return newInst;
|
|
}
|
|
|
|
|
|
/**
|
|
* Copy an array of program instructions.
|
|
* \param dest pointer to destination.
|
|
* \param src pointer to source.
|
|
* \param n number of instructions to copy.
|
|
* \return pointer to destination.
|
|
*/
|
|
struct prog_instruction *
|
|
_mesa_copy_instructions(struct prog_instruction *dest,
|
|
const struct prog_instruction *src, GLuint n)
|
|
{
|
|
GLuint i;
|
|
memcpy(dest, src, n * sizeof(struct prog_instruction));
|
|
for (i = 0; i < n; i++) {
|
|
if (src[i].Comment)
|
|
dest[i].Comment = _mesa_strdup(src[i].Comment);
|
|
}
|
|
return dest;
|
|
}
|
|
|
|
|
|
/**
|
|
* Free an array of instructions
|
|
*/
|
|
void
|
|
_mesa_free_instructions(struct prog_instruction *inst, GLuint count)
|
|
{
|
|
GLuint i;
|
|
for (i = 0; i < count; i++) {
|
|
free(inst[i].Data);
|
|
free((char *)inst[i].Comment);
|
|
}
|
|
free(inst);
|
|
}
|
|
|
|
|
|
/**
|
|
* Basic info about each instruction
|
|
*/
|
|
struct instruction_info
|
|
{
|
|
gl_inst_opcode Opcode;
|
|
const char *Name;
|
|
GLuint NumSrcRegs;
|
|
GLuint NumDstRegs;
|
|
};
|
|
|
|
/**
|
|
* Instruction info
|
|
* \note Opcode should equal array index!
|
|
*/
|
|
static const struct instruction_info InstInfo[MAX_OPCODE] = {
|
|
{ OPCODE_NOP, "NOP", 0, 0 },
|
|
{ OPCODE_ABS, "ABS", 1, 1 },
|
|
{ OPCODE_ADD, "ADD", 2, 1 },
|
|
{ OPCODE_AND, "AND", 2, 1 },
|
|
{ OPCODE_ARL, "ARL", 1, 1 },
|
|
{ OPCODE_BGNLOOP,"BGNLOOP", 0, 0 },
|
|
{ OPCODE_BGNSUB, "BGNSUB", 0, 0 },
|
|
{ OPCODE_BRK, "BRK", 0, 0 },
|
|
{ OPCODE_CAL, "CAL", 0, 0 },
|
|
{ OPCODE_CMP, "CMP", 3, 1 },
|
|
{ OPCODE_CONT, "CONT", 0, 0 },
|
|
{ OPCODE_COS, "COS", 1, 1 },
|
|
{ OPCODE_DDX, "DDX", 1, 1 },
|
|
{ OPCODE_DDY, "DDY", 1, 1 },
|
|
{ OPCODE_DP2, "DP2", 2, 1 },
|
|
{ OPCODE_DP2A, "DP2A", 3, 1 },
|
|
{ OPCODE_DP3, "DP3", 2, 1 },
|
|
{ OPCODE_DP4, "DP4", 2, 1 },
|
|
{ OPCODE_DPH, "DPH", 2, 1 },
|
|
{ OPCODE_DST, "DST", 2, 1 },
|
|
{ OPCODE_ELSE, "ELSE", 0, 0 },
|
|
{ OPCODE_EMIT_VERTEX, "EMIT_VERTEX", 0, 0 },
|
|
{ OPCODE_END, "END", 0, 0 },
|
|
{ OPCODE_END_PRIMITIVE, "END_PRIMITIVE", 0, 0 },
|
|
{ OPCODE_ENDIF, "ENDIF", 0, 0 },
|
|
{ OPCODE_ENDLOOP,"ENDLOOP", 0, 0 },
|
|
{ OPCODE_ENDSUB, "ENDSUB", 0, 0 },
|
|
{ OPCODE_EX2, "EX2", 1, 1 },
|
|
{ OPCODE_EXP, "EXP", 1, 1 },
|
|
{ OPCODE_FLR, "FLR", 1, 1 },
|
|
{ OPCODE_FRC, "FRC", 1, 1 },
|
|
{ OPCODE_IF, "IF", 1, 0 },
|
|
{ OPCODE_KIL, "KIL", 1, 0 },
|
|
{ OPCODE_KIL_NV, "KIL_NV", 0, 0 },
|
|
{ OPCODE_LG2, "LG2", 1, 1 },
|
|
{ OPCODE_LIT, "LIT", 1, 1 },
|
|
{ OPCODE_LOG, "LOG", 1, 1 },
|
|
{ OPCODE_LRP, "LRP", 3, 1 },
|
|
{ OPCODE_MAD, "MAD", 3, 1 },
|
|
{ OPCODE_MAX, "MAX", 2, 1 },
|
|
{ OPCODE_MIN, "MIN", 2, 1 },
|
|
{ OPCODE_MOV, "MOV", 1, 1 },
|
|
{ OPCODE_MUL, "MUL", 2, 1 },
|
|
{ OPCODE_NOISE1, "NOISE1", 1, 1 },
|
|
{ OPCODE_NOISE2, "NOISE2", 1, 1 },
|
|
{ OPCODE_NOISE3, "NOISE3", 1, 1 },
|
|
{ OPCODE_NOISE4, "NOISE4", 1, 1 },
|
|
{ OPCODE_NOT, "NOT", 1, 1 },
|
|
{ OPCODE_NRM3, "NRM3", 1, 1 },
|
|
{ OPCODE_NRM4, "NRM4", 1, 1 },
|
|
{ OPCODE_OR, "OR", 2, 1 },
|
|
{ OPCODE_PK2H, "PK2H", 1, 1 },
|
|
{ OPCODE_PK2US, "PK2US", 1, 1 },
|
|
{ OPCODE_PK4B, "PK4B", 1, 1 },
|
|
{ OPCODE_PK4UB, "PK4UB", 1, 1 },
|
|
{ OPCODE_POW, "POW", 2, 1 },
|
|
{ OPCODE_PRINT, "PRINT", 1, 0 },
|
|
{ OPCODE_RCP, "RCP", 1, 1 },
|
|
{ OPCODE_RET, "RET", 0, 0 },
|
|
{ OPCODE_RFL, "RFL", 1, 1 },
|
|
{ OPCODE_RSQ, "RSQ", 1, 1 },
|
|
{ OPCODE_SCS, "SCS", 1, 1 },
|
|
{ OPCODE_SEQ, "SEQ", 2, 1 },
|
|
{ OPCODE_SFL, "SFL", 0, 1 },
|
|
{ OPCODE_SGE, "SGE", 2, 1 },
|
|
{ OPCODE_SGT, "SGT", 2, 1 },
|
|
{ OPCODE_SIN, "SIN", 1, 1 },
|
|
{ OPCODE_SLE, "SLE", 2, 1 },
|
|
{ OPCODE_SLT, "SLT", 2, 1 },
|
|
{ OPCODE_SNE, "SNE", 2, 1 },
|
|
{ OPCODE_SSG, "SSG", 1, 1 },
|
|
{ OPCODE_STR, "STR", 0, 1 },
|
|
{ OPCODE_SUB, "SUB", 2, 1 },
|
|
{ OPCODE_SWZ, "SWZ", 1, 1 },
|
|
{ OPCODE_TEX, "TEX", 1, 1 },
|
|
{ OPCODE_TXB, "TXB", 1, 1 },
|
|
{ OPCODE_TXD, "TXD", 3, 1 },
|
|
{ OPCODE_TXL, "TXL", 1, 1 },
|
|
{ OPCODE_TXP, "TXP", 1, 1 },
|
|
{ OPCODE_TXP_NV, "TXP_NV", 1, 1 },
|
|
{ OPCODE_TRUNC, "TRUNC", 1, 1 },
|
|
{ OPCODE_UP2H, "UP2H", 1, 1 },
|
|
{ OPCODE_UP2US, "UP2US", 1, 1 },
|
|
{ OPCODE_UP4B, "UP4B", 1, 1 },
|
|
{ OPCODE_UP4UB, "UP4UB", 1, 1 },
|
|
{ OPCODE_X2D, "X2D", 3, 1 },
|
|
{ OPCODE_XOR, "XOR", 2, 1 },
|
|
{ OPCODE_XPD, "XPD", 2, 1 }
|
|
};
|
|
|
|
|
|
/**
|
|
* Return the number of src registers for the given instruction/opcode.
|
|
*/
|
|
GLuint
|
|
_mesa_num_inst_src_regs(gl_inst_opcode opcode)
|
|
{
|
|
ASSERT(opcode < MAX_OPCODE);
|
|
ASSERT(opcode == InstInfo[opcode].Opcode);
|
|
ASSERT(OPCODE_XPD == InstInfo[OPCODE_XPD].Opcode);
|
|
return InstInfo[opcode].NumSrcRegs;
|
|
}
|
|
|
|
|
|
/**
|
|
* Return the number of dst registers for the given instruction/opcode.
|
|
*/
|
|
GLuint
|
|
_mesa_num_inst_dst_regs(gl_inst_opcode opcode)
|
|
{
|
|
ASSERT(opcode < MAX_OPCODE);
|
|
ASSERT(opcode == InstInfo[opcode].Opcode);
|
|
ASSERT(OPCODE_XPD == InstInfo[OPCODE_XPD].Opcode);
|
|
return InstInfo[opcode].NumDstRegs;
|
|
}
|
|
|
|
|
|
GLboolean
|
|
_mesa_is_tex_instruction(gl_inst_opcode opcode)
|
|
{
|
|
return (opcode == OPCODE_TEX ||
|
|
opcode == OPCODE_TXB ||
|
|
opcode == OPCODE_TXD ||
|
|
opcode == OPCODE_TXL ||
|
|
opcode == OPCODE_TXP);
|
|
}
|
|
|
|
|
|
/**
|
|
* Check if there's a potential src/dst register data dependency when
|
|
* using SOA execution.
|
|
* Example:
|
|
* MOV T, T.yxwz;
|
|
* This would expand into:
|
|
* MOV t0, t1;
|
|
* MOV t1, t0;
|
|
* MOV t2, t3;
|
|
* MOV t3, t2;
|
|
* The second instruction will have the wrong value for t0 if executed as-is.
|
|
*/
|
|
GLboolean
|
|
_mesa_check_soa_dependencies(const struct prog_instruction *inst)
|
|
{
|
|
GLuint i, chan;
|
|
|
|
if (inst->DstReg.WriteMask == WRITEMASK_X ||
|
|
inst->DstReg.WriteMask == WRITEMASK_Y ||
|
|
inst->DstReg.WriteMask == WRITEMASK_Z ||
|
|
inst->DstReg.WriteMask == WRITEMASK_W ||
|
|
inst->DstReg.WriteMask == 0x0) {
|
|
/* no chance of data dependency */
|
|
return GL_FALSE;
|
|
}
|
|
|
|
/* loop over src regs */
|
|
for (i = 0; i < 3; i++) {
|
|
if (inst->SrcReg[i].File == inst->DstReg.File &&
|
|
inst->SrcReg[i].Index == inst->DstReg.Index) {
|
|
/* loop over dest channels */
|
|
GLuint channelsWritten = 0x0;
|
|
for (chan = 0; chan < 4; chan++) {
|
|
if (inst->DstReg.WriteMask & (1 << chan)) {
|
|
/* check if we're reading a channel that's been written */
|
|
GLuint swizzle = GET_SWZ(inst->SrcReg[i].Swizzle, chan);
|
|
if (swizzle <= SWIZZLE_W &&
|
|
(channelsWritten & (1 << swizzle))) {
|
|
return GL_TRUE;
|
|
}
|
|
|
|
channelsWritten |= (1 << chan);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return GL_FALSE;
|
|
}
|
|
|
|
|
|
/**
|
|
* Return string name for given program opcode.
|
|
*/
|
|
const char *
|
|
_mesa_opcode_string(gl_inst_opcode opcode)
|
|
{
|
|
if (opcode < MAX_OPCODE)
|
|
return InstInfo[opcode].Name;
|
|
else {
|
|
static char s[20];
|
|
_mesa_snprintf(s, sizeof(s), "OP%u", opcode);
|
|
return s;
|
|
}
|
|
}
|
|
|