#include <string.h>
#include "main/mtypes.h"
+#include "main/imports.h"
+#include "program.h"
#include "prog_parameter.h"
#include "prog_parameter_layout.h"
#include "prog_statevars.h"
static struct asm_symbol *declare_variable(struct asm_parser_state *state,
char *name, enum asm_type t, struct YYLTYPE *locp);
+static int add_state_reference(struct gl_program_parameter_list *param_list,
+ const gl_state_index tokens[STATE_LENGTH]);
+
static int initialize_symbol_from_state(struct gl_program *prog,
struct asm_symbol *param_var, const gl_state_index tokens[STATE_LENGTH]);
static int yyparse(struct asm_parser_state *state);
+static char *make_error_string(const char *fmt, ...);
+
static void yyerror(struct YYLTYPE *locp, struct asm_parser_state *state,
const char *s);
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)
unsigned attrib;
int integer;
float real;
- unsigned state[5];
+ gl_state_index state[STATE_LENGTH];
int negate;
struct asm_vector vector;
gl_inst_opcode opcode;
+
+ struct {
+ unsigned swz;
+ unsigned rgba_valid:1;
+ unsigned xyzw_valid:1;
+ unsigned negate:1;
+ } ext_swizzle;
}
%token ARBvp_10 ARBfp_10
/* 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
%token MATERIAL MAT_PROGRAM MATRIX MATRIXINDEX MODELVIEW MVP
%token NORMAL
%token OBJECT
-%token PALETTE PARAMS PLANE POINT POINTSIZE POSITION PRIMARY PROGRAM PROJECTION
+%token PALETTE PARAMS PLANE POINT_TOK POINTSIZE POSITION PRIMARY PROGRAM PROJECTION
%token RANGE RESULT ROW
-%token SCENECOLOR SECONDARY SHININESS SIZE SPECULAR SPOT STATE
+%token SCENECOLOR SECONDARY SHININESS SIZE_TOK SPECULAR SPOT STATE
%token TEXCOORD TEXENV TEXGEN TEXGEN_Q TEXGEN_R TEXGEN_S TEXGEN_T TEXTURE TRANSPOSE
%token TEXTURE_UNIT TEX_1D TEX_2D TEX_3D TEX_CUBE TEX_RECT
+%token TEX_SHADOW1D TEX_SHADOW2D TEX_SHADOWRECT
+%token TEX_ARRAY1D TEX_ARRAY2D TEX_ARRAYSHADOW1D TEX_ARRAYSHADOW2D
%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
%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 <swiz_mask> scalarSuffix swizzleSuffix extendedSwizzle extSwizComp
+%type <src_reg> srcReg scalarUse scalarSrcReg swizzleSrcReg
+%type <swiz_mask> scalarSuffix swizzleSuffix extendedSwizzle
+%type <ext_swizzle> extSwizComp extSwizSel
%type <swiz_mask> optionalMask
-%type <integer> extSwizSel
%type <sym> progParamArray
%type <integer> addrRegRelOffset addrRegPosOffset addrRegNegOffset
%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
%type <state> stateLightItem stateLightModelItem stateLightProdItem
%type <state> stateTexGenItem stateFogItem stateClipPlaneItem statePointItem
%type <state> stateMatrixItem stateMatrixRow stateMatrixRows
-%type <state> stateTexEnvItem
+%type <state> stateTexEnvItem stateDepthItem
%type <state> stateLModProperty
%type <state> stateMatrixName optMatrixRows
yyerror(& @1, state, "invalid vertex program header");
}
state->mode = ARB_fragment;
+
+ state->option.TexRect =
+ (state->ctx->Extensions.NV_texture_rectangle != GL_FALSE);
}
;
|
;
-option: OPTION IDENTIFIER ';'
+option: OPTION string ';'
{
int valid = 0;
if (!valid) {
- yyerror(& @2, state, "invalid option string");
+ const char *const err_str = (state->mode == ARB_vertex)
+ ? "invalid ARB vertex program option"
+ : "invalid ARB fragment program option";
+
+ yyerror(& @2, state, err_str);
YYERROR;
}
}
;
instruction: ALU_instruction
+ {
+ $$ = $1;
+ state->prog->NumAluInstructions++;
+ }
| TexInstruction
+ {
+ $$ = $1;
+ state->prog->NumTexInstructions++;
+ }
;
ALU_instruction: ARL_instruction
TexInstruction: SAMPLE_instruction
| KIL_instruction
+ | TXD_instruction
;
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) {
- $$->Base.SaturateMode = $1.SaturateMode;
+ const GLbitfield tex_mask = (1U << $6);
+ GLbitfield shadow_tex = 0;
+ GLbitfield target_mask = 0;
+
+
$$->Base.TexSrcUnit = $6;
- $$->Base.TexSrcTarget = $8;
+
+ if ($8 < 0) {
+ shadow_tex = tex_mask;
+
+ $$->Base.TexSrcTarget = -$8;
+ $$->Base.TexShadow = 1;
+ } else {
+ $$->Base.TexSrcTarget = $8;
+ }
+
+ 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[$6] != 0)
+ && ((state->prog->TexturesUsed[$6] != target_mask)
+ || ((state->prog->ShadowSamplers & tex_mask)
+ != shadow_tex))) {
+ yyerror(& @8, state,
+ "multiple targets used on one texture image unit");
+ YYERROR;
+ }
+
+
+ state->prog->TexturesUsed[$6] |= target_mask;
+ state->prog->ShadowSamplers |= shadow_tex;
}
}
;
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;
+ }
}
;
| TEX_3D { $$ = TEXTURE_3D_INDEX; }
| TEX_CUBE { $$ = TEXTURE_CUBE_INDEX; }
| TEX_RECT { $$ = TEXTURE_RECT_INDEX; }
+ | TEX_SHADOW1D { $$ = -TEXTURE_1D_INDEX; }
+ | TEX_SHADOW2D { $$ = -TEXTURE_2D_INDEX; }
+ | TEX_SHADOWRECT { $$ = -TEXTURE_RECT_INDEX; }
+ | TEX_ARRAY1D { $$ = TEXTURE_1D_ARRAY_INDEX; }
+ | TEX_ARRAY2D { $$ = TEXTURE_2D_ARRAY_INDEX; }
+ | TEX_ARRAYSHADOW1D { $$ = -TEXTURE_1D_ARRAY_INDEX; }
+ | TEX_ARRAYSHADOW2D { $$ = -TEXTURE_2D_ARRAY_INDEX; }
;
SWZ_instruction: SWZ maskedDstReg ',' srcReg ',' extendedSwizzle
* FIXME: to the existing swizzle?
*/
$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;
}
;
$$.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
extendedSwizzle: extSwizComp ',' extSwizComp ',' extSwizComp ',' extSwizComp
{
- $$.swizzle = MAKE_SWIZZLE4($1.swizzle, $3.swizzle,
- $5.swizzle, $7.swizzle);
- $$.mask = ($1.mask) | ($3.mask << 1) | ($5.mask << 2)
- | ($7.mask << 3);
+ const unsigned xyzw_valid =
+ ($1.xyzw_valid << 0)
+ | ($3.xyzw_valid << 1)
+ | ($5.xyzw_valid << 2)
+ | ($7.xyzw_valid << 3);
+ const unsigned rgba_valid =
+ ($1.rgba_valid << 0)
+ | ($3.rgba_valid << 1)
+ | ($5.rgba_valid << 2)
+ | ($7.rgba_valid << 3);
+
+ /* All of the swizzle components have to be valid in either RGBA
+ * or XYZW. Note that 0 and 1 are valid in both, so both masks
+ * can have some bits set.
+ *
+ * We somewhat deviate from the spec here. It would be really hard
+ * to figure out which component is the error, and there probably
+ * isn't a lot of benefit.
+ */
+ if ((rgba_valid != 0x0f) && (xyzw_valid != 0x0f)) {
+ yyerror(& @1, state, "cannot combine RGBA and XYZW swizzle "
+ "components");
+ YYERROR;
+ }
+
+ $$.swizzle = MAKE_SWIZZLE4($1.swz, $3.swz, $5.swz, $7.swz);
+ $$.mask = ($1.negate) | ($3.negate << 1) | ($5.negate << 2)
+ | ($7.negate << 3);
}
;
extSwizComp: optionalSign extSwizSel
{
- $$.swizzle = $2;
- $$.mask = ($1) ? 1 : 0;
+ $$ = $2;
+ $$.negate = ($1) ? 1 : 0;
}
;
YYERROR;
}
- $$ = ($1 == 0) ? SWIZZLE_ZERO : SWIZZLE_ONE;
+ $$.swz = ($1 == 0) ? SWIZZLE_ZERO : SWIZZLE_ONE;
+
+ /* 0 and 1 are valid for both RGBA swizzle names and XYZW
+ * swizzle names.
+ */
+ $$.xyzw_valid = 1;
+ $$.rgba_valid = 1;
}
- | IDENTIFIER
+ | string
{
if (strlen($1) > 1) {
yyerror(& @1, state, "invalid extended swizzle selector");
switch ($1[0]) {
case 'x':
- $$ = SWIZZLE_X;
+ $$.swz = SWIZZLE_X;
+ $$.xyzw_valid = 1;
break;
case 'y':
- $$ = SWIZZLE_Y;
+ $$.swz = SWIZZLE_Y;
+ $$.xyzw_valid = 1;
break;
case 'z':
- $$ = SWIZZLE_Z;
+ $$.swz = SWIZZLE_Z;
+ $$.xyzw_valid = 1;
break;
case 'w':
- $$ = SWIZZLE_W;
+ $$.swz = SWIZZLE_W;
+ $$.xyzw_valid = 1;
+ break;
+
+ case 'r':
+ $$.swz = SWIZZLE_X;
+ $$.rgba_valid = 1;
+ break;
+ case 'g':
+ $$.swz = SWIZZLE_Y;
+ $$.rgba_valid = 1;
break;
+ case 'b':
+ $$.swz = SWIZZLE_Z;
+ $$.rgba_valid = 1;
+ break;
+ case 'a':
+ $$.swz = SWIZZLE_W;
+ $$.rgba_valid = 1;
+ break;
+
default:
yyerror(& @1, state, "invalid extended swizzle selector");
YYERROR;
}
;
-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);
$$.Base.Index = s->param_binding_begin;
break;
case at_attrib:
- $$.Base.File = PROGRAM_INPUT;
- $$.Base.Index = s->attrib_binding;
- state->prog->InputsRead |= (1U << $$.Base.Index);
+ $$.Base.File = PROGRAM_INPUT;
+ $$.Base.Index = s->attrib_binding;
+ state->prog->InputsRead |= (1U << $$.Base.Index);
- if (!validate_inputs(& @1, state)) {
- YYERROR;
- }
- break;
+ if (!validate_inputs(& @1, state)) {
+ YYERROR;
+ }
+ break;
default:
YYERROR;
| progParamArray '[' progParamArrayMem ']'
{
if (! $3.Base.RelAddr
- && ($3.Base.Index >= $1->param_binding_length)) {
+ && ((unsigned) $3.Base.Index >= $1->param_binding_length)) {
yyerror(& @3, state, "out of bounds array access");
YYERROR;
}
$$.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);
}
init_dst_reg(& $$);
- if (s->type == at_temp) {
+ switch (s->type) {
+ case at_temp:
$$.File = PROGRAM_TEMPORARY;
$$.Index = s->temp_binding;
- } else {
+ break;
+ case at_output:
+ $$.File = PROGRAM_OUTPUT;
+ $$.Index = s->output_binding;
+ break;
+ default:
$$.File = s->param_binding_type;
$$.Index = s->param_binding_begin;
+ break;
}
}
;
-progParamArray: IDENTIFIER
+progParamArray: USED_IDENTIFIER
{
struct asm_symbol *const s = (struct asm_symbol *)
_mesa_symbol_table_find_symbol(state->st, 0, $1);
addrRegPosOffset: INTEGER
{
if (($1 < 0) || ($1 > 63)) {
- yyerror(& @1, state,
- "relative address offset too large (positive)");
+ char s[100];
+ _mesa_snprintf(s, sizeof(s),
+ "relative address offset too large (%d)", $1);
+ yyerror(& @1, state, s);
YYERROR;
} else {
$$ = $1;
addrRegNegOffset: INTEGER
{
if (($1 < 0) || ($1 > 64)) {
- yyerror(& @1, state,
- "relative address offset too large (negative)");
+ char s[100];
+ _mesa_snprintf(s, sizeof(s),
+ "relative address offset too large (%d)", $1);
+ yyerror(& @1, state, s);
YYERROR;
} else {
$$ = $1;
}
;
-addrReg: IDENTIFIER
+addrReg: USED_IDENTIFIER
{
struct asm_symbol *const s = (struct asm_symbol *)
_mesa_symbol_table_find_symbol(state->st, 0, $1);
| { $$.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
}
| COLOR optColorType
{
+ if (!state->ctx->Extensions.EXT_secondary_color) {
+ yyerror(& @2, state, "GL_EXT_secondary_color not supported");
+ YYERROR;
+ }
+
$$ = VERT_ATTRIB_COLOR0 + $2;
}
| FOGCOORD
{
+ if (!state->ctx->Extensions.EXT_fog_coord) {
+ yyerror(& @1, state, "GL_EXT_fog_coord not supported");
+ YYERROR;
+ }
+
$$ = VERT_ATTRIB_FOG;
}
| TEXCOORD optTexCoordUnitNum
}
| MATRIXINDEX '[' vtxWeightNum ']'
{
+ yyerror(& @1, state, "GL_ARB_matrix_palette not supported");
YYERROR;
}
| VTXATTRIB '[' vtxAttribNum ']'
vtxAttribNum: INTEGER
{
- if ($1 >= state->limits->MaxAttribs) {
+ if ((unsigned) $1 >= state->limits->MaxAttribs) {
yyerror(& @1, state, "invalid vertex attribute reference");
YYERROR;
}
PARAM_multipleStmt: PARAM IDENTIFIER '[' optArraySize ']' paramMultipleInit
{
- if (($4 != 0) && ($4 != $6.param_binding_length)) {
+ if (($4 != 0) && ((unsigned) $4 != $6.param_binding_length)) {
yyerror(& @4, state,
"parameter array size and number of bindings must match");
YYERROR;
}
| INTEGER
{
- if (($1 < 1) || ($1 >= state->limits->MaxParameters)) {
+ if (($1 < 1) || ((unsigned) $1 > state->limits->MaxParameters)) {
yyerror(& @1, state, "invalid parameter array size");
YYERROR;
} else {
| STATE stateClipPlaneItem { memcpy($$, $2, sizeof($$)); }
| STATE statePointItem { memcpy($$, $2, sizeof($$)); }
| STATE stateMatrixRow { memcpy($$, $2, sizeof($$)); }
+ | STATE stateDepthItem { memcpy($$, $2, sizeof($$)); }
;
stateMaterialItem: MATERIAL optFaceType stateMatProperty
}
| ATTENUATION
{
+ if (!state->ctx->Extensions.EXT_point_parameters) {
+ yyerror(& @1, state, "GL_ARB_point_parameters not supported");
+ YYERROR;
+ }
+
$$ = STATE_ATTENUATION;
}
| SPOT stateSpotProperty
stateLightNumber: INTEGER
{
- if ($1 >= state->MaxLights) {
+ if ((unsigned) $1 >= state->MaxLights) {
yyerror(& @1, state, "invalid light selector");
YYERROR;
}
stateClipPlaneNum: INTEGER
{
- if ($1 >= state->MaxClipPlanes) {
+ if ((unsigned) $1 >= state->MaxClipPlanes) {
yyerror(& @1, state, "invalid clip plane selector");
YYERROR;
}
}
;
-statePointItem: POINT statePointProperty
+statePointItem: POINT_TOK statePointProperty
{
memset($$, 0, sizeof($$));
$$[0] = $2;
}
;
-statePointProperty: SIZE
+statePointProperty: SIZE_TOK
{
$$ = STATE_POINT_SIZE;
}
}
| PALETTE '[' statePaletteMatNum ']'
{
+ yyerror(& @1, state, "GL_ARB_matrix_palette not supported");
YYERROR;
}
| MAT_PROGRAM '[' stateProgramMatNum ']'
{
$$ = 0;
}
- | stateModMatNum
+ | '[' stateModMatNum ']'
{
- $$ = $1;
+ $$ = $2;
}
;
stateModMatNum: INTEGER
;
stateProgramMatNum: INTEGER
{
- if ($1 >= state->MaxProgramMatrices) {
+ if ((unsigned) $1 >= state->MaxProgramMatrices) {
yyerror(& @1, state, "invalid program matrix selector");
YYERROR;
}
}
;
+stateDepthItem: DEPTH RANGE
+ {
+ memset($$, 0, sizeof($$));
+ $$[0] = STATE_DEPTH_RANGE;
+ }
+ ;
programSingleItem: progEnvParam | progLocalParam;
progEnvParamNum: INTEGER
{
- if ($1 >= state->limits->MaxEnvParams) {
+ if ((unsigned) $1 >= state->limits->MaxEnvParams) {
yyerror(& @1, state, "invalid environment parameter reference");
YYERROR;
}
progLocalParamNum: INTEGER
{
- if ($1 >= state->limits->MaxLocalParams) {
+ if ((unsigned) $1 >= state->limits->MaxLocalParams) {
yyerror(& @1, state, "invalid local parameter reference");
YYERROR;
}
paramConstScalarDecl: signedFloatConstant
{
- $$.count = 1;
+ $$.count = 4;
$$.data[0] = $1;
+ $$.data[1] = $1;
+ $$.data[2] = $1;
+ $$.data[3] = $1;
}
;
{
$$.count = 1;
$$.data[0] = $1;
+ $$.data[1] = $1;
+ $$.data[2] = $1;
+ $$.data[3] = $1;
}
| INTEGER
{
$$.count = 1;
$$.data[0] = (float) $1;
+ $$.data[1] = (float) $1;
+ $$.data[2] = (float) $1;
+ $$.data[3] = (float) $1;
}
;
paramConstVector: '{' signedFloatConstant '}'
{
- $$.count = 1;
+ $$.count = 4;
$$.data[0] = $2;
+ $$.data[1] = 0.0f;
+ $$.data[2] = 0.0f;
+ $$.data[3] = 1.0f;
}
| '{' signedFloatConstant ',' signedFloatConstant '}'
{
- $$.count = 2;
+ $$.count = 4;
$$.data[0] = $2;
$$.data[1] = $4;
+ $$.data[2] = 0.0f;
+ $$.data[3] = 1.0f;
}
| '{' signedFloatConstant ',' signedFloatConstant ','
signedFloatConstant '}'
{
- $$.count = 3;
+ $$.count = 4;
$$.data[0] = $2;
$$.data[1] = $4;
- $$.data[1] = $6;
+ $$.data[2] = $6;
+ $$.data[3] = 1.0f;
}
| '{' signedFloatConstant ',' signedFloatConstant ','
signedFloatConstant ',' signedFloatConstant '}'
$$.count = 4;
$$.data[0] = $2;
$$.data[1] = $4;
- $$.data[1] = $6;
- $$.data[1] = $8;
+ $$.data[2] = $6;
+ $$.data[3] = $8;
}
;
| { $$ = 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
}
;
-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;
}
}
;
texCoordUnitNum: INTEGER
{
- if ($1 >= state->MaxTextureCoordUnits) {
+ if ((unsigned) $1 >= state->MaxTextureCoordUnits) {
yyerror(& @1, state, "invalid texture coordinate unit selector");
YYERROR;
}
texImageUnitNum: INTEGER
{
- if ($1 >= state->MaxTextureImageUnits) {
+ if ((unsigned) $1 >= state->MaxTextureImageUnits) {
yyerror(& @1, state, "invalid texture image unit selector");
YYERROR;
}
legacyTexUnitNum: INTEGER
{
- if ($1 >= state->MaxTextureUnits) {
+ if ((unsigned) $1 >= state->MaxTextureUnits) {
yyerror(& @1, state, "invalid texture unit selector");
YYERROR;
}
}
;
-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);
"undefined variable binding in ALIAS statement");
YYERROR;
} else {
- _mesa_symbol_table_add_symbol(state->st, 0, $2, target);
+ _mesa_symbol_table_add_symbol(state->st, 0, strdup($2), target);
}
}
;
+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,
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, 1);
+ _mesa_init_instructions(& inst->Base, 1);
inst->Base.Opcode = op;
- inst->Base.DstReg = *dst;
- inst->Base.SrcReg[0] = src0->Base;
- inst->SrcReg[0] = *src0;
+ asm_instruction_set_operands(inst, dst, src0, src1, src2);
+ }
- if (src1 != NULL) {
- inst->Base.SrcReg[1] = src1->Base;
- inst->SrcReg[1] = *src1;
- } else {
- init_src_reg(& inst->SrcReg[1]);
- }
+ return inst;
+}
- 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;
if (exist != NULL) {
yyerror(locp, state, "redeclared identifier");
} else {
- s = calloc(1, sizeof(struct asm_symbol));
- s->name = name;
+ const size_t name_len = strlen(name);
+
+ s = calloc(1, sizeof(struct asm_symbol) + name_len + 1);
+ s->name = (char *)(s + 1);
s->type = t;
+ memcpy((char *) s->name, name, name_len + 1);
+
switch (t) {
case at_temp:
if (state->prog->NumTemporaries >= state->limits->MaxTemps) {
}
_mesa_symbol_table_add_symbol(state->st, 0, s->name, s);
+ s->next = state->sym;
+ state->sym = s;
}
return s;
name = _mesa_program_state_string(tokens);
index = _mesa_add_parameter(param_list, PROGRAM_STATE_VAR, name,
- size, GL_NONE,
- NULL, (gl_state_index *) tokens, 0x0);
+ size, GL_NONE, NULL, tokens, 0x0);
param_list->StateFlags |= _mesa_program_state_flags(tokens);
/* free name string here since we duplicated it in add_parameter() */
memcpy(state_tokens, tokens, sizeof(state_tokens));
param_var->type = at_param;
+ param_var->param_binding_type = PROGRAM_STATE_VAR;
/* If we are adding a STATE_MATRIX that has multiple rows, we need to
* unroll it and call add_state_reference() for each row
|| (state_tokens[1] == STATE_LOCAL));
param_var->type = at_param;
+ param_var->param_binding_type = (state_tokens[1] == STATE_ENV)
+ ? PROGRAM_ENV_PARAM : PROGRAM_LOCAL_PARAM;
/* If we are adding a STATE_ENV or STATE_LOCAL that has multiple elements,
* we need to unroll it and call add_state_reference() for each row
NULL, 0x0);
param_var->type = at_param;
+ param_var->param_binding_type = PROGRAM_CONSTANT;
if (param_var->param_binding_begin == ~0U)
param_var->param_binding_begin = idx;
}
+char *
+make_error_string(const char *fmt, ...)
+{
+ int length;
+ char *str;
+ va_list args;
+
+ va_start(args, fmt);
+
+ /* Call vsnprintf once to determine how large the final string is. Call it
+ * again to do the actual formatting. from the vsnprintf manual page:
+ *
+ * Upon successful return, these functions return the number of
+ * characters printed (not including the trailing '\0' used to end
+ * output to strings).
+ */
+ length = 1 + vsnprintf(NULL, 0, fmt, args);
+
+ str = _mesa_malloc(length);
+ if (str) {
+ vsnprintf(str, length, fmt, args);
+ }
+
+ va_end(args);
+
+ return str;
+}
+
+
void
yyerror(YYLTYPE *locp, struct asm_parser_state *state, const char *s)
{
- (void) state;
+ char *err_str;
+
- fprintf(stderr, "line %u, char %u: error: %s\n", locp->first_line,
- locp->first_column, s);
+ err_str = make_error_string("glProgramStringARB(%s)\n", s);
+ if (err_str) {
+ _mesa_error(state->ctx, GL_INVALID_OPERATION, err_str);
+ _mesa_free(err_str);
+ }
+
+ err_str = make_error_string("line %u, char %u: error: %s\n",
+ locp->first_line, locp->first_column, s);
+ _mesa_set_program_error(state->ctx, locp->position, err_str);
+
+ if (err_str) {
+ _mesa_free(err_str);
+ }
}
+
GLboolean
_mesa_parse_arb_program(GLcontext *ctx, GLenum target, const GLubyte *str,
GLsizei len, struct asm_parser_state *state)
{
- struct gl_program_constants limits;
struct asm_instruction *inst;
unsigned i;
GLubyte *strz;
+ GLboolean result = GL_FALSE;
+ void *temp;
+ struct asm_symbol *sym;
+ state->ctx = ctx;
state->prog->Target = target;
state->prog->Parameters = _mesa_new_parameter_list();
_mesa_memcpy (strz, str, len);
strz[len] = '\0';
+ if (state->prog->String != NULL) {
+ _mesa_free(state->prog->String);
+ state->prog->String = NULL;
+ }
+
state->prog->String = strz;
state->st = _mesa_symbol_table_ctor();
- /* All of these limits should come from ctx.
- */
- limits.MaxInstructions = 128;
- limits.MaxAluInstructions = 128;
- limits.MaxTexInstructions = 128;
- limits.MaxTexIndirections = 128;
- limits.MaxAttribs = 16;
- limits.MaxTemps = 128;
- limits.MaxAddressRegs = 1;
- limits.MaxParameters = 128;
- limits.MaxLocalParams = 256;
- limits.MaxEnvParams = 128;
- limits.MaxNativeInstructions = 128;
- limits.MaxNativeAluInstructions = 128;
- limits.MaxNativeTexInstructions = 128;
- limits.MaxNativeTexIndirections = 128;
- limits.MaxNativeAttribs = 16;
- limits.MaxNativeTemps = 128;
- limits.MaxNativeAddressRegs = 1;
- limits.MaxNativeParameters = 128;
- limits.MaxUniformComponents = 0;
-
- state->limits = & limits;
-
- state->MaxTextureImageUnits = 16;
- state->MaxTextureCoordUnits = 8;
- state->MaxTextureUnits = 8;
- state->MaxClipPlanes = 6;
- state->MaxLights = 8;
- state->MaxProgramMatrices = 8;
+ state->limits = (target == GL_VERTEX_PROGRAM_ARB)
+ ? & ctx->Const.VertexProgram
+ : & ctx->Const.FragmentProgram;
+
+ state->MaxTextureImageUnits = ctx->Const.MaxTextureImageUnits;
+ state->MaxTextureCoordUnits = ctx->Const.MaxTextureCoordUnits;
+ state->MaxTextureUnits = ctx->Const.MaxTextureUnits;
+ state->MaxClipPlanes = ctx->Const.MaxClipPlanes;
+ state->MaxLights = ctx->Const.MaxLights;
+ state->MaxProgramMatrices = ctx->Const.MaxProgramMatrices;
state->state_param_enum = (target == GL_VERTEX_PROGRAM_ARB)
? STATE_VERTEX_PROGRAM : STATE_FRAGMENT_PROGRAM;
_mesa_program_lexer_dtor(state->scanner);
+ if (ctx->Program.ErrorPos != -1) {
+ goto error;
+ }
+
if (! _mesa_layout_parameters(state)) {
- fprintf(stderr, "error: layout\n");
- return GL_FALSE;
+ struct YYLTYPE loc;
+
+ loc.first_line = 0;
+ loc.first_column = 0;
+ loc.position = len;
+
+ yyerror(& loc, state, "invalid PARAM usage");
+ goto error;
}
struct asm_instruction *const temp = inst->next;
state->prog->Instructions[i] = inst->Base;
- _mesa_free(inst);
-
inst = temp;
}
}
state->prog->NumInstructions++;
+ state->prog->NumParameters = state->prog->Parameters->NumParameters;
+ state->prog->NumAttributes = _mesa_bitcount(state->prog->InputsRead);
+
/*
* Initialize native counts to logical counts. The device driver may
* change them if program is translated into a hardware program.
state->prog->NumNativeAttributes = state->prog->NumAttributes;
state->prog->NumNativeAddressRegs = state->prog->NumAddressRegs;
- return GL_TRUE;
+ result = GL_TRUE;
+
+error:
+ for (inst = state->inst_head; inst != NULL; inst = temp) {
+ temp = inst->next;
+ _mesa_free(inst);
+ }
+
+ state->inst_head = NULL;
+ state->inst_tail = NULL;
+
+ for (sym = state->sym; sym != NULL; sym = temp) {
+ temp = sym->next;
+
+ _mesa_free(sym);
+ }
+ state->sym = NULL;
+
+ _mesa_symbol_table_dtor(state->st);
+ state->st = NULL;
+
+ if (state->string_dumpster != NULL) {
+ _mesa_free(state->string_dumpster);
+ state->dumpster_size = 0;
+ }
+
+ return result;
}