wined3d: Add a function to read an opcode from SM1-3 bytecode.
This commit is contained in:
parent
e63bd2ce21
commit
521fcf11db
|
@ -92,6 +92,120 @@ typedef enum _WINED3DSHADER_ADDRESSMODE_TYPE
|
|||
|
||||
static void shader_dump_param(const DWORD param, const DWORD addr_token, int input, DWORD shader_version);
|
||||
|
||||
/* Read a parameter opcode from the input stream,
|
||||
* and possibly a relative addressing token.
|
||||
* Return the number of tokens read */
|
||||
static int shader_get_param(const DWORD *ptr, DWORD shader_version, DWORD *token, DWORD *addr_token)
|
||||
{
|
||||
UINT count = 1;
|
||||
|
||||
*token = *ptr;
|
||||
|
||||
/* PS >= 3.0 have relative addressing (with token)
|
||||
* VS >= 2.0 have relative addressing (with token)
|
||||
* VS >= 1.0 < 2.0 have relative addressing (without token)
|
||||
* The version check below should work in general */
|
||||
if (*ptr & WINED3DSHADER_ADDRMODE_RELATIVE)
|
||||
{
|
||||
if (WINED3DSHADER_VERSION_MAJOR(shader_version) < 2)
|
||||
{
|
||||
*addr_token = (1 << 31)
|
||||
| ((WINED3DSPR_ADDR << WINED3DSP_REGTYPE_SHIFT2) & WINED3DSP_REGTYPE_MASK2)
|
||||
| ((WINED3DSPR_ADDR << WINED3DSP_REGTYPE_SHIFT) & WINED3DSP_REGTYPE_MASK)
|
||||
| (WINED3DSP_NOSWIZZLE << WINED3DSP_SWIZZLE_SHIFT);
|
||||
}
|
||||
else
|
||||
{
|
||||
*addr_token = *(ptr + 1);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const SHADER_OPCODE *shader_get_opcode(const SHADER_OPCODE *opcode_table, DWORD shader_version, DWORD code)
|
||||
{
|
||||
DWORD i = 0;
|
||||
|
||||
/** TODO: use dichotomic search */
|
||||
while (opcode_table[i].name)
|
||||
{
|
||||
if ((code & WINED3DSI_OPCODE_MASK) == opcode_table[i].opcode
|
||||
&& shader_version >= opcode_table[i].min_version
|
||||
&& (!opcode_table[i].max_version || shader_version <= opcode_table[i].max_version))
|
||||
{
|
||||
return &opcode_table[i];
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
FIXME("Unsupported opcode %#x(%d) masked %#x, shader version %#x\n",
|
||||
code, code, code & WINED3DSI_OPCODE_MASK, shader_version);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Return the number of parameters to skip for an opcode */
|
||||
static inline int shader_skip_opcode(const SHADER_OPCODE *opcode_info, DWORD opcode_token, DWORD shader_version)
|
||||
{
|
||||
/* Shaders >= 2.0 may contain address tokens, but fortunately they
|
||||
* have a useful length mask - use it here. Shaders 1.0 contain no such tokens */
|
||||
return (WINED3DSHADER_VERSION_MAJOR(shader_version) >= 2)
|
||||
? ((opcode_token & WINED3DSI_INSTLENGTH_MASK) >> WINED3DSI_INSTLENGTH_SHIFT) : opcode_info->num_params;
|
||||
}
|
||||
|
||||
/* Read the parameters of an unrecognized opcode from the input stream
|
||||
* Return the number of tokens read.
|
||||
*
|
||||
* Note: This function assumes source or destination token format.
|
||||
* It will not work with specially-formatted tokens like DEF or DCL,
|
||||
* but hopefully those would be recognized */
|
||||
static int shader_skip_unrecognized(const DWORD *ptr, DWORD shader_version)
|
||||
{
|
||||
int tokens_read = 0;
|
||||
int i = 0;
|
||||
|
||||
/* TODO: Think of a good name for 0x80000000 and replace it with a constant */
|
||||
while (*ptr & 0x80000000)
|
||||
{
|
||||
DWORD token, addr_token = 0;
|
||||
tokens_read += shader_get_param(ptr, shader_version, &token, &addr_token);
|
||||
ptr += tokens_read;
|
||||
|
||||
FIXME("Unrecognized opcode param: token=0x%08x addr_token=0x%08x name=", token, addr_token);
|
||||
shader_dump_param(token, addr_token, i, shader_version);
|
||||
FIXME("\n");
|
||||
++i;
|
||||
}
|
||||
return tokens_read;
|
||||
}
|
||||
|
||||
static void shader_sm1_read_opcode(const DWORD **ptr, struct wined3d_shader_instruction *ins, UINT *param_size,
|
||||
const SHADER_OPCODE *opcode_table, DWORD shader_version)
|
||||
{
|
||||
const SHADER_OPCODE *opcode_info;
|
||||
DWORD opcode_token;
|
||||
|
||||
opcode_token = *(*ptr)++;
|
||||
opcode_info = shader_get_opcode(opcode_table, shader_version, opcode_token);
|
||||
if (!opcode_info)
|
||||
{
|
||||
FIXME("Unrecognized opcode: token=0x%08x\n", opcode_token);
|
||||
ins->handler_idx = WINED3DSIH_TABLE_SIZE;
|
||||
*param_size = shader_skip_unrecognized(*ptr, shader_version);
|
||||
return;
|
||||
}
|
||||
|
||||
ins->handler_idx = opcode_info->handler_idx;
|
||||
ins->flags = (opcode_token & WINED3D_OPCODESPECIFICCONTROL_MASK) >> WINED3D_OPCODESPECIFICCONTROL_SHIFT;
|
||||
ins->coissue = opcode_token & WINED3DSI_COISSUE;
|
||||
ins->predicate = opcode_token & WINED3DSHADER_INSTRUCTION_PREDICATED;
|
||||
ins->dst_count = opcode_info->dst_token ? 1 : 0;
|
||||
ins->src_count = opcode_info->num_params - opcode_info->dst_token;
|
||||
*param_size = shader_skip_opcode(opcode_info, opcode_token, shader_version);
|
||||
}
|
||||
|
||||
static inline BOOL shader_is_version_token(DWORD token) {
|
||||
return shader_is_pshader_version(token) ||
|
||||
shader_is_vshader_version(token);
|
||||
|
@ -179,96 +293,6 @@ static inline BOOL shader_is_comment(DWORD token)
|
|||
return WINED3DSIO_COMMENT == (token & WINED3DSI_OPCODE_MASK);
|
||||
}
|
||||
|
||||
static const SHADER_OPCODE *shader_get_opcode(const SHADER_OPCODE *opcode_table, DWORD shader_version, DWORD code)
|
||||
{
|
||||
DWORD i = 0;
|
||||
|
||||
/** TODO: use dichotomic search */
|
||||
while (opcode_table[i].name)
|
||||
{
|
||||
if ((code & WINED3DSI_OPCODE_MASK) == opcode_table[i].opcode
|
||||
&& shader_version >= opcode_table[i].min_version
|
||||
&& (!opcode_table[i].max_version || shader_version <= opcode_table[i].max_version))
|
||||
{
|
||||
return &opcode_table[i];
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
FIXME("Unsupported opcode %#x(%d) masked %#x, shader version %#x\n",
|
||||
code, code, code & WINED3DSI_OPCODE_MASK, shader_version);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Read a parameter opcode from the input stream,
|
||||
* and possibly a relative addressing token.
|
||||
* Return the number of tokens read */
|
||||
static int shader_get_param(const DWORD *pToken, DWORD shader_version, DWORD *param, DWORD *addr_token)
|
||||
{
|
||||
UINT count = 1;
|
||||
|
||||
*param = *pToken;
|
||||
|
||||
/* PS >= 3.0 have relative addressing (with token)
|
||||
* VS >= 2.0 have relative addressing (with token)
|
||||
* VS >= 1.0 < 2.0 have relative addressing (without token)
|
||||
* The version check below should work in general */
|
||||
if (*pToken & WINED3DSHADER_ADDRMODE_RELATIVE)
|
||||
{
|
||||
if (WINED3DSHADER_VERSION_MAJOR(shader_version) < 2)
|
||||
{
|
||||
*addr_token = (1 << 31)
|
||||
| ((WINED3DSPR_ADDR << WINED3DSP_REGTYPE_SHIFT2) & WINED3DSP_REGTYPE_MASK2)
|
||||
| ((WINED3DSPR_ADDR << WINED3DSP_REGTYPE_SHIFT) & WINED3DSP_REGTYPE_MASK)
|
||||
| (WINED3DSP_NOSWIZZLE << WINED3DSP_SWIZZLE_SHIFT);
|
||||
}
|
||||
else
|
||||
{
|
||||
*addr_token = *(pToken + 1);
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Return the number of parameters to skip for an opcode */
|
||||
static inline int shader_skip_opcode(const SHADER_OPCODE *curOpcode, DWORD opcode_token, DWORD shader_version)
|
||||
{
|
||||
/* Shaders >= 2.0 may contain address tokens, but fortunately they
|
||||
* have a useful length mask - use it here. Shaders 1.0 contain no such tokens */
|
||||
return (WINED3DSHADER_VERSION_MAJOR(shader_version) >= 2)
|
||||
? ((opcode_token & WINED3DSI_INSTLENGTH_MASK) >> WINED3DSI_INSTLENGTH_SHIFT) : curOpcode->num_params;
|
||||
}
|
||||
|
||||
/* Read the parameters of an unrecognized opcode from the input stream
|
||||
* Return the number of tokens read.
|
||||
*
|
||||
* Note: This function assumes source or destination token format.
|
||||
* It will not work with specially-formatted tokens like DEF or DCL,
|
||||
* but hopefully those would be recognized */
|
||||
static int shader_skip_unrecognized(const DWORD *pToken, DWORD shader_version)
|
||||
{
|
||||
int tokens_read = 0;
|
||||
int i = 0;
|
||||
|
||||
/* TODO: Think of a good name for 0x80000000 and replace it with a constant */
|
||||
while (*pToken & 0x80000000) {
|
||||
|
||||
DWORD param, addr_token = 0;
|
||||
tokens_read += shader_get_param(pToken, shader_version, ¶m, &addr_token);
|
||||
pToken += tokens_read;
|
||||
|
||||
FIXME("Unrecognized opcode param: token=0x%08x "
|
||||
"addr_token=0x%08x name=", param, addr_token);
|
||||
shader_dump_param(param, addr_token, i, shader_version);
|
||||
FIXME("\n");
|
||||
++i;
|
||||
}
|
||||
return tokens_read;
|
||||
}
|
||||
|
||||
/* Convert floating point offset relative
|
||||
* to a register file to an absolute offset for float constants */
|
||||
static unsigned int shader_get_float_offset(const DWORD reg)
|
||||
|
@ -897,7 +921,6 @@ void shader_generate_main(IWineD3DBaseShader *iface, SHADER_BUFFER* buffer,
|
|||
struct wined3d_shader_instruction ins;
|
||||
struct wined3d_shader_context ctx;
|
||||
const DWORD *pToken = pFunction;
|
||||
const SHADER_OPCODE *curOpcode;
|
||||
SHADER_HANDLER hw_fct;
|
||||
DWORD i;
|
||||
|
||||
|
@ -919,7 +942,7 @@ void shader_generate_main(IWineD3DBaseShader *iface, SHADER_BUFFER* buffer,
|
|||
|
||||
while (WINED3DPS_END() != *pToken)
|
||||
{
|
||||
DWORD opcode_token;
|
||||
UINT param_size;
|
||||
|
||||
/* Skip comment tokens */
|
||||
if (shader_is_comment(*pToken))
|
||||
|
@ -930,47 +953,41 @@ void shader_generate_main(IWineD3DBaseShader *iface, SHADER_BUFFER* buffer,
|
|||
}
|
||||
|
||||
/* Read opcode */
|
||||
opcode_token = *pToken++;
|
||||
curOpcode = shader_get_opcode(opcode_table, shader_version, opcode_token);
|
||||
shader_sm1_read_opcode(&pToken, &ins, ¶m_size, opcode_table, shader_version);
|
||||
|
||||
/* Unknown opcode and its parameters */
|
||||
if (!curOpcode)
|
||||
if (ins.handler_idx == WINED3DSIH_TABLE_SIZE)
|
||||
{
|
||||
FIXME("Unrecognized opcode: token=0x%08x\n", opcode_token);
|
||||
pToken += shader_skip_unrecognized(pToken, shader_version);
|
||||
TRACE("Skipping unrecognized instruction.\n");
|
||||
pToken += param_size;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Nothing to do */
|
||||
if (WINED3DSIO_DCL == curOpcode->opcode
|
||||
|| WINED3DSIO_NOP == curOpcode->opcode
|
||||
|| WINED3DSIO_DEF == curOpcode->opcode
|
||||
|| WINED3DSIO_DEFI == curOpcode->opcode
|
||||
|| WINED3DSIO_DEFB == curOpcode->opcode
|
||||
|| WINED3DSIO_PHASE == curOpcode->opcode
|
||||
|| WINED3DSIO_RET == curOpcode->opcode)
|
||||
if (ins.handler_idx == WINED3DSIH_DCL
|
||||
|| ins.handler_idx == WINED3DSIH_NOP
|
||||
|| ins.handler_idx == WINED3DSIH_DEF
|
||||
|| ins.handler_idx == WINED3DSIH_DEFI
|
||||
|| ins.handler_idx == WINED3DSIH_DEFB
|
||||
|| ins.handler_idx == WINED3DSIH_PHASE
|
||||
|| ins.handler_idx == WINED3DSIH_RET)
|
||||
{
|
||||
pToken += shader_skip_opcode(curOpcode, opcode_token, shader_version);
|
||||
pToken += param_size;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Select handler */
|
||||
hw_fct = handler_table[curOpcode->handler_idx];
|
||||
hw_fct = handler_table[ins.handler_idx];
|
||||
|
||||
/* Unhandled opcode */
|
||||
if (!hw_fct)
|
||||
{
|
||||
FIXME("Can't handle opcode %s in hwShader\n", curOpcode->name);
|
||||
pToken += shader_skip_opcode(curOpcode, opcode_token, shader_version);
|
||||
FIXME("Backend can't handle opcode %#x\n", ins.handler_idx);
|
||||
pToken += param_size;
|
||||
continue;
|
||||
}
|
||||
|
||||
ins.handler_idx = curOpcode->handler_idx;
|
||||
ins.flags = (opcode_token & WINED3D_OPCODESPECIFICCONTROL_MASK) >> WINED3D_OPCODESPECIFICCONTROL_SHIFT;
|
||||
ins.coissue = opcode_token & WINED3DSI_COISSUE;
|
||||
|
||||
/* Destination token */
|
||||
ins.dst_count = curOpcode->dst_token ? 1 : 0;
|
||||
if (ins.dst_count)
|
||||
{
|
||||
DWORD param, addr_param;
|
||||
|
@ -988,10 +1005,9 @@ void shader_generate_main(IWineD3DBaseShader *iface, SHADER_BUFFER* buffer,
|
|||
}
|
||||
|
||||
/* Predication token */
|
||||
if (opcode_token & WINED3DSHADER_INSTRUCTION_PREDICATED) ins.predicate = *pToken++;
|
||||
if (ins.predicate) ins.predicate = *pToken++;
|
||||
|
||||
/* Other source tokens */
|
||||
ins.src_count = curOpcode->num_params - curOpcode->dst_token;
|
||||
for (i = 0; i < ins.src_count; ++i)
|
||||
{
|
||||
DWORD param, addr_param;
|
||||
|
|
Loading…
Reference in New Issue