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 <samplertype> sampdcl
259 %type <rel_reg> rel_reg
260 %type <reg> predicate
261 %type <immval> immsum
266 shader: version_marker instructions
268 asm_ctx.funcs->end(&asm_ctx);
271 version_marker: VER_VS10
273 TRACE("Vertex shader 1.0\n");
274 set_parse_status(&asm_ctx, PARSE_ERR);
279 TRACE("Vertex shader 1.1\n");
280 set_parse_status(&asm_ctx, PARSE_ERR);
285 TRACE("Vertex shader 2.0\n");
286 set_parse_status(&asm_ctx, PARSE_ERR);
291 TRACE("Vertex shader 2.x\n");
292 set_parse_status(&asm_ctx, PARSE_ERR);
297 TRACE("Vertex shader 3.0\n");
298 create_vs30_parser(&asm_ctx);
302 TRACE("Pixel shader 1.0\n");
303 set_parse_status(&asm_ctx, PARSE_ERR);
308 TRACE("Pixel shader 1.1\n");
309 set_parse_status(&asm_ctx, PARSE_ERR);
314 TRACE("Pixel shader 1.2\n");
315 set_parse_status(&asm_ctx, PARSE_ERR);
320 TRACE("Pixel shader 1.3\n");
321 set_parse_status(&asm_ctx, PARSE_ERR);
326 TRACE("Pixel shader 1.4\n");
327 set_parse_status(&asm_ctx, PARSE_ERR);
332 TRACE("Pixel shader 2.0\n");
333 set_parse_status(&asm_ctx, PARSE_ERR);
338 TRACE("Pixel shader 2.x\n");
339 set_parse_status(&asm_ctx, PARSE_ERR);
344 TRACE("Pixel shader 3.0\n");
345 set_parse_status(&asm_ctx, PARSE_ERR);
349 instructions: /* empty */
350 | instructions complexinstr
355 complexinstr: instruction
359 | predicate instruction
361 TRACE("predicate\n");
362 asm_ctx.funcs->predicate(&asm_ctx, &$1);
365 instruction: INSTR_ADD omods dreg ',' sregs
368 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ADD, $2.mod, $2.shift, 0, &$3, &$5, 2);
373 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_NOP, 0, 0, 0, 0, 0, 0);
375 | INSTR_MOV omods dreg ',' sregs
378 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MOV, $2.mod, $2.shift, 0, &$3, &$5, 1);
380 | INSTR_SUB omods dreg ',' sregs
383 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SUB, $2.mod, $2.shift, 0, &$3, &$5, 2);
385 | INSTR_MAD omods dreg ',' sregs
388 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MAD, $2.mod, $2.shift, 0, &$3, &$5, 3);
390 | INSTR_MUL omods dreg ',' sregs
393 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MUL, $2.mod, $2.shift, 0, &$3, &$5, 2);
395 | INSTR_RCP omods dreg ',' sregs
398 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_RCP, $2.mod, $2.shift, 0, &$3, &$5, 1);
400 | INSTR_RSQ omods dreg ',' sregs
403 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_RSQ, $2.mod, $2.shift, 0, &$3, &$5, 1);
405 | INSTR_DP3 omods dreg ',' sregs
408 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DP3, $2.mod, $2.shift, 0, &$3, &$5, 2);
410 | INSTR_DP4 omods dreg ',' sregs
413 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DP4, $2.mod, $2.shift, 0, &$3, &$5, 2);
415 | INSTR_MIN omods dreg ',' sregs
418 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MIN, $2.mod, $2.shift, 0, &$3, &$5, 2);
420 | INSTR_MAX omods dreg ',' sregs
423 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MAX, $2.mod, $2.shift, 0, &$3, &$5, 2);
425 | INSTR_SLT omods dreg ',' sregs
428 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SLT, $2.mod, $2.shift, 0, &$3, &$5, 2);
430 | INSTR_SGE omods dreg ',' sregs
433 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SGE, $2.mod, $2.shift, 0, &$3, &$5, 2);
435 | INSTR_ABS omods dreg ',' sregs
438 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ABS, $2.mod, $2.shift, 0, &$3, &$5, 1);
440 | INSTR_EXP omods dreg ',' sregs
443 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_EXP, $2.mod, $2.shift, 0, &$3, &$5, 1);
445 | INSTR_LOG omods dreg ',' sregs
448 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LOG, $2.mod, $2.shift, 0, &$3, &$5, 1);
450 | INSTR_LOGP omods dreg ',' sregs
453 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LOGP, $2.mod, $2.shift, 0, &$3, &$5, 1);
455 | INSTR_EXPP omods dreg ',' sregs
458 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_EXPP, $2.mod, $2.shift, 0, &$3, &$5, 1);
460 | INSTR_DST omods dreg ',' sregs
463 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DST, $2.mod, $2.shift, 0, &$3, &$5, 2);
465 | INSTR_LRP omods dreg ',' sregs
468 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LRP, $2.mod, $2.shift, 0, &$3, &$5, 3);
470 | INSTR_FRC omods dreg ',' sregs
473 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_FRC, $2.mod, $2.shift, 0, &$3, &$5, 1);
475 | INSTR_POW omods dreg ',' sregs
478 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_POW, $2.mod, $2.shift, 0, &$3, &$5, 2);
480 | INSTR_CRS omods dreg ',' sregs
483 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CRS, $2.mod, $2.shift, 0, &$3, &$5, 2);
485 | INSTR_SGN omods dreg ',' sregs
488 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SGN, $2.mod, $2.shift, 0, &$3, &$5, 3);
490 | INSTR_NRM omods dreg ',' sregs
493 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_NRM, $2.mod, $2.shift, 0, &$3, &$5, 1);
495 | INSTR_SINCOS omods dreg ',' sregs
498 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SINCOS, $2.mod, $2.shift, 0, &$3, &$5, 1);
500 | INSTR_M4x4 omods dreg ',' sregs
503 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M4x4, $2.mod, $2.shift, 0, &$3, &$5, 2);
505 | INSTR_M4x3 omods dreg ',' sregs
508 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M4x3, $2.mod, $2.shift, 0, &$3, &$5, 2);
510 | INSTR_M3x4 omods dreg ',' sregs
513 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M3x4, $2.mod, $2.shift, 0, &$3, &$5, 2);
515 | INSTR_M3x3 omods dreg ',' sregs
518 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M3x3, $2.mod, $2.shift, 0, &$3, &$5, 2);
520 | INSTR_M3x2 omods dreg ',' sregs
523 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_M3x2, $2.mod, $2.shift, 0, &$3, &$5, 2);
525 | INSTR_DCL dclusage REG_OUTPUT
527 struct shader_reg reg;
528 TRACE("Output reg declaration\n");
529 ZeroMemory(®, sizeof(reg));
530 reg.type = BWRITERSPR_OUTPUT;
534 reg.writemask = BWRITERSP_WRITEMASK_ALL;
535 asm_ctx.funcs->dcl_output(&asm_ctx, $2.dclusage, $2.regnum, ®);
537 | INSTR_DCL dclusage REG_OUTPUT writemask
539 struct shader_reg reg;
540 TRACE("Output reg declaration\n");
541 ZeroMemory(®, sizeof(reg));
542 reg.type = BWRITERSPR_OUTPUT;
547 asm_ctx.funcs->dcl_output(&asm_ctx, $2.dclusage, $2.regnum, ®);
549 | INSTR_DCL dclusage REG_INPUT
551 struct shader_reg reg;
552 TRACE("Input reg declaration\n");
553 ZeroMemory(®, sizeof(reg));
554 reg.type = BWRITERSPR_INPUT;
558 reg.writemask = BWRITERSP_WRITEMASK_ALL;
559 asm_ctx.funcs->dcl_input(&asm_ctx, $2.dclusage, $2.regnum, ®);
561 | INSTR_DCL dclusage REG_INPUT writemask
563 struct shader_reg reg;
564 TRACE("Input reg declaration\n");
565 ZeroMemory(®, sizeof(reg));
566 reg.type = BWRITERSPR_INPUT;
571 asm_ctx.funcs->dcl_input(&asm_ctx, $2.dclusage, $2.regnum, ®);
573 | INSTR_DCL sampdcl REG_SAMPLER
575 TRACE("Sampler declared\n");
576 asm_ctx.funcs->dcl_sampler(&asm_ctx, $2, $3, asm_ctx.line_no);
578 | INSTR_DCL sampdcl REG_INPUT
580 TRACE("Error rule: sampler decl of input reg\n");
581 asmparser_message(&asm_ctx, "Line %u: Sampler declarations of input regs is not valid\n",
583 set_parse_status(&asm_ctx, PARSE_WARN);
585 | INSTR_DCL sampdcl REG_OUTPUT
587 TRACE("Error rule: sampler decl of output reg\n");
588 asmparser_message(&asm_ctx, "Line %u: Sampler declarations of output regs is not valid\n",
590 set_parse_status(&asm_ctx, PARSE_WARN);
592 | INSTR_DEF REG_CONSTFLOAT ',' IMMVAL ',' IMMVAL ',' IMMVAL ',' IMMVAL
594 asm_ctx.funcs->constF(&asm_ctx, $2, $4.val, $6.val, $8.val, $10.val);
596 | INSTR_DEFI REG_CONSTINT ',' IMMVAL ',' IMMVAL ',' IMMVAL ',' IMMVAL
598 asm_ctx.funcs->constI(&asm_ctx, $2, $4.val, $6.val, $8.val, $10.val);
600 | INSTR_DEFB REG_CONSTBOOL ',' IMMBOOL
602 asm_ctx.funcs->constB(&asm_ctx, $2, $4);
607 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_REP, 0, 0, 0, 0, &$2, 1);
612 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ENDREP, 0, 0, 0, 0, 0, 0);
617 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_IF, 0, 0, 0, 0, &$2, 1);
619 | INSTR_IF comp sregs
622 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_IFC, 0, 0, $2, 0, &$3, 2);
627 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ELSE, 0, 0, 0, 0, 0, 0);
632 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ENDIF, 0, 0, 0, 0, 0, 0);
637 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_BREAK, 0, 0, 0, 0, 0, 0);
639 | INSTR_BREAK comp sregs
642 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_BREAKC, 0, 0, $2, 0, &$3, 2);
647 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_BREAKP, 0, 0, 0, 0, &$2, 1);
652 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CALL, 0, 0, 0, 0, &$2, 1);
657 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CALLNZ, 0, 0, 0, 0, &$2, 2);
662 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LOOP, 0, 0, 0, 0, &$2, 2);
667 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_RET, 0, 0, 0, 0, 0, 0);
672 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_ENDLOOP, 0, 0, 0, 0, 0, 0);
677 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LABEL, 0, 0, 0, 0, &$2, 1);
679 | INSTR_SETP comp dreg ',' sregs
682 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_SETP, 0, 0, $2, &$3, &$5, 2);
684 | INSTR_TEXLDL omods dreg ',' sregs
687 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXLDL, $2.mod, $2.shift, 0, &$3, &$5, 2);
689 | INSTR_LIT omods dreg ',' sregs
692 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_LIT, $2.mod, $2.shift, 0, &$3, &$5, 1);
694 | INSTR_MOVA omods dreg ',' sregs
697 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MOVA, $2.mod, $2.shift, 0, &$3, &$5, 1);
699 | INSTR_CMP omods dreg ',' sregs
702 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_CMP, $2.mod, $2.shift, 0, &$3, &$5, 3);
704 | INSTR_DP2ADD omods dreg ',' sregs
707 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DP2ADD, $2.mod, $2.shift, 0, &$3, &$5, 3);
709 | INSTR_TEXLD omods dreg ',' sregs
712 /* There is more than one acceptable syntax for texld:
713 with 1 sreg (PS 1.4) or
714 with 2 sregs (PS 2.0+)
715 Moreover, texld shares the same opcode as the tex instruction,
716 so there are a total of 3 valid syntaxes
717 These variations are handled in asmparser.c */
718 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEX, $2.mod, $2.shift, 0, &$3, &$5, 2);
720 | INSTR_TEXLDP omods dreg ',' sregs
723 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEX | ( BWRITERSI_TEXLD_PROJECT << BWRITER_OPCODESPECIFICCONTROL_SHIFT ), $2.mod, $2.shift, 0, &$3, &$5, 2);
725 | INSTR_TEXLDB omods dreg ',' sregs
728 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEX | ( BWRITERSI_TEXLD_BIAS << BWRITER_OPCODESPECIFICCONTROL_SHIFT ), $2.mod, $2.shift, 0, &$3, &$5, 2);
730 | INSTR_DSX omods dreg ',' sregs
733 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DSX, $2.mod, $2.shift, 0, &$3, &$5, 1);
735 | INSTR_DSY omods dreg ',' sregs
738 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_DSY, $2.mod, $2.shift, 0, &$3, &$5, 1);
740 | INSTR_TEXLDD omods dreg ',' sregs
743 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_TEXLDD, $2.mod, $2.shift, 0, &$3, &$5, 4);
746 dreg: dreg_name rel_reg
748 $$.regnum = $1.regnum;
750 $$.writemask = BWRITERSP_WRITEMASK_ALL;
751 $$.srcmod = BWRITERSPSM_NONE;
752 set_rel_reg(&$$, &$2);
754 | dreg_name writemask
756 $$.regnum = $1.regnum;
759 $$.srcmod = BWRITERSPSM_NONE;
765 $$.regnum = $1; $$.type = BWRITERSPR_TEMP;
769 $$.regnum = $1; $$.type = BWRITERSPR_OUTPUT;
773 asmparser_message(&asm_ctx, "Line %u: Register v%u is not a valid destination register\n",
774 asm_ctx.line_no, $1);
775 set_parse_status(&asm_ctx, PARSE_WARN);
779 asmparser_message(&asm_ctx, "Line %u: Register c%u is not a valid destination register\n",
780 asm_ctx.line_no, $1);
781 set_parse_status(&asm_ctx, PARSE_WARN);
785 asmparser_message(&asm_ctx, "Line %u: Register i%u is not a valid destination register\n",
786 asm_ctx.line_no, $1);
787 set_parse_status(&asm_ctx, PARSE_WARN);
791 asmparser_message(&asm_ctx, "Line %u: Register b%u is not a valid destination register\n",
792 asm_ctx.line_no, $1);
793 set_parse_status(&asm_ctx, PARSE_WARN);
797 $$.regnum = $1; $$.type = BWRITERSPR_TEXTURE;
801 $$.regnum = $1; $$.type = BWRITERSPR_TEXCRDOUT;
805 asmparser_message(&asm_ctx, "Line %u: Register s%u is not a valid destination register\n",
806 asm_ctx.line_no, $1);
807 set_parse_status(&asm_ctx, PARSE_WARN);
811 $$.regnum = BWRITERSRO_POSITION; $$.type = BWRITERSPR_RASTOUT;
815 $$.regnum = BWRITERSRO_POINT_SIZE; $$.type = BWRITERSPR_RASTOUT;
819 $$.regnum = BWRITERSRO_FOG; $$.type = BWRITERSPR_RASTOUT;
823 $$.regnum = $1; $$.type = BWRITERSPR_ATTROUT;
827 $$.regnum = $1; $$.type = BWRITERSPR_COLOROUT;
831 $$.regnum = 0; $$.type = BWRITERSPR_DEPTHOUT;
835 $$.regnum = 0; $$.type = BWRITERSPR_PREDICATE;
839 asmparser_message(&asm_ctx, "Line %u: Register vPos is not a valid destination register\n",
841 set_parse_status(&asm_ctx, PARSE_WARN);
845 asmparser_message(&asm_ctx, "Line %u: Register vFace is not a valid destination register\n",
847 set_parse_status(&asm_ctx, PARSE_WARN);
851 /* index 0 is hardcoded for the addr register */
852 $$.regnum = 0; $$.type = BWRITERSPR_ADDR;
856 asmparser_message(&asm_ctx, "Line %u: Register aL is not a valid destination register\n",
858 set_parse_status(&asm_ctx, PARSE_WARN);
861 writemask: '.' wm_components
863 if($2.writemask == SWIZZLE_ERR) {
864 asmparser_message(&asm_ctx, "Line %u: Invalid writemask specified\n",
866 set_parse_status(&asm_ctx, PARSE_ERR);
867 /* Provide a correct writemask to prevent following complaints */
868 $$ = BWRITERSP_WRITEMASK_ALL;
872 TRACE("Writemask: %x\n", $$);
876 wm_components: COMPONENT
878 $$.writemask = 1 << $1;
882 | wm_components COMPONENT
884 if($1.writemask == SWIZZLE_ERR || $1.idx == 4)
885 /* Wrong writemask */
886 $$.writemask = SWIZZLE_ERR;
889 $$.writemask = SWIZZLE_ERR;
891 $$.writemask = $1.writemask | (1 << $2);
899 $$ = BWRITERVS_NOSWIZZLE;
900 TRACE("Default swizzle: %08x\n", $$);
904 if($2.swizzle == SWIZZLE_ERR) {
905 asmparser_message(&asm_ctx, "Line %u: Invalid swizzle\n",
907 set_parse_status(&asm_ctx, PARSE_ERR);
908 /* Provide a correct swizzle to prevent following complaints */
909 $$ = BWRITERVS_NOSWIZZLE;
914 $$ = $2.swizzle << BWRITERVS_SWIZZLE_SHIFT;
915 /* Fill the swizzle by extending the last component */
916 last = ($2.swizzle >> 2 * ($2.idx - 1)) & 0x03;
917 for(i = $2.idx; i < 4; i++){
918 $$ |= last << (BWRITERVS_SWIZZLE_SHIFT + 2 * i);
920 TRACE("Got a swizzle: %08x\n", $$);
924 sw_components: COMPONENT
929 | sw_components COMPONENT
932 /* Too many sw_components */
933 $$.swizzle = SWIZZLE_ERR;
937 $$.swizzle = $1.swizzle | ($2 << 2 * $1.idx);
949 $$.mod = $1.mod | $2.mod;
950 if($1.shift && $2.shift) {
951 asmparser_message(&asm_ctx, "Line %u: More than one shift flag\n",
953 set_parse_status(&asm_ctx, PARSE_ERR);
956 $$.shift = $1.shift | $2.shift;
962 $$.mod = BWRITERSPDM_SATURATE;
967 $$.mod = BWRITERSPDM_PARTIALPRECISION;
972 $$.mod = BWRITERSPDM_MSAMPCENTROID;
983 if($$.count == MAX_SRC_REGS){
984 asmparser_message(&asm_ctx, "Line %u: Too many source registers in this instruction\n",
986 set_parse_status(&asm_ctx, PARSE_ERR);
989 $$.reg[$$.count++] = $3;
992 sreg: sreg_name rel_reg swizzle
995 $$.regnum = $1.regnum;
997 $$.srcmod = BWRITERSPSM_NONE;
998 set_rel_reg(&$$, &$2);
1000 | sreg_name rel_reg smod swizzle
1003 $$.regnum = $1.regnum;
1004 set_rel_reg(&$$, &$2);
1008 | '-' sreg_name rel_reg swizzle
1011 $$.regnum = $2.regnum;
1012 $$.srcmod = BWRITERSPSM_NEG;
1013 set_rel_reg(&$$, &$3);
1016 | '-' sreg_name rel_reg smod swizzle
1019 $$.regnum = $2.regnum;
1020 set_rel_reg(&$$, &$3);
1022 case BWRITERSPSM_ABS: $$.srcmod = BWRITERSPSM_ABSNEG; break;
1024 FIXME("Unhandled combination of NEGATE and %u\n", $4);
1028 | SMOD_NOT sreg_name swizzle
1031 $$.regnum = $2.regnum;
1033 $$.srcmod = BWRITERSPSM_NOT;
1037 rel_reg: /* empty */
1039 $$.has_rel_reg = FALSE;
1040 $$.additional_offset = 0;
1044 $$.has_rel_reg = FALSE;
1045 $$.additional_offset = $2.val;
1047 | '[' relreg_name swizzle ']'
1049 $$.has_rel_reg = TRUE;
1051 $$.additional_offset = 0;
1052 $$.rel_regnum = $2.regnum;
1055 | '[' immsum '+' relreg_name swizzle ']'
1057 $$.has_rel_reg = TRUE;
1059 $$.additional_offset = $2.val;
1060 $$.rel_regnum = $4.regnum;
1063 | '[' relreg_name swizzle '+' immsum ']'
1065 $$.has_rel_reg = TRUE;
1067 $$.additional_offset = $5.val;
1068 $$.rel_regnum = $2.regnum;
1071 | '[' immsum '+' relreg_name swizzle '+' immsum ']'
1073 $$.has_rel_reg = TRUE;
1075 $$.additional_offset = $2.val + $7.val;
1076 $$.rel_regnum = $4.regnum;
1083 asmparser_message(&asm_ctx, "Line %u: Unexpected float %f\n",
1084 asm_ctx.line_no, $1.val);
1085 set_parse_status(&asm_ctx, PARSE_ERR);
1092 asmparser_message(&asm_ctx, "Line %u: Unexpected float %f\n",
1093 asm_ctx.line_no, $3.val);
1094 set_parse_status(&asm_ctx, PARSE_ERR);
1096 $$.val = $1.val + $3.val;
1101 $$ = BWRITERSPSM_ABS;
1104 relreg_name: REG_ADDRESS
1106 $$.regnum = 0; $$.type = BWRITERSPR_ADDR;
1110 $$.regnum = 0; $$.type = BWRITERSPR_LOOP;
1115 $$.regnum = $1; $$.type = BWRITERSPR_TEMP;
1119 asmparser_message(&asm_ctx, "Line %u: Register o%u is not a valid source register\n",
1120 asm_ctx.line_no, $1);
1121 set_parse_status(&asm_ctx, PARSE_WARN);
1125 $$.regnum = $1; $$.type = BWRITERSPR_INPUT;
1129 $$.regnum = $1; $$.type = BWRITERSPR_CONST;
1133 $$.regnum = $1; $$.type = BWRITERSPR_CONSTINT;
1137 $$.regnum = $1; $$.type = BWRITERSPR_CONSTBOOL;
1141 $$.regnum = $1; $$.type = BWRITERSPR_TEXTURE;
1145 asmparser_message(&asm_ctx, "Line %u: Register oT%u is not a valid source register\n",
1146 asm_ctx.line_no, $1);
1147 set_parse_status(&asm_ctx, PARSE_WARN);
1151 $$.regnum = $1; $$.type = BWRITERSPR_SAMPLER;
1155 asmparser_message(&asm_ctx, "Line %u: Register oPos is not a valid source register\n",
1157 set_parse_status(&asm_ctx, PARSE_WARN);
1161 asmparser_message(&asm_ctx, "Line %u: Register oFog is not a valid source register\n",
1163 set_parse_status(&asm_ctx, PARSE_WARN);
1167 asmparser_message(&asm_ctx, "Line %u: Register oD%u is not a valid source register\n",
1168 asm_ctx.line_no, $1);
1169 set_parse_status(&asm_ctx, PARSE_WARN);
1173 asmparser_message(&asm_ctx, "Line %u: Register oC%u is not a valid source register\n",
1174 asm_ctx.line_no, $1);
1175 set_parse_status(&asm_ctx, PARSE_WARN);
1179 asmparser_message(&asm_ctx, "Line %u: Register oDepth is not a valid source register\n",
1181 set_parse_status(&asm_ctx, PARSE_WARN);
1185 $$.regnum = 0; $$.type = BWRITERSPR_PREDICATE;
1189 $$.regnum = 0; $$.type = BWRITERSPR_MISCTYPE;
1193 $$.regnum = 1; $$.type = BWRITERSPR_MISCTYPE;
1197 $$.regnum = 0; $$.type = BWRITERSPR_ADDR;
1201 $$.regnum = 0; $$.type = BWRITERSPR_LOOP;
1205 $$.regnum = $1; $$.type = BWRITERSPR_LABEL;
1208 comp: COMP_GT { $$ = BWRITER_COMPARISON_GT; }
1209 | COMP_LT { $$ = BWRITER_COMPARISON_LT; }
1210 | COMP_GE { $$ = BWRITER_COMPARISON_GE; }
1211 | COMP_LE { $$ = BWRITER_COMPARISON_LE; }
1212 | COMP_EQ { $$ = BWRITER_COMPARISON_EQ; }
1213 | COMP_NE { $$ = BWRITER_COMPARISON_NE; }
1215 dclusage: USAGE_POSITION
1217 TRACE("dcl_position%u\n", $1);
1219 $$.dclusage = BWRITERDECLUSAGE_POSITION;
1223 TRACE("dcl_blendweight%u\n", $1);
1225 $$.dclusage = BWRITERDECLUSAGE_BLENDWEIGHT;
1227 | USAGE_BLENDINDICES
1229 TRACE("dcl_blendindices%u\n", $1);
1231 $$.dclusage = BWRITERDECLUSAGE_BLENDINDICES;
1235 TRACE("dcl_normal%u\n", $1);
1237 $$.dclusage = BWRITERDECLUSAGE_NORMAL;
1241 TRACE("dcl_psize%u\n", $1);
1243 $$.dclusage = BWRITERDECLUSAGE_PSIZE;
1247 TRACE("dcl_texcoord%u\n", $1);
1249 $$.dclusage = BWRITERDECLUSAGE_TEXCOORD;
1253 TRACE("dcl_tangent%u\n", $1);
1255 $$.dclusage = BWRITERDECLUSAGE_TANGENT;
1259 TRACE("dcl_binormal%u\n", $1);
1261 $$.dclusage = BWRITERDECLUSAGE_BINORMAL;
1265 TRACE("dcl_tessfactor%u\n", $1);
1267 $$.dclusage = BWRITERDECLUSAGE_TESSFACTOR;
1271 TRACE("dcl_positiont%u\n", $1);
1273 $$.dclusage = BWRITERDECLUSAGE_POSITIONT;
1277 TRACE("dcl_color%u\n", $1);
1279 $$.dclusage = BWRITERDECLUSAGE_COLOR;
1283 TRACE("dcl_fog%u\n", $1);
1285 $$.dclusage = BWRITERDECLUSAGE_FOG;
1289 TRACE("dcl_depth%u\n", $1);
1291 $$.dclusage = BWRITERDECLUSAGE_DEPTH;
1295 TRACE("dcl_sample%u\n", $1);
1297 $$.dclusage = BWRITERDECLUSAGE_SAMPLE;
1300 sampdcl: SAMPTYPE_1D
1310 $$ = BWRITERSTT_CUBE;
1314 $$ = BWRITERSTT_VOLUME;
1317 predicate: '(' REG_PREDICATE swizzle ')'
1319 $$.type = BWRITERSPR_PREDICATE;
1322 $$.srcmod = BWRITERSPSM_NONE;
1325 | '(' SMOD_NOT REG_PREDICATE swizzle ')'
1327 $$.type = BWRITERSPR_PREDICATE;
1330 $$.srcmod = BWRITERSPSM_NOT;
1336 void asmshader_error (char const *s) {
1337 asmparser_message(&asm_ctx, "Line %u: Error \"%s\" from bison\n", asm_ctx.line_no, s);
1338 set_parse_status(&asm_ctx, PARSE_ERR);
1341 /* Error reporting function */
1342 void asmparser_message(struct asm_parser *ctx, const char *fmt, ...) {
1347 if(ctx->messagecapacity == 0) {
1348 ctx->messages = asm_alloc(MESSAGEBUFFER_INITIAL_SIZE);
1349 if(ctx->messages == NULL) {
1350 ERR("Error allocating memory for parser messages\n");
1353 ctx->messagecapacity = MESSAGEBUFFER_INITIAL_SIZE;
1357 va_start(args, fmt);
1358 rc = vsnprintf(ctx->messages + ctx->messagesize,
1359 ctx->messagecapacity - ctx->messagesize, fmt, args);
1362 if (rc < 0 || /* C89 */
1363 rc >= ctx->messagecapacity - ctx->messagesize) { /* C99 */
1364 /* Resize the buffer */
1365 newsize = ctx->messagecapacity * 2;
1366 newbuffer = asm_realloc(ctx->messages, newsize);
1367 if(newbuffer == NULL){
1368 ERR("Error reallocating memory for parser messages\n");
1371 ctx->messages = newbuffer;
1372 ctx->messagecapacity = newsize;
1374 ctx->messagesize += rc;
1380 /* New status is the worst between current status and parameter value */
1381 void set_parse_status(struct asm_parser *ctx, enum parse_status status) {
1382 if(status == PARSE_ERR) ctx->status = PARSE_ERR;
1383 else if(status == PARSE_WARN && ctx->status == PARSE_SUCCESS) ctx->status = PARSE_WARN;
1386 struct bwriter_shader *parse_asm_shader(char **messages) {
1387 struct bwriter_shader *ret = NULL;
1389 asm_ctx.shader = NULL;
1390 asm_ctx.status = PARSE_SUCCESS;
1391 asm_ctx.messagesize = asm_ctx.messagecapacity = 0;
1392 asm_ctx.line_no = 1;
1396 if(asm_ctx.status != PARSE_ERR) ret = asm_ctx.shader;
1397 else if(asm_ctx.shader) SlDeleteShader(asm_ctx.shader);
1400 if(asm_ctx.messagesize) {
1401 /* Shrink the buffer to the used size */
1402 *messages = asm_realloc(asm_ctx.messages, asm_ctx.messagesize + 1);
1404 ERR("Out of memory, no messages reported\n");
1405 asm_free(asm_ctx.messages);
1411 if(asm_ctx.messagecapacity) asm_free(asm_ctx.messages);