2 * Direct3D asm shader parser
4 * Copyright 2008 Stefan Dösinger
5 * Copyright 2009 Matteo Bruni
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "wine/port.h"
25 #include "wine/debug.h"
27 #include "d3dx9_36_private.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(asmshader);
30 WINE_DECLARE_DEBUG_CHANNEL(parsed_shader);
33 /****************************************************************
34 * Common(non-version specific) shader parser control code *
35 ****************************************************************/
37 static void asmparser_end(struct asm_parser *This) {
38 TRACE("Finalizing shader\n");
41 static void asmparser_constF(struct asm_parser *This, DWORD reg, float x, float y, float z, float w) {
42 if(!This->shader) return;
43 TRACE("Adding float constant %u at pos %u\n", reg, This->shader->num_cf);
44 TRACE_(parsed_shader)("def c%u, %f, %f, %f, %f\n", reg, x, y, z, w);
45 if(!add_constF(This->shader, reg, x, y, z, w)) {
46 ERR("Out of memory\n");
47 set_parse_status(This, PARSE_ERR);
51 static void asmparser_constB(struct asm_parser *This, DWORD reg, BOOL x) {
52 if(!This->shader) return;
53 TRACE("Adding boolean constant %u at pos %u\n", reg, This->shader->num_cb);
54 TRACE_(parsed_shader)("def b%u, %s\n", reg, x ? "true" : "false");
55 if(!add_constB(This->shader, reg, x)) {
56 ERR("Out of memory\n");
57 set_parse_status(This, PARSE_ERR);
61 static void asmparser_constI(struct asm_parser *This, DWORD reg, INT x, INT y, INT z, INT w) {
62 if(!This->shader) return;
63 TRACE("Adding integer constant %u at pos %u\n", reg, This->shader->num_ci);
64 TRACE_(parsed_shader)("def i%u, %d, %d, %d, %d\n", reg, x, y, z, w);
65 if(!add_constI(This->shader, reg, x, y, z, w)) {
66 ERR("Out of memory\n");
67 set_parse_status(This, PARSE_ERR);
71 static void asmparser_dcl_output(struct asm_parser *This, DWORD usage, DWORD num,
72 const struct shader_reg *reg) {
73 if(!This->shader) return;
74 if(This->shader->type == ST_PIXEL) {
75 asmparser_message(This, "Line %u: Output register declared in a pixel shader\n", This->line_no);
76 set_parse_status(This, PARSE_ERR);
78 if(!record_declaration(This->shader, usage, num, TRUE, reg->regnum, reg->writemask)) {
79 ERR("Out of memory\n");
80 set_parse_status(This, PARSE_ERR);
84 static void asmparser_dcl_input(struct asm_parser *This, DWORD usage, DWORD num,
85 const struct shader_reg *reg) {
86 if(!This->shader) return;
87 if(!record_declaration(This->shader, usage, num, FALSE, reg->regnum, reg->writemask)) {
88 ERR("Out of memory\n");
89 set_parse_status(This, PARSE_ERR);
93 static void asmparser_dcl_sampler(struct asm_parser *This, DWORD samptype, DWORD regnum, unsigned int line_no) {
94 if(!This->shader) return;
95 if(!record_sampler(This->shader, samptype, regnum)) {
96 ERR("Out of memory\n");
97 set_parse_status(This, PARSE_ERR);
101 static void asmparser_instr(struct asm_parser *This, DWORD opcode,
102 DWORD mod, DWORD shift,
103 BWRITER_COMPARISON_TYPE comp,
104 const struct shader_reg *dst,
105 const struct src_regs *srcs, int expectednsrcs) {
106 struct instruction *instr;
108 BOOL firstreg = TRUE;
109 unsigned int src_count = srcs ? srcs->count : 0;
111 if(!This->shader) return;
113 TRACE_(parsed_shader)("%s%s%s ", debug_print_opcode(opcode),
114 debug_print_dstmod(mod),
115 debug_print_comp(comp));
117 TRACE_(parsed_shader)("%s", debug_print_dstreg(dst, This->shader->type));
120 for(i = 0; i < src_count; i++) {
121 if(!firstreg) TRACE_(parsed_shader)(", ");
122 else firstreg = FALSE;
123 TRACE_(parsed_shader)("%s", debug_print_srcreg(&srcs->reg[i],
124 This->shader->type));
126 TRACE_(parsed_shader)("\n");
128 if(src_count != expectednsrcs) {
129 asmparser_message(This, "Line %u: Wrong number of source registers\n", This->line_no);
130 set_parse_status(This, PARSE_ERR);
134 instr = alloc_instr(src_count);
136 ERR("Error allocating memory for the instruction\n");
137 set_parse_status(This, PARSE_ERR);
141 instr->opcode = opcode;
143 instr->shift = shift;
144 instr->comptype = comp;
145 if(dst) This->funcs->dstreg(This, instr, dst);
146 for(i = 0; i < src_count; i++) {
147 This->funcs->srcreg(This, instr, i, &srcs->reg[i]);
150 if(!add_instruction(This->shader, instr)) {
151 ERR("Out of memory\n");
152 set_parse_status(This, PARSE_ERR);
156 /* Checks for unsupported source modifiers in VS (all versions) or
158 static void check_legacy_srcmod(struct asm_parser *This, DWORD srcmod) {
159 if(srcmod == BWRITERSPSM_BIAS || srcmod == BWRITERSPSM_BIASNEG ||
160 srcmod == BWRITERSPSM_SIGN || srcmod == BWRITERSPSM_SIGNNEG ||
161 srcmod == BWRITERSPSM_COMP || srcmod == BWRITERSPSM_X2 ||
162 srcmod == BWRITERSPSM_X2NEG || srcmod == BWRITERSPSM_DZ ||
163 srcmod == BWRITERSPSM_DW) {
164 asmparser_message(This, "Line %u: Source modifier %s not supported in this shader version\n",
166 debug_print_srcmod(srcmod));
167 set_parse_status(This, PARSE_ERR);
171 static void check_loop_swizzle(struct asm_parser *This,
172 const struct shader_reg *src) {
173 if((src->type == BWRITERSPR_LOOP && src->swizzle != BWRITERVS_NOSWIZZLE) ||
174 (src->rel_reg && src->rel_reg->type == BWRITERSPR_LOOP &&
175 src->rel_reg->swizzle != BWRITERVS_NOSWIZZLE)) {
176 asmparser_message(This, "Line %u: Swizzle not allowed on aL register\n", This->line_no);
177 set_parse_status(This, PARSE_ERR);
181 static void check_shift_dstmod(struct asm_parser *This, DWORD shift) {
183 asmparser_message(This, "Line %u: Shift modifiers not supported in this shader version\n",
185 set_parse_status(This, PARSE_ERR);
189 static void check_ps_dstmod(struct asm_parser *This, DWORD dstmod) {
190 if(dstmod == BWRITERSPDM_PARTIALPRECISION ||
191 dstmod == BWRITERSPDM_MSAMPCENTROID) {
192 asmparser_message(This, "Line %u: Instruction modifier %s not supported in this shader version\n",
194 debug_print_dstmod(dstmod));
195 set_parse_status(This, PARSE_ERR);
199 struct allowed_reg_type {
204 static BOOL check_reg_type(const struct shader_reg *reg,
205 const struct allowed_reg_type *allowed) {
208 while(allowed[i].type != ~0U) {
209 if(reg->type == allowed[i].type) {
210 if(reg->rel_reg) return TRUE; /* The relative addressing register
211 can have a negative value, we
212 can't check the register index */
213 if(reg->regnum < allowed[i].count) return TRUE;
221 /* Native assembler doesn't do separate checks for src and dst registers */
222 static const struct allowed_reg_type vs_3_reg_allowed[] = {
223 { BWRITERSPR_TEMP, 32 },
224 { BWRITERSPR_INPUT, 16 },
225 { BWRITERSPR_CONST, ~0U },
226 { BWRITERSPR_ADDR, 1 },
227 { BWRITERSPR_CONSTBOOL, 16 },
228 { BWRITERSPR_CONSTINT, 16 },
229 { BWRITERSPR_LOOP, 1 },
230 { BWRITERSPR_LABEL, 2048 },
231 { BWRITERSPR_PREDICATE, 1 },
232 { BWRITERSPR_SAMPLER, 4 },
233 { BWRITERSPR_OUTPUT, 12 },
234 { ~0U, 0 } /* End tag */
237 static void asmparser_srcreg_vs_3(struct asm_parser *This,
238 struct instruction *instr, int num,
239 const struct shader_reg *src) {
240 if(!check_reg_type(src, vs_3_reg_allowed)) {
241 asmparser_message(This, "Line %u: Source register %s not supported in VS 3.0\n",
243 debug_print_srcreg(src, ST_VERTEX));
244 set_parse_status(This, PARSE_ERR);
246 check_loop_swizzle(This, src);
247 check_legacy_srcmod(This, src->srcmod);
248 memcpy(&instr->src[num], src, sizeof(*src));
251 static const struct allowed_reg_type ps_3_reg_allowed[] = {
252 { BWRITERSPR_INPUT, 10 },
253 { BWRITERSPR_TEMP, 32 },
254 { BWRITERSPR_CONST, 224 },
255 { BWRITERSPR_CONSTINT, 16 },
256 { BWRITERSPR_CONSTBOOL, 16 },
257 { BWRITERSPR_PREDICATE, 1 },
258 { BWRITERSPR_SAMPLER, 16 },
259 { BWRITERSPR_MISCTYPE, 2 }, /* vPos and vFace */
260 { BWRITERSPR_LOOP, 1 },
261 { BWRITERSPR_LABEL, 2048 },
262 { BWRITERSPR_COLOROUT, ~0U },
263 { BWRITERSPR_DEPTHOUT, 1 },
264 { ~0U, 0 } /* End tag */
267 static void asmparser_srcreg_ps_3(struct asm_parser *This,
268 struct instruction *instr, int num,
269 const struct shader_reg *src) {
270 if(!check_reg_type(src, ps_3_reg_allowed)) {
271 asmparser_message(This, "Line %u: Source register %s not supported in PS 3.0\n",
273 debug_print_srcreg(src, ST_PIXEL));
274 set_parse_status(This, PARSE_ERR);
276 check_loop_swizzle(This, src);
277 check_legacy_srcmod(This, src->srcmod);
278 memcpy(&instr->src[num], src, sizeof(*src));
281 static void asmparser_dstreg_vs_3(struct asm_parser *This,
282 struct instruction *instr,
283 const struct shader_reg *dst) {
284 if(!check_reg_type(dst, vs_3_reg_allowed)) {
285 asmparser_message(This, "Line %u: Destination register %s not supported in VS 3.0\n",
287 debug_print_dstreg(dst, ST_VERTEX));
288 set_parse_status(This, PARSE_ERR);
290 check_ps_dstmod(This, instr->dstmod);
291 check_shift_dstmod(This, instr->shift);
292 memcpy(&instr->dst, dst, sizeof(*dst));
293 instr->has_dst = TRUE;
296 static void asmparser_dstreg_ps_3(struct asm_parser *This,
297 struct instruction *instr,
298 const struct shader_reg *dst) {
299 if(!check_reg_type(dst, ps_3_reg_allowed)) {
300 asmparser_message(This, "Line %u: Destination register %s not supported in PS 3.0\n",
302 debug_print_dstreg(dst, ST_PIXEL));
303 set_parse_status(This, PARSE_ERR);
305 check_shift_dstmod(This, instr->shift);
306 memcpy(&instr->dst, dst, sizeof(*dst));
307 instr->has_dst = TRUE;
310 static void asmparser_predicate_supported(struct asm_parser *This,
311 const struct shader_reg *predicate) {
312 /* this sets the predicate of the last instruction added to the shader */
313 if(!This->shader) return;
314 if(This->shader->num_instrs == 0) ERR("Predicate without an instruction\n");
315 This->shader->instr[This->shader->num_instrs - 1]->has_predicate = TRUE;
316 memcpy(&This->shader->instr[This->shader->num_instrs - 1]->predicate, predicate, sizeof(*predicate));
320 static void asmparser_predicate_unsupported(struct asm_parser *This,
321 const struct shader_reg *predicate) {
322 asmparser_message(This, "Line %u: Predicate not supported in < VS 2.0 or PS 2.x\n", This->line_no);
323 set_parse_status(This, PARSE_ERR);
327 static void asmparser_coissue_unsupported(struct asm_parser *This) {
328 asmparser_message(This, "Line %u: Coissue is only supported in pixel shaders versions <= 1.4\n", This->line_no);
329 set_parse_status(This, PARSE_ERR);
332 static const struct asmparser_backend parser_vs_3 = {
337 asmparser_dstreg_vs_3,
338 asmparser_srcreg_vs_3,
340 asmparser_predicate_supported,
341 asmparser_coissue_unsupported,
343 asmparser_dcl_output,
345 asmparser_dcl_sampler,
352 static const struct asmparser_backend parser_ps_3 = {
357 asmparser_dstreg_ps_3,
358 asmparser_srcreg_ps_3,
360 asmparser_predicate_supported,
361 asmparser_coissue_unsupported,
363 asmparser_dcl_output,
365 asmparser_dcl_sampler,
372 void create_vs30_parser(struct asm_parser *ret) {
373 TRACE_(parsed_shader)("vs_3_0\n");
375 ret->shader = asm_alloc(sizeof(*ret->shader));
377 ERR("Failed to allocate memory for the shader\n");
378 set_parse_status(ret, PARSE_ERR);
382 ret->shader->type = ST_VERTEX;
383 ret->shader->version = BWRITERVS_VERSION(3, 0);
384 ret->funcs = &parser_vs_3;
387 void create_ps30_parser(struct asm_parser *ret) {
388 TRACE_(parsed_shader)("ps_3_0\n");
390 ret->shader = asm_alloc(sizeof(*ret->shader));
392 ERR("Failed to allocate memory for the shader\n");
393 set_parse_status(ret, PARSE_ERR);
397 ret->shader->type = ST_PIXEL;
398 ret->shader->version = BWRITERPS_VERSION(3, 0);
399 ret->funcs = &parser_ps_3;