d3dx9: Shader assembler <= ps_1_3 support.
This commit is contained in:
parent
8ce3ecea0d
commit
d567a030ec
|
@ -226,6 +226,86 @@ static void asmparser_sincos(struct asm_parser *This, DWORD mod, DWORD shift,
|
|||
}
|
||||
}
|
||||
|
||||
static struct shader_reg map_oldps_register(const struct shader_reg *reg, BOOL tex_varying) {
|
||||
struct shader_reg ret;
|
||||
switch(reg->type) {
|
||||
case BWRITERSPR_TEXTURE:
|
||||
if(tex_varying) {
|
||||
ret = *reg;
|
||||
ret.type = BWRITERSPR_INPUT;
|
||||
switch(reg->regnum) {
|
||||
case 0: ret.regnum = T0_VARYING; break;
|
||||
case 1: ret.regnum = T1_VARYING; break;
|
||||
case 2: ret.regnum = T2_VARYING; break;
|
||||
case 3: ret.regnum = T3_VARYING; break;
|
||||
case 4: ret.regnum = T4_VARYING; break;
|
||||
case 5: ret.regnum = T5_VARYING; break;
|
||||
case 6: ret.regnum = T6_VARYING; break;
|
||||
case 7: ret.regnum = T7_VARYING; break;
|
||||
default:
|
||||
FIXME("Unexpected TEXTURE register t%u\n", reg->regnum);
|
||||
return *reg;
|
||||
}
|
||||
return ret;
|
||||
} else {
|
||||
ret = *reg;
|
||||
ret.type = BWRITERSPR_TEMP;
|
||||
switch(reg->regnum) {
|
||||
case 0: ret.regnum = T0_REG; break;
|
||||
case 1: ret.regnum = T1_REG; break;
|
||||
case 2: ret.regnum = T2_REG; break;
|
||||
case 3: ret.regnum = T3_REG; break;
|
||||
default:
|
||||
FIXME("Unexpected TEXTURE register t%u\n", reg->regnum);
|
||||
return *reg;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* case BWRITERSPR_INPUT - Identical mapping of 1.x/2.0 color varyings
|
||||
to 3.0 ones */
|
||||
|
||||
default: return *reg;
|
||||
}
|
||||
}
|
||||
|
||||
static void asmparser_texcoord(struct asm_parser *This, DWORD mod, DWORD shift,
|
||||
const struct shader_reg *dst,
|
||||
const struct src_regs *srcs) {
|
||||
struct instruction *instr;
|
||||
|
||||
if(srcs) {
|
||||
asmparser_message(This, "Line %u: Source registers in texcoord instruction\n", This->line_no);
|
||||
set_parse_status(This, PARSE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
instr = alloc_instr(1);
|
||||
if(!instr) {
|
||||
ERR("Error allocating memory for the instruction\n");
|
||||
set_parse_status(This, PARSE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
/* texcoord copies the texture coord data into a temporary register-like
|
||||
* readable form. In newer shader models this equals a MOV from v0 to r0,
|
||||
* record it as this.
|
||||
*/
|
||||
instr->opcode = BWRITERSIO_MOV;
|
||||
instr->dstmod = mod | BWRITERSPDM_SATURATE; /* texcoord clamps to [0;1] */
|
||||
instr->shift = shift;
|
||||
instr->comptype = 0;
|
||||
|
||||
This->funcs->dstreg(This, instr, dst);
|
||||
/* The src reg needs special care */
|
||||
instr->src[0] = map_oldps_register(dst, TRUE);
|
||||
|
||||
if(!add_instruction(This->shader, instr)) {
|
||||
ERR("Out of memory\n");
|
||||
set_parse_status(This, PARSE_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
static void asmparser_texcrd(struct asm_parser *This, DWORD mod, DWORD shift,
|
||||
const struct shader_reg *dst,
|
||||
const struct src_regs *srcs) {
|
||||
|
@ -259,6 +339,82 @@ static void asmparser_texcrd(struct asm_parser *This, DWORD mod, DWORD shift,
|
|||
}
|
||||
}
|
||||
|
||||
static void asmparser_texkill(struct asm_parser *This,
|
||||
const struct shader_reg *dst) {
|
||||
struct instruction *instr = alloc_instr(0);
|
||||
|
||||
if(!instr) {
|
||||
ERR("Error allocating memory for the instruction\n");
|
||||
set_parse_status(This, PARSE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
instr->opcode = BWRITERSIO_TEXKILL;
|
||||
instr->dstmod = 0;
|
||||
instr->shift = 0;
|
||||
instr->comptype = 0;
|
||||
|
||||
/* Do not run the dst register through the normal
|
||||
* register conversion. If used with ps_1_0 to ps_1_3
|
||||
* the texture coordinate from that register is used,
|
||||
* not the temporary register value. In ps_1_4 and
|
||||
* ps_2_0 t0 is always a varying and temporaries can
|
||||
* be used with texkill.
|
||||
*/
|
||||
instr->dst = map_oldps_register(dst, TRUE);
|
||||
instr->has_dst = TRUE;
|
||||
|
||||
if(!add_instruction(This->shader, instr)) {
|
||||
ERR("Out of memory\n");
|
||||
set_parse_status(This, PARSE_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
static void asmparser_texhelper(struct asm_parser *This, DWORD mod, DWORD shift,
|
||||
const struct shader_reg *dst,
|
||||
const struct shader_reg *src0) {
|
||||
struct instruction *instr = alloc_instr(2);
|
||||
|
||||
if(!instr) {
|
||||
ERR("Error allocating memory for the instruction\n");
|
||||
set_parse_status(This, PARSE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
instr->opcode = BWRITERSIO_TEX;
|
||||
instr->dstmod = mod;
|
||||
instr->shift = shift;
|
||||
instr->comptype = 0;
|
||||
/* The dest register can be mapped normally to a temporary register */
|
||||
This->funcs->dstreg(This, instr, dst);
|
||||
/* Use the src passed as parameter by the specific instruction handler */
|
||||
instr->src[0] = *src0;
|
||||
|
||||
/* The 2nd source register is the sampler register with the
|
||||
* destination's regnum
|
||||
*/
|
||||
ZeroMemory(&instr->src[1], sizeof(instr->src[1]));
|
||||
instr->src[1].type = BWRITERSPR_SAMPLER;
|
||||
instr->src[1].regnum = dst->regnum;
|
||||
instr->src[1].swizzle = BWRITERVS_NOSWIZZLE;
|
||||
instr->src[1].srcmod = BWRITERSPSM_NONE;
|
||||
instr->src[1].rel_reg = NULL;
|
||||
|
||||
if(!add_instruction(This->shader, instr)) {
|
||||
ERR("Out of memory\n");
|
||||
set_parse_status(This, PARSE_ERR);
|
||||
}
|
||||
}
|
||||
|
||||
static void asmparser_tex(struct asm_parser *This, DWORD mod, DWORD shift,
|
||||
const struct shader_reg *dst) {
|
||||
struct shader_reg src;
|
||||
|
||||
/* The first source register is the varying containing the coordinate */
|
||||
src = map_oldps_register(dst, TRUE);
|
||||
asmparser_texhelper(This, mod, shift, dst, &src);
|
||||
}
|
||||
|
||||
static void asmparser_texld14(struct asm_parser *This, DWORD mod, DWORD shift,
|
||||
const struct shader_reg *dst,
|
||||
const struct src_regs *srcs) {
|
||||
|
@ -304,6 +460,46 @@ static void asmparser_texld14(struct asm_parser *This, DWORD mod, DWORD shift,
|
|||
}
|
||||
}
|
||||
|
||||
static void asmparser_texreg2ar(struct asm_parser *This, DWORD mod, DWORD shift,
|
||||
const struct shader_reg *dst,
|
||||
const struct shader_reg *src0) {
|
||||
struct shader_reg src;
|
||||
|
||||
src = map_oldps_register(src0, FALSE);
|
||||
/* Supply the correct swizzle */
|
||||
src.swizzle = BWRITERVS_X_W | BWRITERVS_Y_X | BWRITERVS_Z_X | BWRITERVS_W_X;
|
||||
asmparser_texhelper(This, mod, shift, dst, &src);
|
||||
}
|
||||
|
||||
static void asmparser_texreg2gb(struct asm_parser *This, DWORD mod, DWORD shift,
|
||||
const struct shader_reg *dst,
|
||||
const struct shader_reg *src0) {
|
||||
struct shader_reg src;
|
||||
|
||||
src = map_oldps_register(src0, FALSE);
|
||||
/* Supply the correct swizzle */
|
||||
src.swizzle = BWRITERVS_X_Y | BWRITERVS_Y_Z | BWRITERVS_Z_Z | BWRITERVS_W_Z;
|
||||
asmparser_texhelper(This, mod, shift, dst, &src);
|
||||
}
|
||||
|
||||
static void asmparser_texreg2rgb(struct asm_parser *This, DWORD mod, DWORD shift,
|
||||
const struct shader_reg *dst,
|
||||
const struct shader_reg *src0) {
|
||||
struct shader_reg src;
|
||||
|
||||
src = map_oldps_register(src0, FALSE);
|
||||
/* Supply the correct swizzle */
|
||||
src.swizzle = BWRITERVS_X_X | BWRITERVS_Y_Y | BWRITERVS_Z_Z | BWRITERVS_W_Z;
|
||||
asmparser_texhelper(This, mod, shift, dst, &src);
|
||||
}
|
||||
|
||||
/* Complex pixel shader 1.3 instructions like texm3x3tex are tricky - the
|
||||
* bytecode writer works instruction by instruction, so we can't properly
|
||||
* convert these from/to equivalent ps_3_0 instructions. Then simply keep using
|
||||
* the ps_1_3 opcodes and just adapt the registers in the common fashion (i.e.
|
||||
* go through asmparser_instr).
|
||||
*/
|
||||
|
||||
static void asmparser_instr(struct asm_parser *This, DWORD opcode,
|
||||
DWORD mod, DWORD shift,
|
||||
BWRITER_COMPARISON_TYPE comp,
|
||||
|
@ -345,12 +541,20 @@ ns */
|
|||
break;
|
||||
case BWRITERSIO_TEXCOORD:
|
||||
/* texcoord/texcrd are two instructions present only in PS <= 1.3 and PS 1.4 respectively */
|
||||
asmparser_texcrd(This, mod, shift, dst, srcs);
|
||||
if(This->shader->version == BWRITERPS_VERSION(1, 4))
|
||||
asmparser_texcrd(This, mod, shift, dst, srcs);
|
||||
else asmparser_texcoord(This, mod, shift, dst, srcs);
|
||||
return;
|
||||
case BWRITERSIO_TEX:
|
||||
/* this encodes both the tex PS 1.x instruction and the
|
||||
texld 1.4/2.0+ instruction */
|
||||
if(This->shader->version == BWRITERPS_VERSION(1, 4)) {
|
||||
if(This->shader->version == BWRITERPS_VERSION(1, 1) ||
|
||||
This->shader->version == BWRITERPS_VERSION(1, 2) ||
|
||||
This->shader->version == BWRITERPS_VERSION(1, 3)) {
|
||||
asmparser_tex(This, mod, shift, dst);
|
||||
return;
|
||||
}
|
||||
else if(This->shader->version == BWRITERPS_VERSION(1, 4)) {
|
||||
asmparser_texld14(This, mod, shift, dst, srcs);
|
||||
return;
|
||||
}
|
||||
|
@ -364,6 +568,22 @@ ns */
|
|||
return;
|
||||
}
|
||||
|
||||
/* Handle PS 1.x instructions, "regularizing" them */
|
||||
switch(opcode) {
|
||||
case BWRITERSIO_TEXKILL:
|
||||
asmparser_texkill(This, dst);
|
||||
return;
|
||||
case BWRITERSIO_TEXREG2AR:
|
||||
asmparser_texreg2ar(This, mod, shift, dst, &srcs->reg[0]);
|
||||
return;
|
||||
case BWRITERSIO_TEXREG2GB:
|
||||
asmparser_texreg2gb(This, mod, shift, dst, &srcs->reg[0]);
|
||||
return;
|
||||
case BWRITERSIO_TEXREG2RGB:
|
||||
asmparser_texreg2rgb(This, mod, shift, dst, &srcs->reg[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
instr = alloc_instr(src_count);
|
||||
if(!instr) {
|
||||
ERR("Error allocating memory for the instruction\n");
|
||||
|
@ -444,39 +664,6 @@ static struct shader_reg map_oldvs_register(const struct shader_reg *reg) {
|
|||
}
|
||||
}
|
||||
|
||||
static struct shader_reg map_oldps_register(const struct shader_reg *reg, BOOL tex_varying) {
|
||||
struct shader_reg ret;
|
||||
switch(reg->type) {
|
||||
case BWRITERSPR_TEXTURE:
|
||||
if(tex_varying) {
|
||||
ret = *reg;
|
||||
ret.type = BWRITERSPR_INPUT;
|
||||
switch(reg->regnum) {
|
||||
case 0: ret.regnum = T0_VARYING; break;
|
||||
case 1: ret.regnum = T1_VARYING; break;
|
||||
case 2: ret.regnum = T2_VARYING; break;
|
||||
case 3: ret.regnum = T3_VARYING; break;
|
||||
case 4: ret.regnum = T4_VARYING; break;
|
||||
case 5: ret.regnum = T5_VARYING; break;
|
||||
case 6: ret.regnum = T6_VARYING; break;
|
||||
case 7: ret.regnum = T7_VARYING; break;
|
||||
default:
|
||||
FIXME("Unexpected TEXTURE register t%u\n", reg->regnum);
|
||||
return *reg;
|
||||
}
|
||||
return ret;
|
||||
} else {
|
||||
FIXME("TODO: ps_1_x texture register mapping\n");
|
||||
return *reg;
|
||||
}
|
||||
|
||||
/* case BWRITERSPR_INPUT - Identical mapping of 1.x/2.0 color varyings
|
||||
to 3.0 ones */
|
||||
|
||||
default: return *reg;
|
||||
}
|
||||
}
|
||||
|
||||
/* Checks for unsupported source modifiers in VS (all versions) or
|
||||
PS 2.0 and newer */
|
||||
static void check_legacy_srcmod(struct asm_parser *This, DWORD srcmod) {
|
||||
|
@ -660,6 +847,30 @@ static void asmparser_srcreg_vs_3(struct asm_parser *This,
|
|||
memcpy(&instr->src[num], src, sizeof(*src));
|
||||
}
|
||||
|
||||
static const struct allowed_reg_type ps_1_0123_reg_allowed[] = {
|
||||
{ BWRITERSPR_CONST, 8, FALSE },
|
||||
{ BWRITERSPR_TEMP, 2, FALSE },
|
||||
{ BWRITERSPR_TEXTURE, 4, FALSE },
|
||||
{ BWRITERSPR_INPUT, 2, FALSE },
|
||||
{ ~0U, 0 } /* End tag */
|
||||
};
|
||||
|
||||
static void asmparser_srcreg_ps_1_0123(struct asm_parser *This,
|
||||
struct instruction *instr, int num,
|
||||
const struct shader_reg *src) {
|
||||
struct shader_reg reg;
|
||||
|
||||
if(!check_reg_type(src, ps_1_0123_reg_allowed)) {
|
||||
asmparser_message(This, "Line %u: Source register %s not supported in <== PS 1.3\n",
|
||||
This->line_no,
|
||||
debug_print_srcreg(src));
|
||||
set_parse_status(This, PARSE_ERR);
|
||||
}
|
||||
check_abs_srcmod(This, src->srcmod);
|
||||
reg = map_oldps_register(src, FALSE);
|
||||
memcpy(&instr->src[num], ®, sizeof(reg));
|
||||
}
|
||||
|
||||
static const struct allowed_reg_type ps_1_4_reg_allowed[] = {
|
||||
{ BWRITERSPR_CONST, 8, FALSE },
|
||||
{ BWRITERSPR_TEMP, 6, FALSE },
|
||||
|
@ -827,6 +1038,22 @@ static void asmparser_dstreg_vs_3(struct asm_parser *This,
|
|||
instr->has_dst = TRUE;
|
||||
}
|
||||
|
||||
static void asmparser_dstreg_ps_1_0123(struct asm_parser *This,
|
||||
struct instruction *instr,
|
||||
const struct shader_reg *dst) {
|
||||
struct shader_reg reg;
|
||||
|
||||
if(!check_reg_type(dst, ps_1_0123_reg_allowed)) {
|
||||
asmparser_message(This, "Line %u: Destination register %s not supported in PS 1\n",
|
||||
This->line_no,
|
||||
debug_print_dstreg(dst));
|
||||
set_parse_status(This, PARSE_ERR);
|
||||
}
|
||||
reg = map_oldps_register(dst, FALSE);
|
||||
memcpy(&instr->dst, ®, sizeof(reg));
|
||||
instr->has_dst = TRUE;
|
||||
}
|
||||
|
||||
static void asmparser_dstreg_ps_1_4(struct asm_parser *This,
|
||||
struct instruction *instr,
|
||||
const struct shader_reg *dst) {
|
||||
|
@ -981,6 +1208,26 @@ static const struct asmparser_backend parser_vs_3 = {
|
|||
asmparser_instr,
|
||||
};
|
||||
|
||||
static const struct asmparser_backend parser_ps_1_0123 = {
|
||||
asmparser_constF,
|
||||
asmparser_constI,
|
||||
asmparser_constB,
|
||||
|
||||
asmparser_dstreg_ps_1_0123,
|
||||
asmparser_srcreg_ps_1_0123,
|
||||
|
||||
asmparser_predicate_unsupported,
|
||||
asmparser_coissue_supported,
|
||||
|
||||
asmparser_dcl_output_unsupported,
|
||||
asmparser_dcl_input_unsupported,
|
||||
asmparser_dcl_sampler_unsupported,
|
||||
|
||||
asmparser_end,
|
||||
|
||||
asmparser_instr,
|
||||
};
|
||||
|
||||
static const struct asmparser_backend parser_ps_1_4 = {
|
||||
asmparser_constF,
|
||||
asmparser_constI,
|
||||
|
@ -1171,6 +1418,70 @@ void create_vs30_parser(struct asm_parser *ret) {
|
|||
ret->funcs = &parser_vs_3;
|
||||
}
|
||||
|
||||
void create_ps10_parser(struct asm_parser *ret) {
|
||||
TRACE_(parsed_shader)("ps_1_0\n");
|
||||
|
||||
ret->shader = asm_alloc(sizeof(*ret->shader));
|
||||
if(!ret->shader) {
|
||||
ERR("Failed to allocate memory for the shader\n");
|
||||
set_parse_status(ret, PARSE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
ret->shader->type = ST_PIXEL;
|
||||
ret->shader->version = BWRITERPS_VERSION(1, 0);
|
||||
ret->funcs = &parser_ps_1_0123;
|
||||
gen_oldps_input(ret->shader, 4);
|
||||
}
|
||||
|
||||
void create_ps11_parser(struct asm_parser *ret) {
|
||||
TRACE_(parsed_shader)("ps_1_1\n");
|
||||
|
||||
ret->shader = asm_alloc(sizeof(*ret->shader));
|
||||
if(!ret->shader) {
|
||||
ERR("Failed to allocate memory for the shader\n");
|
||||
set_parse_status(ret, PARSE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
ret->shader->type = ST_PIXEL;
|
||||
ret->shader->version = BWRITERPS_VERSION(1, 1);
|
||||
ret->funcs = &parser_ps_1_0123;
|
||||
gen_oldps_input(ret->shader, 4);
|
||||
}
|
||||
|
||||
void create_ps12_parser(struct asm_parser *ret) {
|
||||
TRACE_(parsed_shader)("ps_1_2\n");
|
||||
|
||||
ret->shader = asm_alloc(sizeof(*ret->shader));
|
||||
if(!ret->shader) {
|
||||
ERR("Failed to allocate memory for the shader\n");
|
||||
set_parse_status(ret, PARSE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
ret->shader->type = ST_PIXEL;
|
||||
ret->shader->version = BWRITERPS_VERSION(1, 2);
|
||||
ret->funcs = &parser_ps_1_0123;
|
||||
gen_oldps_input(ret->shader, 4);
|
||||
}
|
||||
|
||||
void create_ps13_parser(struct asm_parser *ret) {
|
||||
TRACE_(parsed_shader)("ps_1_3\n");
|
||||
|
||||
ret->shader = asm_alloc(sizeof(*ret->shader));
|
||||
if(!ret->shader) {
|
||||
ERR("Failed to allocate memory for the shader\n");
|
||||
set_parse_status(ret, PARSE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
ret->shader->type = ST_PIXEL;
|
||||
ret->shader->version = BWRITERPS_VERSION(1, 3);
|
||||
ret->funcs = &parser_ps_1_0123;
|
||||
gen_oldps_input(ret->shader, 4);
|
||||
}
|
||||
|
||||
void create_ps14_parser(struct asm_parser *ret) {
|
||||
TRACE_(parsed_shader)("ps_1_4\n");
|
||||
|
||||
|
|
|
@ -329,26 +329,22 @@ version_marker: VER_VS10
|
|||
| VER_PS10
|
||||
{
|
||||
TRACE("Pixel shader 1.0\n");
|
||||
set_parse_status(&asm_ctx, PARSE_ERR);
|
||||
YYABORT;
|
||||
create_ps10_parser(&asm_ctx);
|
||||
}
|
||||
| VER_PS11
|
||||
{
|
||||
TRACE("Pixel shader 1.1\n");
|
||||
set_parse_status(&asm_ctx, PARSE_ERR);
|
||||
YYABORT;
|
||||
create_ps11_parser(&asm_ctx);
|
||||
}
|
||||
| VER_PS12
|
||||
{
|
||||
TRACE("Pixel shader 1.2\n");
|
||||
set_parse_status(&asm_ctx, PARSE_ERR);
|
||||
YYABORT;
|
||||
create_ps12_parser(&asm_ctx);
|
||||
}
|
||||
| VER_PS13
|
||||
{
|
||||
TRACE("Pixel shader 1.3\n");
|
||||
set_parse_status(&asm_ctx, PARSE_ERR);
|
||||
YYABORT;
|
||||
create_ps13_parser(&asm_ctx);
|
||||
}
|
||||
| VER_PS14
|
||||
{
|
||||
|
|
|
@ -578,7 +578,7 @@ static HRESULT find_ps_builtin_semantics(struct bc_writer *This,
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
static void ps_1_4_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
|
||||
static void ps_1_x_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
|
||||
HRESULT hr;
|
||||
|
||||
/* First check the constants and varyings, and complain if unsupported things are used */
|
||||
|
@ -589,6 +589,27 @@ static void ps_1_4_header(struct bc_writer *This, const struct bwriter_shader *s
|
|||
return;
|
||||
}
|
||||
|
||||
hr = find_ps_builtin_semantics(This, shader, 4);
|
||||
if(FAILED(hr)) {
|
||||
This->state = hr;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Declare the shader type and version */
|
||||
put_dword(buffer, This->version);
|
||||
write_constF(shader, buffer, TRUE);
|
||||
}
|
||||
|
||||
static void ps_1_4_header(struct bc_writer *This, const struct bwriter_shader *shader, struct bytecode_buffer *buffer) {
|
||||
HRESULT hr;
|
||||
|
||||
/* First check the constants and varyings, and complain if unsupported things are used */
|
||||
if(shader->num_ci || shader->num_cb) {
|
||||
WARN("Int and bool constants are not supported in shader model 1 shaders\n");
|
||||
WARN("Got %u int and %u boolean constants\n", shader->num_ci, shader->num_cb);
|
||||
This->state = E_INVALIDARG;
|
||||
return;
|
||||
}
|
||||
hr = find_ps_builtin_semantics(This, shader, 6);
|
||||
if(FAILED(hr)) {
|
||||
This->state = hr;
|
||||
|
@ -808,6 +829,27 @@ static void write_srcregs(struct bc_writer *This, const struct instruction *inst
|
|||
}
|
||||
}
|
||||
|
||||
static DWORD map_ps13_temp(struct bc_writer *This, const struct shader_reg *reg) {
|
||||
DWORD token = 0;
|
||||
if(reg->regnum == T0_REG) {
|
||||
token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
|
||||
token |= 0 & D3DSP_REGNUM_MASK; /* No shift */
|
||||
} else if(reg->regnum == T1_REG) {
|
||||
token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
|
||||
token |= 1 & D3DSP_REGNUM_MASK; /* No shift */
|
||||
} else if(reg->regnum == T2_REG) {
|
||||
token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
|
||||
token |= 2 & D3DSP_REGNUM_MASK; /* No shift */
|
||||
} else if(reg->regnum == T3_REG) {
|
||||
token |= (D3DSPR_TEXTURE << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
|
||||
token |= 3 & D3DSP_REGNUM_MASK; /* No shift */
|
||||
} else {
|
||||
token |= (D3DSPR_TEMP << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
|
||||
token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
static DWORD map_ps_input(struct bc_writer *This,
|
||||
const struct shader_reg *reg) {
|
||||
DWORD i, token = 0;
|
||||
|
@ -832,6 +874,86 @@ static DWORD map_ps_input(struct bc_writer *This,
|
|||
return token;
|
||||
}
|
||||
|
||||
static void ps_1_0123_srcreg(struct bc_writer *This, const struct shader_reg *reg,
|
||||
struct bytecode_buffer *buffer) {
|
||||
DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
|
||||
if(reg->rel_reg) {
|
||||
WARN("Relative addressing not supported in <= ps_3_0\n");
|
||||
This->state = E_INVALIDARG;
|
||||
return;
|
||||
}
|
||||
|
||||
switch(reg->type) {
|
||||
case BWRITERSPR_INPUT:
|
||||
token |= map_ps_input(This, reg);
|
||||
break;
|
||||
|
||||
/* Take care about the texture temporaries. There's a problem: They aren't
|
||||
* declared anywhere, so we can only hardcode the values that are used
|
||||
* to map ps_1_3 shaders to the common shader structure
|
||||
*/
|
||||
case BWRITERSPR_TEMP:
|
||||
token |= map_ps13_temp(This, reg);
|
||||
break;
|
||||
|
||||
case BWRITERSPR_CONST: /* Can be mapped 1:1 */
|
||||
token |= (reg->type << D3DSP_REGTYPE_SHIFT) & D3DSP_REGTYPE_MASK;
|
||||
token |= reg->regnum & D3DSP_REGNUM_MASK; /* No shift */
|
||||
break;
|
||||
|
||||
default:
|
||||
WARN("Invalid register type for <= ps_1_3 shader\n");
|
||||
This->state = E_INVALIDARG;
|
||||
return;
|
||||
}
|
||||
|
||||
token |= d3d9_swizzle(reg->swizzle) & D3DVS_SWIZZLE_MASK; /* already shifted */
|
||||
|
||||
if(reg->srcmod == BWRITERSPSM_DZ || reg->srcmod == BWRITERSPSM_DW ||
|
||||
reg->srcmod == BWRITERSPSM_ABS || reg->srcmod == BWRITERSPSM_ABSNEG ||
|
||||
reg->srcmod == BWRITERSPSM_NOT) {
|
||||
WARN("Invalid source modifier %u for <= ps_1_3\n", reg->srcmod);
|
||||
This->state = E_INVALIDARG;
|
||||
return;
|
||||
}
|
||||
token |= d3d9_srcmod(reg->srcmod);
|
||||
put_dword(buffer, token);
|
||||
}
|
||||
|
||||
static void ps_1_0123_dstreg(struct bc_writer *This, const struct shader_reg *reg,
|
||||
struct bytecode_buffer *buffer,
|
||||
DWORD shift, DWORD mod) {
|
||||
DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
|
||||
|
||||
if(reg->rel_reg) {
|
||||
WARN("Relative addressing not supported for destination registers\n");
|
||||
This->state = E_INVALIDARG;
|
||||
return;
|
||||
}
|
||||
|
||||
switch(reg->type) {
|
||||
case BWRITERSPR_TEMP:
|
||||
token |= map_ps13_temp(This, reg);
|
||||
break;
|
||||
|
||||
/* texkill uses the input register as a destination parameter */
|
||||
case BWRITERSPR_INPUT:
|
||||
token |= map_ps_input(This, reg);
|
||||
break;
|
||||
|
||||
default:
|
||||
WARN("Invalid dest register type for 1.x pshader\n");
|
||||
This->state = E_INVALIDARG;
|
||||
return;
|
||||
}
|
||||
|
||||
token |= (shift << D3DSP_DSTSHIFT_SHIFT) & D3DSP_DSTSHIFT_MASK;
|
||||
token |= d3d9_dstmod(mod);
|
||||
|
||||
token |= d3d9_writemask(reg->writemask);
|
||||
put_dword(buffer, token);
|
||||
}
|
||||
|
||||
/* The length of an instruction consists of the destination register (if any),
|
||||
* the number of source registers, the number of address registers used for
|
||||
* indirect addressing, and optionally the predicate register
|
||||
|
@ -910,6 +1032,168 @@ static const struct bytecode_backend vs_1_x_backend = {
|
|||
vs_1_x_handlers
|
||||
};
|
||||
|
||||
static void instr_ps_1_0123_texld(struct bc_writer *This,
|
||||
const struct instruction *instr,
|
||||
struct bytecode_buffer *buffer) {
|
||||
DWORD idx, srcidx;
|
||||
struct shader_reg reg;
|
||||
DWORD swizzlemask;
|
||||
|
||||
if(instr->src[1].type != BWRITERSPR_SAMPLER ||
|
||||
instr->src[1].regnum > 3) {
|
||||
WARN("Unsupported sampler type %u regnum %u\n",
|
||||
instr->src[1].type, instr->src[1].regnum);
|
||||
This->state = E_INVALIDARG;
|
||||
return;
|
||||
} else if(instr->dst.type != BWRITERSPR_TEMP) {
|
||||
WARN("Can only sample into a temp register\n");
|
||||
This->state = E_INVALIDARG;
|
||||
return;
|
||||
}
|
||||
|
||||
idx = instr->src[1].regnum;
|
||||
if((idx == 0 && instr->dst.regnum != T0_REG) ||
|
||||
(idx == 1 && instr->dst.regnum != T1_REG) ||
|
||||
(idx == 2 && instr->dst.regnum != T2_REG) ||
|
||||
(idx == 3 && instr->dst.regnum != T3_REG)) {
|
||||
WARN("Sampling from sampler s%u to register r%u is not possible in ps_1_x\n",
|
||||
idx, instr->dst.regnum);
|
||||
This->state = E_INVALIDARG;
|
||||
return;
|
||||
}
|
||||
if(instr->src[0].type == BWRITERSPR_INPUT) {
|
||||
/* A simple non-dependent read tex instruction */
|
||||
if(instr->src[0].regnum != This->t_regnum[idx]) {
|
||||
WARN("Cannot sample from s%u with texture address data from interpolator %u\n",
|
||||
idx, instr->src[0].regnum);
|
||||
This->state = E_INVALIDARG;
|
||||
return;
|
||||
}
|
||||
This->funcs->opcode(This, instr, D3DSIO_TEX & D3DSI_OPCODE_MASK, buffer);
|
||||
|
||||
/* map the temp dstreg to the ps_1_3 texture temporary register */
|
||||
This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
|
||||
} else if(instr->src[0].type == BWRITERSPR_TEMP) {
|
||||
if(instr->src[0].regnum == T0_REG) {
|
||||
srcidx = 0;
|
||||
} else if(instr->src[0].regnum == T1_REG) {
|
||||
srcidx = 1;
|
||||
} else if(instr->src[0].regnum == T2_REG) {
|
||||
srcidx = 2;
|
||||
} else if(instr->src[0].regnum == T3_REG) {
|
||||
srcidx = 3;
|
||||
} else {
|
||||
WARN("Invalid address data source register r%u\n", instr->src[0].regnum);
|
||||
}
|
||||
|
||||
swizzlemask = (3 << BWRITERVS_SWIZZLE_SHIFT) |
|
||||
(3 << (BWRITERVS_SWIZZLE_SHIFT + 2)) |
|
||||
(3 << (BWRITERVS_SWIZZLE_SHIFT + 4));
|
||||
if((instr->src[0].swizzle & swizzlemask) == (BWRITERVS_X_X | BWRITERVS_Y_Y | BWRITERVS_Z_Z)) {
|
||||
TRACE("writing texreg2rgb\n");
|
||||
This->funcs->opcode(This, instr, D3DSIO_TEXREG2RGB & D3DSI_OPCODE_MASK, buffer);
|
||||
} else if(instr->src[0].swizzle == (BWRITERVS_X_W | BWRITERVS_Y_X | BWRITERVS_Z_X | BWRITERVS_W_X)) {
|
||||
TRACE("writing texreg2ar\n");
|
||||
This->funcs->opcode(This, instr, D3DSIO_TEXREG2AR & D3DSI_OPCODE_MASK, buffer);
|
||||
} else if(instr->src[0].swizzle == (BWRITERVS_X_Y | BWRITERVS_Y_Z | BWRITERVS_Z_Z | BWRITERVS_W_Z)) {
|
||||
TRACE("writing texreg2gb\n");
|
||||
This->funcs->opcode(This, instr, D3DSIO_TEXREG2GB & D3DSI_OPCODE_MASK, buffer);
|
||||
} else {
|
||||
WARN("Unsupported src addr swizzle in dependent texld: 0x%08x\n", instr->src[0].swizzle);
|
||||
This->state = E_INVALIDARG;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Dst and src reg can be mapped normally. Both registers are temporary registers in the
|
||||
* source shader and have to be mapped to the temporary form of the texture registers. However,
|
||||
* the src reg doesn't have a swizzle
|
||||
*/
|
||||
This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
|
||||
reg = instr->src[0];
|
||||
reg.swizzle = BWRITERVS_NOSWIZZLE;
|
||||
This->funcs->srcreg(This, ®, buffer);
|
||||
} else {
|
||||
WARN("Invalid address data source register\n");
|
||||
This->state = E_INVALIDARG;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void instr_ps_1_0123_mov(struct bc_writer *This,
|
||||
const struct instruction *instr,
|
||||
struct bytecode_buffer *buffer) {
|
||||
DWORD token = D3DSIO_MOV & D3DSI_OPCODE_MASK;
|
||||
|
||||
if(instr->dst.type == BWRITERSPR_TEMP && instr->src[0].type == BWRITERSPR_INPUT) {
|
||||
if((instr->dst.regnum == T0_REG && instr->src[0].regnum == This->t_regnum[0]) ||
|
||||
(instr->dst.regnum == T1_REG && instr->src[0].regnum == This->t_regnum[1]) ||
|
||||
(instr->dst.regnum == T2_REG && instr->src[0].regnum == This->t_regnum[2]) ||
|
||||
(instr->dst.regnum == T3_REG && instr->src[0].regnum == This->t_regnum[3])) {
|
||||
if(instr->dstmod & BWRITERSPDM_SATURATE) {
|
||||
This->funcs->opcode(This, instr, D3DSIO_TEXCOORD & D3DSI_OPCODE_MASK, buffer);
|
||||
/* Remove the SATURATE flag, it's implicit to the instruction */
|
||||
This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod & (~BWRITERSPDM_SATURATE));
|
||||
return;
|
||||
} else {
|
||||
WARN("A varying -> temp copy is only supported with the SATURATE modifier in <=ps_1_3\n");
|
||||
This->state = E_INVALIDARG;
|
||||
return;
|
||||
}
|
||||
} else if(instr->src[0].regnum == This->v_regnum[0] ||
|
||||
instr->src[0].regnum == This->v_regnum[1]) {
|
||||
/* Handled by the normal mov below. Just drop out of the if condition */
|
||||
} else {
|
||||
WARN("Unsupported varying -> temp mov in <= ps_1_3\n");
|
||||
This->state = E_INVALIDARG;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
This->funcs->opcode(This, instr, token, buffer);
|
||||
This->funcs->dstreg(This, &instr->dst, buffer, instr->shift, instr->dstmod);
|
||||
This->funcs->srcreg(This, &instr->src[0], buffer);
|
||||
}
|
||||
|
||||
static const struct instr_handler_table ps_1_0123_handlers[] = {
|
||||
{BWRITERSIO_ADD, instr_handler},
|
||||
{BWRITERSIO_NOP, instr_handler},
|
||||
{BWRITERSIO_MOV, instr_ps_1_0123_mov},
|
||||
{BWRITERSIO_SUB, instr_handler},
|
||||
{BWRITERSIO_MAD, instr_handler},
|
||||
{BWRITERSIO_MUL, instr_handler},
|
||||
{BWRITERSIO_DP3, instr_handler},
|
||||
{BWRITERSIO_DP4, instr_handler},
|
||||
{BWRITERSIO_LRP, instr_handler},
|
||||
|
||||
/* pshader instructions */
|
||||
{BWRITERSIO_CND, instr_handler},
|
||||
{BWRITERSIO_CMP, instr_handler},
|
||||
{BWRITERSIO_TEXKILL, instr_handler},
|
||||
{BWRITERSIO_TEX, instr_ps_1_0123_texld},
|
||||
{BWRITERSIO_TEXBEM, instr_handler},
|
||||
{BWRITERSIO_TEXBEML, instr_handler},
|
||||
{BWRITERSIO_TEXM3x2PAD, instr_handler},
|
||||
{BWRITERSIO_TEXM3x3PAD, instr_handler},
|
||||
{BWRITERSIO_TEXM3x3SPEC, instr_handler},
|
||||
{BWRITERSIO_TEXM3x3VSPEC, instr_handler},
|
||||
{BWRITERSIO_TEXM3x3TEX, instr_handler},
|
||||
{BWRITERSIO_TEXM3x3, instr_handler},
|
||||
{BWRITERSIO_TEXM3x2DEPTH, instr_handler},
|
||||
{BWRITERSIO_TEXM3x2TEX, instr_handler},
|
||||
{BWRITERSIO_TEXDP3, instr_handler},
|
||||
{BWRITERSIO_TEXDP3TEX, instr_handler},
|
||||
{BWRITERSIO_END, NULL},
|
||||
};
|
||||
|
||||
static const struct bytecode_backend ps_1_0123_backend = {
|
||||
ps_1_x_header,
|
||||
end,
|
||||
ps_1_0123_srcreg,
|
||||
ps_1_0123_dstreg,
|
||||
sm_1_x_opcode,
|
||||
ps_1_0123_handlers
|
||||
};
|
||||
|
||||
static void ps_1_4_srcreg(struct bc_writer *This, const struct shader_reg *reg,
|
||||
struct bytecode_buffer *buffer) {
|
||||
DWORD token = (1 << 31); /* Bit 31 of registers is 1 */
|
||||
|
@ -1860,6 +2144,26 @@ static void init_vs30_dx9_writer(struct bc_writer *writer) {
|
|||
writer->funcs = &vs_3_backend;
|
||||
}
|
||||
|
||||
static void init_ps10_dx9_writer(struct bc_writer *writer) {
|
||||
TRACE("Creating DirectX9 pixel shader 1.0 writer\n");
|
||||
writer->funcs = &ps_1_0123_backend;
|
||||
}
|
||||
|
||||
static void init_ps11_dx9_writer(struct bc_writer *writer) {
|
||||
TRACE("Creating DirectX9 pixel shader 1.1 writer\n");
|
||||
writer->funcs = &ps_1_0123_backend;
|
||||
}
|
||||
|
||||
static void init_ps12_dx9_writer(struct bc_writer *writer) {
|
||||
TRACE("Creating DirectX9 pixel shader 1.2 writer\n");
|
||||
writer->funcs = &ps_1_0123_backend;
|
||||
}
|
||||
|
||||
static void init_ps13_dx9_writer(struct bc_writer *writer) {
|
||||
TRACE("Creating DirectX9 pixel shader 1.3 writer\n");
|
||||
writer->funcs = &ps_1_0123_backend;
|
||||
}
|
||||
|
||||
static void init_ps14_dx9_writer(struct bc_writer *writer) {
|
||||
TRACE("Creating DirectX9 pixel shader 1.4 writer\n");
|
||||
writer->funcs = &ps_1_4_backend;
|
||||
|
@ -1930,28 +2234,28 @@ static struct bc_writer *create_writer(DWORD version, DWORD dxversion) {
|
|||
WARN("Unsupported dxversion for pixel shader 1.0 requested: %u\n", dxversion);
|
||||
goto fail;
|
||||
}
|
||||
/* TODO: Set the appropriate writer backend */
|
||||
init_ps10_dx9_writer(ret);
|
||||
break;
|
||||
case BWRITERPS_VERSION(1, 1):
|
||||
if(dxversion != 9) {
|
||||
WARN("Unsupported dxversion for pixel shader 1.1 requested: %u\n", dxversion);
|
||||
goto fail;
|
||||
}
|
||||
/* TODO: Set the appropriate writer backend */
|
||||
init_ps11_dx9_writer(ret);
|
||||
break;
|
||||
case BWRITERPS_VERSION(1, 2):
|
||||
if(dxversion != 9) {
|
||||
WARN("Unsupported dxversion for pixel shader 1.2 requested: %u\n", dxversion);
|
||||
goto fail;
|
||||
}
|
||||
/* TODO: Set the appropriate writer backend */
|
||||
init_ps12_dx9_writer(ret);
|
||||
break;
|
||||
case BWRITERPS_VERSION(1, 3):
|
||||
if(dxversion != 9) {
|
||||
WARN("Unsupported dxversion for pixel shader 1.3 requested: %u\n", dxversion);
|
||||
goto fail;
|
||||
}
|
||||
/* TODO: Set the appropriate writer backend */
|
||||
init_ps13_dx9_writer(ret);
|
||||
break;
|
||||
case BWRITERPS_VERSION(1, 4):
|
||||
if(dxversion != 9) {
|
||||
|
|
|
@ -323,6 +323,10 @@ void create_vs11_parser(struct asm_parser *ret);
|
|||
void create_vs20_parser(struct asm_parser *ret);
|
||||
void create_vs2x_parser(struct asm_parser *ret);
|
||||
void create_vs30_parser(struct asm_parser *ret);
|
||||
void create_ps10_parser(struct asm_parser *ret);
|
||||
void create_ps11_parser(struct asm_parser *ret);
|
||||
void create_ps12_parser(struct asm_parser *ret);
|
||||
void create_ps13_parser(struct asm_parser *ret);
|
||||
void create_ps14_parser(struct asm_parser *ret);
|
||||
void create_ps20_parser(struct asm_parser *ret);
|
||||
void create_ps2x_parser(struct asm_parser *ret);
|
||||
|
@ -639,6 +643,12 @@ typedef enum _BWRITERDECLUSAGE {
|
|||
BWRITERDECLUSAGE_SAMPLE
|
||||
} BWRITERDECLUSAGE;
|
||||
|
||||
/* ps 1.x texture registers mappings */
|
||||
#define T0_REG 2
|
||||
#define T1_REG 3
|
||||
#define T2_REG 4
|
||||
#define T3_REG 5
|
||||
|
||||
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);
|
||||
|
|
|
@ -132,6 +132,11 @@ static void ps_1_1_test(void) {
|
|||
{0xffff0101, 0x00000042, 0xb00f0000, 0x00000002, 0x80070000, 0x80e40000,
|
||||
0x80e40001, 0x40000001, 0x80080000, 0xb0e40000, 0x0000ffff}
|
||||
},
|
||||
{ /* shader 1 */
|
||||
"ps.1.1\n"
|
||||
"mov_d4 r0, r1\n",
|
||||
{0xffff0101, 0x00000001, 0x8e0f0000, 0x80e40001, 0x0000ffff}
|
||||
},
|
||||
};
|
||||
|
||||
exec_tests("ps_1_1", tests, sizeof(tests) / sizeof(tests[0]));
|
||||
|
@ -478,6 +483,43 @@ static void ps_1_3_test(void) {
|
|||
"mov_x4_sat r0.a, -r1_bx2.a\n",
|
||||
{0xffff0103, 0x00000001, 0x82180000, 0x85ff0001, 0x0000ffff}
|
||||
},
|
||||
{ /* shader 30 */
|
||||
"ps_1_3\n"
|
||||
"texcoord_x2 t0\n",
|
||||
{0xffff0103, 0x00000040, 0xb10f0000, 0x0000ffff}
|
||||
},
|
||||
{ /* shader 31 */
|
||||
"ps_1_3\n"
|
||||
"tex_x2 t0\n",
|
||||
{0xffff0103, 0x00000042, 0xb10f0000, 0x0000ffff}
|
||||
},
|
||||
{ /* shader 32 */
|
||||
"ps_1_3\n"
|
||||
"texreg2ar_x4 t0, t1\n",
|
||||
{0xffff0103, 0x00000045, 0xb20f0000, 0xb0e40001, 0x0000ffff}
|
||||
},
|
||||
{ /* shader 33 */
|
||||
"ps_1_3\n"
|
||||
"texbem_d4 t1, t0\n",
|
||||
{0xffff0103, 0x00000043, 0xbe0f0001, 0xb0e40000, 0x0000ffff}
|
||||
},
|
||||
{ /* shader 34 */
|
||||
"ps_1_3\n"
|
||||
"tex t0\n"
|
||||
"texm3x3pad_x2 t1, t0\n"
|
||||
"texm3x3pad_x2 t2, t0\n"
|
||||
"texm3x3tex_x2 t3, t0\n",
|
||||
{0xffff0103, 0x00000042, 0xb00f0000, 0x00000049, 0xb10f0001, 0xb0e40000,
|
||||
0x00000049, 0xb10f0002, 0xb0e40000, 0x0000004a, 0xb10f0003, 0xb0e40000,
|
||||
0x0000ffff}
|
||||
},
|
||||
{ /* shader 35 */
|
||||
"ps_1_3\n"
|
||||
"tex t0\n"
|
||||
"texdp3tex_x8 t1, t0\n",
|
||||
{0xffff0103, 0x00000042, 0xb00f0000, 0x00000053, 0xb30f0001, 0xb0e40000,
|
||||
0x0000ffff}
|
||||
},
|
||||
};
|
||||
|
||||
exec_tests("ps_1_3", tests, sizeof(tests) / sizeof(tests[0]));
|
||||
|
@ -1661,9 +1703,9 @@ static void assembleshader_test(void) {
|
|||
START_TEST(asm)
|
||||
{
|
||||
preproc_test();
|
||||
todo_wine ps_1_1_test();
|
||||
ps_1_1_test();
|
||||
vs_1_1_test();
|
||||
todo_wine ps_1_3_test();
|
||||
ps_1_3_test();
|
||||
ps_1_4_test();
|
||||
vs_2_0_test();
|
||||
vs_2_x_test();
|
||||
|
|
Loading…
Reference in New Issue