502 lines
21 KiB
Plaintext
502 lines
21 KiB
Plaintext
/*
|
|
* Direct3D shader assembler
|
|
*
|
|
* Copyright 2008 Stefan Dösinger
|
|
* Copyright 2009 Matteo Bruni
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
%{
|
|
#include "config.h"
|
|
#include "wine/port.h"
|
|
#include "wine/debug.h"
|
|
|
|
#include "d3dcompiler_private.h"
|
|
#include "asmshader.tab.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(asmshader);
|
|
%}
|
|
|
|
%option noyywrap
|
|
%option prefix="asmshader_"
|
|
%option noinput nounput
|
|
|
|
/* Swizzles and writemasks consist of a dot and up to 4 x, y, z or w characters,
|
|
* or up to 4 a, r, g, b characters. There are different rules for swizzles and
|
|
* writemasks wrt repetition, those are handled in the grammar.
|
|
*/
|
|
DOT \.
|
|
COMPONENT [xyzw]|[rgba]
|
|
|
|
/* Registers */
|
|
REG_TEMP r[0-9]+
|
|
/* for relative addressing in the form o[x], v[x] and c[x] */
|
|
REG_OUTPUT o[0-9]*
|
|
REG_INPUT v[0-9]*
|
|
REG_CONSTFLOAT c[0-9]*
|
|
REG_CONSTINT i[0-9]+
|
|
REG_CONSTBOOL b[0-9]+
|
|
REG_TEXTURE t[0-9]+
|
|
REG_TEXCRDOUT oT[0-9]+
|
|
REG_SAMPLER s[0-9]+
|
|
REG_OPOS oPos
|
|
REG_OFOG oFog
|
|
REG_OPTS oPts
|
|
REG_VERTEXCOLOR oD[01]
|
|
REG_FRAGCOLOR oC[0-9]+
|
|
REG_FRAGDEPTH oDepth
|
|
REG_VPOS vPos
|
|
REG_VFACE vFace
|
|
REG_ADDRESS a0
|
|
REG_LOOP aL
|
|
REG_PREDICATE p0
|
|
/* Not really a register, but it is considered as such */
|
|
REG_LABEL l[0-9]+
|
|
|
|
DCL_POSITION _position[0-9]*
|
|
DCL_BLENDWEIGHT _blendweight[0-9]*
|
|
DCL_BLENDINDICES _blendindices[0-9]*
|
|
DCL_NORMAL _normal[0-9]*
|
|
DCL_PSIZE _psize[0-9]*
|
|
DCL_TEXCOORD _texcoord[0-9]*
|
|
DCL_TANGENT _tangent[0-9]*
|
|
DCL_BINORMAL _binormal[0-9]*
|
|
DCL_TESSFACTOR _tessfactor[0-9]*
|
|
DCL_POSITIONT _positiont[0-9]*
|
|
DCL_COLOR _color[0-9]*
|
|
DCL_FOG _fog[0-9]*
|
|
DCL_DEPTH _depth[0-9]*
|
|
DCL_SAMPLE _sample[0-9]*
|
|
|
|
DCL_SAMPLER1D _1d
|
|
DCL_SAMPLER2D _2d
|
|
DCL_SAMPLERCUBE _cube
|
|
DCL_SAMPLERVOLUME _volume
|
|
|
|
PREPROCESSORDIRECTIVE #[^\n]*\n
|
|
|
|
/* Comments */
|
|
DOUBLESLASHCOMMENT "//"[^\n]*
|
|
SEMICOLONCOMMENT ";"[^\n]*
|
|
|
|
/* Whitespaces are spaces, tabs and newlines */
|
|
WHITESPACE [ \t]+
|
|
NEWLINE (\n)|(\r\n)
|
|
|
|
COMMA ","
|
|
|
|
IMMVAL \-?(([0-9]+)|([0-9]*\.[0-9]+))(f)?
|
|
|
|
ANY (.)
|
|
|
|
%%
|
|
|
|
/* Common instructions(vertex and pixel shaders) */
|
|
add {return INSTR_ADD; }
|
|
nop {return INSTR_NOP; }
|
|
mov {return INSTR_MOV; }
|
|
sub {return INSTR_SUB; }
|
|
mad {return INSTR_MAD; }
|
|
mul {return INSTR_MUL; }
|
|
rcp {return INSTR_RCP; }
|
|
rsq {return INSTR_RSQ; }
|
|
dp3 {return INSTR_DP3; }
|
|
dp4 {return INSTR_DP4; }
|
|
min {return INSTR_MIN; }
|
|
max {return INSTR_MAX; }
|
|
slt {return INSTR_SLT; }
|
|
sge {return INSTR_SGE; }
|
|
abs {return INSTR_ABS; }
|
|
exp {return INSTR_EXP; }
|
|
log {return INSTR_LOG; }
|
|
expp {return INSTR_EXPP; }
|
|
logp {return INSTR_LOGP; }
|
|
dst {return INSTR_DST; }
|
|
lrp {return INSTR_LRP; }
|
|
frc {return INSTR_FRC; }
|
|
pow {return INSTR_POW; }
|
|
crs {return INSTR_CRS; }
|
|
sgn {return INSTR_SGN; }
|
|
nrm {return INSTR_NRM; }
|
|
sincos {return INSTR_SINCOS; }
|
|
m4x4 {return INSTR_M4x4; }
|
|
m4x3 {return INSTR_M4x3; }
|
|
m3x4 {return INSTR_M3x4; }
|
|
m3x3 {return INSTR_M3x3; }
|
|
m3x2 {return INSTR_M3x2; }
|
|
dcl {return INSTR_DCL; }
|
|
def {return INSTR_DEF; }
|
|
defb {return INSTR_DEFB; }
|
|
defi {return INSTR_DEFI; }
|
|
rep {return INSTR_REP; }
|
|
endrep {return INSTR_ENDREP; }
|
|
if {return INSTR_IF; }
|
|
else {return INSTR_ELSE; }
|
|
endif {return INSTR_ENDIF; }
|
|
break {return INSTR_BREAK; }
|
|
breakp {return INSTR_BREAKP; }
|
|
call {return INSTR_CALL; }
|
|
callnz {return INSTR_CALLNZ; }
|
|
loop {return INSTR_LOOP; }
|
|
ret {return INSTR_RET; }
|
|
endloop {return INSTR_ENDLOOP; }
|
|
label {return INSTR_LABEL; }
|
|
setp {return INSTR_SETP; }
|
|
texldl {return INSTR_TEXLDL; }
|
|
|
|
/* Vertex shader only instructions */
|
|
lit {return INSTR_LIT; }
|
|
mova {return INSTR_MOVA; }
|
|
|
|
/* Pixel shader only instructions */
|
|
cnd {return INSTR_CND; }
|
|
cmp {return INSTR_CMP; }
|
|
dp2add {return INSTR_DP2ADD; }
|
|
texcoord {return INSTR_TEXCOORD; }
|
|
texcrd {return INSTR_TEXCRD; }
|
|
texkill {return INSTR_TEXKILL; }
|
|
tex {return INSTR_TEX; }
|
|
texld {return INSTR_TEXLD; }
|
|
texbem {return INSTR_TEXBEM; }
|
|
texbeml {return INSTR_TEXBEML; }
|
|
texreg2ar {return INSTR_TEXREG2AR; }
|
|
texreg2gb {return INSTR_TEXREG2GB; }
|
|
texreg2rgb {return INSTR_TEXREG2RGB; }
|
|
texm3x2pad {return INSTR_TEXM3x2PAD; }
|
|
texm3x2tex {return INSTR_TEXM3x2TEX; }
|
|
texm3x3pad {return INSTR_TEXM3x3PAD; }
|
|
texm3x3spec {return INSTR_TEXM3x3SPEC; }
|
|
texm3x3vspec {return INSTR_TEXM3x3VSPEC; }
|
|
texm3x3tex {return INSTR_TEXM3x3TEX; }
|
|
texdp3tex {return INSTR_TEXDP3TEX; }
|
|
texm3x2depth {return INSTR_TEXM3x2DEPTH; }
|
|
texdp3 {return INSTR_TEXDP3; }
|
|
texm3x3 {return INSTR_TEXM3x3; }
|
|
texdepth {return INSTR_TEXDEPTH; }
|
|
bem {return INSTR_BEM; }
|
|
dsx {return INSTR_DSX; }
|
|
dsy {return INSTR_DSY; }
|
|
texldp {return INSTR_TEXLDP; }
|
|
texldb {return INSTR_TEXLDB; }
|
|
texldd {return INSTR_TEXLDD; }
|
|
phase {return INSTR_PHASE; }
|
|
|
|
{REG_TEMP} {
|
|
asmshader_lval.regnum = atoi(yytext + 1);
|
|
return REG_TEMP;
|
|
}
|
|
{REG_OUTPUT} {
|
|
asmshader_lval.regnum = atoi(yytext + 1);
|
|
return REG_OUTPUT;
|
|
}
|
|
{REG_INPUT} {
|
|
asmshader_lval.regnum = atoi(yytext + 1);
|
|
return REG_INPUT;
|
|
}
|
|
{REG_CONSTFLOAT} {
|
|
asmshader_lval.regnum = atoi(yytext + 1);
|
|
return REG_CONSTFLOAT;
|
|
}
|
|
{REG_CONSTINT} {
|
|
asmshader_lval.regnum = atoi(yytext + 1);
|
|
return REG_CONSTINT;
|
|
}
|
|
{REG_CONSTBOOL} {
|
|
asmshader_lval.regnum = atoi(yytext + 1);
|
|
return REG_CONSTBOOL;
|
|
}
|
|
{REG_TEXTURE} {
|
|
asmshader_lval.regnum = atoi(yytext + 1);
|
|
return REG_TEXTURE;
|
|
}
|
|
{REG_TEXCRDOUT} {
|
|
asmshader_lval.regnum = atoi(yytext + 2);
|
|
return REG_TEXCRDOUT;
|
|
}
|
|
{REG_SAMPLER} {
|
|
asmshader_lval.regnum = atoi(yytext + 1);
|
|
return REG_SAMPLER;
|
|
}
|
|
{REG_OPOS} {return REG_OPOS; }
|
|
{REG_OFOG} {return REG_OFOG; }
|
|
{REG_OPTS} {return REG_OPTS; }
|
|
{REG_VERTEXCOLOR} {
|
|
asmshader_lval.regnum = atoi(yytext + 2);
|
|
return REG_VERTEXCOLOR;
|
|
}
|
|
{REG_FRAGCOLOR} {
|
|
asmshader_lval.regnum = atoi(yytext + 2);
|
|
return REG_FRAGCOLOR;
|
|
}
|
|
{REG_FRAGDEPTH} {return REG_FRAGDEPTH; }
|
|
{REG_VPOS} {return REG_VPOS; }
|
|
{REG_VFACE} {return REG_VFACE; }
|
|
{REG_ADDRESS} {return REG_ADDRESS; }
|
|
{REG_LOOP} {return REG_LOOP; }
|
|
{REG_PREDICATE} {return REG_PREDICATE; }
|
|
|
|
{REG_LABEL} {
|
|
asmshader_lval.regnum = atoi(yytext + 1);
|
|
return REG_LABEL;
|
|
}
|
|
|
|
/* Shader versions. These are important to select the correct
|
|
* parser profile.
|
|
*/
|
|
vs\.1\.0|vs_1_0 {return VER_VS10; }
|
|
vs\.1\.1|vs_1_1 {return VER_VS11; }
|
|
|
|
vs_2_0 {return VER_VS20; }
|
|
vs_2_x {return VER_VS2X; }
|
|
vs_3_0 {return VER_VS30; }
|
|
|
|
ps\.1\.0|ps_1_0 {return VER_PS10; }
|
|
ps\.1\.1|ps_1_1 {return VER_PS11; }
|
|
ps\.1\.2|ps_1_2 {return VER_PS12; }
|
|
ps\.1\.3|ps_1_3 {return VER_PS13; }
|
|
ps\.1\.4|ps_1_4 {return VER_PS14; }
|
|
|
|
ps_2_0 {return VER_PS20; }
|
|
ps_2_x {return VER_PS2X; }
|
|
ps_3_0 {return VER_PS30; }
|
|
|
|
{DOT} {return yytext[0]; }
|
|
{COMPONENT} {
|
|
switch(yytext[0]) {
|
|
case 'x':
|
|
case 'r':
|
|
asmshader_lval.component = 0;
|
|
break;
|
|
case 'y':
|
|
case 'g':
|
|
asmshader_lval.component = 1;
|
|
break;
|
|
case 'z':
|
|
case 'b':
|
|
asmshader_lval.component = 2;
|
|
break;
|
|
case 'w':
|
|
case 'a':
|
|
asmshader_lval.component = 3;
|
|
break;
|
|
}
|
|
return COMPONENT;
|
|
}
|
|
|
|
/* Output modifiers */
|
|
\_x2 {return SHIFT_X2; }
|
|
\_x4 {return SHIFT_X4; }
|
|
\_x8 {return SHIFT_X8; }
|
|
\_d2 {return SHIFT_D2; }
|
|
\_d4 {return SHIFT_D4; }
|
|
\_d8 {return SHIFT_D8; }
|
|
\_sat {return MOD_SAT; }
|
|
\_pp {return MOD_PP; }
|
|
\_centroid {return MOD_CENTROID; }
|
|
|
|
/* compare params */
|
|
\_gt {return COMP_GT; }
|
|
\_lt {return COMP_LT; }
|
|
\_ge {return COMP_GE; }
|
|
\_le {return COMP_LE; }
|
|
\_eq {return COMP_EQ; }
|
|
\_ne {return COMP_NE; }
|
|
|
|
{IMMVAL} {
|
|
asmshader_lval.immval.val = atof(yytext);
|
|
asmshader_lval.immval.integer = ((strstr(yytext, ".") == NULL) && (strstr(yytext, "f") == NULL));
|
|
return IMMVAL;
|
|
}
|
|
true {
|
|
asmshader_lval.immbool = TRUE;
|
|
return IMMBOOL;
|
|
}
|
|
false {
|
|
asmshader_lval.immbool = FALSE;
|
|
return IMMBOOL;
|
|
}
|
|
|
|
{COMMA} {return yytext[0]; }
|
|
- {return yytext[0]; }
|
|
\( {return yytext[0]; }
|
|
\) {return yytext[0]; }
|
|
|
|
/* for relative addressing */
|
|
\[|\]|\+ {return yytext[0]; }
|
|
|
|
\_bias {return SMOD_BIAS; }
|
|
/* No _x2 here; it is identical to MOD_X2 */
|
|
\_bx2 {return SMOD_SCALEBIAS; }
|
|
\_dz {return SMOD_DZ; }
|
|
\_dw {return SMOD_DW; }
|
|
\_abs {return SMOD_ABS; }
|
|
|
|
! {return SMOD_NOT; }
|
|
|
|
{DCL_POSITION} {
|
|
if(yytext[strlen("_position")] == '\0') {
|
|
asmshader_lval.regnum = 0;
|
|
} else {
|
|
asmshader_lval.regnum = atoi(yytext + strlen("_position"));
|
|
}
|
|
return USAGE_POSITION;
|
|
}
|
|
{DCL_BLENDWEIGHT} {
|
|
if(yytext[strlen("_blendweight")] == '\0') {
|
|
asmshader_lval.regnum = 0;
|
|
} else {
|
|
asmshader_lval.regnum = atoi(yytext + strlen("_blendweight"));
|
|
}
|
|
return USAGE_BLENDWEIGHT;
|
|
}
|
|
{DCL_BLENDINDICES} {
|
|
if(yytext[strlen("_blendindices")] == '\0') {
|
|
asmshader_lval.regnum = 0;
|
|
} else {
|
|
asmshader_lval.regnum = atoi(yytext + strlen("_blendindices"));
|
|
}
|
|
return USAGE_BLENDINDICES;
|
|
}
|
|
{DCL_NORMAL} {
|
|
if(yytext[strlen("_normal")] == '\0') {
|
|
asmshader_lval.regnum = 0;
|
|
} else {
|
|
asmshader_lval.regnum = atoi(yytext + strlen("_normal"));
|
|
}
|
|
return USAGE_NORMAL;
|
|
}
|
|
{DCL_PSIZE} {
|
|
if(yytext[strlen("_psize")] == '\0') {
|
|
asmshader_lval.regnum = 0;
|
|
} else {
|
|
asmshader_lval.regnum = atoi(yytext + strlen("_psize"));
|
|
}
|
|
return USAGE_PSIZE;
|
|
}
|
|
{DCL_TEXCOORD} {
|
|
if(yytext[strlen("_texcoord")] == '\0') {
|
|
asmshader_lval.regnum = 0;
|
|
} else {
|
|
asmshader_lval.regnum = atoi(yytext + strlen("_texcoord"));
|
|
}
|
|
return USAGE_TEXCOORD;
|
|
}
|
|
{DCL_TANGENT} {
|
|
if(yytext[strlen("_tangent")] == '\0') {
|
|
asmshader_lval.regnum = 0;
|
|
} else {
|
|
asmshader_lval.regnum = atoi(yytext + strlen("_tangent"));
|
|
}
|
|
return USAGE_TANGENT;
|
|
}
|
|
{DCL_BINORMAL} {
|
|
if(yytext[strlen("_binormal")] == '\0') {
|
|
asmshader_lval.regnum = 0;
|
|
} else {
|
|
asmshader_lval.regnum = atoi(yytext + strlen("_binormal"));
|
|
}
|
|
return USAGE_BINORMAL;
|
|
}
|
|
{DCL_TESSFACTOR} {
|
|
if(yytext[strlen("_tessfactor")] == '\0') {
|
|
asmshader_lval.regnum = 0;
|
|
} else {
|
|
asmshader_lval.regnum = atoi(yytext + strlen("_tessfactor"));
|
|
}
|
|
return USAGE_TESSFACTOR;
|
|
}
|
|
{DCL_POSITIONT} {
|
|
if(yytext[strlen("_positiont")] == '\0') {
|
|
asmshader_lval.regnum = 0;
|
|
} else {
|
|
asmshader_lval.regnum = atoi(yytext + strlen("_positiont"));
|
|
}
|
|
return USAGE_POSITIONT;
|
|
}
|
|
{DCL_COLOR} {
|
|
if(yytext[strlen("_color")] == '\0') {
|
|
asmshader_lval.regnum = 0;
|
|
} else {
|
|
asmshader_lval.regnum = atoi(yytext + strlen("_color"));
|
|
}
|
|
return USAGE_COLOR;
|
|
}
|
|
{DCL_FOG} {
|
|
if(yytext[strlen("_fog")] == '\0') {
|
|
asmshader_lval.regnum = 0;
|
|
} else {
|
|
asmshader_lval.regnum = atoi(yytext + strlen("_fog"));
|
|
}
|
|
return USAGE_FOG;
|
|
}
|
|
{DCL_DEPTH} {
|
|
if(yytext[strlen("_depth")] == '\0') {
|
|
asmshader_lval.regnum = 0;
|
|
} else {
|
|
asmshader_lval.regnum = atoi(yytext + strlen("_depth"));
|
|
}
|
|
return USAGE_DEPTH;
|
|
}
|
|
{DCL_SAMPLE} {
|
|
if(yytext[strlen("_sample")] == '\0') {
|
|
asmshader_lval.regnum = 0;
|
|
} else {
|
|
asmshader_lval.regnum = atoi(yytext + strlen("_sample"));
|
|
}
|
|
return USAGE_SAMPLE;
|
|
}
|
|
|
|
{DCL_SAMPLER1D} { return SAMPTYPE_1D; }
|
|
{DCL_SAMPLER2D} { return SAMPTYPE_2D; }
|
|
{DCL_SAMPLERCUBE} { return SAMPTYPE_CUBE; }
|
|
{DCL_SAMPLERVOLUME} { return SAMPTYPE_VOLUME; }
|
|
|
|
{PREPROCESSORDIRECTIVE} {
|
|
/* TODO: update current line information */
|
|
TRACE("line info update: %s", yytext);
|
|
}
|
|
|
|
/* Skip comments */
|
|
{DOUBLESLASHCOMMENT} { }
|
|
{SEMICOLONCOMMENT} { }
|
|
|
|
{WHITESPACE} { /* Do nothing */ }
|
|
{NEWLINE} {
|
|
asm_ctx.line_no++;
|
|
}
|
|
|
|
{ANY} {
|
|
asmparser_message(&asm_ctx, "Line %u: Unexpected input %s\n", asm_ctx.line_no, yytext);
|
|
set_parse_status(&asm_ctx, PARSE_ERR);
|
|
}
|
|
|
|
%%
|
|
|
|
struct bwriter_shader *SlAssembleShader(const char *text, char **messages) {
|
|
struct bwriter_shader *ret = NULL;
|
|
YY_BUFFER_STATE buffer;
|
|
TRACE("%p, %p\n", text, messages);
|
|
|
|
buffer = asmshader__scan_string(text);
|
|
asmshader__switch_to_buffer(buffer);
|
|
|
|
ret = parse_asm_shader(messages);
|
|
|
|
asmshader__delete_buffer(buffer);
|
|
|
|
return ret;
|
|
}
|