d3dx9: Add swizzle and writemask support to the shader assembler.

This commit is contained in:
Matteo Bruni 2010-04-21 16:15:46 +02:00 committed by Alexandre Julliard
parent 82fdc926a2
commit 9019267bfa
5 changed files with 203 additions and 6 deletions

View File

@ -34,6 +34,13 @@ WINE_DEFAULT_DEBUG_CHANNEL(asmshader);
%option prefix="asmshader_"
%option noinput nounput
/* Swizzles and writemasks consist of a dot and up to 4 x, y, z or w characters,
* or up to 4 a, r, g, b characters. There are different rules for swizzles and
* writemasks wrt repetition, those are handled in the grammar.
*/
DOT \.
COMPONENT [xyzw]|[rgba]
/* Registers */
REG_TEMP r[0-9]+
/* for relative addressing in the form o[x], v[x] and c[x] */
@ -89,6 +96,29 @@ ps_2_0 {return VER_PS20; }
ps_2_x {return VER_PS2X; }
ps_3_0 {return VER_PS30; }
{DOT} {return yytext[0]; }
{COMPONENT} {
switch(yytext[0]) {
case 'x':
case 'r':
asmshader_lval.component = 0;
break;
case 'y':
case 'g':
asmshader_lval.component = 1;
break;
case 'z':
case 'b':
asmshader_lval.component = 2;
break;
case 'w':
case 'a':
asmshader_lval.component = 3;
break;
}
return COMPONENT;
}
{COMMA} {return yytext[0]; }
- {return yytext[0]; }
\( {return yytext[0]; }

View File

@ -45,12 +45,18 @@ void set_rel_reg(struct shader_reg *reg, struct rel_reg *rel) {
%union {
unsigned int regnum;
struct shader_reg reg;
DWORD writemask;
struct {
DWORD writemask;
DWORD idx;
DWORD last;
} wm_components;
DWORD swizzle;
struct {
DWORD swizzle;
DWORD writemask;
} swizzle_wmask;
DWORD writemask;
DWORD swizzle;
DWORD idx;
} sw_components;
DWORD component;
struct {
DWORD mod;
DWORD shift;
@ -82,12 +88,17 @@ void set_rel_reg(struct shader_reg *reg, struct rel_reg *rel) {
%token VER_PS2X
%token VER_PS30
/* Misc stuff */
%token <component> COMPONENT
%type <reg> dreg_name
%type <reg> dreg
%type <reg> sreg_name
%type <reg> sreg
%type <writemask> writemask
%type <wm_components> wm_components
%type <swizzle> swizzle
%type <sw_components> sw_components
%type <modshift> omods
%type <rel_reg> rel_reg
%type <sregs> sregs
@ -202,17 +213,100 @@ dreg: dreg_name rel_reg
$$.srcmod = BWRITERSPSM_NONE;
set_rel_reg(&$$, &$2);
}
| dreg_name writemask
{
$$.regnum = $1.regnum;
$$.type = $1.type;
$$.writemask = $2;
$$.srcmod = BWRITERSPSM_NONE;
$$.rel_reg = NULL;
}
dreg_name: REG_TEMP
{
$$.regnum = $1; $$.type = BWRITERSPR_TEMP;
}
writemask: '.' wm_components
{
if($2.writemask == SWIZZLE_ERR) {
asmparser_message(&asm_ctx, "Line %u: Invalid writemask specified\n",
asm_ctx.line_no);
set_parse_status(&asm_ctx, PARSE_ERR);
/* Provide a correct writemask to prevent following complaints */
$$ = BWRITERSP_WRITEMASK_ALL;
}
else {
$$ = $2.writemask;
TRACE("Writemask: %x\n", $$);
}
}
wm_components: COMPONENT
{
$$.writemask = 1 << $1;
$$.last = $1;
$$.idx = 1;
}
| wm_components COMPONENT
{
if($1.writemask == SWIZZLE_ERR || $1.idx == 4)
/* Wrong writemask */
$$.writemask = SWIZZLE_ERR;
else {
if($2 <= $1.last)
$$.writemask = SWIZZLE_ERR;
else {
$$.writemask = $1.writemask | (1 << $2);
$$.idx = $1.idx + 1;
}
}
}
swizzle: /* empty */
{
$$ = BWRITERVS_NOSWIZZLE;
TRACE("Default swizzle: %08x\n", $$);
}
| '.' sw_components
{
if($2.swizzle == SWIZZLE_ERR) {
asmparser_message(&asm_ctx, "Line %u: Invalid swizzle\n",
asm_ctx.line_no);
set_parse_status(&asm_ctx, PARSE_ERR);
/* Provide a correct swizzle to prevent following complaints */
$$ = BWRITERVS_NOSWIZZLE;
}
else {
DWORD last, i;
$$ = $2.swizzle << BWRITERVS_SWIZZLE_SHIFT;
/* Fill the swizzle by extending the last component */
last = ($2.swizzle >> 2 * ($2.idx - 1)) & 0x03;
for(i = $2.idx; i < 4; i++){
$$ |= last << (BWRITERVS_SWIZZLE_SHIFT + 2 * i);
}
TRACE("Got a swizzle: %08x\n", $$);
}
}
sw_components: COMPONENT
{
$$.swizzle = $1;
$$.idx = 1;
}
| sw_components COMPONENT
{
if($1.idx == 4) {
/* Too many sw_components */
$$.swizzle = SWIZZLE_ERR;
$$.idx = 4;
}
else {
$$.swizzle = $1.swizzle | ($2 << 2 * $1.idx);
$$.idx = $1.idx + 1;
}
}
omods: /* Empty */
{

View File

@ -99,14 +99,66 @@ static const char *get_regname(const struct shader_reg *reg, shader_type st) {
}
}
const char *debug_print_writemask(DWORD mask) {
char ret[6];
unsigned char pos = 1;
if(mask == BWRITERSP_WRITEMASK_ALL) return "";
ret[0] = '.';
if(mask & BWRITERSP_WRITEMASK_0) ret[pos++] = 'x';
if(mask & BWRITERSP_WRITEMASK_1) ret[pos++] = 'y';
if(mask & BWRITERSP_WRITEMASK_2) ret[pos++] = 'z';
if(mask & BWRITERSP_WRITEMASK_3) ret[pos++] = 'w';
ret[pos] = 0;
return wine_dbg_sprintf("%s", ret);
}
const char *debug_print_dstreg(const struct shader_reg *reg, shader_type st) {
return get_regname(reg, st);
return wine_dbg_sprintf("%s%s", get_regname(reg, st),
debug_print_writemask(reg->writemask));
}
const char *debug_print_swizzle(DWORD arg) {
char ret[6];
unsigned int i;
DWORD swizzle[4];
switch(arg) {
case BWRITERVS_NOSWIZZLE:
return "";
case BWRITERVS_SWIZZLE_X:
return ".x";
case BWRITERVS_SWIZZLE_Y:
return ".y";
case BWRITERVS_SWIZZLE_Z:
return ".z";
case BWRITERVS_SWIZZLE_W:
return ".w";
}
swizzle[0] = (arg >> (BWRITERVS_SWIZZLE_SHIFT + 0)) & 0x03;
swizzle[1] = (arg >> (BWRITERVS_SWIZZLE_SHIFT + 2)) & 0x03;
swizzle[2] = (arg >> (BWRITERVS_SWIZZLE_SHIFT + 4)) & 0x03;
swizzle[3] = (arg >> (BWRITERVS_SWIZZLE_SHIFT + 6)) & 0x03;
ret[0] = '.';
for(i = 0; i < 4; i++) {
switch(swizzle[i]) {
case 0: ret[1 + i] = 'x'; break;
case 1: ret[1 + i] = 'y'; break;
case 2: ret[1 + i] = 'z'; break;
case 3: ret[1 + i] = 'w'; break;
}
}
ret[5] = '\0';
return wine_dbg_sprintf("%s", ret);
}
const char *debug_print_srcreg(const struct shader_reg *reg, shader_type st) {
switch(reg->srcmod) {
case BWRITERSPSM_NONE:
return get_regname(reg, st);
return wine_dbg_sprintf("%s%s", get_regname(reg, st),
debug_print_swizzle(reg->swizzle));
}
return "Unknown modifier";
}

View File

@ -342,6 +342,8 @@ struct bc_writer {
/* Debug utility routines */
const char *debug_print_dstreg(const struct shader_reg *reg, shader_type st);
const char *debug_print_srcreg(const struct shader_reg *reg, shader_type st);
const char *debug_print_swizzle(DWORD swizzle);
const char *debug_print_writemask(DWORD mask);
const char *debug_print_opcode(DWORD opcode);
/* Utilities for internal->d3d constant mapping */
@ -350,6 +352,9 @@ DWORD d3d9_writemask(DWORD bwriter_writemask);
DWORD d3d9_register(DWORD bwriter_register);
DWORD d3d9_opcode(DWORD bwriter_opcode);
/* Used to signal an incorrect swizzle/writemask */
#define SWIZZLE_ERR ~0U
/*
Enumerations and defines used in the bytecode writer
intermediate representation
@ -407,6 +412,11 @@ typedef enum _BWRITERSHADER_PARAM_SRCMOD_TYPE {
#define BWRITERVS_NOSWIZZLE (BWRITERVS_X_X | BWRITERVS_Y_Y | BWRITERVS_Z_Z | BWRITERVS_W_W)
#define BWRITERVS_SWIZZLE_X (BWRITERVS_X_X | BWRITERVS_Y_X | BWRITERVS_Z_X | BWRITERVS_W_X)
#define BWRITERVS_SWIZZLE_Y (BWRITERVS_X_Y | BWRITERVS_Y_Y | BWRITERVS_Z_Y | BWRITERVS_W_Y)
#define BWRITERVS_SWIZZLE_Z (BWRITERVS_X_Z | BWRITERVS_Y_Z | BWRITERVS_Z_Z | BWRITERVS_W_Z)
#define BWRITERVS_SWIZZLE_W (BWRITERVS_X_W | BWRITERVS_Y_W | BWRITERVS_Z_W | BWRITERVS_W_W)
struct bwriter_shader *SlAssembleShader(const char *text, char **messages);
DWORD SlWriteBytecode(const struct bwriter_shader *shader, int dxversion, DWORD **result);
void SlDeleteShader(struct bwriter_shader *shader);

View File

@ -1058,6 +1058,17 @@ static void vs_3_0_test(void) {
"mov r2, r1_abs\n",
{0xfffe0300, 0x02000001, 0x800f0002, 0x8be40001, 0x0000ffff}
},*/
{ /* shader 9 */
"vs_3_0\n"
"mov r2, r1.xygb\n",
{0xfffe0300, 0x02000001, 0x800f0002, 0x80940001, 0x0000ffff}
},
{ /* shader 10 */
"vs_3_0\n"
"mov r2.xyb, r1\n",
{0xfffe0300, 0x02000001, 0x80070002, 0x80e40001, 0x0000ffff}
},
};
exec_tests("vs_3_0", tests, sizeof(tests) / sizeof(tests[0]));