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
) {
47 struct shader_reg reg
;
65 struct rel_reg rel_reg
;
66 struct src_regs sregs
;
69 /* Common instructions between vertex and pixel shaders */
73 %token
<regnum
> REG_TEMP
74 %token
<regnum
> REG_CONSTFLOAT
92 /* Output modifiers */
97 /* Source register modifiers */
101 %token
<component
> COMPONENT
103 %type
<reg
> dreg_name
105 %type
<reg
> sreg_name
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
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
);
132 TRACE
("Vertex shader 1.1\n");
133 set_parse_status
(&asm_ctx
, PARSE_ERR
);
138 TRACE
("Vertex shader 2.0\n");
139 set_parse_status
(&asm_ctx
, PARSE_ERR
);
144 TRACE
("Vertex shader 2.x\n");
145 set_parse_status
(&asm_ctx
, PARSE_ERR
);
150 TRACE
("Vertex shader 3.0\n");
151 create_vs30_parser
(&asm_ctx
);
155 TRACE
("Pixel shader 1.0\n");
156 set_parse_status
(&asm_ctx
, PARSE_ERR
);
161 TRACE
("Pixel shader 1.1\n");
162 set_parse_status
(&asm_ctx
, PARSE_ERR
);
167 TRACE
("Pixel shader 1.2\n");
168 set_parse_status
(&asm_ctx
, PARSE_ERR
);
173 TRACE
("Pixel shader 1.3\n");
174 set_parse_status
(&asm_ctx
, PARSE_ERR
);
179 TRACE
("Pixel shader 1.4\n");
180 set_parse_status
(&asm_ctx
, PARSE_ERR
);
185 TRACE
("Pixel shader 2.0\n");
186 set_parse_status
(&asm_ctx
, PARSE_ERR
);
191 TRACE
("Pixel shader 2.x\n");
192 set_parse_status
(&asm_ctx
, PARSE_ERR
);
197 TRACE
("Pixel shader 3.0\n");
198 set_parse_status
(&asm_ctx
, PARSE_ERR
);
202 instructions: /* empty */
203 | instructions complexinstr
208 complexinstr: instruction
213 instruction: INSTR_MOV omods dreg
',' sregs
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
;
223 $$.writemask
= BWRITERSP_WRITEMASK_ALL
;
224 $$.srcmod
= BWRITERSPSM_NONE
;
225 set_rel_reg
(&$$
, &$2);
227 | dreg_name writemask
229 $$.regnum
= $1.regnum
;
232 $$.srcmod
= BWRITERSPSM_NONE
;
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",
246 set_parse_status
(&asm_ctx
, PARSE_ERR
);
247 /* Provide a correct writemask to prevent following complaints */
248 $$
= BWRITERSP_WRITEMASK_ALL
;
252 TRACE
("Writemask: %x\n", $$
);
256 wm_components: COMPONENT
258 $$.writemask
= 1 << $1;
262 | wm_components COMPONENT
264 if
($1.writemask
== SWIZZLE_ERR ||
$1.idx
== 4)
265 /* Wrong writemask */
266 $$.writemask
= SWIZZLE_ERR
;
269 $$.writemask
= SWIZZLE_ERR
;
271 $$.writemask
= $1.writemask |
(1 << $2);
279 $$
= BWRITERVS_NOSWIZZLE
;
280 TRACE
("Default swizzle: %08x\n", $$
);
284 if
($2.swizzle
== SWIZZLE_ERR
) {
285 asmparser_message
(&asm_ctx
, "Line %u: Invalid swizzle\n",
287 set_parse_status
(&asm_ctx
, PARSE_ERR
);
288 /* Provide a correct swizzle to prevent following complaints */
289 $$
= BWRITERVS_NOSWIZZLE
;
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
309 | sw_components COMPONENT
312 /* Too many sw_components */
313 $$.swizzle
= SWIZZLE_ERR
;
317 $$.swizzle
= $1.swizzle |
($2 << 2 * $1.idx
);
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",
333 set_parse_status
(&asm_ctx
, PARSE_ERR
);
336 $$.shift
= $1.shift |
$2.shift
;
342 $$.mod
= BWRITERSPDM_SATURATE
;
347 $$.mod
= BWRITERSPDM_PARTIALPRECISION
;
352 $$.mod
= BWRITERSPDM_MSAMPCENTROID
;
363 if
($$.count
== MAX_SRC_REGS
){
364 asmparser_message
(&asm_ctx
, "Line %u: Too many source registers in this instruction\n",
366 set_parse_status
(&asm_ctx
, PARSE_ERR
);
369 $$.reg
[$$.count
++] = $3;
372 sreg: sreg_name rel_reg swizzle
375 $$.regnum
= $1.regnum
;
377 $$.srcmod
= BWRITERSPSM_NONE
;
378 set_rel_reg
(&$$
, &$2);
380 | sreg_name rel_reg smod swizzle
383 $$.regnum
= $1.regnum
;
384 set_rel_reg
(&$$
, &$2);
388 |
'-' sreg_name rel_reg swizzle
391 $$.regnum
= $2.regnum
;
392 $$.srcmod
= BWRITERSPSM_NEG
;
393 set_rel_reg
(&$$
, &$3);
396 |
'-' sreg_name rel_reg smod swizzle
399 $$.regnum
= $2.regnum
;
400 set_rel_reg
(&$$
, &$3);
402 case BWRITERSPSM_ABS
: $$.srcmod
= BWRITERSPSM_ABSNEG
; break
;
404 FIXME
("Unhandled combination of NEGATE and %u\n", $4);
411 $$.has_rel_reg
= FALSE
;
412 $$.additional_offset
= 0;
417 $$
= BWRITERSPSM_ABS
;
422 $$.regnum
= $1; $$.type
= BWRITERSPR_TEMP
;
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
, ...
) {
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");
448 ctx
->messagecapacity
= MESSAGEBUFFER_INITIAL_SIZE
;
453 rc
= vsnprintf
(ctx
->messages
+ ctx
->messagesize
,
454 ctx
->messagecapacity
- ctx
->messagesize
, fmt
, 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");
466 ctx
->messages
= newbuffer
;
467 ctx
->messagecapacity
= newsize
;
469 ctx
->messagesize
+= rc
;
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;
491 if
(asm_ctx.status
!= PARSE_ERR
) ret
= asm_ctx.shader
;
492 else if
(asm_ctx.shader
) SlDeleteShader
(asm_ctx.shader
);
495 if
(asm_ctx.messagesize
) {
496 /* Shrink the buffer to the used size */
497 *messages
= asm_realloc
(asm_ctx.messages
, asm_ctx.messagesize
+ 1);
499 ERR
("Out of memory, no messages reported\n");
500 asm_free
(asm_ctx.messages
);
506 if
(asm_ctx.messagecapacity
) asm_free
(asm_ctx.messages
);