summaryrefslogtreecommitdiff
path: root/src/mesa/shader/program_parse.y
diff options
context:
space:
mode:
Diffstat (limited to 'src/mesa/shader/program_parse.y')
-rw-r--r--src/mesa/shader/program_parse.y388
1 files changed, 333 insertions, 55 deletions
diff --git a/src/mesa/shader/program_parse.y b/src/mesa/shader/program_parse.y
index 89da91064b..9703e8e670 100644
--- a/src/mesa/shader/program_parse.y
+++ b/src/mesa/shader/program_parse.y
@@ -68,10 +68,19 @@ static void init_dst_reg(struct prog_dst_register *r);
static void init_src_reg(struct asm_src_register *r);
+static void asm_instruction_set_operands(struct asm_instruction *inst,
+ const struct prog_dst_register *dst, const struct asm_src_register *src0,
+ const struct asm_src_register *src1, const struct asm_src_register *src2);
+
static struct asm_instruction *asm_instruction_ctor(gl_inst_opcode op,
const struct prog_dst_register *dst, const struct asm_src_register *src0,
const struct asm_src_register *src1, const struct asm_src_register *src2);
+static struct asm_instruction *asm_instruction_copy_ctor(
+ const struct prog_instruction *base, const struct prog_dst_register *dst,
+ const struct asm_src_register *src0, const struct asm_src_register *src1,
+ const struct asm_src_register *src2);
+
#ifndef FALSE
#define FALSE 0
#define TRUE (!FALSE)
@@ -142,7 +151,7 @@ static struct asm_instruction *asm_instruction_ctor(gl_inst_opcode op,
/* Tokens for instructions */
%token <temp_inst> BIN_OP BINSC_OP SAMPLE_OP SCALAR_OP TRI_OP VECTOR_OP
-%token <temp_inst> ARL KIL SWZ
+%token <temp_inst> ARL KIL SWZ TXD_OP
%token <integer> INTEGER
%token <real> REAL
@@ -169,7 +178,8 @@ static struct asm_instruction *asm_instruction_ctor(gl_inst_opcode op,
%token VERTEX VTXATTRIB
%token WEIGHT
-%token <string> IDENTIFIER
+%token <string> IDENTIFIER USED_IDENTIFIER
+%type <string> string
%token <swiz_mask> MASK4 MASK3 MASK2 MASK1 SWIZZLE
%token DOT_DOT
%token DOT
@@ -177,11 +187,11 @@ static struct asm_instruction *asm_instruction_ctor(gl_inst_opcode op,
%type <inst> instruction ALU_instruction TexInstruction
%type <inst> ARL_instruction VECTORop_instruction
%type <inst> SCALARop_instruction BINSCop_instruction BINop_instruction
-%type <inst> TRIop_instruction SWZ_instruction SAMPLE_instruction
+%type <inst> TRIop_instruction TXD_instruction SWZ_instruction SAMPLE_instruction
%type <inst> KIL_instruction
%type <dst_reg> dstReg maskedDstReg maskedAddrReg
-%type <src_reg> srcReg scalarSrcReg swizzleSrcReg
+%type <src_reg> srcReg scalarUse scalarSrcReg swizzleSrcReg
%type <swiz_mask> scalarSuffix swizzleSuffix extendedSwizzle
%type <ext_swizzle> extSwizComp extSwizSel
%type <swiz_mask> optionalMask
@@ -192,6 +202,8 @@ static struct asm_instruction *asm_instruction_ctor(gl_inst_opcode op,
%type <sym> addrReg
%type <swiz_mask> addrComponent addrWriteMask
+%type <dst_reg> ccMaskRule ccTest ccMaskRule2 ccTest2 optionalCcMask
+
%type <result> resultBinding resultColBinding
%type <integer> optFaceType optColorType
%type <integer> optResultFaceType optResultColorType
@@ -280,7 +292,7 @@ optionSequence: optionSequence option
|
;
-option: OPTION IDENTIFIER ';'
+option: OPTION string ';'
{
int valid = 0;
@@ -347,6 +359,7 @@ ALU_instruction: ARL_instruction
TexInstruction: SAMPLE_instruction
| KIL_instruction
+ | TXD_instruction
;
ARL_instruction: ARL maskedAddrReg ',' scalarSrcReg
@@ -357,51 +370,45 @@ ARL_instruction: ARL maskedAddrReg ',' scalarSrcReg
VECTORop_instruction: VECTOR_OP maskedDstReg ',' swizzleSrcReg
{
- $$ = asm_instruction_ctor($1.Opcode, & $2, & $4, NULL, NULL);
- $$->Base.SaturateMode = $1.SaturateMode;
+ $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL);
}
;
SCALARop_instruction: SCALAR_OP maskedDstReg ',' scalarSrcReg
{
- $$ = asm_instruction_ctor($1.Opcode, & $2, & $4, NULL, NULL);
- $$->Base.SaturateMode = $1.SaturateMode;
+ $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL);
}
;
BINSCop_instruction: BINSC_OP maskedDstReg ',' scalarSrcReg ',' scalarSrcReg
{
- $$ = asm_instruction_ctor($1.Opcode, & $2, & $4, & $6, NULL);
- $$->Base.SaturateMode = $1.SaturateMode;
+ $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, NULL);
}
;
BINop_instruction: BIN_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg
{
- $$ = asm_instruction_ctor($1.Opcode, & $2, & $4, & $6, NULL);
- $$->Base.SaturateMode = $1.SaturateMode;
+ $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, NULL);
}
;
TRIop_instruction: TRI_OP maskedDstReg ','
swizzleSrcReg ',' swizzleSrcReg ',' swizzleSrcReg
{
- $$ = asm_instruction_ctor($1.Opcode, & $2, & $4, & $6, & $8);
- $$->Base.SaturateMode = $1.SaturateMode;
+ $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, & $8);
}
;
SAMPLE_instruction: SAMPLE_OP maskedDstReg ',' swizzleSrcReg ',' texImageUnit ',' texTarget
{
- $$ = asm_instruction_ctor($1.Opcode, & $2, & $4, NULL, NULL);
+ $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL);
if ($$ != NULL) {
const GLbitfield tex_mask = (1U << $6);
GLbitfield shadow_tex = 0;
GLbitfield target_mask = 0;
- $$->Base.SaturateMode = $1.SaturateMode;
$$->Base.TexSrcUnit = $6;
if ($8 < 0) {
@@ -442,6 +449,58 @@ KIL_instruction: KIL swizzleSrcReg
$$ = asm_instruction_ctor(OPCODE_KIL, NULL, & $2, NULL, NULL);
state->fragment.UsesKill = 1;
}
+ | KIL ccTest
+ {
+ $$ = asm_instruction_ctor(OPCODE_KIL_NV, NULL, NULL, NULL, NULL);
+ $$->Base.DstReg.CondMask = $2.CondMask;
+ $$->Base.DstReg.CondSwizzle = $2.CondSwizzle;
+ $$->Base.DstReg.CondSrc = $2.CondSrc;
+ state->fragment.UsesKill = 1;
+ }
+ ;
+
+TXD_instruction: TXD_OP maskedDstReg ',' swizzleSrcReg ',' swizzleSrcReg ',' swizzleSrcReg ',' texImageUnit ',' texTarget
+ {
+ $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, & $6, & $8);
+ if ($$ != NULL) {
+ const GLbitfield tex_mask = (1U << $10);
+ GLbitfield shadow_tex = 0;
+ GLbitfield target_mask = 0;
+
+
+ $$->Base.TexSrcUnit = $10;
+
+ if ($12 < 0) {
+ shadow_tex = tex_mask;
+
+ $$->Base.TexSrcTarget = -$12;
+ $$->Base.TexShadow = 1;
+ } else {
+ $$->Base.TexSrcTarget = $12;
+ }
+
+ target_mask = (1U << $$->Base.TexSrcTarget);
+
+ /* If this texture unit was previously accessed and that access
+ * had a different texture target, generate an error.
+ *
+ * If this texture unit was previously accessed and that access
+ * had a different shadow mode, generate an error.
+ */
+ if ((state->prog->TexturesUsed[$10] != 0)
+ && ((state->prog->TexturesUsed[$10] != target_mask)
+ || ((state->prog->ShadowSamplers & tex_mask)
+ != shadow_tex))) {
+ yyerror(& @12, state,
+ "multiple targets used on one texture image unit");
+ YYERROR;
+ }
+
+
+ state->prog->TexturesUsed[$10] |= target_mask;
+ state->prog->ShadowSamplers |= shadow_tex;
+ }
+ }
;
texImageUnit: TEXTURE_UNIT optTexImageUnitNum
@@ -472,21 +531,58 @@ SWZ_instruction: SWZ maskedDstReg ',' srcReg ',' extendedSwizzle
$4.Base.Swizzle = $6.swizzle;
$4.Base.Negate = $6.mask;
- $$ = asm_instruction_ctor(OPCODE_SWZ, & $2, & $4, NULL, NULL);
- $$->Base.SaturateMode = $1.SaturateMode;
+ $$ = asm_instruction_copy_ctor(& $1, & $2, & $4, NULL, NULL);
}
;
-scalarSrcReg: optionalSign srcReg scalarSuffix
+scalarSrcReg: optionalSign scalarUse
{
$$ = $2;
if ($1) {
$$.Base.Negate = ~$$.Base.Negate;
}
+ }
+ | optionalSign '|' scalarUse '|'
+ {
+ $$ = $3;
+
+ if (!state->option.NV_fragment) {
+ yyerror(& @2, state, "unexpected character '|'");
+ YYERROR;
+ }
+
+ if ($1) {
+ $$.Base.Negate = ~$$.Base.Negate;
+ }
+
+ $$.Base.Abs = 1;
+ }
+ ;
+
+scalarUse: srcReg scalarSuffix
+ {
+ $$ = $1;
$$.Base.Swizzle = _mesa_combine_swizzles($$.Base.Swizzle,
- $3.swizzle);
+ $2.swizzle);
+ }
+ | paramConstScalarUse
+ {
+ struct asm_symbol temp_sym;
+
+ if (!state->option.NV_fragment) {
+ yyerror(& @1, state, "expected scalar suffix");
+ YYERROR;
+ }
+
+ memset(& temp_sym, 0, sizeof(temp_sym));
+ temp_sym.param_binding_begin = ~0;
+ initialize_symbol_from_const(state->prog, & temp_sym, & $1);
+
+ init_src_reg(& $$);
+ $$.Base.File = PROGRAM_CONSTANT;
+ $$.Base.Index = temp_sym.param_binding_begin;
}
;
@@ -501,12 +597,33 @@ swizzleSrcReg: optionalSign srcReg swizzleSuffix
$$.Base.Swizzle = _mesa_combine_swizzles($$.Base.Swizzle,
$3.swizzle);
}
+ | optionalSign '|' srcReg swizzleSuffix '|'
+ {
+ $$ = $3;
+
+ if (!state->option.NV_fragment) {
+ yyerror(& @2, state, "unexpected character '|'");
+ YYERROR;
+ }
+
+ if ($1) {
+ $$.Base.Negate = ~$$.Base.Negate;
+ }
+
+ $$.Base.Abs = 1;
+ $$.Base.Swizzle = _mesa_combine_swizzles($$.Base.Swizzle,
+ $4.swizzle);
+ }
+
;
-maskedDstReg: dstReg optionalMask
+maskedDstReg: dstReg optionalMask optionalCcMask
{
$$ = $1;
$$.WriteMask = $2.mask;
+ $$.CondMask = $3.CondMask;
+ $$.CondSwizzle = $3.CondSwizzle;
+ $$.CondSrc = $3.CondSrc;
if ($$.File == PROGRAM_OUTPUT) {
/* Technically speaking, this should check that it is in
@@ -589,7 +706,7 @@ extSwizSel: INTEGER
$$.xyzw_valid = 1;
$$.rgba_valid = 1;
}
- | IDENTIFIER
+ | string
{
if (strlen($1) > 1) {
yyerror(& @1, state, "invalid extended swizzle selector");
@@ -639,7 +756,7 @@ extSwizSel: INTEGER
}
;
-srcReg: IDENTIFIER /* temporaryReg | progParamSingle */
+srcReg: USED_IDENTIFIER /* temporaryReg | progParamSingle */
{
struct asm_symbol *const s = (struct asm_symbol *)
_mesa_symbol_table_find_symbol(state->st, 0, $1);
@@ -729,7 +846,7 @@ dstReg: resultBinding
$$.File = PROGRAM_OUTPUT;
$$.Index = $1;
}
- | IDENTIFIER /* temporaryReg | vertexResultReg */
+ | USED_IDENTIFIER /* temporaryReg | vertexResultReg */
{
struct asm_symbol *const s = (struct asm_symbol *)
_mesa_symbol_table_find_symbol(state->st, 0, $1);
@@ -760,7 +877,7 @@ dstReg: resultBinding
}
;
-progParamArray: IDENTIFIER
+progParamArray: USED_IDENTIFIER
{
struct asm_symbol *const s = (struct asm_symbol *)
_mesa_symbol_table_find_symbol(state->st, 0, $1);
@@ -831,7 +948,7 @@ addrRegNegOffset: INTEGER
}
;
-addrReg: IDENTIFIER
+addrReg: USED_IDENTIFIER
{
struct asm_symbol *const s = (struct asm_symbol *)
_mesa_symbol_table_find_symbol(state->st, 0, $1);
@@ -884,6 +1001,82 @@ optionalMask: MASK4 | MASK3 | MASK2 | MASK1
| { $$.swizzle = SWIZZLE_NOOP; $$.mask = WRITEMASK_XYZW; }
;
+optionalCcMask: '(' ccTest ')'
+ {
+ $$ = $2;
+ }
+ | '(' ccTest2 ')'
+ {
+ $$ = $2;
+ }
+ |
+ {
+ $$.CondMask = COND_TR;
+ $$.CondSwizzle = SWIZZLE_NOOP;
+ $$.CondSrc = 0;
+ }
+ ;
+
+ccTest: ccMaskRule swizzleSuffix
+ {
+ $$ = $1;
+ $$.CondSwizzle = $2.swizzle;
+ }
+ ;
+
+ccTest2: ccMaskRule2 swizzleSuffix
+ {
+ $$ = $1;
+ $$.CondSwizzle = $2.swizzle;
+ }
+ ;
+
+ccMaskRule: IDENTIFIER
+ {
+ const int cond = _mesa_parse_cc($1);
+ if ((cond == 0) || ($1[2] != '\0')) {
+ char *const err_str =
+ make_error_string("invalid condition code \"%s\"", $1);
+
+ yyerror(& @1, state, (err_str != NULL)
+ ? err_str : "invalid condition code");
+
+ if (err_str != NULL) {
+ _mesa_free(err_str);
+ }
+
+ YYERROR;
+ }
+
+ $$.CondMask = cond;
+ $$.CondSwizzle = SWIZZLE_NOOP;
+ $$.CondSrc = 0;
+ }
+ ;
+
+ccMaskRule2: USED_IDENTIFIER
+ {
+ const int cond = _mesa_parse_cc($1);
+ if ((cond == 0) || ($1[2] != '\0')) {
+ char *const err_str =
+ make_error_string("invalid condition code \"%s\"", $1);
+
+ yyerror(& @1, state, (err_str != NULL)
+ ? err_str : "invalid condition code");
+
+ if (err_str != NULL) {
+ _mesa_free(err_str);
+ }
+
+ YYERROR;
+ }
+
+ $$.CondMask = cond;
+ $$.CondSwizzle = SWIZZLE_NOOP;
+ $$.CondSrc = 0;
+ }
+ ;
+
namingStatement: ATTRIB_statement
| PARAM_statement
| TEMP_statement
@@ -1712,7 +1905,46 @@ optionalSign: '+' { $$ = FALSE; }
| { $$ = FALSE; }
;
-TEMP_statement: TEMP { $<integer>$ = $1; } varNameList
+TEMP_statement: optVarSize TEMP { $<integer>$ = $2; } varNameList
+ ;
+
+optVarSize: string
+ {
+ /* NV_fragment_program_option defines the size qualifiers in a
+ * fairly broken way. "SHORT" or "LONG" can optionally be used
+ * before TEMP or OUTPUT. However, neither is a reserved word!
+ * This means that we have to parse it as an identifier, then check
+ * to make sure it's one of the valid values. *sigh*
+ *
+ * In addition, the grammar in the extension spec does *not* allow
+ * the size specifier to be optional, but all known implementations
+ * do.
+ */
+ if (!state->option.NV_fragment) {
+ yyerror(& @1, state, "unexpected IDENTIFIER");
+ YYERROR;
+ }
+
+ if (strcmp("SHORT", $1) == 0) {
+ } else if (strcmp("LONG", $1) == 0) {
+ } else {
+ char *const err_str =
+ make_error_string("invalid storage size specifier \"%s\"",
+ $1);
+
+ yyerror(& @1, state, (err_str != NULL)
+ ? err_str : "invalid storage size specifier");
+
+ if (err_str != NULL) {
+ _mesa_free(err_str);
+ }
+
+ YYERROR;
+ }
+ }
+ |
+ {
+ }
;
ADDRESS_statement: ADDRESS { $<integer>$ = $1; } varNameList
@@ -1732,15 +1964,15 @@ varNameList: varNameList ',' IDENTIFIER
}
;
-OUTPUT_statement: OUTPUT IDENTIFIER '=' resultBinding
+OUTPUT_statement: optVarSize OUTPUT IDENTIFIER '=' resultBinding
{
struct asm_symbol *const s =
- declare_variable(state, $2, at_output, & @2);
+ declare_variable(state, $3, at_output, & @3);
if (s == NULL) {
YYERROR;
} else {
- s->output_binding = $4;
+ s->output_binding = $5;
}
}
;
@@ -1907,7 +2139,7 @@ legacyTexUnitNum: INTEGER
}
;
-ALIAS_statement: ALIAS IDENTIFIER '=' IDENTIFIER
+ALIAS_statement: ALIAS IDENTIFIER '=' USED_IDENTIFIER
{
struct asm_symbol *exist = (struct asm_symbol *)
_mesa_symbol_table_find_symbol(state->st, 0, $2);
@@ -1928,8 +2160,54 @@ ALIAS_statement: ALIAS IDENTIFIER '=' IDENTIFIER
}
;
+string: IDENTIFIER
+ | USED_IDENTIFIER
+ ;
+
%%
+void
+asm_instruction_set_operands(struct asm_instruction *inst,
+ const struct prog_dst_register *dst,
+ const struct asm_src_register *src0,
+ const struct asm_src_register *src1,
+ const struct asm_src_register *src2)
+{
+ /* In the core ARB extensions only the KIL instruction doesn't have a
+ * destination register.
+ */
+ if (dst == NULL) {
+ init_dst_reg(& inst->Base.DstReg);
+ } else {
+ inst->Base.DstReg = *dst;
+ }
+
+ /* The only instruction that doesn't have any source registers is the
+ * condition-code based KIL instruction added by NV_fragment_program_option.
+ */
+ if (src0 != NULL) {
+ inst->Base.SrcReg[0] = src0->Base;
+ inst->SrcReg[0] = *src0;
+ } else {
+ init_src_reg(& inst->SrcReg[0]);
+ }
+
+ if (src1 != NULL) {
+ inst->Base.SrcReg[1] = src1->Base;
+ inst->SrcReg[1] = *src1;
+ } else {
+ init_src_reg(& inst->SrcReg[1]);
+ }
+
+ if (src2 != NULL) {
+ inst->Base.SrcReg[2] = src2->Base;
+ inst->SrcReg[2] = *src2;
+ } else {
+ init_src_reg(& inst->SrcReg[2]);
+ }
+}
+
+
struct asm_instruction *
asm_instruction_ctor(gl_inst_opcode op,
const struct prog_dst_register *dst,
@@ -1937,37 +2215,37 @@ asm_instruction_ctor(gl_inst_opcode op,
const struct asm_src_register *src1,
const struct asm_src_register *src2)
{
- struct asm_instruction *inst = calloc(1, sizeof(struct asm_instruction));
+ struct asm_instruction *inst = CALLOC_STRUCT(asm_instruction);
if (inst) {
_mesa_init_instructions(& inst->Base, 1);
inst->Base.Opcode = op;
- /* In the core ARB extensions only the KIL instruction doesn't have a
- * destination register.
- */
- if (dst == NULL) {
- init_dst_reg(& inst->Base.DstReg);
- } else {
- inst->Base.DstReg = *dst;
- }
+ asm_instruction_set_operands(inst, dst, src0, src1, src2);
+ }
- inst->Base.SrcReg[0] = src0->Base;
- inst->SrcReg[0] = *src0;
+ return inst;
+}
- if (src1 != NULL) {
- inst->Base.SrcReg[1] = src1->Base;
- inst->SrcReg[1] = *src1;
- } else {
- init_src_reg(& inst->SrcReg[1]);
- }
- if (src2 != NULL) {
- inst->Base.SrcReg[2] = src2->Base;
- inst->SrcReg[2] = *src2;
- } else {
- init_src_reg(& inst->SrcReg[2]);
- }
+struct asm_instruction *
+asm_instruction_copy_ctor(const struct prog_instruction *base,
+ const struct prog_dst_register *dst,
+ const struct asm_src_register *src0,
+ const struct asm_src_register *src1,
+ const struct asm_src_register *src2)
+{
+ struct asm_instruction *inst = CALLOC_STRUCT(asm_instruction);
+
+ if (inst) {
+ _mesa_init_instructions(& inst->Base, 1);
+ inst->Base.Opcode = base->Opcode;
+ inst->Base.CondUpdate = base->CondUpdate;
+ inst->Base.CondDst = base->CondDst;
+ inst->Base.SaturateMode = base->SaturateMode;
+ inst->Base.Precision = base->Precision;
+
+ asm_instruction_set_operands(inst, dst, src0, src1, src2);
}
return inst;