d3dx9: Add source register modifiers (sm 2+) support to the shader assembler.
[wine.git] / dlls / d3dx9_36 / asmshader.y
blob2c801fcf2fb0da5058de772108075d218471734d
1 /*
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
23 #include "config.h"
24 #include "wine/port.h"
25 #include "wine/debug.h"
27 #include "d3dx9_36_private.h"
29 #include <stdio.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 reg->rel_reg = NULL;
45 %union {
46 unsigned int regnum;
47 struct shader_reg reg;
48 DWORD srcmod;
49 DWORD writemask;
50 struct {
51 DWORD writemask;
52 DWORD idx;
53 DWORD last;
54 } wm_components;
55 DWORD swizzle;
56 struct {
57 DWORD swizzle;
58 DWORD idx;
59 } sw_components;
60 DWORD component;
61 struct {
62 DWORD mod;
63 DWORD shift;
64 } modshift;
65 struct rel_reg rel_reg;
66 struct src_regs sregs;
69 /* Common instructions between vertex and pixel shaders */
70 %token INSTR_MOV
72 /* Registers */
73 %token <regnum> REG_TEMP
74 %token <regnum> REG_CONSTFLOAT
76 /* Version tokens */
77 %token VER_VS10
78 %token VER_VS11
79 %token VER_VS20
80 %token VER_VS2X
81 %token VER_VS30
83 %token VER_PS10
84 %token VER_PS11
85 %token VER_PS12
86 %token VER_PS13
87 %token VER_PS14
88 %token VER_PS20
89 %token VER_PS2X
90 %token VER_PS30
92 /* Output modifiers */
93 %token MOD_SAT
94 %token MOD_PP
95 %token MOD_CENTROID
97 /* Source register modifiers */
98 %token SMOD_ABS
100 /* Misc stuff */
101 %token <component> COMPONENT
103 %type <reg> dreg_name
104 %type <reg> dreg
105 %type <reg> sreg_name
106 %type <reg> sreg
107 %type <srcmod> smod
108 %type <writemask> writemask
109 %type <wm_components> wm_components
110 %type <swizzle> swizzle
111 %type <sw_components> sw_components
112 %type <modshift> omods
113 %type <modshift> omodifier
114 %type <rel_reg> rel_reg
115 %type <sregs> sregs
119 shader: version_marker instructions
121 asm_ctx.funcs->end(&asm_ctx);
124 version_marker: VER_VS10
126 TRACE("Vertex shader 1.0\n");
127 set_parse_status(&asm_ctx, PARSE_ERR);
128 YYABORT;
130 | VER_VS11
132 TRACE("Vertex shader 1.1\n");
133 set_parse_status(&asm_ctx, PARSE_ERR);
134 YYABORT;
136 | VER_VS20
138 TRACE("Vertex shader 2.0\n");
139 set_parse_status(&asm_ctx, PARSE_ERR);
140 YYABORT;
142 | VER_VS2X
144 TRACE("Vertex shader 2.x\n");
145 set_parse_status(&asm_ctx, PARSE_ERR);
146 YYABORT;
148 | VER_VS30
150 TRACE("Vertex shader 3.0\n");
151 create_vs30_parser(&asm_ctx);
153 | VER_PS10
155 TRACE("Pixel shader 1.0\n");
156 set_parse_status(&asm_ctx, PARSE_ERR);
157 YYABORT;
159 | VER_PS11
161 TRACE("Pixel shader 1.1\n");
162 set_parse_status(&asm_ctx, PARSE_ERR);
163 YYABORT;
165 | VER_PS12
167 TRACE("Pixel shader 1.2\n");
168 set_parse_status(&asm_ctx, PARSE_ERR);
169 YYABORT;
171 | VER_PS13
173 TRACE("Pixel shader 1.3\n");
174 set_parse_status(&asm_ctx, PARSE_ERR);
175 YYABORT;
177 | VER_PS14
179 TRACE("Pixel shader 1.4\n");
180 set_parse_status(&asm_ctx, PARSE_ERR);
181 YYABORT;
183 | VER_PS20
185 TRACE("Pixel shader 2.0\n");
186 set_parse_status(&asm_ctx, PARSE_ERR);
187 YYABORT;
189 | VER_PS2X
191 TRACE("Pixel shader 2.x\n");
192 set_parse_status(&asm_ctx, PARSE_ERR);
193 YYABORT;
195 | VER_PS30
197 TRACE("Pixel shader 3.0\n");
198 set_parse_status(&asm_ctx, PARSE_ERR);
199 YYABORT;
202 instructions: /* empty */
203 | instructions complexinstr
205 /* Nothing to do */
208 complexinstr: instruction
213 instruction: INSTR_MOV omods dreg ',' sregs
215 TRACE("MOV\n");
216 asm_ctx.funcs->instr(&asm_ctx, BWRITERSIO_MOV, $2.mod, $2.shift, 0, &$3, &$5, 1);
219 dreg: dreg_name rel_reg
221 $$.regnum = $1.regnum;
222 $$.type = $1.type;
223 $$.writemask = BWRITERSP_WRITEMASK_ALL;
224 $$.srcmod = BWRITERSPSM_NONE;
225 set_rel_reg(&$$, &$2);
227 | dreg_name writemask
229 $$.regnum = $1.regnum;
230 $$.type = $1.type;
231 $$.writemask = $2;
232 $$.srcmod = BWRITERSPSM_NONE;
233 $$.rel_reg = NULL;
236 dreg_name: REG_TEMP
238 $$.regnum = $1; $$.type = BWRITERSPR_TEMP;
241 writemask: '.' wm_components
243 if($2.writemask == SWIZZLE_ERR) {
244 asmparser_message(&asm_ctx, "Line %u: Invalid writemask specified\n",
245 asm_ctx.line_no);
246 set_parse_status(&asm_ctx, PARSE_ERR);
247 /* Provide a correct writemask to prevent following complaints */
248 $$ = BWRITERSP_WRITEMASK_ALL;
250 else {
251 $$ = $2.writemask;
252 TRACE("Writemask: %x\n", $$);
256 wm_components: COMPONENT
258 $$.writemask = 1 << $1;
259 $$.last = $1;
260 $$.idx = 1;
262 | wm_components COMPONENT
264 if($1.writemask == SWIZZLE_ERR || $1.idx == 4)
265 /* Wrong writemask */
266 $$.writemask = SWIZZLE_ERR;
267 else {
268 if($2 <= $1.last)
269 $$.writemask = SWIZZLE_ERR;
270 else {
271 $$.writemask = $1.writemask | (1 << $2);
272 $$.idx = $1.idx + 1;
277 swizzle: /* empty */
279 $$ = BWRITERVS_NOSWIZZLE;
280 TRACE("Default swizzle: %08x\n", $$);
282 | '.' sw_components
284 if($2.swizzle == SWIZZLE_ERR) {
285 asmparser_message(&asm_ctx, "Line %u: Invalid swizzle\n",
286 asm_ctx.line_no);
287 set_parse_status(&asm_ctx, PARSE_ERR);
288 /* Provide a correct swizzle to prevent following complaints */
289 $$ = BWRITERVS_NOSWIZZLE;
291 else {
292 DWORD last, i;
294 $$ = $2.swizzle << BWRITERVS_SWIZZLE_SHIFT;
295 /* Fill the swizzle by extending the last component */
296 last = ($2.swizzle >> 2 * ($2.idx - 1)) & 0x03;
297 for(i = $2.idx; i < 4; i++){
298 $$ |= last << (BWRITERVS_SWIZZLE_SHIFT + 2 * i);
300 TRACE("Got a swizzle: %08x\n", $$);
304 sw_components: COMPONENT
306 $$.swizzle = $1;
307 $$.idx = 1;
309 | sw_components COMPONENT
311 if($1.idx == 4) {
312 /* Too many sw_components */
313 $$.swizzle = SWIZZLE_ERR;
314 $$.idx = 4;
316 else {
317 $$.swizzle = $1.swizzle | ($2 << 2 * $1.idx);
318 $$.idx = $1.idx + 1;
322 omods: /* Empty */
324 $$.mod = 0;
325 $$.shift = 0;
327 | omods omodifier
329 $$.mod = $1.mod | $2.mod;
330 if($1.shift && $2.shift) {
331 asmparser_message(&asm_ctx, "Line %u: More than one shift flag\n",
332 asm_ctx.line_no);
333 set_parse_status(&asm_ctx, PARSE_ERR);
334 $$.shift = $1.shift;
335 } else {
336 $$.shift = $1.shift | $2.shift;
340 omodifier: MOD_SAT
342 $$.mod = BWRITERSPDM_SATURATE;
343 $$.shift = 0;
345 | MOD_PP
347 $$.mod = BWRITERSPDM_PARTIALPRECISION;
348 $$.shift = 0;
350 | MOD_CENTROID
352 $$.mod = BWRITERSPDM_MSAMPCENTROID;
353 $$.shift = 0;
356 sregs: sreg
358 $$.reg[0] = $1;
359 $$.count = 1;
361 | sregs ',' sreg
363 if($$.count == MAX_SRC_REGS){
364 asmparser_message(&asm_ctx, "Line %u: Too many source registers in this instruction\n",
365 asm_ctx.line_no);
366 set_parse_status(&asm_ctx, PARSE_ERR);
368 else
369 $$.reg[$$.count++] = $3;
372 sreg: sreg_name rel_reg swizzle
374 $$.type = $1.type;
375 $$.regnum = $1.regnum;
376 $$.swizzle = $3;
377 $$.srcmod = BWRITERSPSM_NONE;
378 set_rel_reg(&$$, &$2);
380 | sreg_name rel_reg smod swizzle
382 $$.type = $1.type;
383 $$.regnum = $1.regnum;
384 set_rel_reg(&$$, &$2);
385 $$.srcmod = $3;
386 $$.swizzle = $4;
388 | '-' sreg_name rel_reg swizzle
390 $$.type = $2.type;
391 $$.regnum = $2.regnum;
392 $$.srcmod = BWRITERSPSM_NEG;
393 set_rel_reg(&$$, &$3);
394 $$.swizzle = $4;
396 | '-' sreg_name rel_reg smod swizzle
398 $$.type = $2.type;
399 $$.regnum = $2.regnum;
400 set_rel_reg(&$$, &$3);
401 switch($4) {
402 case BWRITERSPSM_ABS: $$.srcmod = BWRITERSPSM_ABSNEG; break;
403 default:
404 FIXME("Unhandled combination of NEGATE and %u\n", $4);
406 $$.swizzle = $5;
409 rel_reg: /* empty */
411 $$.has_rel_reg = FALSE;
412 $$.additional_offset = 0;
415 smod: SMOD_ABS
417 $$ = BWRITERSPSM_ABS;
420 sreg_name: REG_TEMP
422 $$.regnum = $1; $$.type = BWRITERSPR_TEMP;
424 | REG_CONSTFLOAT
426 $$.regnum = $1; $$.type = BWRITERSPR_CONST;
431 void asmshader_error (char const *s) {
432 asmparser_message(&asm_ctx, "Line %u: Error \"%s\" from bison\n", asm_ctx.line_no, s);
433 set_parse_status(&asm_ctx, PARSE_ERR);
436 /* Error reporting function */
437 void asmparser_message(struct asm_parser *ctx, const char *fmt, ...) {
438 va_list args;
439 char* newbuffer;
440 int rc, newsize;
442 if(ctx->messagecapacity == 0) {
443 ctx->messages = asm_alloc(MESSAGEBUFFER_INITIAL_SIZE);
444 if(ctx->messages == NULL) {
445 ERR("Error allocating memory for parser messages\n");
446 return;
448 ctx->messagecapacity = MESSAGEBUFFER_INITIAL_SIZE;
451 while(1) {
452 va_start(args, fmt);
453 rc = vsnprintf(ctx->messages + ctx->messagesize,
454 ctx->messagecapacity - ctx->messagesize, fmt, args);
455 va_end(args);
457 if (rc < 0 || /* C89 */
458 rc >= ctx->messagecapacity - ctx->messagesize) { /* C99 */
459 /* Resize the buffer */
460 newsize = ctx->messagecapacity * 2;
461 newbuffer = asm_realloc(ctx->messages, newsize);
462 if(newbuffer == NULL){
463 ERR("Error reallocating memory for parser messages\n");
464 return;
466 ctx->messages = newbuffer;
467 ctx->messagecapacity = newsize;
468 } else {
469 ctx->messagesize += rc;
470 return;
475 /* New status is the worst between current status and parameter value */
476 void set_parse_status(struct asm_parser *ctx, enum parse_status status) {
477 if(status == PARSE_ERR) ctx->status = PARSE_ERR;
478 else if(status == PARSE_WARN && ctx->status == PARSE_SUCCESS) ctx->status = PARSE_WARN;
481 struct bwriter_shader *parse_asm_shader(char **messages) {
482 struct bwriter_shader *ret = NULL;
484 asm_ctx.shader = NULL;
485 asm_ctx.status = PARSE_SUCCESS;
486 asm_ctx.messagesize = asm_ctx.messagecapacity = 0;
487 asm_ctx.line_no = 1;
489 asmshader_parse();
491 if(asm_ctx.status != PARSE_ERR) ret = asm_ctx.shader;
492 else if(asm_ctx.shader) SlDeleteShader(asm_ctx.shader);
494 if(messages) {
495 if(asm_ctx.messagesize) {
496 /* Shrink the buffer to the used size */
497 *messages = asm_realloc(asm_ctx.messages, asm_ctx.messagesize + 1);
498 if(!*messages) {
499 ERR("Out of memory, no messages reported\n");
500 asm_free(asm_ctx.messages);
502 } else {
503 *messages = NULL;
505 } else {
506 if(asm_ctx.messagecapacity) asm_free(asm_ctx.messages);
509 return ret;