2 * Direct3D shader assembler
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"
31 WINE_DEFAULT_DEBUG_CHANNEL(asmshader);
33 struct asm_parser asm_ctx;
35 /* Needed lexer functions declarations */
36 void asmshader_error(const char *s);
37 int asmshader_lex(void);
39 void set_rel_reg(struct shader_reg *reg, struct rel_reg *rel) {
40 /* We can have an additional offset without true relative addressing
42 reg->regnum += rel->additional_offset;
43 if(!rel->has_rel_reg) {
46 reg->rel_reg = asm_alloc(sizeof(*reg->rel_reg));
50 reg->rel_reg->type = rel->type;
51 reg->rel_reg->swizzle = rel->swizzle;
52 reg->rel_reg->regnum = rel->rel_regnum;
65 struct shader_reg reg;
83 BWRITER_COMPARISON_TYPE comptype;
88 BWRITERSAMPLER_TEXTURE_TYPE samplertype;
89 struct rel_reg rel_reg;
90 struct src_regs sregs;
93 /* Common instructions between vertex and pixel shaders */
146 /* Vertex shader only instructions */
150 /* Pixel shader only instructions */
162 %token <regnum> REG_TEMP
163 %token <regnum> REG_OUTPUT
164 %token <regnum> REG_INPUT
165 %token <regnum> REG_CONSTFLOAT
166 %token <regnum> REG_CONSTINT
167 %token <regnum> REG_CONSTBOOL
168 %token <regnum> REG_TEXTURE
169 %token <regnum> REG_SAMPLER
170 %token <regnum> REG_TEXCRDOUT
174 %token <regnum> REG_VERTEXCOLOR
175 %token <regnum> REG_FRAGCOLOR
182 %token <regnum> REG_LABEL
200 /* Output modifiers */
213 /* Source register modifiers */
221 %token SAMPTYPE_VOLUME
223 /* Usage declaration tokens */
224 %token <regnum> USAGE_POSITION
225 %token <regnum> USAGE_BLENDWEIGHT
226 %token <regnum> USAGE_BLENDINDICES
227 %token <regnum> USAGE_NORMAL
228 %token <regnum> USAGE_PSIZE
229 %token <regnum> USAGE_TEXCOORD
230 %token <regnum> USAGE_TANGENT
231 %token <regnum> USAGE_BINORMAL
232 %token <regnum> USAGE_TESSFACTOR
233 %token <regnum> USAGE_POSITIONT
234 %token <regnum> USAGE_COLOR
235 %token <regnum> USAGE_FOG
236 %token <regnum> USAGE_DEPTH
237 %token <regnum> USAGE_SAMPLE
240 %token <component> COMPONENT
241 %token <immval> IMMVAL
242 %token <immbool> IMMBOOL
244 %type <reg> dreg_name
246 %type <reg> sreg_name
247 %type <reg> relreg_name
250 %type <writemask> writemask
251 %type <wm_components> wm_components
252 %type <swizzle> swizzle
253 %type <sw_components> sw_components
254 %type <modshift> omods
255 %type <modshift> omodifier
256 %type <comptype> comp
257 %type <declaration> dclusage
258 %type <reg> dcl_inputreg
259 %type <samplertype> sampdcl
260 %type <rel_reg> rel_reg
261 %type <reg> predicate
262 %type <immval> immsum
267 shader: version_marker instructions
269 asm_ctx.funcs->end(&asm_ctx);
272 version_marker: VER_VS10
274 TRACE("Vertex shader 1.0\n");
275 create_vs10_parser(&asm_ctx);
279 TRACE("Vertex shader 1.1\n");
280 create_vs11_parser(&asm_ctx);
284 TRACE("Vertex shader 2.0\n");
285 create_vs20_parser(&asm_ctx);
289 TRACE("Vertex shader 2.x\n");
290 create_vs2x_parser(&asm_ctx);
294 TRACE("Vertex shader 3.0\n");
295 create_vs30_parser(&asm_ctx);
299 TRACE("Pixel shader 1.0\n");
300 set_parse_status(&asm_ctx, PARSE_ERR);
305 TRACE("Pixel shader 1.1\n");
306 set_parse_status(&asm_ctx, PARSE_ERR);
311 TRACE("Pixel shader 1.2\n");
312 set_parse_status(&asm_ctx, PARSE_ERR);
317 TRACE("Pixel shader 1.3\n");
318 set_parse_status(&asm_ctx, PARSE_ERR);
323 TRACE("Pixel shader 1.4\n");
324 set_parse_status(&asm_ctx, PARSE_ERR);
329 TRACE("Pixel shader 2.0\n");
330 create_ps20_parser(&asm_ctx);
334 TRACE("Pixel shader 2.x\n");
335 create_ps2x_parser(&asm_ctx);
339 TRACE("Pixel shader 3.0\n");
340 create_ps30_parser(&asm_ctx);
343 instructions: /* empty */
344 | instructions complexinstr
349 complexinstr: instruction
353 | predicate instruction
355 TRACE("predicate\n");
356 asm_ctx.funcs->predicate(&asm_ctx, &$1);
359 instruction: INSTR_ADD omods dreg ',' sregs
362 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ADD, $2.mod, $2.shift, 0, &$3, &$5, 2);
367 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_NOP, 0, 0, 0, 0, 0, 0);
369 | INSTR_MOV omods dreg ',' sregs
372 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MOV, $2.mod, $2.shift, 0, &$3, &$5, 1);
374 | INSTR_SUB omods dreg ',' sregs
377 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SUB, $2.mod, $2.shift, 0, &$3, &$5, 2);
379 | INSTR_MAD omods dreg ',' sregs
382 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MAD, $2.mod, $2.shift, 0, &$3, &$5, 3);
384 | INSTR_MUL omods dreg ',' sregs
387 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MUL, $2.mod, $2.shift, 0, &$3, &$5, 2);
389 | INSTR_RCP omods dreg ',' sregs
392 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_RCP, $2.mod, $2.shift, 0, &$3, &$5, 1);
394 | INSTR_RSQ omods dreg ',' sregs
397 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_RSQ, $2.mod, $2.shift, 0, &$3, &$5, 1);
399 | INSTR_DP3 omods dreg ',' sregs
402 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DP3, $2.mod, $2.shift, 0, &$3, &$5, 2);
404 | INSTR_DP4 omods dreg ',' sregs
407 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DP4, $2.mod, $2.shift, 0, &$3, &$5, 2);
409 | INSTR_MIN omods dreg ',' sregs
412 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MIN, $2.mod, $2.shift, 0, &$3, &$5, 2);
414 | INSTR_MAX omods dreg ',' sregs
417 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MAX, $2.mod, $2.shift, 0, &$3, &$5, 2);
419 | INSTR_SLT omods dreg ',' sregs
422 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SLT, $2.mod, $2.shift, 0, &$3, &$5, 2);
424 | INSTR_SGE omods dreg ',' sregs
427 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SGE, $2.mod, $2.shift, 0, &$3, &$5, 2);
429 | INSTR_ABS omods dreg ',' sregs
432 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ABS, $2.mod, $2.shift, 0, &$3, &$5, 1);
434 | INSTR_EXP omods dreg ',' sregs
437 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_EXP, $2.mod, $2.shift, 0, &$3, &$5, 1);
439 | INSTR_LOG omods dreg ',' sregs
442 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LOG, $2.mod, $2.shift, 0, &$3, &$5, 1);
444 | INSTR_LOGP omods dreg ',' sregs
447 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LOGP, $2.mod, $2.shift, 0, &$3, &$5, 1);
449 | INSTR_EXPP omods dreg ',' sregs
452 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_EXPP, $2.mod, $2.shift, 0, &$3, &$5, 1);
454 | INSTR_DST omods dreg ',' sregs
457 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DST, $2.mod, $2.shift, 0, &$3, &$5, 2);
459 | INSTR_LRP omods dreg ',' sregs
462 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LRP, $2.mod, $2.shift, 0, &$3, &$5, 3);
464 | INSTR_FRC omods dreg ',' sregs
467 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_FRC, $2.mod, $2.shift, 0, &$3, &$5, 1);
469 | INSTR_POW omods dreg ',' sregs
472 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_POW, $2.mod, $2.shift, 0, &$3, &$5, 2);
474 | INSTR_CRS omods dreg ',' sregs
477 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CRS, $2.mod, $2.shift, 0, &$3, &$5, 2);
479 | INSTR_SGN omods dreg ',' sregs
482 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SGN, $2.mod, $2.shift, 0, &$3, &$5, 3);
484 | INSTR_NRM omods dreg ',' sregs
487 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_NRM, $2.mod, $2.shift, 0, &$3, &$5, 1);
489 | INSTR_SINCOS omods dreg ',' sregs
492 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SINCOS, $2.mod, $2.shift, 0, &$3, &$5, 1);
494 | INSTR_M4x4 omods dreg ',' sregs
497 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M4x4, $2.mod, $2.shift, 0, &$3, &$5, 2);
499 | INSTR_M4x3 omods dreg ',' sregs
502 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M4x3, $2.mod, $2.shift, 0, &$3, &$5, 2);
504 | INSTR_M3x4 omods dreg ',' sregs
507 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M3x4, $2.mod, $2.shift, 0, &$3, &$5, 2);
509 | INSTR_M3x3 omods dreg ',' sregs
512 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M3x3, $2.mod, $2.shift, 0, &$3, &$5, 2);
514 | INSTR_M3x2 omods dreg ',' sregs
517 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M3x2, $2.mod, $2.shift, 0, &$3, &$5, 2);
519 | INSTR_DCL dclusage REG_OUTPUT
521 struct shader_reg reg;
522 TRACE("Output reg declaration\n");
523 ZeroMemory(®, sizeof(reg));
524 reg.type = BWRITERSPR_OUTPUT;
528 reg.writemask = BWRITERSP_WRITEMASK_ALL;
529 asm_ctx.funcs->dcl_output(&asm_ctx, $2.dclusage, $2.regnum, ®);
531 | INSTR_DCL dclusage REG_OUTPUT writemask
533 struct shader_reg reg;
534 TRACE("Output reg declaration\n");
535 ZeroMemory(®, sizeof(reg));
536 reg.type = BWRITERSPR_OUTPUT;
541 asm_ctx.funcs->dcl_output(&asm_ctx, $2.dclusage, $2.regnum, ®);
543 | INSTR_DCL dclusage omods dcl_inputreg
545 struct shader_reg reg;
546 TRACE("Input reg declaration\n");
548 asmparser_message(&asm_ctx, "Line %u: Shift modifier not allowed here\n",
550 set_parse_status(&asm_ctx, PARSE_ERR);
552 ZeroMemory(®, sizeof(reg));
554 reg.regnum = $4.regnum;
557 reg.writemask = BWRITERSP_WRITEMASK_ALL;
558 asm_ctx.funcs->dcl_input(&asm_ctx, $2.dclusage, $2.regnum, $3.mod, ®);
560 | INSTR_DCL dclusage omods dcl_inputreg writemask
562 struct shader_reg reg;
563 TRACE("Input reg declaration\n");
565 asmparser_message(&asm_ctx, "Line %u: Shift modifier not allowed here\n",
567 set_parse_status(&asm_ctx, PARSE_ERR);
569 ZeroMemory(®, sizeof(reg));
571 reg.regnum = $4.regnum;
575 asm_ctx.funcs->dcl_input(&asm_ctx, $2.dclusage, $2.regnum, $3.mod, ®);
577 | INSTR_DCL omods dcl_inputreg
579 struct shader_reg reg;
580 TRACE("Input reg declaration\n");
582 asmparser_message(&asm_ctx, "Line %u: Shift modifier not allowed here\n",
584 set_parse_status(&asm_ctx, PARSE_ERR);
586 ZeroMemory(®, sizeof(reg));
588 reg.regnum = $3.regnum;
591 reg.writemask = BWRITERSP_WRITEMASK_ALL;
592 asm_ctx.funcs->dcl_input(&asm_ctx, 0, 0, $2.mod, ®);
594 | INSTR_DCL omods dcl_inputreg writemask
596 struct shader_reg reg;
597 TRACE("Input reg declaration\n");
599 asmparser_message(&asm_ctx, "Line %u: Shift modifier not allowed here\n",
601 set_parse_status(&asm_ctx, PARSE_ERR);
603 ZeroMemory(®, sizeof(reg));
605 reg.regnum = $3.regnum;
609 asm_ctx.funcs->dcl_input(&asm_ctx, 0, 0, $2.mod, ®);
611 | INSTR_DCL sampdcl omods REG_SAMPLER
613 TRACE("Sampler declared\n");
615 asmparser_message(&asm_ctx, "Line %u: Shift modifier not allowed here\n",
617 set_parse_status(&asm_ctx, PARSE_ERR);
619 asm_ctx.funcs->dcl_sampler(&asm_ctx, $2, $3.mod, $4, asm_ctx.line_no);
621 | INSTR_DCL omods REG_SAMPLER
623 TRACE("Sampler declared\n");
625 asmparser_message(&asm_ctx, "Line %u: Shift modifier not allowed here\n",
627 set_parse_status(&asm_ctx, PARSE_ERR);
629 if(asm_ctx.shader->type != ST_PIXEL) {
630 asmparser_message(&asm_ctx, "Line %u: Declaration needs a sampler type\n",
632 set_parse_status(&asm_ctx, PARSE_ERR);
634 asm_ctx.funcs->dcl_sampler(&asm_ctx, BWRITERSTT_UNKNOWN, $2.mod, $3, asm_ctx.line_no);
636 | INSTR_DCL sampdcl omods dcl_inputreg
638 TRACE("Error rule: sampler decl of input reg\n");
639 asmparser_message(&asm_ctx, "Line %u: Sampler declarations of input regs is not valid\n",
641 set_parse_status(&asm_ctx, PARSE_WARN);
643 | INSTR_DCL sampdcl omods REG_OUTPUT
645 TRACE("Error rule: sampler decl of output reg\n");
646 asmparser_message(&asm_ctx, "Line %u: Sampler declarations of output regs is not valid\n",
648 set_parse_status(&asm_ctx, PARSE_WARN);
650 | INSTR_DEF REG_CONSTFLOAT ',' IMMVAL ',' IMMVAL ',' IMMVAL ',' IMMVAL
652 asm_ctx.funcs->constF(&asm_ctx, $2, $4.val, $6.val, $8.val, $10.val);
654 | INSTR_DEFI REG_CONSTINT ',' IMMVAL ',' IMMVAL ',' IMMVAL ',' IMMVAL
656 asm_ctx.funcs->constI(&asm_ctx, $2, $4.val, $6.val, $8.val, $10.val);
658 | INSTR_DEFB REG_CONSTBOOL ',' IMMBOOL
660 asm_ctx.funcs->constB(&asm_ctx, $2, $4);
665 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_REP, 0, 0, 0, 0, &$2, 1);
670 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ENDREP, 0, 0, 0, 0, 0, 0);
675 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_IF, 0, 0, 0, 0, &$2, 1);
677 | INSTR_IF comp sregs
680 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_IFC, 0, 0, $2, 0, &$3, 2);
685 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ELSE, 0, 0, 0, 0, 0, 0);
690 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ENDIF, 0, 0, 0, 0, 0, 0);
695 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_BREAK, 0, 0, 0, 0, 0, 0);
697 | INSTR_BREAK comp sregs
700 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_BREAKC, 0, 0, $2, 0, &$3, 2);
705 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_BREAKP, 0, 0, 0, 0, &$2, 1);
710 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CALL, 0, 0, 0, 0, &$2, 1);
715 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CALLNZ, 0, 0, 0, 0, &$2, 2);
720 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LOOP, 0, 0, 0, 0, &$2, 2);
725 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_RET, 0, 0, 0, 0, 0, 0);
730 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ENDLOOP, 0, 0, 0, 0, 0, 0);
735 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LABEL, 0, 0, 0, 0, &$2, 1);
737 | INSTR_SETP comp dreg ',' sregs
740 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SETP, 0, 0, $2, &$3, &$5, 2);
742 | INSTR_TEXLDL omods dreg ',' sregs
745 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXLDL, $2.mod, $2.shift, 0, &$3, &$5, 2);
747 | INSTR_LIT omods dreg ',' sregs
750 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LIT, $2.mod, $2.shift, 0, &$3, &$5, 1);
752 | INSTR_MOVA omods dreg ',' sregs
755 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MOVA, $2.mod, $2.shift, 0, &$3, &$5, 1);
757 | INSTR_CMP omods dreg ',' sregs
760 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CMP, $2.mod, $2.shift, 0, &$3, &$5, 3);
762 | INSTR_DP2ADD omods dreg ',' sregs
765 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DP2ADD, $2.mod, $2.shift, 0, &$3, &$5, 3);
770 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXKILL, 0, 0, 0, &$2, 0, 0);
772 | INSTR_TEXLD omods dreg ',' sregs
775 /* There is more than one acceptable syntax for texld:
776 with 1 sreg (PS 1.4) or
777 with 2 sregs (PS 2.0+)
778 Moreover, texld shares the same opcode as the tex instruction,
779 so there are a total of 3 valid syntaxes
780 These variations are handled in asmparser.c */
781 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEX, $2.mod, $2.shift, 0, &$3, &$5, 2);
783 | INSTR_TEXLDP omods dreg ',' sregs
786 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXLDP, $2.mod, $2.shift, 0, &$3, &$5, 2);
788 | INSTR_TEXLDB omods dreg ',' sregs
791 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXLDB, $2.mod, $2.shift, 0, &$3, &$5, 2);
793 | INSTR_DSX omods dreg ',' sregs
796 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DSX, $2.mod, $2.shift, 0, &$3, &$5, 1);
798 | INSTR_DSY omods dreg ',' sregs
801 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DSY, $2.mod, $2.shift, 0, &$3, &$5, 1);
803 | INSTR_TEXLDD omods dreg ',' sregs
806 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXLDD, $2.mod, $2.shift, 0, &$3, &$5, 4);
809 dreg: dreg_name rel_reg
811 $$.regnum = $1.regnum;
813 $$.writemask = BWRITERSP_WRITEMASK_ALL;
814 $$.srcmod = BWRITERSPSM_NONE;
815 set_rel_reg(&$$, &$2);
817 | dreg_name writemask
819 $$.regnum = $1.regnum;
822 $$.srcmod = BWRITERSPSM_NONE;
828 $$.regnum = $1; $$.type = BWRITERSPR_TEMP;
832 $$.regnum = $1; $$.type = BWRITERSPR_OUTPUT;
836 $$.regnum = $1; $$.type = BWRITERSPR_INPUT;
840 asmparser_message(&asm_ctx, "Line %u: Register c%u is not a valid destination register\n",
841 asm_ctx.line_no, $1);
842 set_parse_status(&asm_ctx, PARSE_WARN);
846 asmparser_message(&asm_ctx, "Line %u: Register i%u is not a valid destination register\n",
847 asm_ctx.line_no, $1);
848 set_parse_status(&asm_ctx, PARSE_WARN);
852 asmparser_message(&asm_ctx, "Line %u: Register b%u is not a valid destination register\n",
853 asm_ctx.line_no, $1);
854 set_parse_status(&asm_ctx, PARSE_WARN);
858 $$.regnum = $1; $$.type = BWRITERSPR_TEXTURE;
862 $$.regnum = $1; $$.type = BWRITERSPR_TEXCRDOUT;
866 asmparser_message(&asm_ctx, "Line %u: Register s%u is not a valid destination register\n",
867 asm_ctx.line_no, $1);
868 set_parse_status(&asm_ctx, PARSE_WARN);
872 $$.regnum = BWRITERSRO_POSITION; $$.type = BWRITERSPR_RASTOUT;
876 $$.regnum = BWRITERSRO_POINT_SIZE; $$.type = BWRITERSPR_RASTOUT;
880 $$.regnum = BWRITERSRO_FOG; $$.type = BWRITERSPR_RASTOUT;
884 $$.regnum = $1; $$.type = BWRITERSPR_ATTROUT;
888 $$.regnum = $1; $$.type = BWRITERSPR_COLOROUT;
892 $$.regnum = 0; $$.type = BWRITERSPR_DEPTHOUT;
896 $$.regnum = 0; $$.type = BWRITERSPR_PREDICATE;
900 asmparser_message(&asm_ctx, "Line %u: Register vPos is not a valid destination register\n",
902 set_parse_status(&asm_ctx, PARSE_WARN);
906 asmparser_message(&asm_ctx, "Line %u: Register vFace is not a valid destination register\n",
908 set_parse_status(&asm_ctx, PARSE_WARN);
912 /* index 0 is hardcoded for the addr register */
913 $$.regnum = 0; $$.type = BWRITERSPR_ADDR;
917 asmparser_message(&asm_ctx, "Line %u: Register aL is not a valid destination register\n",
919 set_parse_status(&asm_ctx, PARSE_WARN);
922 writemask: '.' wm_components
924 if($2.writemask == SWIZZLE_ERR) {
925 asmparser_message(&asm_ctx, "Line %u: Invalid writemask specified\n",
927 set_parse_status(&asm_ctx, PARSE_ERR);
928 /* Provide a correct writemask to prevent following complaints */
929 $$ = BWRITERSP_WRITEMASK_ALL;
933 TRACE("Writemask: %x\n", $$);
937 wm_components: COMPONENT
939 $$.writemask = 1 << $1;
943 | wm_components COMPONENT
945 if($1.writemask == SWIZZLE_ERR || $1.idx == 4)
946 /* Wrong writemask */
947 $$.writemask = SWIZZLE_ERR;
950 $$.writemask = SWIZZLE_ERR;
952 $$.writemask = $1.writemask | (1 << $2);
960 $$ = BWRITERVS_NOSWIZZLE;
961 TRACE("Default swizzle: %08x\n", $$);
965 if($2.swizzle == SWIZZLE_ERR) {
966 asmparser_message(&asm_ctx, "Line %u: Invalid swizzle\n",
968 set_parse_status(&asm_ctx, PARSE_ERR);
969 /* Provide a correct swizzle to prevent following complaints */
970 $$ = BWRITERVS_NOSWIZZLE;
975 $$ = $2.swizzle << BWRITERVS_SWIZZLE_SHIFT;
976 /* Fill the swizzle by extending the last component */
977 last = ($2.swizzle >> 2 * ($2.idx - 1)) & 0x03;
978 for(i = $2.idx; i < 4; i++){
979 $$ |= last << (BWRITERVS_SWIZZLE_SHIFT + 2 * i);
981 TRACE("Got a swizzle: %08x\n", $$);
985 sw_components: COMPONENT
990 | sw_components COMPONENT
993 /* Too many sw_components */
994 $$.swizzle = SWIZZLE_ERR;
998 $$.swizzle = $1.swizzle | ($2 << 2 * $1.idx);
1010 $$.mod = $1.mod | $2.mod;
1011 if($1.shift && $2.shift) {
1012 asmparser_message(&asm_ctx, "Line %u: More than one shift flag\n",
1014 set_parse_status(&asm_ctx, PARSE_ERR);
1015 $$.shift = $1.shift;
1017 $$.shift = $1.shift | $2.shift;
1023 $$.mod = BWRITERSPDM_SATURATE;
1028 $$.mod = BWRITERSPDM_PARTIALPRECISION;
1033 $$.mod = BWRITERSPDM_MSAMPCENTROID;
1044 if($$.count == MAX_SRC_REGS){
1045 asmparser_message(&asm_ctx, "Line %u: Too many source registers in this instruction\n",
1047 set_parse_status(&asm_ctx, PARSE_ERR);
1050 $$.reg[$$.count++] = $3;
1053 sreg: sreg_name rel_reg swizzle
1056 $$.regnum = $1.regnum;
1058 $$.srcmod = BWRITERSPSM_NONE;
1059 set_rel_reg(&$$, &$2);
1061 | sreg_name rel_reg smod swizzle
1064 $$.regnum = $1.regnum;
1065 set_rel_reg(&$$, &$2);
1069 | '-' sreg_name rel_reg swizzle
1072 $$.regnum = $2.regnum;
1073 $$.srcmod = BWRITERSPSM_NEG;
1074 set_rel_reg(&$$, &$3);
1077 | '-' sreg_name rel_reg smod swizzle
1080 $$.regnum = $2.regnum;
1081 set_rel_reg(&$$, &$3);
1083 case BWRITERSPSM_ABS: $$.srcmod = BWRITERSPSM_ABSNEG; break;
1085 FIXME("Unhandled combination of NEGATE and %u\n", $4);
1089 | SMOD_NOT sreg_name swizzle
1092 $$.regnum = $2.regnum;
1094 $$.srcmod = BWRITERSPSM_NOT;
1098 rel_reg: /* empty */
1100 $$.has_rel_reg = FALSE;
1101 $$.additional_offset = 0;
1105 $$.has_rel_reg = FALSE;
1106 $$.additional_offset = $2.val;
1108 | '[' relreg_name swizzle ']'
1110 $$.has_rel_reg = TRUE;
1112 $$.additional_offset = 0;
1113 $$.rel_regnum = $2.regnum;
1116 | '[' immsum '+' relreg_name swizzle ']'
1118 $$.has_rel_reg = TRUE;
1120 $$.additional_offset = $2.val;
1121 $$.rel_regnum = $4.regnum;
1124 | '[' relreg_name swizzle '+' immsum ']'
1126 $$.has_rel_reg = TRUE;
1128 $$.additional_offset = $5.val;
1129 $$.rel_regnum = $2.regnum;
1132 | '[' immsum '+' relreg_name swizzle '+' immsum ']'
1134 $$.has_rel_reg = TRUE;
1136 $$.additional_offset = $2.val + $7.val;
1137 $$.rel_regnum = $4.regnum;
1144 asmparser_message(&asm_ctx, "Line %u: Unexpected float %f\n",
1145 asm_ctx.line_no, $1.val);
1146 set_parse_status(&asm_ctx, PARSE_ERR);
1153 asmparser_message(&asm_ctx, "Line %u: Unexpected float %f\n",
1154 asm_ctx.line_no, $3.val);
1155 set_parse_status(&asm_ctx, PARSE_ERR);
1157 $$.val = $1.val + $3.val;
1162 $$ = BWRITERSPSM_ABS;
1165 relreg_name: REG_ADDRESS
1167 $$.regnum = 0; $$.type = BWRITERSPR_ADDR;
1171 $$.regnum = 0; $$.type = BWRITERSPR_LOOP;
1176 $$.regnum = $1; $$.type = BWRITERSPR_TEMP;
1180 asmparser_message(&asm_ctx, "Line %u: Register o%u is not a valid source register\n",
1181 asm_ctx.line_no, $1);
1182 set_parse_status(&asm_ctx, PARSE_WARN);
1186 $$.regnum = $1; $$.type = BWRITERSPR_INPUT;
1190 $$.regnum = $1; $$.type = BWRITERSPR_CONST;
1194 $$.regnum = $1; $$.type = BWRITERSPR_CONSTINT;
1198 $$.regnum = $1; $$.type = BWRITERSPR_CONSTBOOL;
1202 $$.regnum = $1; $$.type = BWRITERSPR_TEXTURE;
1206 asmparser_message(&asm_ctx, "Line %u: Register oT%u is not a valid source register\n",
1207 asm_ctx.line_no, $1);
1208 set_parse_status(&asm_ctx, PARSE_WARN);
1212 $$.regnum = $1; $$.type = BWRITERSPR_SAMPLER;
1216 asmparser_message(&asm_ctx, "Line %u: Register oPos is not a valid source register\n",
1218 set_parse_status(&asm_ctx, PARSE_WARN);
1222 asmparser_message(&asm_ctx, "Line %u: Register oFog is not a valid source register\n",
1224 set_parse_status(&asm_ctx, PARSE_WARN);
1228 asmparser_message(&asm_ctx, "Line %u: Register oD%u is not a valid source register\n",
1229 asm_ctx.line_no, $1);
1230 set_parse_status(&asm_ctx, PARSE_WARN);
1234 asmparser_message(&asm_ctx, "Line %u: Register oC%u is not a valid source register\n",
1235 asm_ctx.line_no, $1);
1236 set_parse_status(&asm_ctx, PARSE_WARN);
1240 asmparser_message(&asm_ctx, "Line %u: Register oDepth is not a valid source register\n",
1242 set_parse_status(&asm_ctx, PARSE_WARN);
1246 $$.regnum = 0; $$.type = BWRITERSPR_PREDICATE;
1250 $$.regnum = 0; $$.type = BWRITERSPR_MISCTYPE;
1254 $$.regnum = 1; $$.type = BWRITERSPR_MISCTYPE;
1258 $$.regnum = 0; $$.type = BWRITERSPR_ADDR;
1262 $$.regnum = 0; $$.type = BWRITERSPR_LOOP;
1266 $$.regnum = $1; $$.type = BWRITERSPR_LABEL;
1269 comp: COMP_GT { $$ = BWRITER_COMPARISON_GT; }
1270 | COMP_LT { $$ = BWRITER_COMPARISON_LT; }
1271 | COMP_GE { $$ = BWRITER_COMPARISON_GE; }
1272 | COMP_LE { $$ = BWRITER_COMPARISON_LE; }
1273 | COMP_EQ { $$ = BWRITER_COMPARISON_EQ; }
1274 | COMP_NE { $$ = BWRITER_COMPARISON_NE; }
1276 dclusage: USAGE_POSITION
1278 TRACE("dcl_position%u\n", $1);
1280 $$.dclusage = BWRITERDECLUSAGE_POSITION;
1284 TRACE("dcl_blendweight%u\n", $1);
1286 $$.dclusage = BWRITERDECLUSAGE_BLENDWEIGHT;
1288 | USAGE_BLENDINDICES
1290 TRACE("dcl_blendindices%u\n", $1);
1292 $$.dclusage = BWRITERDECLUSAGE_BLENDINDICES;
1296 TRACE("dcl_normal%u\n", $1);
1298 $$.dclusage = BWRITERDECLUSAGE_NORMAL;
1302 TRACE("dcl_psize%u\n", $1);
1304 $$.dclusage = BWRITERDECLUSAGE_PSIZE;
1308 TRACE("dcl_texcoord%u\n", $1);
1310 $$.dclusage = BWRITERDECLUSAGE_TEXCOORD;
1314 TRACE("dcl_tangent%u\n", $1);
1316 $$.dclusage = BWRITERDECLUSAGE_TANGENT;
1320 TRACE("dcl_binormal%u\n", $1);
1322 $$.dclusage = BWRITERDECLUSAGE_BINORMAL;
1326 TRACE("dcl_tessfactor%u\n", $1);
1328 $$.dclusage = BWRITERDECLUSAGE_TESSFACTOR;
1332 TRACE("dcl_positiont%u\n", $1);
1334 $$.dclusage = BWRITERDECLUSAGE_POSITIONT;
1338 TRACE("dcl_color%u\n", $1);
1340 $$.dclusage = BWRITERDECLUSAGE_COLOR;
1344 TRACE("dcl_fog%u\n", $1);
1346 $$.dclusage = BWRITERDECLUSAGE_FOG;
1350 TRACE("dcl_depth%u\n", $1);
1352 $$.dclusage = BWRITERDECLUSAGE_DEPTH;
1356 TRACE("dcl_sample%u\n", $1);
1358 $$.dclusage = BWRITERDECLUSAGE_SAMPLE;
1361 dcl_inputreg: REG_INPUT
1363 $$.regnum = $1; $$.type = BWRITERSPR_INPUT;
1367 $$.regnum = $1; $$.type = BWRITERSPR_TEXTURE;
1370 sampdcl: SAMPTYPE_1D
1380 $$ = BWRITERSTT_CUBE;
1384 $$ = BWRITERSTT_VOLUME;
1387 predicate: '(' REG_PREDICATE swizzle ')'
1389 $$.type = BWRITERSPR_PREDICATE;
1392 $$.srcmod = BWRITERSPSM_NONE;
1395 | '(' SMOD_NOT REG_PREDICATE swizzle ')'
1397 $$.type = BWRITERSPR_PREDICATE;
1400 $$.srcmod = BWRITERSPSM_NOT;
1406 void asmshader_error (char const *s) {
1407 asmparser_message(&asm_ctx, "Line %u: Error \"%s\" from bison\n", asm_ctx.line_no, s);
1408 set_parse_status(&asm_ctx, PARSE_ERR);
1411 /* Error reporting function */
1412 void asmparser_message(struct asm_parser *ctx, const char *fmt, ...) {
1417 if(ctx->messagecapacity == 0) {
1418 ctx->messages = asm_alloc(MESSAGEBUFFER_INITIAL_SIZE);
1419 if(ctx->messages == NULL) {
1420 ERR("Error allocating memory for parser messages\n");
1423 ctx->messagecapacity = MESSAGEBUFFER_INITIAL_SIZE;
1427 va_start(args, fmt);
1428 rc = vsnprintf(ctx->messages + ctx->messagesize,
1429 ctx->messagecapacity - ctx->messagesize, fmt, args);
1432 if (rc < 0 || /* C89 */
1433 rc >= ctx->messagecapacity - ctx->messagesize) { /* C99 */
1434 /* Resize the buffer */
1435 newsize = ctx->messagecapacity * 2;
1436 newbuffer = asm_realloc(ctx->messages, newsize);
1437 if(newbuffer == NULL){
1438 ERR("Error reallocating memory for parser messages\n");
1441 ctx->messages = newbuffer;
1442 ctx->messagecapacity = newsize;
1444 ctx->messagesize += rc;
1450 /* New status is the worst between current status and parameter value */
1451 void set_parse_status(struct asm_parser *ctx, enum parse_status status) {
1452 if(status == PARSE_ERR) ctx->status = PARSE_ERR;
1453 else if(status == PARSE_WARN && ctx->status == PARSE_SUCCESS) ctx->status = PARSE_WARN;
1456 struct bwriter_shader *parse_asm_shader(char **messages) {
1457 struct bwriter_shader *ret = NULL;
1459 asm_ctx.shader = NULL;
1460 asm_ctx.status = PARSE_SUCCESS;
1461 asm_ctx.messagesize = asm_ctx.messagecapacity = 0;
1462 asm_ctx.line_no = 1;
1466 if(asm_ctx.status != PARSE_ERR) ret = asm_ctx.shader;
1467 else if(asm_ctx.shader) SlDeleteShader(asm_ctx.shader);
1470 if(asm_ctx.messagesize) {
1471 /* Shrink the buffer to the used size */
1472 *messages = asm_realloc(asm_ctx.messages, asm_ctx.messagesize + 1);
1474 ERR("Out of memory, no messages reported\n");
1475 asm_free(asm_ctx.messages);
1481 if(asm_ctx.messagecapacity) asm_free(asm_ctx.messages);