|  | /* | 
|  | * Direct3D asm shader parser | 
|  | * | 
|  | * Copyright 2008 Stefan Dösinger | 
|  | * Copyright 2009 Matteo Bruni | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | * | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  | #include "wine/port.h" | 
|  | #include "wine/debug.h" | 
|  |  | 
|  | #include "d3dcompiler_private.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(asmshader); | 
|  | WINE_DECLARE_DEBUG_CHANNEL(parsed_shader); | 
|  |  | 
|  |  | 
|  | /* How to map vs 1.0 and 2.0 varyings to 3.0 ones | 
|  | * oTx is mapped to ox, which happens to be an | 
|  | * identical mapping since BWRITERSPR_TEXCRDOUT == BWRITERSPR_OUTPUT | 
|  | * oPos, oFog and point size are mapped to general output regs as well. | 
|  | * the vs 1.x and 2.x parser functions add varying declarations | 
|  | * to the shader, and the 1.x and 2.x output functions check those varyings | 
|  | */ | 
|  | #define OT0_REG         0 | 
|  | #define OT1_REG         1 | 
|  | #define OT2_REG         2 | 
|  | #define OT3_REG         3 | 
|  | #define OT4_REG         4 | 
|  | #define OT5_REG         5 | 
|  | #define OT6_REG         6 | 
|  | #define OT7_REG         7 | 
|  | #define OPOS_REG        8 | 
|  | #define OFOG_REG        9 | 
|  | #define OFOG_WRITEMASK  BWRITERSP_WRITEMASK_0 | 
|  | #define OPTS_REG        9 | 
|  | #define OPTS_WRITEMASK  BWRITERSP_WRITEMASK_1 | 
|  | #define OD0_REG         10 | 
|  | #define OD1_REG         11 | 
|  |  | 
|  | /* Input color registers 0-1 are identically mapped */ | 
|  | #define C0_VARYING      0 | 
|  | #define C1_VARYING      1 | 
|  | #define T0_VARYING      2 | 
|  | #define T1_VARYING      3 | 
|  | #define T2_VARYING      4 | 
|  | #define T3_VARYING      5 | 
|  | #define T4_VARYING      6 | 
|  | #define T5_VARYING      7 | 
|  | #define T6_VARYING      8 | 
|  | #define T7_VARYING      9 | 
|  |  | 
|  | /**************************************************************** | 
|  | * Common(non-version specific) shader parser control code      * | 
|  | ****************************************************************/ | 
|  |  | 
|  | static void asmparser_end(struct asm_parser *This) { | 
|  | TRACE("Finalizing shader\n"); | 
|  | } | 
|  |  | 
|  | static void asmparser_constF(struct asm_parser *This, DWORD reg, float x, float y, float z, float w) { | 
|  | if(!This->shader) return; | 
|  | TRACE("Adding float constant %u at pos %u\n", reg, This->shader->num_cf); | 
|  | TRACE_(parsed_shader)("def c%u, %f, %f, %f, %f\n", reg, x, y, z, w); | 
|  | if(!add_constF(This->shader, reg, x, y, z, w)) { | 
|  | ERR("Out of memory\n"); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void asmparser_constB(struct asm_parser *This, DWORD reg, BOOL x) { | 
|  | if(!This->shader) return; | 
|  | TRACE("Adding boolean constant %u at pos %u\n", reg, This->shader->num_cb); | 
|  | TRACE_(parsed_shader)("def b%u, %s\n", reg, x ? "true" : "false"); | 
|  | if(!add_constB(This->shader, reg, x)) { | 
|  | ERR("Out of memory\n"); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void asmparser_constI(struct asm_parser *This, DWORD reg, INT x, INT y, INT z, INT w) { | 
|  | if(!This->shader) return; | 
|  | TRACE("Adding integer constant %u at pos %u\n", reg, This->shader->num_ci); | 
|  | TRACE_(parsed_shader)("def i%u, %d, %d, %d, %d\n", reg, x, y, z, w); | 
|  | if(!add_constI(This->shader, reg, x, y, z, w)) { | 
|  | ERR("Out of memory\n"); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void asmparser_dcl_output(struct asm_parser *This, DWORD usage, DWORD num, | 
|  | const struct shader_reg *reg) { | 
|  | if(!This->shader) return; | 
|  | if(This->shader->type == ST_PIXEL) { | 
|  | asmparser_message(This, "Line %u: Output register declared in a pixel shader\n", This->line_no); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | if(!record_declaration(This->shader, usage, num, 0, TRUE, reg->regnum, reg->u.writemask, FALSE)) { | 
|  | ERR("Out of memory\n"); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void asmparser_dcl_output_unsupported(struct asm_parser *This, DWORD usage, DWORD num, | 
|  | const struct shader_reg *reg) { | 
|  | asmparser_message(This, "Line %u: Output declaration unsupported in this shader version\n", This->line_no); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  |  | 
|  | static void asmparser_dcl_input(struct asm_parser *This, DWORD usage, DWORD num, | 
|  | DWORD mod, const struct shader_reg *reg) { | 
|  | struct instruction instr; | 
|  |  | 
|  | if(!This->shader) return; | 
|  | if(mod != 0 && | 
|  | (This->shader->version != BWRITERPS_VERSION(3, 0) || | 
|  | (mod != BWRITERSPDM_MSAMPCENTROID && | 
|  | mod != BWRITERSPDM_PARTIALPRECISION))) { | 
|  | asmparser_message(This, "Line %u: Unsupported modifier in dcl instruction\n", This->line_no); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* Check register type and modifiers */ | 
|  | instr.dstmod = mod; | 
|  | instr.shift = 0; | 
|  | This->funcs->dstreg(This, &instr, reg); | 
|  |  | 
|  | if(!record_declaration(This->shader, usage, num, mod, FALSE, reg->regnum, reg->u.writemask, FALSE)) { | 
|  | ERR("Out of memory\n"); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void asmparser_dcl_input_ps_2(struct asm_parser *This, DWORD usage, DWORD num, | 
|  | DWORD mod, const struct shader_reg *reg) { | 
|  | struct instruction instr; | 
|  |  | 
|  | if(!This->shader) return; | 
|  | instr.dstmod = mod; | 
|  | instr.shift = 0; | 
|  | This->funcs->dstreg(This, &instr, reg); | 
|  | if(!record_declaration(This->shader, usage, num, mod, FALSE, instr.dst.regnum, instr.dst.u.writemask, FALSE)) { | 
|  | ERR("Out of memory\n"); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void asmparser_dcl_input_unsupported(struct asm_parser *This, | 
|  | DWORD usage, DWORD num, DWORD mod, const struct shader_reg *reg) | 
|  | { | 
|  | asmparser_message(This, "Line %u: Input declaration unsupported in this shader version\n", This->line_no); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  |  | 
|  | static void asmparser_dcl_sampler(struct asm_parser *This, DWORD samptype, | 
|  | DWORD mod, DWORD regnum, | 
|  | unsigned int line_no) { | 
|  | if(!This->shader) return; | 
|  | if(mod != 0 && | 
|  | (This->shader->version != BWRITERPS_VERSION(3, 0) || | 
|  | (mod != BWRITERSPDM_MSAMPCENTROID && | 
|  | mod != BWRITERSPDM_PARTIALPRECISION))) { | 
|  | asmparser_message(This, "Line %u: Unsupported modifier in dcl instruction\n", This->line_no); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | return; | 
|  | } | 
|  | if(!record_sampler(This->shader, samptype, mod, regnum)) { | 
|  | ERR("Out of memory\n"); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void asmparser_dcl_sampler_unsupported(struct asm_parser *This, | 
|  | DWORD samptype, DWORD mod, DWORD regnum, unsigned int line_no) | 
|  | { | 
|  | asmparser_message(This, "Line %u: Sampler declaration unsupported in this shader version\n", This->line_no); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  |  | 
|  | static void asmparser_sincos(struct asm_parser *This, DWORD mod, DWORD shift, | 
|  | const struct shader_reg *dst, | 
|  | const struct src_regs *srcs) { | 
|  | struct instruction *instr; | 
|  |  | 
|  | if(!srcs || srcs->count != 3) { | 
|  | asmparser_message(This, "Line %u: sincos (vs 2) has an incorrect number of source registers\n", This->line_no); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | return; | 
|  | } | 
|  |  | 
|  | instr = alloc_instr(3); | 
|  | if(!instr) { | 
|  | ERR("Error allocating memory for the instruction\n"); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | return; | 
|  | } | 
|  |  | 
|  | instr->opcode = BWRITERSIO_SINCOS; | 
|  | instr->dstmod = mod; | 
|  | instr->shift = shift; | 
|  | instr->comptype = 0; | 
|  |  | 
|  | This->funcs->dstreg(This, instr, dst); | 
|  | This->funcs->srcreg(This, instr, 0, &srcs->reg[0]); | 
|  | This->funcs->srcreg(This, instr, 1, &srcs->reg[1]); | 
|  | This->funcs->srcreg(This, instr, 2, &srcs->reg[2]); | 
|  |  | 
|  | if(!add_instruction(This->shader, instr)) { | 
|  | ERR("Out of memory\n"); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | } | 
|  |  | 
|  | 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) { | 
|  | struct instruction *instr; | 
|  |  | 
|  | if(!srcs || srcs->count != 1) { | 
|  | asmparser_message(This, "Line %u: Wrong number of source registers in texcrd 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; | 
|  | } | 
|  |  | 
|  | /* The job of texcrd is done by mov in later shader versions */ | 
|  | instr->opcode = BWRITERSIO_MOV; | 
|  | instr->dstmod = mod; | 
|  | instr->shift = shift; | 
|  | instr->comptype = 0; | 
|  |  | 
|  | This->funcs->dstreg(This, instr, dst); | 
|  | This->funcs->srcreg(This, instr, 0, &srcs->reg[0]); | 
|  |  | 
|  | if(!add_instruction(This->shader, instr)) { | 
|  | ERR("Out of memory\n"); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | } | 
|  |  | 
|  | 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].u.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) { | 
|  | struct instruction *instr; | 
|  |  | 
|  | if(!srcs || srcs->count != 1) { | 
|  | asmparser_message(This, "Line %u: texld (PS 1.4) has a wrong number of source registers\n", This->line_no); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | return; | 
|  | } | 
|  |  | 
|  | instr = alloc_instr(2); | 
|  | if(!instr) { | 
|  | ERR("Error allocating memory for the instruction\n"); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | return; | 
|  | } | 
|  |  | 
|  | /* This code is recording a texld instruction, not tex. However, | 
|  | * texld borrows the opcode of tex | 
|  | */ | 
|  | instr->opcode = BWRITERSIO_TEX; | 
|  | instr->dstmod = mod; | 
|  | instr->shift = shift; | 
|  | instr->comptype = 0; | 
|  |  | 
|  | This->funcs->dstreg(This, instr, dst); | 
|  | This->funcs->srcreg(This, instr, 0, &srcs->reg[0]); | 
|  |  | 
|  | /* 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].u.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_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.u.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.u.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.u.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, | 
|  | const struct shader_reg *dst, | 
|  | const struct src_regs *srcs, int expectednsrcs) { | 
|  | struct instruction *instr; | 
|  | unsigned int i; | 
|  | BOOL firstreg = TRUE; | 
|  | unsigned int src_count = srcs ? srcs->count : 0; | 
|  |  | 
|  | if(!This->shader) return; | 
|  |  | 
|  | TRACE_(parsed_shader)("%s%s%s%s ", debug_print_opcode(opcode), | 
|  | debug_print_dstmod(mod), | 
|  | debug_print_shift(shift), | 
|  | debug_print_comp(comp)); | 
|  | if(dst) { | 
|  | TRACE_(parsed_shader)("%s", debug_print_dstreg(dst)); | 
|  | firstreg = FALSE; | 
|  | } | 
|  | for(i = 0; i < src_count; i++) { | 
|  | if(!firstreg) TRACE_(parsed_shader)(", "); | 
|  | else firstreg = FALSE; | 
|  | TRACE_(parsed_shader)("%s", debug_print_srcreg(&srcs->reg[i])); | 
|  | } | 
|  | TRACE_(parsed_shader)("\n"); | 
|  |  | 
|  | /* Check for instructions with different syntaxes in different shader versions */ | 
|  | switch(opcode) { | 
|  | case BWRITERSIO_SINCOS: | 
|  | /* The syntax changes between vs 2 and the other shader versions */ | 
|  | if(This->shader->version == BWRITERVS_VERSION(2, 0) || | 
|  | This->shader->version == BWRITERVS_VERSION(2, 1)) { | 
|  | asmparser_sincos(This, mod, shift, dst, srcs); | 
|  | return; | 
|  | } | 
|  | /* Use the default handling */ | 
|  | break; | 
|  | case BWRITERSIO_TEXCOORD: | 
|  | /* texcoord/texcrd are two instructions present only in PS <= 1.3 and PS 1.4 respectively */ | 
|  | 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, 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; | 
|  | } | 
|  | /* else fallback to the standard behavior */ | 
|  | break; | 
|  | } | 
|  |  | 
|  | if(src_count != expectednsrcs) { | 
|  | asmparser_message(This, "Line %u: Wrong number of source registers\n", This->line_no); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | 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"); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | return; | 
|  | } | 
|  |  | 
|  | instr->opcode = opcode; | 
|  | instr->dstmod = mod; | 
|  | instr->shift = shift; | 
|  | instr->comptype = comp; | 
|  | if(dst) This->funcs->dstreg(This, instr, dst); | 
|  | for(i = 0; i < src_count; i++) { | 
|  | This->funcs->srcreg(This, instr, i, &srcs->reg[i]); | 
|  | } | 
|  |  | 
|  | if(!add_instruction(This->shader, instr)) { | 
|  | ERR("Out of memory\n"); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | } | 
|  |  | 
|  | static struct shader_reg map_oldvs_register(const struct shader_reg *reg) { | 
|  | struct shader_reg ret; | 
|  | switch(reg->type) { | 
|  | case BWRITERSPR_RASTOUT: | 
|  | ret = *reg; | 
|  | ret.type = BWRITERSPR_OUTPUT; | 
|  | switch(reg->regnum) { | 
|  | case BWRITERSRO_POSITION: | 
|  | ret.regnum = OPOS_REG; | 
|  | break; | 
|  | case BWRITERSRO_FOG: | 
|  | ret.regnum = OFOG_REG; | 
|  | ret.u.writemask = OFOG_WRITEMASK; | 
|  | break; | 
|  | case BWRITERSRO_POINT_SIZE: | 
|  | ret.regnum = OPTS_REG; | 
|  | ret.u.writemask = OPTS_WRITEMASK; | 
|  | break; | 
|  | default: | 
|  | FIXME("Unhandled RASTOUT register %u\n", reg->regnum); | 
|  | return *reg; | 
|  | } | 
|  | return ret; | 
|  |  | 
|  | case BWRITERSPR_TEXCRDOUT: | 
|  | ret = *reg; | 
|  | ret.type = BWRITERSPR_OUTPUT; | 
|  | switch(reg->regnum) { | 
|  | case 0: ret.regnum = OT0_REG; break; | 
|  | case 1: ret.regnum = OT1_REG; break; | 
|  | case 2: ret.regnum = OT2_REG; break; | 
|  | case 3: ret.regnum = OT3_REG; break; | 
|  | case 4: ret.regnum = OT4_REG; break; | 
|  | case 5: ret.regnum = OT5_REG; break; | 
|  | case 6: ret.regnum = OT6_REG; break; | 
|  | case 7: ret.regnum = OT7_REG; break; | 
|  | default: | 
|  | FIXME("Unhandled TEXCRDOUT regnum %u\n", reg->regnum); | 
|  | return *reg; | 
|  | } | 
|  | return ret; | 
|  |  | 
|  | case BWRITERSPR_ATTROUT: | 
|  | ret = *reg; | 
|  | ret.type = BWRITERSPR_OUTPUT; | 
|  | switch(reg->regnum) { | 
|  | case 0: ret.regnum = OD0_REG; break; | 
|  | case 1: ret.regnum = OD1_REG; break; | 
|  | default: | 
|  | FIXME("Unhandled ATTROUT regnum %u\n", reg->regnum); | 
|  | return *reg; | 
|  | } | 
|  | return ret; | 
|  |  | 
|  | 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) { | 
|  | if(srcmod == BWRITERSPSM_BIAS || srcmod == BWRITERSPSM_BIASNEG || | 
|  | srcmod == BWRITERSPSM_SIGN || srcmod == BWRITERSPSM_SIGNNEG || | 
|  | srcmod == BWRITERSPSM_COMP || srcmod == BWRITERSPSM_X2 || | 
|  | srcmod == BWRITERSPSM_X2NEG || srcmod == BWRITERSPSM_DZ || | 
|  | srcmod == BWRITERSPSM_DW) { | 
|  | asmparser_message(This, "Line %u: Source modifier %s not supported in this shader version\n", | 
|  | This->line_no, | 
|  | debug_print_srcmod(srcmod)); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void check_abs_srcmod(struct asm_parser *This, DWORD srcmod) { | 
|  | if(srcmod == BWRITERSPSM_ABS || srcmod == BWRITERSPSM_ABSNEG) { | 
|  | asmparser_message(This, "Line %u: Source modifier %s not supported in this shader version\n", | 
|  | This->line_no, | 
|  | debug_print_srcmod(srcmod)); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void check_loop_swizzle(struct asm_parser *This, | 
|  | const struct shader_reg *src) { | 
|  | if((src->type == BWRITERSPR_LOOP && src->u.swizzle != BWRITERVS_NOSWIZZLE) || | 
|  | (src->rel_reg && src->rel_reg->type == BWRITERSPR_LOOP && | 
|  | src->rel_reg->u.swizzle != BWRITERVS_NOSWIZZLE)) { | 
|  | asmparser_message(This, "Line %u: Swizzle not allowed on aL register\n", This->line_no); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void check_shift_dstmod(struct asm_parser *This, DWORD shift) { | 
|  | if(shift != 0) { | 
|  | asmparser_message(This, "Line %u: Shift modifiers not supported in this shader version\n", | 
|  | This->line_no); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | } | 
|  |  | 
|  | static void check_ps_dstmod(struct asm_parser *This, DWORD dstmod) { | 
|  | if(dstmod == BWRITERSPDM_PARTIALPRECISION || | 
|  | dstmod == BWRITERSPDM_MSAMPCENTROID) { | 
|  | asmparser_message(This, "Line %u: Instruction modifier %s not supported in this shader version\n", | 
|  | This->line_no, | 
|  | debug_print_dstmod(dstmod)); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | } | 
|  |  | 
|  | struct allowed_reg_type { | 
|  | DWORD type; | 
|  | DWORD count; | 
|  | BOOL reladdr; | 
|  | }; | 
|  |  | 
|  | static BOOL check_reg_type(const struct shader_reg *reg, | 
|  | const struct allowed_reg_type *allowed) { | 
|  | unsigned int i = 0; | 
|  |  | 
|  | while(allowed[i].type != ~0U) { | 
|  | if(reg->type == allowed[i].type) { | 
|  | if(reg->rel_reg) { | 
|  | if(allowed[i].reladdr) | 
|  | return TRUE; /* The relative addressing register | 
|  | can have a negative value, we | 
|  | can't check the register index */ | 
|  | return FALSE; | 
|  | } | 
|  | if(reg->regnum < allowed[i].count) return TRUE; | 
|  | return FALSE; | 
|  | } | 
|  | i++; | 
|  | } | 
|  | return FALSE; | 
|  | } | 
|  |  | 
|  | /* Native assembler doesn't do separate checks for src and dst registers */ | 
|  | static const struct allowed_reg_type vs_1_reg_allowed[] = { | 
|  | { BWRITERSPR_TEMP,         12,  FALSE }, | 
|  | { BWRITERSPR_INPUT,        16,  FALSE }, | 
|  | { BWRITERSPR_CONST,       ~0U,   TRUE }, | 
|  | { BWRITERSPR_ADDR,          1,  FALSE }, | 
|  | { BWRITERSPR_RASTOUT,       3,  FALSE }, /* oPos, oFog and oPts */ | 
|  | { BWRITERSPR_ATTROUT,       2,  FALSE }, | 
|  | { BWRITERSPR_TEXCRDOUT,     8,  FALSE }, | 
|  | { ~0U, 0 } /* End tag */ | 
|  | }; | 
|  |  | 
|  | /* struct instruction *asmparser_srcreg | 
|  | * | 
|  | * Records a source register in the instruction and does shader version | 
|  | * specific checks and modifications on it | 
|  | * | 
|  | * Parameters: | 
|  | *  This: Shader parser instance | 
|  | *  instr: instruction to store the register in | 
|  | *  num: Number of source register | 
|  | *  src: Pointer to source the register structure. The caller can free | 
|  | *  it afterwards | 
|  | */ | 
|  | static void asmparser_srcreg_vs_1(struct asm_parser *This, | 
|  | struct instruction *instr, int num, | 
|  | const struct shader_reg *src) { | 
|  | struct shader_reg reg; | 
|  |  | 
|  | if(!check_reg_type(src, vs_1_reg_allowed)) { | 
|  | asmparser_message(This, "Line %u: Source register %s not supported in VS 1\n", | 
|  | This->line_no, | 
|  | debug_print_srcreg(src)); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | check_legacy_srcmod(This, src->srcmod); | 
|  | check_abs_srcmod(This, src->srcmod); | 
|  | reg = map_oldvs_register(src); | 
|  | memcpy(&instr->src[num], ®, sizeof(reg)); | 
|  | } | 
|  |  | 
|  | static const struct allowed_reg_type vs_2_reg_allowed[] = { | 
|  | { BWRITERSPR_TEMP,      12,  FALSE }, | 
|  | { BWRITERSPR_INPUT,     16,  FALSE }, | 
|  | { BWRITERSPR_CONST,    ~0U,   TRUE }, | 
|  | { BWRITERSPR_ADDR,       1,  FALSE }, | 
|  | { BWRITERSPR_CONSTBOOL, 16,  FALSE }, | 
|  | { BWRITERSPR_CONSTINT,  16,  FALSE }, | 
|  | { BWRITERSPR_LOOP,       1,  FALSE }, | 
|  | { BWRITERSPR_LABEL,   2048,  FALSE }, | 
|  | { BWRITERSPR_PREDICATE,  1,  FALSE }, | 
|  | { BWRITERSPR_RASTOUT,    3,  FALSE }, /* oPos, oFog and oPts */ | 
|  | { BWRITERSPR_ATTROUT,    2,  FALSE }, | 
|  | { BWRITERSPR_TEXCRDOUT,  8,  FALSE }, | 
|  | { ~0U, 0 } /* End tag */ | 
|  | }; | 
|  |  | 
|  | static void asmparser_srcreg_vs_2(struct asm_parser *This, | 
|  | struct instruction *instr, int num, | 
|  | const struct shader_reg *src) { | 
|  | struct shader_reg reg; | 
|  |  | 
|  | if(!check_reg_type(src, vs_2_reg_allowed)) { | 
|  | asmparser_message(This, "Line %u: Source register %s not supported in VS 2\n", | 
|  | This->line_no, | 
|  | debug_print_srcreg(src)); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | check_loop_swizzle(This, src); | 
|  | check_legacy_srcmod(This, src->srcmod); | 
|  | check_abs_srcmod(This, src->srcmod); | 
|  | reg = map_oldvs_register(src); | 
|  | memcpy(&instr->src[num], ®, sizeof(reg)); | 
|  | } | 
|  |  | 
|  | static const struct allowed_reg_type vs_3_reg_allowed[] = { | 
|  | { BWRITERSPR_TEMP,         32,  FALSE }, | 
|  | { BWRITERSPR_INPUT,        16,   TRUE }, | 
|  | { BWRITERSPR_CONST,       ~0U,   TRUE }, | 
|  | { BWRITERSPR_ADDR,          1,  FALSE }, | 
|  | { BWRITERSPR_CONSTBOOL,    16,  FALSE }, | 
|  | { BWRITERSPR_CONSTINT,     16,  FALSE }, | 
|  | { BWRITERSPR_LOOP,          1,  FALSE }, | 
|  | { BWRITERSPR_LABEL,      2048,  FALSE }, | 
|  | { BWRITERSPR_PREDICATE,     1,  FALSE }, | 
|  | { BWRITERSPR_SAMPLER,       4,  FALSE }, | 
|  | { BWRITERSPR_OUTPUT,       12,   TRUE }, | 
|  | { ~0U, 0 } /* End tag */ | 
|  | }; | 
|  |  | 
|  | static void asmparser_srcreg_vs_3(struct asm_parser *This, | 
|  | struct instruction *instr, int num, | 
|  | const struct shader_reg *src) { | 
|  | if(!check_reg_type(src, vs_3_reg_allowed)) { | 
|  | asmparser_message(This, "Line %u: Source register %s not supported in VS 3.0\n", | 
|  | This->line_no, | 
|  | debug_print_srcreg(src)); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | check_loop_swizzle(This, src); | 
|  | check_legacy_srcmod(This, src->srcmod); | 
|  | 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 }, | 
|  | { BWRITERSPR_TEXTURE,   6,  FALSE }, | 
|  | { BWRITERSPR_INPUT,     2,  FALSE }, | 
|  | { ~0U, 0 } /* End tag */ | 
|  | }; | 
|  |  | 
|  | static void asmparser_srcreg_ps_1_4(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_4_reg_allowed)) { | 
|  | asmparser_message(This, "Line %u: Source register %s not supported in PS 1.4\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, TRUE); | 
|  | memcpy(&instr->src[num], ®, sizeof(reg)); | 
|  | } | 
|  |  | 
|  | static const struct allowed_reg_type ps_2_0_reg_allowed[] = { | 
|  | { BWRITERSPR_INPUT,         2,  FALSE }, | 
|  | { BWRITERSPR_TEMP,         32,  FALSE }, | 
|  | { BWRITERSPR_CONST,        32,  FALSE }, | 
|  | { BWRITERSPR_CONSTINT,     16,  FALSE }, | 
|  | { BWRITERSPR_CONSTBOOL,    16,  FALSE }, | 
|  | { BWRITERSPR_SAMPLER,      16,  FALSE }, | 
|  | { BWRITERSPR_TEXTURE,       8,  FALSE }, | 
|  | { BWRITERSPR_COLOROUT,      4,  FALSE }, | 
|  | { BWRITERSPR_DEPTHOUT,      1,  FALSE }, | 
|  | { ~0U, 0 } /* End tag */ | 
|  | }; | 
|  |  | 
|  | static void asmparser_srcreg_ps_2(struct asm_parser *This, | 
|  | struct instruction *instr, int num, | 
|  | const struct shader_reg *src) { | 
|  | struct shader_reg reg; | 
|  |  | 
|  | if(!check_reg_type(src, ps_2_0_reg_allowed)) { | 
|  | asmparser_message(This, "Line %u: Source register %s not supported in PS 2.0\n", | 
|  | This->line_no, | 
|  | debug_print_srcreg(src)); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | check_legacy_srcmod(This, src->srcmod); | 
|  | check_abs_srcmod(This, src->srcmod); | 
|  | reg = map_oldps_register(src, TRUE); | 
|  | memcpy(&instr->src[num], ®, sizeof(reg)); | 
|  | } | 
|  |  | 
|  | static const struct allowed_reg_type ps_2_x_reg_allowed[] = { | 
|  | { BWRITERSPR_INPUT,         2,  FALSE }, | 
|  | { BWRITERSPR_TEMP,         32,  FALSE }, | 
|  | { BWRITERSPR_CONST,        32,  FALSE }, | 
|  | { BWRITERSPR_CONSTINT,     16,  FALSE }, | 
|  | { BWRITERSPR_CONSTBOOL,    16,  FALSE }, | 
|  | { BWRITERSPR_PREDICATE,     1,  FALSE }, | 
|  | { BWRITERSPR_SAMPLER,      16,  FALSE }, | 
|  | { BWRITERSPR_TEXTURE,       8,  FALSE }, | 
|  | { BWRITERSPR_LABEL,      2048,  FALSE }, | 
|  | { BWRITERSPR_COLOROUT,      4,  FALSE }, | 
|  | { BWRITERSPR_DEPTHOUT,      1,  FALSE }, | 
|  | { ~0U, 0 } /* End tag */ | 
|  | }; | 
|  |  | 
|  | static void asmparser_srcreg_ps_2_x(struct asm_parser *This, | 
|  | struct instruction *instr, int num, | 
|  | const struct shader_reg *src) { | 
|  | struct shader_reg reg; | 
|  |  | 
|  | if(!check_reg_type(src, ps_2_x_reg_allowed)) { | 
|  | asmparser_message(This, "Line %u: Source register %s not supported in PS 2.x\n", | 
|  | This->line_no, | 
|  | debug_print_srcreg(src)); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | check_legacy_srcmod(This, src->srcmod); | 
|  | check_abs_srcmod(This, src->srcmod); | 
|  | reg = map_oldps_register(src, TRUE); | 
|  | memcpy(&instr->src[num], ®, sizeof(reg)); | 
|  | } | 
|  |  | 
|  | static const struct allowed_reg_type ps_3_reg_allowed[] = { | 
|  | { BWRITERSPR_INPUT,        10,   TRUE }, | 
|  | { BWRITERSPR_TEMP,         32,  FALSE }, | 
|  | { BWRITERSPR_CONST,       224,  FALSE }, | 
|  | { BWRITERSPR_CONSTINT,     16,  FALSE }, | 
|  | { BWRITERSPR_CONSTBOOL,    16,  FALSE }, | 
|  | { BWRITERSPR_PREDICATE,     1,  FALSE }, | 
|  | { BWRITERSPR_SAMPLER,      16,  FALSE }, | 
|  | { BWRITERSPR_MISCTYPE,      2,  FALSE }, /* vPos and vFace */ | 
|  | { BWRITERSPR_LOOP,          1,  FALSE }, | 
|  | { BWRITERSPR_LABEL,      2048,  FALSE }, | 
|  | { BWRITERSPR_COLOROUT,      4,  FALSE }, | 
|  | { BWRITERSPR_DEPTHOUT,      1,  FALSE }, | 
|  | { ~0U, 0 } /* End tag */ | 
|  | }; | 
|  |  | 
|  | static void asmparser_srcreg_ps_3(struct asm_parser *This, | 
|  | struct instruction *instr, int num, | 
|  | const struct shader_reg *src) { | 
|  | if(!check_reg_type(src, ps_3_reg_allowed)) { | 
|  | asmparser_message(This, "Line %u: Source register %s not supported in PS 3.0\n", | 
|  | This->line_no, | 
|  | debug_print_srcreg(src)); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | check_loop_swizzle(This, src); | 
|  | check_legacy_srcmod(This, src->srcmod); | 
|  | memcpy(&instr->src[num], src, sizeof(*src)); | 
|  | } | 
|  |  | 
|  | static void asmparser_dstreg_vs_1(struct asm_parser *This, | 
|  | struct instruction *instr, | 
|  | const struct shader_reg *dst) { | 
|  | struct shader_reg reg; | 
|  |  | 
|  | if(!check_reg_type(dst, vs_1_reg_allowed)) { | 
|  | asmparser_message(This, "Line %u: Destination register %s not supported in VS 1\n", | 
|  | This->line_no, | 
|  | debug_print_dstreg(dst)); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | check_ps_dstmod(This, instr->dstmod); | 
|  | check_shift_dstmod(This, instr->shift); | 
|  | reg = map_oldvs_register(dst); | 
|  | memcpy(&instr->dst, ®, sizeof(reg)); | 
|  | instr->has_dst = TRUE; | 
|  | } | 
|  |  | 
|  | static void asmparser_dstreg_vs_2(struct asm_parser *This, | 
|  | struct instruction *instr, | 
|  | const struct shader_reg *dst) { | 
|  | struct shader_reg reg; | 
|  |  | 
|  | if(!check_reg_type(dst, vs_2_reg_allowed)) { | 
|  | asmparser_message(This, "Line %u: Destination register %s not supported in VS 2.0\n", | 
|  | This->line_no, | 
|  | debug_print_dstreg(dst)); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | check_ps_dstmod(This, instr->dstmod); | 
|  | check_shift_dstmod(This, instr->shift); | 
|  | reg = map_oldvs_register(dst); | 
|  | memcpy(&instr->dst, ®, sizeof(reg)); | 
|  | instr->has_dst = TRUE; | 
|  | } | 
|  |  | 
|  | static void asmparser_dstreg_vs_3(struct asm_parser *This, | 
|  | struct instruction *instr, | 
|  | const struct shader_reg *dst) { | 
|  | if(!check_reg_type(dst, vs_3_reg_allowed)) { | 
|  | asmparser_message(This, "Line %u: Destination register %s not supported in VS 3.0\n", | 
|  | This->line_no, | 
|  | debug_print_dstreg(dst)); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | check_ps_dstmod(This, instr->dstmod); | 
|  | check_shift_dstmod(This, instr->shift); | 
|  | memcpy(&instr->dst, dst, sizeof(*dst)); | 
|  | 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) { | 
|  | struct shader_reg reg; | 
|  |  | 
|  | if(!check_reg_type(dst, ps_1_4_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, TRUE); | 
|  | memcpy(&instr->dst, ®, sizeof(reg)); | 
|  | instr->has_dst = TRUE; | 
|  | } | 
|  |  | 
|  | static void asmparser_dstreg_ps_2(struct asm_parser *This, | 
|  | struct instruction *instr, | 
|  | const struct shader_reg *dst) { | 
|  | struct shader_reg reg; | 
|  |  | 
|  | if(!check_reg_type(dst, ps_2_0_reg_allowed)) { | 
|  | asmparser_message(This, "Line %u: Destination register %s not supported in PS 2.0\n", | 
|  | This->line_no, | 
|  | debug_print_dstreg(dst)); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | check_shift_dstmod(This, instr->shift); | 
|  | reg = map_oldps_register(dst, TRUE); | 
|  | memcpy(&instr->dst, ®, sizeof(reg)); | 
|  | instr->has_dst = TRUE; | 
|  | } | 
|  |  | 
|  | static void asmparser_dstreg_ps_2_x(struct asm_parser *This, | 
|  | struct instruction *instr, | 
|  | const struct shader_reg *dst) { | 
|  | struct shader_reg reg; | 
|  |  | 
|  | if(!check_reg_type(dst, ps_2_x_reg_allowed)) { | 
|  | asmparser_message(This, "Line %u: Destination register %s not supported in PS 2.x\n", | 
|  | This->line_no, | 
|  | debug_print_dstreg(dst)); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | check_shift_dstmod(This, instr->shift); | 
|  | reg = map_oldps_register(dst, TRUE); | 
|  | memcpy(&instr->dst, ®, sizeof(reg)); | 
|  | instr->has_dst = TRUE; | 
|  | } | 
|  |  | 
|  | static void asmparser_dstreg_ps_3(struct asm_parser *This, | 
|  | struct instruction *instr, | 
|  | const struct shader_reg *dst) { | 
|  | if(!check_reg_type(dst, ps_3_reg_allowed)) { | 
|  | asmparser_message(This, "Line %u: Destination register %s not supported in PS 3.0\n", | 
|  | This->line_no, | 
|  | debug_print_dstreg(dst)); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | check_shift_dstmod(This, instr->shift); | 
|  | memcpy(&instr->dst, dst, sizeof(*dst)); | 
|  | instr->has_dst = TRUE; | 
|  | } | 
|  |  | 
|  | static void asmparser_predicate_supported(struct asm_parser *This, | 
|  | const struct shader_reg *predicate) { | 
|  | /* this sets the predicate of the last instruction added to the shader */ | 
|  | if(!This->shader) return; | 
|  | if(This->shader->num_instrs == 0) ERR("Predicate without an instruction\n"); | 
|  | This->shader->instr[This->shader->num_instrs - 1]->has_predicate = TRUE; | 
|  | memcpy(&This->shader->instr[This->shader->num_instrs - 1]->predicate, predicate, sizeof(*predicate)); | 
|  | } | 
|  |  | 
|  | static void asmparser_predicate_unsupported(struct asm_parser *This, | 
|  | const struct shader_reg *predicate) { | 
|  | asmparser_message(This, "Line %u: Predicate not supported in < VS 2.0 or PS 2.x\n", This->line_no); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  |  | 
|  | static void asmparser_coissue_supported(struct asm_parser *This) { | 
|  | /* this sets the coissue flag of the last instruction added to the shader */ | 
|  | if(!This->shader) return; | 
|  | if(This->shader->num_instrs == 0){ | 
|  | asmparser_message(This, "Line %u: Coissue flag on the first shader instruction\n", This->line_no); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  | This->shader->instr[This->shader->num_instrs-1]->coissue = TRUE; | 
|  | } | 
|  |  | 
|  | static void asmparser_coissue_unsupported(struct asm_parser *This) { | 
|  | asmparser_message(This, "Line %u: Coissue is only supported in pixel shaders versions <= 1.4\n", This->line_no); | 
|  | set_parse_status(This, PARSE_ERR); | 
|  | } | 
|  |  | 
|  | static const struct asmparser_backend parser_vs_1 = { | 
|  | asmparser_constF, | 
|  | asmparser_constI, | 
|  | asmparser_constB, | 
|  |  | 
|  | asmparser_dstreg_vs_1, | 
|  | asmparser_srcreg_vs_1, | 
|  |  | 
|  | asmparser_predicate_unsupported, | 
|  | asmparser_coissue_unsupported, | 
|  |  | 
|  | asmparser_dcl_output_unsupported, | 
|  | asmparser_dcl_input, | 
|  | asmparser_dcl_sampler_unsupported, | 
|  |  | 
|  | asmparser_end, | 
|  |  | 
|  | asmparser_instr, | 
|  | }; | 
|  |  | 
|  | static const struct asmparser_backend parser_vs_2 = { | 
|  | asmparser_constF, | 
|  | asmparser_constI, | 
|  | asmparser_constB, | 
|  |  | 
|  | asmparser_dstreg_vs_2, | 
|  | asmparser_srcreg_vs_2, | 
|  |  | 
|  | asmparser_predicate_supported, | 
|  | asmparser_coissue_unsupported, | 
|  |  | 
|  | asmparser_dcl_output_unsupported, | 
|  | asmparser_dcl_input, | 
|  | asmparser_dcl_sampler_unsupported, | 
|  |  | 
|  | asmparser_end, | 
|  |  | 
|  | asmparser_instr, | 
|  | }; | 
|  |  | 
|  | static const struct asmparser_backend parser_vs_3 = { | 
|  | asmparser_constF, | 
|  | asmparser_constI, | 
|  | asmparser_constB, | 
|  |  | 
|  | asmparser_dstreg_vs_3, | 
|  | asmparser_srcreg_vs_3, | 
|  |  | 
|  | asmparser_predicate_supported, | 
|  | asmparser_coissue_unsupported, | 
|  |  | 
|  | asmparser_dcl_output, | 
|  | asmparser_dcl_input, | 
|  | asmparser_dcl_sampler, | 
|  |  | 
|  | asmparser_end, | 
|  |  | 
|  | 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, | 
|  | asmparser_constB, | 
|  |  | 
|  | asmparser_dstreg_ps_1_4, | 
|  | asmparser_srcreg_ps_1_4, | 
|  |  | 
|  | 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_2 = { | 
|  | asmparser_constF, | 
|  | asmparser_constI, | 
|  | asmparser_constB, | 
|  |  | 
|  | asmparser_dstreg_ps_2, | 
|  | asmparser_srcreg_ps_2, | 
|  |  | 
|  | asmparser_predicate_unsupported, | 
|  | asmparser_coissue_unsupported, | 
|  |  | 
|  | asmparser_dcl_output_unsupported, | 
|  | asmparser_dcl_input_ps_2, | 
|  | asmparser_dcl_sampler, | 
|  |  | 
|  | asmparser_end, | 
|  |  | 
|  | asmparser_instr, | 
|  | }; | 
|  |  | 
|  | static const struct asmparser_backend parser_ps_2_x = { | 
|  | asmparser_constF, | 
|  | asmparser_constI, | 
|  | asmparser_constB, | 
|  |  | 
|  | asmparser_dstreg_ps_2_x, | 
|  | asmparser_srcreg_ps_2_x, | 
|  |  | 
|  | asmparser_predicate_supported, | 
|  | asmparser_coissue_unsupported, | 
|  |  | 
|  | asmparser_dcl_output_unsupported, | 
|  | asmparser_dcl_input_ps_2, | 
|  | asmparser_dcl_sampler, | 
|  |  | 
|  | asmparser_end, | 
|  |  | 
|  | asmparser_instr, | 
|  | }; | 
|  |  | 
|  | static const struct asmparser_backend parser_ps_3 = { | 
|  | asmparser_constF, | 
|  | asmparser_constI, | 
|  | asmparser_constB, | 
|  |  | 
|  | asmparser_dstreg_ps_3, | 
|  | asmparser_srcreg_ps_3, | 
|  |  | 
|  | asmparser_predicate_supported, | 
|  | asmparser_coissue_unsupported, | 
|  |  | 
|  | asmparser_dcl_output_unsupported, | 
|  | asmparser_dcl_input, | 
|  | asmparser_dcl_sampler, | 
|  |  | 
|  | asmparser_end, | 
|  |  | 
|  | asmparser_instr, | 
|  | }; | 
|  |  | 
|  | static void gen_oldvs_output(struct bwriter_shader *shader) { | 
|  | record_declaration(shader, BWRITERDECLUSAGE_POSITION, 0, 0, TRUE, OPOS_REG, BWRITERSP_WRITEMASK_ALL, TRUE); | 
|  | record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 0, 0, TRUE, OT0_REG, BWRITERSP_WRITEMASK_ALL, TRUE); | 
|  | record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 1, 0, TRUE, OT1_REG, BWRITERSP_WRITEMASK_ALL, TRUE); | 
|  | record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 2, 0, TRUE, OT2_REG, BWRITERSP_WRITEMASK_ALL, TRUE); | 
|  | record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 3, 0, TRUE, OT3_REG, BWRITERSP_WRITEMASK_ALL, TRUE); | 
|  | record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 4, 0, TRUE, OT4_REG, BWRITERSP_WRITEMASK_ALL, TRUE); | 
|  | record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 5, 0, TRUE, OT5_REG, BWRITERSP_WRITEMASK_ALL, TRUE); | 
|  | record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 6, 0, TRUE, OT6_REG, BWRITERSP_WRITEMASK_ALL, TRUE); | 
|  | record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 7, 0, TRUE, OT7_REG, BWRITERSP_WRITEMASK_ALL, TRUE); | 
|  | record_declaration(shader, BWRITERDECLUSAGE_FOG, 0, 0, TRUE, OFOG_REG, OFOG_WRITEMASK, TRUE); | 
|  | record_declaration(shader, BWRITERDECLUSAGE_PSIZE, 0, 0, TRUE, OPTS_REG, OPTS_WRITEMASK, TRUE); | 
|  | record_declaration(shader, BWRITERDECLUSAGE_COLOR, 0, 0, TRUE, OD0_REG, BWRITERSP_WRITEMASK_ALL, TRUE); | 
|  | record_declaration(shader, BWRITERDECLUSAGE_COLOR, 1, 0, TRUE, OD1_REG, BWRITERSP_WRITEMASK_ALL, TRUE); | 
|  | } | 
|  |  | 
|  | static void gen_oldps_input(struct bwriter_shader *shader, DWORD texcoords) { | 
|  | switch(texcoords) { | 
|  | case 8: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 7, 0, FALSE, T7_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE); | 
|  | /* fall through */ | 
|  | case 7: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 6, 0, FALSE, T6_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE); | 
|  | /* fall through */ | 
|  | case 6: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 5, 0, FALSE, T5_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE); | 
|  | /* fall through */ | 
|  | case 5: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 4, 0, FALSE, T4_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE); | 
|  | /* fall through */ | 
|  | case 4: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 3, 0, FALSE, T3_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE); | 
|  | /* fall through */ | 
|  | case 3: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 2, 0, FALSE, T2_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE); | 
|  | /* fall through */ | 
|  | case 2: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 1, 0, FALSE, T1_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE); | 
|  | /* fall through */ | 
|  | case 1: record_declaration(shader, BWRITERDECLUSAGE_TEXCOORD, 0, 0, FALSE, T0_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE); | 
|  | }; | 
|  | record_declaration(shader, BWRITERDECLUSAGE_COLOR, 0, 0, FALSE, C0_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE); | 
|  | record_declaration(shader, BWRITERDECLUSAGE_COLOR, 1, 0, FALSE, C1_VARYING, BWRITERSP_WRITEMASK_ALL, TRUE); | 
|  | } | 
|  |  | 
|  | void create_vs10_parser(struct asm_parser *ret) { | 
|  | TRACE_(parsed_shader)("vs_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_VERTEX; | 
|  | ret->shader->version = BWRITERVS_VERSION(1, 0); | 
|  | ret->funcs = &parser_vs_1; | 
|  | gen_oldvs_output(ret->shader); | 
|  | } | 
|  |  | 
|  | void create_vs11_parser(struct asm_parser *ret) { | 
|  | TRACE_(parsed_shader)("vs_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_VERTEX; | 
|  | ret->shader->version = BWRITERVS_VERSION(1, 1); | 
|  | ret->funcs = &parser_vs_1; | 
|  | gen_oldvs_output(ret->shader); | 
|  | } | 
|  |  | 
|  | void create_vs20_parser(struct asm_parser *ret) { | 
|  | TRACE_(parsed_shader)("vs_2_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_VERTEX; | 
|  | ret->shader->version = BWRITERVS_VERSION(2, 0); | 
|  | ret->funcs = &parser_vs_2; | 
|  | gen_oldvs_output(ret->shader); | 
|  | } | 
|  |  | 
|  | void create_vs2x_parser(struct asm_parser *ret) { | 
|  | TRACE_(parsed_shader)("vs_2_x\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_VERTEX; | 
|  | ret->shader->version = BWRITERVS_VERSION(2, 1); | 
|  | ret->funcs = &parser_vs_2; | 
|  | gen_oldvs_output(ret->shader); | 
|  | } | 
|  |  | 
|  | void create_vs30_parser(struct asm_parser *ret) { | 
|  | TRACE_(parsed_shader)("vs_3_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_VERTEX; | 
|  | ret->shader->version = BWRITERVS_VERSION(3, 0); | 
|  | 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"); | 
|  |  | 
|  | 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, 4); | 
|  | ret->funcs = &parser_ps_1_4; | 
|  | gen_oldps_input(ret->shader, 6); | 
|  | } | 
|  |  | 
|  | void create_ps20_parser(struct asm_parser *ret) { | 
|  | TRACE_(parsed_shader)("ps_2_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(2, 0); | 
|  | ret->funcs = &parser_ps_2; | 
|  | gen_oldps_input(ret->shader, 8); | 
|  | } | 
|  |  | 
|  | void create_ps2x_parser(struct asm_parser *ret) { | 
|  | TRACE_(parsed_shader)("ps_2_x\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(2, 1); | 
|  | ret->funcs = &parser_ps_2_x; | 
|  | gen_oldps_input(ret->shader, 8); | 
|  | } | 
|  |  | 
|  | void create_ps30_parser(struct asm_parser *ret) { | 
|  | TRACE_(parsed_shader)("ps_3_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(3, 0); | 
|  | ret->funcs = &parser_ps_3; | 
|  | } |