mesa/src/gallium/frontends/d3d10umd/ShaderParse.c
Jose Fonseca 54b8137141 d3d10umd,d3d10sw: Initial import.
This change adds a gallium D3D10 state tracker that works as a WDDM UMD
software driver, similar to Microsoft WARP, but using llvmpipe/softpipe.

The final deliverable is a d3d10sw.dll, which is similar to WARP's
d3d10warp.dll.

This has been used to run Microsoft Windows HCK wgf11* tests with
llvmpipe, and they were at one point passing 100%.

Known limitations:
- TGSI (no NIR)
- D3D10 only (no D3D11 support yet)
- no WINE integration (WINE doesn't implement WDDM DDI.)

For further details see:
- src/gallium/frontends/d3d10umd/README.md
- src/gallium/targets/d3d10sw/README.md

v2: Drop the DXBC-based disassembly.  Add missing break statements.
v3: Incorporate Jesse's feedback.

Reviewed-by: Roland Scheidegger <sroland@vmware.com>
Acked-by: Jesse Natalie <jenatali@microsoft.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/10687>
2021-05-19 13:50:07 +00:00

610 lines
25 KiB
C

/**************************************************************************
*
* Copyright 2012-2021 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
**************************************************************************/
/*
* ShaderParse.c --
* Functions for parsing shader tokens.
*/
#include "Debug.h"
#include "ShaderParse.h"
#include "util/u_memory.h"
void
Shader_parse_init(struct Shader_parser *parser,
const unsigned *code)
{
parser->curr = parser->code = code;
parser->header.type = DECODE_D3D10_SB_TOKENIZED_PROGRAM_TYPE(*parser->curr);
parser->header.major_version = DECODE_D3D10_SB_TOKENIZED_PROGRAM_MAJOR_VERSION(*parser->curr);
parser->header.minor_version = DECODE_D3D10_SB_TOKENIZED_PROGRAM_MINOR_VERSION(*parser->curr);
parser->curr++;
parser->header.size = DECODE_D3D10_SB_TOKENIZED_PROGRAM_LENGTH(*parser->curr);
parser->curr++;
}
#define OP_NOT_DONE (1 << 0) /* not implemented yet */
#define OP_SATURATE (1 << 1) /* saturate in opcode specific control */
#define OP_TEST_BOOLEAN (1 << 2) /* test boolean in opcode specific control */
#define OP_DCL (1 << 3) /* custom opcode specific control */
#define OP_RESINFO_RET_TYPE (1 << 4) /* return type for resinfo */
struct dx10_opcode_info {
D3D10_SB_OPCODE_TYPE type;
const char *name;
unsigned num_dst;
unsigned num_src;
unsigned flags;
};
#define _(_opcode) _opcode, #_opcode
static const struct dx10_opcode_info
opcode_info[D3D10_SB_NUM_OPCODES] = {
{_(D3D10_SB_OPCODE_ADD), 1, 2, OP_SATURATE},
{_(D3D10_SB_OPCODE_AND), 1, 2, 0},
{_(D3D10_SB_OPCODE_BREAK), 0, 0, 0},
{_(D3D10_SB_OPCODE_BREAKC), 0, 1, OP_TEST_BOOLEAN},
{_(D3D10_SB_OPCODE_CALL), 0, 1, 0},
{_(D3D10_SB_OPCODE_CALLC), 0, 2, OP_TEST_BOOLEAN},
{_(D3D10_SB_OPCODE_CASE), 0, 1, 0},
{_(D3D10_SB_OPCODE_CONTINUE), 0, 0, 0},
{_(D3D10_SB_OPCODE_CONTINUEC), 0, 1, OP_TEST_BOOLEAN},
{_(D3D10_SB_OPCODE_CUT), 0, 0, 0},
{_(D3D10_SB_OPCODE_DEFAULT), 0, 0, 0},
{_(D3D10_SB_OPCODE_DERIV_RTX), 1, 1, OP_SATURATE},
{_(D3D10_SB_OPCODE_DERIV_RTY), 1, 1, OP_SATURATE},
{_(D3D10_SB_OPCODE_DISCARD), 0, 1, OP_TEST_BOOLEAN},
{_(D3D10_SB_OPCODE_DIV), 1, 2, OP_SATURATE},
{_(D3D10_SB_OPCODE_DP2), 1, 2, OP_SATURATE},
{_(D3D10_SB_OPCODE_DP3), 1, 2, OP_SATURATE},
{_(D3D10_SB_OPCODE_DP4), 1, 2, OP_SATURATE},
{_(D3D10_SB_OPCODE_ELSE), 0, 0, 0},
{_(D3D10_SB_OPCODE_EMIT), 0, 0, 0},
{_(D3D10_SB_OPCODE_EMITTHENCUT), 0, 0, 0},
{_(D3D10_SB_OPCODE_ENDIF), 0, 0, 0},
{_(D3D10_SB_OPCODE_ENDLOOP), 0, 0, 0},
{_(D3D10_SB_OPCODE_ENDSWITCH), 0, 0, 0},
{_(D3D10_SB_OPCODE_EQ), 1, 2, 0},
{_(D3D10_SB_OPCODE_EXP), 1, 1, OP_SATURATE},
{_(D3D10_SB_OPCODE_FRC), 1, 1, OP_SATURATE},
{_(D3D10_SB_OPCODE_FTOI), 1, 1, 0},
{_(D3D10_SB_OPCODE_FTOU), 1, 1, 0},
{_(D3D10_SB_OPCODE_GE), 1, 2, 0},
{_(D3D10_SB_OPCODE_IADD), 1, 2, 0},
{_(D3D10_SB_OPCODE_IF), 0, 1, OP_TEST_BOOLEAN},
{_(D3D10_SB_OPCODE_IEQ), 1, 2, 0},
{_(D3D10_SB_OPCODE_IGE), 1, 2, 0},
{_(D3D10_SB_OPCODE_ILT), 1, 2, 0},
{_(D3D10_SB_OPCODE_IMAD), 1, 3, 0},
{_(D3D10_SB_OPCODE_IMAX), 1, 2, 0},
{_(D3D10_SB_OPCODE_IMIN), 1, 2, 0},
{_(D3D10_SB_OPCODE_IMUL), 2, 2, 0},
{_(D3D10_SB_OPCODE_INE), 1, 2, 0},
{_(D3D10_SB_OPCODE_INEG), 1, 1, 0},
{_(D3D10_SB_OPCODE_ISHL), 1, 2, 0},
{_(D3D10_SB_OPCODE_ISHR), 1, 2, 0},
{_(D3D10_SB_OPCODE_ITOF), 1, 1, 0},
{_(D3D10_SB_OPCODE_LABEL), 0, 1, 0},
{_(D3D10_SB_OPCODE_LD), 1, 2, 0},
{_(D3D10_SB_OPCODE_LD_MS), 1, 3, 0},
{_(D3D10_SB_OPCODE_LOG), 1, 1, OP_SATURATE},
{_(D3D10_SB_OPCODE_LOOP), 0, 0, 0},
{_(D3D10_SB_OPCODE_LT), 1, 2, 0},
{_(D3D10_SB_OPCODE_MAD), 1, 3, OP_SATURATE},
{_(D3D10_SB_OPCODE_MIN), 1, 2, OP_SATURATE},
{_(D3D10_SB_OPCODE_MAX), 1, 2, OP_SATURATE},
{_(D3D10_SB_OPCODE_CUSTOMDATA), 0, 0, 0},
{_(D3D10_SB_OPCODE_MOV), 1, 1, OP_SATURATE},
{_(D3D10_SB_OPCODE_MOVC), 1, 3, OP_SATURATE},
{_(D3D10_SB_OPCODE_MUL), 1, 2, OP_SATURATE},
{_(D3D10_SB_OPCODE_NE), 1, 2, 0},
{_(D3D10_SB_OPCODE_NOP), 0, 0, 0},
{_(D3D10_SB_OPCODE_NOT), 1, 1, 0},
{_(D3D10_SB_OPCODE_OR), 1, 2, 0},
{_(D3D10_SB_OPCODE_RESINFO), 1, 2, OP_RESINFO_RET_TYPE},
{_(D3D10_SB_OPCODE_RET), 0, 0, 0},
{_(D3D10_SB_OPCODE_RETC), 0, 1, OP_TEST_BOOLEAN},
{_(D3D10_SB_OPCODE_ROUND_NE), 1, 1, OP_SATURATE},
{_(D3D10_SB_OPCODE_ROUND_NI), 1, 1, OP_SATURATE},
{_(D3D10_SB_OPCODE_ROUND_PI), 1, 1, OP_SATURATE},
{_(D3D10_SB_OPCODE_ROUND_Z), 1, 1, OP_SATURATE},
{_(D3D10_SB_OPCODE_RSQ), 1, 1, OP_SATURATE},
{_(D3D10_SB_OPCODE_SAMPLE), 1, 3, 0},
{_(D3D10_SB_OPCODE_SAMPLE_C), 1, 4, 0},
{_(D3D10_SB_OPCODE_SAMPLE_C_LZ), 1, 4, 0},
{_(D3D10_SB_OPCODE_SAMPLE_L), 1, 4, 0},
{_(D3D10_SB_OPCODE_SAMPLE_D), 1, 5, 0},
{_(D3D10_SB_OPCODE_SAMPLE_B), 1, 4, 0},
{_(D3D10_SB_OPCODE_SQRT), 1, 1, OP_SATURATE},
{_(D3D10_SB_OPCODE_SWITCH), 0, 1, 0},
{_(D3D10_SB_OPCODE_SINCOS), 2, 1, OP_SATURATE},
{_(D3D10_SB_OPCODE_UDIV), 2, 2, 0},
{_(D3D10_SB_OPCODE_ULT), 1, 2, 0},
{_(D3D10_SB_OPCODE_UGE), 1, 2, 0},
{_(D3D10_SB_OPCODE_UMUL), 2, 2, 0},
{_(D3D10_SB_OPCODE_UMAD), 1, 3, 0},
{_(D3D10_SB_OPCODE_UMAX), 1, 2, 0},
{_(D3D10_SB_OPCODE_UMIN), 1, 2, 0},
{_(D3D10_SB_OPCODE_USHR), 1, 2, 0},
{_(D3D10_SB_OPCODE_UTOF), 1, 1, 0},
{_(D3D10_SB_OPCODE_XOR), 1, 2, 0},
{_(D3D10_SB_OPCODE_DCL_RESOURCE), 1, 0, OP_DCL},
{_(D3D10_SB_OPCODE_DCL_CONSTANT_BUFFER), 0, 1, OP_DCL},
{_(D3D10_SB_OPCODE_DCL_SAMPLER), 1, 0, OP_DCL},
{_(D3D10_SB_OPCODE_DCL_INDEX_RANGE), 1, 0, OP_DCL},
{_(D3D10_SB_OPCODE_DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY), 0, 0, OP_DCL},
{_(D3D10_SB_OPCODE_DCL_GS_INPUT_PRIMITIVE), 0, 0, OP_DCL},
{_(D3D10_SB_OPCODE_DCL_MAX_OUTPUT_VERTEX_COUNT), 0, 0, OP_DCL},
{_(D3D10_SB_OPCODE_DCL_INPUT), 1, 0, OP_DCL},
{_(D3D10_SB_OPCODE_DCL_INPUT_SGV), 1, 0, OP_DCL},
{_(D3D10_SB_OPCODE_DCL_INPUT_SIV), 1, 0, OP_DCL},
{_(D3D10_SB_OPCODE_DCL_INPUT_PS), 1, 0, OP_DCL},
{_(D3D10_SB_OPCODE_DCL_INPUT_PS_SGV), 1, 0, OP_DCL},
{_(D3D10_SB_OPCODE_DCL_INPUT_PS_SIV), 1, 0, OP_DCL},
{_(D3D10_SB_OPCODE_DCL_OUTPUT), 1, 0, OP_DCL},
{_(D3D10_SB_OPCODE_DCL_OUTPUT_SGV), 1, 0, OP_DCL},
{_(D3D10_SB_OPCODE_DCL_OUTPUT_SIV), 1, 0, OP_DCL},
{_(D3D10_SB_OPCODE_DCL_TEMPS), 0, 0, OP_DCL},
{_(D3D10_SB_OPCODE_DCL_INDEXABLE_TEMP), 0, 0, OP_DCL},
{_(D3D10_SB_OPCODE_DCL_GLOBAL_FLAGS), 0, 0, OP_DCL},
{_(D3D10_SB_OPCODE_RESERVED0), 0, 0, OP_NOT_DONE},
{_(D3D10_1_SB_OPCODE_LOD), 0, 0, OP_NOT_DONE},
{_(D3D10_1_SB_OPCODE_GATHER4), 0, 0, OP_NOT_DONE},
{_(D3D10_1_SB_OPCODE_SAMPLE_POS), 0, 0, OP_NOT_DONE},
{_(D3D10_1_SB_OPCODE_SAMPLE_INFO), 0, 0, OP_NOT_DONE}
};
#undef _
static void
parse_operand(const unsigned **curr,
struct Shader_operand *operand)
{
operand->type = DECODE_D3D10_SB_OPERAND_TYPE(**curr);
/* Index dimension. */
switch (DECODE_D3D10_SB_OPERAND_INDEX_DIMENSION(**curr)) {
case D3D10_SB_OPERAND_INDEX_0D:
operand->index_dim = 0;
break;
case D3D10_SB_OPERAND_INDEX_1D:
operand->index_dim = 1;
break;
case D3D10_SB_OPERAND_INDEX_2D:
operand->index_dim = 2;
break;
default:
assert(0);
}
if (operand->index_dim >= 1) {
operand->index[0].index_rep = DECODE_D3D10_SB_OPERAND_INDEX_REPRESENTATION(0, **curr);
if (operand->index_dim >= 2) {
operand->index[1].index_rep = DECODE_D3D10_SB_OPERAND_INDEX_REPRESENTATION(1, **curr);
}
}
(*curr)++;
}
static void
parse_relative_operand(const unsigned **curr,
struct Shader_relative_operand *operand)
{
assert(!DECODE_IS_D3D10_SB_OPERAND_EXTENDED(**curr));
assert(DECODE_D3D10_SB_OPERAND_NUM_COMPONENTS(**curr) == D3D10_SB_OPERAND_4_COMPONENT);
assert(DECODE_D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE(**curr) == D3D10_SB_OPERAND_4_COMPONENT_SELECT_1_MODE);
operand->comp = DECODE_D3D10_SB_OPERAND_4_COMPONENT_SELECT_1(**curr);
operand->type = DECODE_D3D10_SB_OPERAND_TYPE(**curr);
assert(operand->type != D3D10_SB_OPERAND_TYPE_IMMEDIATE32);
/* Index dimension. */
assert(DECODE_D3D10_SB_OPERAND_INDEX_REPRESENTATION(0, **curr) == D3D10_SB_OPERAND_INDEX_IMMEDIATE32);
if (DECODE_D3D10_SB_OPERAND_INDEX_DIMENSION(**curr) == D3D10_SB_OPERAND_INDEX_1D) {
(*curr)++;
operand->index[0].imm = **curr;
} else {
assert(DECODE_D3D10_SB_OPERAND_INDEX_DIMENSION(**curr) == D3D10_SB_OPERAND_INDEX_2D);
(*curr)++;
operand->index[0].imm = **curr;
(*curr)++;
operand->index[1].imm = **curr;
}
(*curr)++;
}
static void
parse_index(const unsigned **curr,
struct Shader_index *index)
{
switch (index->index_rep) {
case D3D10_SB_OPERAND_INDEX_IMMEDIATE32:
index->imm = *(*curr)++;
break;
case D3D10_SB_OPERAND_INDEX_RELATIVE:
index->imm = 0;
parse_relative_operand(curr, &index->rel);
break;
case D3D10_SB_OPERAND_INDEX_IMMEDIATE32_PLUS_RELATIVE:
index->imm = *(*curr)++;
parse_relative_operand(curr, &index->rel);
break;
default:
/* XXX: Support other index representations.
*/
assert(0);
}
}
static void
parse_operand_index(const unsigned **curr,
struct Shader_operand *operand)
{
if (operand->index_dim >= 1) {
parse_index(curr, &operand->index[0]);
if (operand->index_dim >= 2) {
parse_index(curr, &operand->index[1]);
}
}
}
boolean
Shader_parse_opcode(struct Shader_parser *parser,
struct Shader_opcode *opcode)
{
const unsigned *curr = parser->curr;
const struct dx10_opcode_info *info;
unsigned length;
boolean opcode_is_extended;
unsigned i;
if (curr >= parser->code + parser->header.size) {
return FALSE;
}
memset(opcode, 0, sizeof *opcode);
/* Opcode type. */
opcode->type = DECODE_D3D10_SB_OPCODE_TYPE(*curr);
if (opcode->type == D3D10_SB_OPCODE_CUSTOMDATA) {
opcode->customdata._class = DECODE_D3D10_SB_CUSTOMDATA_CLASS(*curr);
curr++;
assert(opcode->customdata._class == D3D10_SB_CUSTOMDATA_DCL_IMMEDIATE_CONSTANT_BUFFER);
opcode->customdata.u.constbuf.count = *curr - 2;
curr++;
opcode->customdata.u.constbuf.data = MALLOC(opcode->customdata.u.constbuf.count * sizeof(unsigned));
assert(opcode->customdata.u.constbuf.data);
memcpy(opcode->customdata.u.constbuf.data,
curr,
opcode->customdata.u.constbuf.count * sizeof(unsigned));
curr += opcode->customdata.u.constbuf.count;
parser->curr = curr;
return TRUE;
}
opcode->dcl_siv_name = D3D10_SB_NAME_UNDEFINED;
/* Lookup extra information based on opcode type. */
assert(opcode->type < D3D10_SB_NUM_OPCODES);
info = &opcode_info[opcode->type];
/* Opcode specific. */
switch (opcode->type) {
case D3D10_SB_OPCODE_DCL_RESOURCE:
opcode->specific.dcl_resource_dimension = DECODE_D3D10_SB_RESOURCE_DIMENSION(*curr);
break;
case D3D10_SB_OPCODE_DCL_SAMPLER:
opcode->specific.dcl_sampler_mode = DECODE_D3D10_SB_SAMPLER_MODE(*curr);
break;
case D3D10_SB_OPCODE_DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY:
opcode->specific.dcl_gs_output_primitive_topology = DECODE_D3D10_SB_GS_OUTPUT_PRIMITIVE_TOPOLOGY(*curr);
break;
case D3D10_SB_OPCODE_DCL_GS_INPUT_PRIMITIVE:
opcode->specific.dcl_gs_input_primitive = DECODE_D3D10_SB_GS_INPUT_PRIMITIVE(*curr);
break;
case D3D10_SB_OPCODE_DCL_INPUT_PS:
case D3D10_SB_OPCODE_DCL_INPUT_PS_SIV:
opcode->specific.dcl_in_ps_interp = DECODE_D3D10_SB_INPUT_INTERPOLATION_MODE(*curr);
break;
case D3D10_SB_OPCODE_DCL_GLOBAL_FLAGS:
opcode->specific.global_flags.refactoring_allowed = DECODE_D3D10_SB_GLOBAL_FLAGS(*curr) ? 1 : 0;
break;
default:
/* Parse opcode-specific control bits */
if (info->flags & OP_DCL) {
/* no-op */
} else if (info->flags & OP_SATURATE) {
opcode->saturate =
!!DECODE_IS_D3D10_SB_INSTRUCTION_SATURATE_ENABLED(*curr);
} else if (info->flags & OP_TEST_BOOLEAN) {
opcode->specific.test_boolean =
DECODE_D3D10_SB_INSTRUCTION_TEST_BOOLEAN(*curr);
} else if (info->flags & OP_RESINFO_RET_TYPE) {
opcode->specific.resinfo_ret_type =
DECODE_D3D10_SB_RESINFO_INSTRUCTION_RETURN_TYPE(*curr);
} else {
/* Warn if there are bits set in the opcode-specific controls (bits 23:11 inclusive)*/
if (*curr & ((1 << 24) - (1 << 11))) {
debug_printf("warning: unexpected opcode-specific control in opcode %s\n",
info->name);
}
}
break;
}
/* Opcode length in DWORDs. */
length = DECODE_D3D10_SB_TOKENIZED_INSTRUCTION_LENGTH(*curr);
assert(curr + length <= parser->code + parser->header.size);
/* Opcode specific fields in token0. */
switch (opcode->type) {
case D3D10_SB_OPCODE_DCL_CONSTANT_BUFFER:
opcode->specific.dcl_cb_access_pattern =
DECODE_D3D10_SB_CONSTANT_BUFFER_ACCESS_PATTERN(*curr);
break;
default:
break;
}
opcode_is_extended = DECODE_IS_D3D10_SB_OPCODE_EXTENDED(*curr);
curr++;
if (opcode_is_extended) {
/* NOTE: DECODE_IS_D3D10_SB_OPCODE_DOUBLE_EXTENDED is broken.
*/
assert(!((*curr & D3D10_SB_OPCODE_DOUBLE_EXTENDED_MASK) >> D3D10_SB_OPERAND_DOUBLE_EXTENDED_SHIFT));
switch (DECODE_D3D10_SB_EXTENDED_OPCODE_TYPE(*curr)) {
case D3D10_SB_EXTENDED_OPCODE_EMPTY:
break;
case D3D10_SB_EXTENDED_OPCODE_SAMPLE_CONTROLS:
opcode->imm_texel_offset.u = DECODE_IMMEDIATE_D3D10_SB_ADDRESS_OFFSET(D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_U, *curr);
opcode->imm_texel_offset.v = DECODE_IMMEDIATE_D3D10_SB_ADDRESS_OFFSET(D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_V, *curr);
opcode->imm_texel_offset.w = DECODE_IMMEDIATE_D3D10_SB_ADDRESS_OFFSET(D3D10_SB_IMMEDIATE_ADDRESS_OFFSET_W, *curr);
break;
default:
assert(0);
}
curr++;
}
if (info->flags & OP_NOT_DONE) {
/* XXX: Need to figure out the number of operands for this opcode.
* Should be okay to continue execution -- we have enough info
* to skip to the next instruction.
*/
LOG_UNSUPPORTED(TRUE);
opcode->num_dst = 0;
opcode->num_src = 0;
goto skip;
}
opcode->num_dst = info->num_dst;
opcode->num_src = info->num_src;
/* Destination operands. */
for (i = 0; i < info->num_dst; i++) {
D3D10_SB_OPERAND_NUM_COMPONENTS num_components;
assert(!DECODE_IS_D3D10_SB_OPERAND_EXTENDED(*curr));
num_components = DECODE_D3D10_SB_OPERAND_NUM_COMPONENTS(*curr);
if (num_components == D3D10_SB_OPERAND_4_COMPONENT) {
D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE selection_mode;
selection_mode = DECODE_D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE(*curr);
assert(selection_mode == D3D10_SB_OPERAND_4_COMPONENT_MASK_MODE);
opcode->dst[i].mask = DECODE_D3D10_SB_OPERAND_4_COMPONENT_MASK(*curr);
} else {
assert(num_components == D3D10_SB_OPERAND_0_COMPONENT ||
num_components == D3D10_SB_OPERAND_1_COMPONENT);
opcode->dst[i].mask = D3D10_SB_OPERAND_4_COMPONENT_MASK_X;
}
parse_operand(&curr, &opcode->dst[i].base);
parse_operand_index(&curr, &opcode->dst[i].base);
}
/* Source operands. */
for (i = 0; i < info->num_src; i++) {
boolean extended;
D3D10_SB_OPERAND_NUM_COMPONENTS num_components;
extended = DECODE_IS_D3D10_SB_OPERAND_EXTENDED(*curr);
num_components = DECODE_D3D10_SB_OPERAND_NUM_COMPONENTS(*curr);
if (num_components == D3D10_SB_OPERAND_4_COMPONENT) {
D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE selection_mode;
selection_mode = DECODE_D3D10_SB_OPERAND_4_COMPONENT_SELECTION_MODE(*curr);
if (selection_mode == D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE_MODE) {
opcode->src[i].swizzle[0] = DECODE_D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE_SOURCE(*curr, 0);
opcode->src[i].swizzle[1] = DECODE_D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE_SOURCE(*curr, 1);
opcode->src[i].swizzle[2] = DECODE_D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE_SOURCE(*curr, 2);
opcode->src[i].swizzle[3] = DECODE_D3D10_SB_OPERAND_4_COMPONENT_SWIZZLE_SOURCE(*curr, 3);
} else if (selection_mode == D3D10_SB_OPERAND_4_COMPONENT_SELECT_1_MODE) {
opcode->src[i].swizzle[0] =
opcode->src[i].swizzle[1] =
opcode->src[i].swizzle[2] =
opcode->src[i].swizzle[3] = DECODE_D3D10_SB_OPERAND_4_COMPONENT_SELECT_1(*curr);
} else {
/* This case apparently happens only for 4-component 32-bit
* immediate operands.
*/
assert(selection_mode == D3D10_SB_OPERAND_4_COMPONENT_MASK_MODE);
assert(DECODE_D3D10_SB_OPERAND_4_COMPONENT_MASK(*curr) == 0);
assert(DECODE_D3D10_SB_OPERAND_TYPE(*curr) == D3D10_SB_OPERAND_TYPE_IMMEDIATE32);
opcode->src[i].swizzle[0] = D3D10_SB_4_COMPONENT_X;
opcode->src[i].swizzle[1] = D3D10_SB_4_COMPONENT_Y;
opcode->src[i].swizzle[2] = D3D10_SB_4_COMPONENT_Z;
opcode->src[i].swizzle[3] = D3D10_SB_4_COMPONENT_W;
}
} else if (num_components == D3D10_SB_OPERAND_1_COMPONENT) {
opcode->src[i].swizzle[0] =
opcode->src[i].swizzle[1] =
opcode->src[i].swizzle[2] =
opcode->src[i].swizzle[3] = D3D10_SB_4_COMPONENT_X;
} else {
/* Samplers only?
*/
assert(num_components == D3D10_SB_OPERAND_0_COMPONENT);
assert(DECODE_D3D10_SB_OPERAND_TYPE(*curr) == D3D10_SB_OPERAND_TYPE_SAMPLER ||
DECODE_D3D10_SB_OPERAND_TYPE(*curr) == D3D10_SB_OPERAND_TYPE_LABEL);
opcode->src[i].swizzle[0] = D3D10_SB_4_COMPONENT_X;
opcode->src[i].swizzle[1] = D3D10_SB_4_COMPONENT_Y;
opcode->src[i].swizzle[2] = D3D10_SB_4_COMPONENT_Z;
opcode->src[i].swizzle[3] = D3D10_SB_4_COMPONENT_W;
}
parse_operand(&curr, &opcode->src[i].base);
opcode->src[i].modifier = D3D10_SB_OPERAND_MODIFIER_NONE;
if (extended) {
/* NOTE: DECODE_IS_D3D10_SB_OPERAND_DOUBLE_EXTENDED is broken.
*/
assert(!((*curr & D3D10_SB_OPERAND_DOUBLE_EXTENDED_MASK) >> D3D10_SB_OPERAND_DOUBLE_EXTENDED_SHIFT));
switch (DECODE_D3D10_SB_EXTENDED_OPERAND_TYPE(*curr)) {
case D3D10_SB_EXTENDED_OPERAND_EMPTY:
break;
case D3D10_SB_EXTENDED_OPERAND_MODIFIER:
opcode->src[i].modifier = DECODE_D3D10_SB_OPERAND_MODIFIER(*curr);
break;
default:
assert(0);
}
curr++;
}
parse_operand_index(&curr, &opcode->src[i].base);
if (opcode->src[i].base.type == D3D10_SB_OPERAND_TYPE_IMMEDIATE32) {
switch (num_components) {
case D3D10_SB_OPERAND_1_COMPONENT:
opcode->src[i].imm[0].u32 =
opcode->src[i].imm[1].u32 =
opcode->src[i].imm[2].u32 =
opcode->src[i].imm[3].u32 = *curr++;
break;
case D3D10_SB_OPERAND_4_COMPONENT:
opcode->src[i].imm[0].u32 = *curr++;
opcode->src[i].imm[1].u32 = *curr++;
opcode->src[i].imm[2].u32 = *curr++;
opcode->src[i].imm[3].u32 = *curr++;
break;
default:
/* XXX: Support other component sizes.
*/
assert(0);
}
}
}
/* Opcode specific trailing operands. */
switch (opcode->type) {
case D3D10_SB_OPCODE_DCL_RESOURCE:
opcode->dcl_resource_ret_type[0] = DECODE_D3D10_SB_RESOURCE_RETURN_TYPE(*curr, 0);
opcode->dcl_resource_ret_type[1] = DECODE_D3D10_SB_RESOURCE_RETURN_TYPE(*curr, 1);
opcode->dcl_resource_ret_type[2] = DECODE_D3D10_SB_RESOURCE_RETURN_TYPE(*curr, 2);
opcode->dcl_resource_ret_type[3] = DECODE_D3D10_SB_RESOURCE_RETURN_TYPE(*curr, 3);
curr++;
break;
case D3D10_SB_OPCODE_DCL_MAX_OUTPUT_VERTEX_COUNT:
opcode->specific.dcl_max_output_vertex_count = *curr;
curr++;
break;
case D3D10_SB_OPCODE_DCL_INPUT_SGV:
case D3D10_SB_OPCODE_DCL_INPUT_SIV:
case D3D10_SB_OPCODE_DCL_INPUT_PS_SGV:
case D3D10_SB_OPCODE_DCL_INPUT_PS_SIV:
case D3D10_SB_OPCODE_DCL_OUTPUT_SIV:
case D3D10_SB_OPCODE_DCL_OUTPUT_SGV:
opcode->dcl_siv_name = DECODE_D3D10_SB_NAME(*curr);
curr++;
break;
case D3D10_SB_OPCODE_DCL_TEMPS:
opcode->specific.dcl_num_temps = *curr;
curr++;
break;
case D3D10_SB_OPCODE_DCL_INDEXABLE_TEMP:
opcode->specific.dcl_indexable_temp.index = *curr++;
opcode->specific.dcl_indexable_temp.count = *curr++;
opcode->specific.dcl_indexable_temp.components = *curr++;
break;
case D3D10_SB_OPCODE_DCL_INDEX_RANGE:
opcode->specific.index_range_count = *curr++;
break;
default:
break;
}
assert(curr == parser->curr + length);
skip:
/* Advance to the next opcode. */
parser->curr += length;
return TRUE;
}
void
Shader_opcode_free(struct Shader_opcode *opcode)
{
if (opcode->type == D3D10_SB_OPCODE_CUSTOMDATA) {
if (opcode->customdata._class == D3D10_SB_CUSTOMDATA_DCL_IMMEDIATE_CONSTANT_BUFFER) {
FREE(opcode->customdata.u.constbuf.data);
}
}
}