#include "slang_print.h"
+/** Max iterations to unroll */
+const GLuint MAX_FOR_LOOP_UNROLL_ITERATIONS = 32;
+
+/** Max for-loop body size (in slang operations) to unroll */
+const GLuint MAX_FOR_LOOP_UNROLL_BODY_SIZE = 50;
+
+/** Max for-loop body complexity to unroll.
+ * We'll compute complexity as the product of the number of iterations
+ * and the size of the body. So long-ish loops with very simple bodies
+ * can be unrolled, as well as short loops with larger bodies.
+ */
+const GLuint MAX_FOR_LOOP_UNROLL_COMPLEXITY = 256;
+
+
+
static slang_ir_node *
_slang_gen_operation(slang_assemble_ctx * A, slang_operation *oper);
break;
case SLANG_SPEC_STRUCT:
sz = _slang_field_offset(spec, 0); /* special use */
- if (sz > 4) {
+ if (sz == 1) {
+ /* 1-float structs are actually troublesome to deal with since they
+ * might get placed at R.x, R.y, R.z or R.z. Return size=2 to
+ * ensure the object is placed at R.x
+ */
+ sz = 2;
+ }
+ else if (sz > 4) {
sz = (sz + 3) & ~0x3; /* round up to multiple of four */
}
break;
/**
- * Establish the binding between a slang_ir_node and a slang_variable.
- * Then, allocate/attach a slang_ir_storage object to the IR node if needed.
- * The IR node must be a IR_VAR or IR_VAR_DECL node.
- * \param n the IR node
- * \param var the variable to associate with the IR node
+ * Query variable/array length (number of elements).
+ * This is slightly non-trivial because there are two ways to express
+ * arrays: "float x[3]" vs. "float[3] x".
+ * \return the length of the array for the given variable, or 0 if not an array
*/
-static void
-_slang_attach_storage(slang_ir_node *n, slang_variable *var)
+static GLint
+_slang_array_length(const slang_variable *var)
{
- assert(n);
- assert(var);
- assert(n->Opcode == IR_VAR || n->Opcode == IR_VAR_DECL);
- assert(!n->Var || n->Var == var);
-
- n->Var = var;
-
- if (!n->Store) {
- /* need to setup storage */
- if (n->Var && n->Var->store) {
- /* node storage info = var storage info */
- n->Store = n->Var->store;
- }
- else {
- /* alloc new storage info */
- n->Store = _slang_new_ir_storage(PROGRAM_UNDEFINED, -7, -5);
-#if 0
- printf("%s var=%s Store=%p Size=%d\n", __FUNCTION__,
- (char*) var->a_name,
- (void*) n->Store, n->Store->Size);
-#endif
- if (n->Var)
- n->Var->store = n->Store;
- assert(n->Var->store);
- }
+ if (var->type.array_len > 0) {
+ /* Ex: float[4] x; */
+ return var->type.array_len;
+ }
+ if (var->array_len > 0) {
+ /* Ex: float x[4]; */
+ return var->array_len;
+ }
+ return 0;
+}
+
+
+/**
+ * Compute total size of array give size of element, number of elements.
+ * \return size in floats
+ */
+static GLint
+_slang_array_size(GLint elemSize, GLint arrayLen)
+{
+ GLint total;
+ assert(elemSize > 0);
+ if (arrayLen > 1) {
+ /* round up base type to multiple of 4 */
+ total = ((elemSize + 3) & ~0x3) * MAX2(arrayLen, 1);
+ }
+ else {
+ total = elemSize;
}
+ return total;
}
const struct input_info *inputs
= (target == GL_VERTEX_PROGRAM_ARB) ? vertInputs : fragInputs;
- ASSERT(MAX_TEXTURE_UNITS == 8); /* if this fails, fix vertInputs above */
+ ASSERT(MAX_TEXTURE_COORD_UNITS == 8); /* if this fails, fix vertInputs above */
for (i = 0; inputs[i].Name; i++) {
if (strcmp(inputs[i].Name, name) == 0) {
{ NULL, 0 }
};
static const struct output_info fragOutputs[] = {
- { "gl_FragColor", FRAG_RESULT_COLR },
- { "gl_FragDepth", FRAG_RESULT_DEPR },
+ { "gl_FragColor", FRAG_RESULT_COLOR },
+ { "gl_FragDepth", FRAG_RESULT_DEPTH },
{ "gl_FragData", FRAG_RESULT_DATA0 },
{ NULL, 0 }
};
/* float binary op */
{ "float_power", IR_POW, 1, 2 },
/* texture / sampler */
- { "vec4_tex1d", IR_TEX, 1, 2 },
- { "vec4_texb1d", IR_TEXB, 1, 2 }, /* 1d w/ bias */
- { "vec4_texp1d", IR_TEXP, 1, 2 }, /* 1d w/ projection */
- { "vec4_tex2d", IR_TEX, 1, 2 },
- { "vec4_texb2d", IR_TEXB, 1, 2 }, /* 2d w/ bias */
- { "vec4_texp2d", IR_TEXP, 1, 2 }, /* 2d w/ projection */
- { "vec4_tex3d", IR_TEX, 1, 2 },
- { "vec4_texb3d", IR_TEXB, 1, 2 }, /* 3d w/ bias */
- { "vec4_texp3d", IR_TEXP, 1, 2 }, /* 3d w/ projection */
- { "vec4_texcube", IR_TEX, 1, 2 }, /* cubemap */
- { "vec4_tex_rect", IR_TEX, 1, 2 }, /* rectangle */
- { "vec4_texp_rect", IR_TEX, 1, 2 },/* rectangle w/ projection */
+ { "vec4_tex_1d", IR_TEX, 1, 2 },
+ { "vec4_tex_1d_bias", IR_TEXB, 1, 2 }, /* 1d w/ bias */
+ { "vec4_tex_1d_proj", IR_TEXP, 1, 2 }, /* 1d w/ projection */
+ { "vec4_tex_2d", IR_TEX, 1, 2 },
+ { "vec4_tex_2d_bias", IR_TEXB, 1, 2 }, /* 2d w/ bias */
+ { "vec4_tex_2d_proj", IR_TEXP, 1, 2 }, /* 2d w/ projection */
+ { "vec4_tex_3d", IR_TEX, 1, 2 },
+ { "vec4_tex_3d_bias", IR_TEXB, 1, 2 }, /* 3d w/ bias */
+ { "vec4_tex_3d_proj", IR_TEXP, 1, 2 }, /* 3d w/ projection */
+ { "vec4_tex_cube", IR_TEX, 1, 2 }, /* cubemap */
+ { "vec4_tex_rect", IR_TEX, 1, 2 }, /* rectangle */
+ { "vec4_tex_rect_bias", IR_TEX, 1, 2 }, /* rectangle w/ projection */
+
+ /* texture / sampler but with shadow comparison */
+ { "vec4_tex_1d_shadow", IR_TEX_SH, 1, 2 },
+ { "vec4_tex_1d_bias_shadow", IR_TEXB_SH, 1, 2 },
+ { "vec4_tex_1d_proj_shadow", IR_TEXP_SH, 1, 2 },
+ { "vec4_tex_2d_shadow", IR_TEX_SH, 1, 2 },
+ { "vec4_tex_2d_bias_shadow", IR_TEXB_SH, 1, 2 },
+ { "vec4_tex_2d_proj_shadow", IR_TEXP_SH, 1, 2 },
+ { "vec4_tex_rect_shadow", IR_TEX_SH, 1, 2 },
+ { "vec4_tex_rect_proj_shadow", IR_TEXP_SH, 1, 2 },
/* unary op */
{ "ivec4_to_vec4", IR_I_TO_F, 1, 1 }, /* int[4] to float[4] */
{
slang_ir_node *n = new_node0(IR_VAR);
if (n) {
- _slang_attach_storage(n, var);
+ ASSERT(var);
+ ASSERT(var->store);
+ ASSERT(!n->Store);
+ ASSERT(!n->Var);
+
+ /* Set IR node's Var and Store pointers */
+ n->Var = var;
+ n->Store = var->store;
}
return n;
}
/*_slang_label_delete(A->curFuncEndLabel);*/
A->curFuncEndLabel = prevFuncEndLabel;
+ if (A->pragmas->Debug) {
+ char s[1000];
+ snprintf(s, sizeof(s), "Call/inline %s()", (char *) fun->header.a_name);
+ n->Comment = _slang_strdup(s);
+ }
+
return n;
}
}
-/**
- * Return the default swizzle mask for accessing a variable of the
- * given size (in floats). If size = 1, comp is used to identify
- * which component [0..3] of the register holds the variable.
- */
-static GLuint
-_slang_var_swizzle(GLint size, GLint comp)
-{
- switch (size) {
- case 1:
- return MAKE_SWIZZLE4(comp, comp, comp, comp);
- case 2:
- return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_NIL, SWIZZLE_NIL);
- case 3:
- return MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_NIL);
- default:
- return SWIZZLE_XYZW;
- }
-}
-
-
/**
* Some write-masked assignments are simple, but others are hard.
* Simple example:
}
+#if 0 /* not used, but don't remove just yet */
/**
* Recursively traverse 'oper' to produce a swizzle mask in the event
* of any vector subscripts and swizzle suffixes.
return SWIZZLE_XYZW;
}
}
+#endif
+#if 0
/**
* Recursively descend through swizzle nodes to find the node's storage info.
*/
}
return n->Store;
}
-
+#endif
/**
}
+#if 0
static void
print_funcs(struct slang_function_scope_ *scope, const char *name)
{
if (scope->outer_scope)
print_funcs(scope->outer_scope, name);
}
+#endif
/**
*/
slang_variable *p = slang_variable_scope_grow(fun->parameters);
char name[10];
- snprintf(name, sizeof(name), "p%d", i);
+ _mesa_snprintf(name, sizeof(name), "p%d", i);
p->a_name = slang_atom_pool_atom(A->atoms, name);
p->type.qualifier = SLANG_QUAL_CONST;
p->type.specifier.type = baseType;
/* Create a float/literal IR node encoding the array length */
n = new_node0(IR_FLOAT);
if (n) {
- n->Value[0] = (float) var->array_len;
+ n->Value[0] = (float) _slang_array_length(var);
n->Store = _slang_new_ir_storage(PROGRAM_CONSTANT, -1, 1);
}
return n;
/**
- * Generate for-loop using high-level IR_LOOP instruction.
+ * Recursively count the number of operations rooted at 'oper'.
+ * This gives some kind of indication of the size/complexity of an operation.
+ */
+static GLuint
+sizeof_operation(const slang_operation *oper)
+{
+ if (oper) {
+ GLuint count = 1; /* me */
+ GLuint i;
+ for (i = 0; i < oper->num_children; i++) {
+ count += sizeof_operation(&oper->children[i]);
+ }
+ return count;
+ }
+ else {
+ return 0;
+ }
+}
+
+
+/**
+ * Determine if a for-loop can be unrolled.
+ * At this time, only a rather narrow class of for loops can be unrolled.
+ * See code for details.
+ * When a loop can't be unrolled because it's too large we'll emit a
+ * message to the log.
+ */
+static GLboolean
+_slang_can_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper)
+{
+ GLuint bodySize;
+ GLint start, end;
+ const char *varName;
+ slang_atom varId;
+
+ assert(oper->type == SLANG_OPER_FOR);
+ assert(oper->num_children == 4);
+
+ /* children[0] must be either "int i=constant" or "i=constant" */
+ if (oper->children[0].type == SLANG_OPER_BLOCK_NO_NEW_SCOPE) {
+ slang_variable *var;
+
+ if (oper->children[0].children[0].type != SLANG_OPER_VARIABLE_DECL)
+ return GL_FALSE;
+
+ varId = oper->children[0].children[0].a_id;
+
+ var = _slang_variable_locate(oper->children[0].children[0].locals,
+ varId, GL_TRUE);
+ if (!var)
+ return GL_FALSE;
+ if (!var->initializer)
+ return GL_FALSE;
+ if (var->initializer->type != SLANG_OPER_LITERAL_INT)
+ return GL_FALSE;
+ start = (GLint) var->initializer->literal[0];
+ }
+ else if (oper->children[0].type == SLANG_OPER_EXPRESSION) {
+ if (oper->children[0].children[0].type != SLANG_OPER_ASSIGN)
+ return GL_FALSE;
+ if (oper->children[0].children[0].children[0].type != SLANG_OPER_IDENTIFIER)
+ return GL_FALSE;
+ if (oper->children[0].children[0].children[1].type != SLANG_OPER_LITERAL_INT)
+ return GL_FALSE;
+
+ varId = oper->children[0].children[0].children[0].a_id;
+
+ start = (GLint) oper->children[0].children[0].children[1].literal[0];
+ }
+ else {
+ return GL_FALSE;
+ }
+
+ /* children[1] must be "i<constant" */
+ if (oper->children[1].type != SLANG_OPER_EXPRESSION)
+ return GL_FALSE;
+ if (oper->children[1].children[0].type != SLANG_OPER_LESS)
+ return GL_FALSE;
+ if (oper->children[1].children[0].children[0].type != SLANG_OPER_IDENTIFIER)
+ return GL_FALSE;
+ if (oper->children[1].children[0].children[1].type != SLANG_OPER_LITERAL_INT)
+ return GL_FALSE;
+
+ end = (GLint) oper->children[1].children[0].children[1].literal[0];
+
+ /* children[2] must be "i++" or "++i" */
+ if (oper->children[2].type != SLANG_OPER_POSTINCREMENT &&
+ oper->children[2].type != SLANG_OPER_PREINCREMENT)
+ return GL_FALSE;
+ if (oper->children[2].children[0].type != SLANG_OPER_IDENTIFIER)
+ return GL_FALSE;
+
+ /* make sure the same variable name is used in all places */
+ if ((oper->children[1].children[0].children[0].a_id != varId) ||
+ (oper->children[2].children[0].a_id != varId))
+ return GL_FALSE;
+
+ varName = (const char *) varId;
+
+ /* children[3], the loop body, can't be too large */
+ bodySize = sizeof_operation(&oper->children[3]);
+ if (bodySize > MAX_FOR_LOOP_UNROLL_BODY_SIZE) {
+ slang_info_log_print(A->log,
+ "Note: 'for (%s ... )' body is too large/complex"
+ " to unroll",
+ varName);
+ return GL_FALSE;
+ }
+
+ if (start >= end)
+ return GL_FALSE; /* degenerate case */
+
+ if (end - start > MAX_FOR_LOOP_UNROLL_ITERATIONS) {
+ slang_info_log_print(A->log,
+ "Note: 'for (%s=%d; %s<%d; ++%s)' is too"
+ " many iterations to unroll",
+ varName, start, varName, end, varName);
+ return GL_FALSE;
+ }
+
+ if ((end - start) * bodySize > MAX_FOR_LOOP_UNROLL_COMPLEXITY) {
+ slang_info_log_print(A->log,
+ "Note: 'for (%s=%d; %s<%d; ++%s)' will generate"
+ " too much code to unroll",
+ varName, start, varName, end, varName);
+ return GL_FALSE;
+ }
+
+ return GL_TRUE; /* we can unroll the loop */
+}
+
+
+static void
+_unroll_loop_inc(slang_assemble_ctx * A)
+{
+ A->UnrollLoop++;
+}
+
+
+static void
+_unroll_loop_dec(slang_assemble_ctx * A)
+{
+ A->UnrollLoop--;
+}
+
+
+/**
+ * Unroll a for-loop.
+ * First we determine the number of iterations to unroll.
+ * Then for each iteration:
+ * make a copy of the loop body
+ * replace instances of the loop variable with the current iteration value
+ * generate IR code for the body
+ * \return pointer to generated IR code or NULL if error, out of memory, etc.
+ */
+static slang_ir_node *
+_slang_unroll_for_loop(slang_assemble_ctx * A, const slang_operation *oper)
+{
+ GLint start, end, iter;
+ slang_ir_node *n, *root = NULL;
+ slang_atom varId;
+
+ /* Set flag so code generator knows we're unrolling loops */
+ _unroll_loop_inc( A );
+
+ if (oper->children[0].type == SLANG_OPER_BLOCK_NO_NEW_SCOPE) {
+ /* for (int i=0; ... */
+ slang_variable *var;
+
+ varId = oper->children[0].children[0].a_id;
+ var = _slang_variable_locate(oper->children[0].children[0].locals,
+ varId, GL_TRUE);
+ start = (GLint) var->initializer->literal[0];
+ }
+ else {
+ /* for (i=0; ... */
+ varId = oper->children[0].children[0].children[0].a_id;
+ start = (GLint) oper->children[0].children[0].children[1].literal[0];
+ }
+
+ end = (GLint) oper->children[1].children[0].children[1].literal[0];
+
+ for (iter = start; iter < end; iter++) {
+ slang_operation *body;
+
+ /* make a copy of the loop body */
+ body = slang_operation_new(1);
+ if (!body) {
+ _unroll_loop_dec( A );
+ return NULL;
+ }
+
+ if (!slang_operation_copy(body, &oper->children[3])) {
+ _unroll_loop_dec( A );
+ return NULL;
+ }
+
+ /* in body, replace instances of 'varId' with literal 'iter' */
+ {
+ slang_variable *oldVar;
+ slang_operation *newOper;
+
+ oldVar = _slang_variable_locate(oper->locals, varId, GL_TRUE);
+ if (!oldVar) {
+ /* undeclared loop variable */
+ slang_operation_delete(body);
+ _unroll_loop_dec( A );
+ return NULL;
+ }
+
+ newOper = slang_operation_new(1);
+ newOper->type = SLANG_OPER_LITERAL_INT;
+ newOper->literal_size = 1;
+ newOper->literal[0] = iter;
+
+ /* replace instances of the loop variable with newOper */
+ slang_substitute(A, body, 1, &oldVar, &newOper, GL_FALSE);
+ }
+
+ /* do IR codegen for body */
+ n = _slang_gen_operation(A, body);
+ if (!n) {
+ _unroll_loop_dec( A );
+ return NULL;
+ }
+
+ root = new_seq(root, n);
+
+ slang_operation_delete(body);
+ }
+
+ _unroll_loop_dec( A );
+
+ return root;
+}
+
+
+/**
+ * Generate IR for a for-loop. Unrolling will be done when possible.
*/
static slang_ir_node *
_slang_gen_for(slang_assemble_ctx * A, const slang_operation *oper)
{
- /*
- * init code (child[0])
- * LOOP:
- * BREAK if !expr (child[1])
- * body code (child[3])
- * tail code:
- * incr code (child[2]) // XXX continue here
- */
- slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body, *init, *incr;
+ GLboolean unroll = _slang_can_unroll_for_loop(A, oper);
- init = _slang_gen_operation(A, &oper->children[0]);
- loop = new_loop(NULL);
+ if (unroll) {
+ slang_ir_node *code = _slang_unroll_for_loop(A, oper);
+ if (code)
+ return code;
+ }
- /* save old, push new loop */
- prevLoop = A->CurLoop;
- A->CurLoop = loop;
+ /* conventional for-loop code generation */
+ {
+ /*
+ * init code (child[0])
+ * LOOP:
+ * BREAK if !expr (child[1])
+ * body code (child[3])
+ * tail code:
+ * incr code (child[2]) // XXX continue here
+ */
+ slang_ir_node *prevLoop, *loop, *cond, *breakIf, *body, *init, *incr;
+ init = _slang_gen_operation(A, &oper->children[0]);
+ loop = new_loop(NULL);
- cond = new_cond(new_not(_slang_gen_operation(A, &oper->children[1])));
- breakIf = new_break_if_true(A->CurLoop, cond);
- body = _slang_gen_operation(A, &oper->children[3]);
- incr = _slang_gen_operation(A, &oper->children[2]);
+ /* save old, push new loop */
+ prevLoop = A->CurLoop;
+ A->CurLoop = loop;
- loop->Children[0] = new_seq(breakIf, body);
- loop->Children[1] = incr; /* tail code */
+ cond = new_cond(new_not(_slang_gen_operation(A, &oper->children[1])));
+ breakIf = new_break_if_true(A->CurLoop, cond);
+ body = _slang_gen_operation(A, &oper->children[3]);
+ incr = _slang_gen_operation(A, &oper->children[2]);
- /* pop loop, restore prev */
- A->CurLoop = prevLoop;
+ loop->Children[0] = new_seq(breakIf, body);
+ loop->Children[1] = incr; /* tail code */
- return new_seq(init, loop);
+ /* pop loop, restore prev */
+ A->CurLoop = prevLoop;
+
+ return new_seq(init, loop);
+ }
}
if (is_operation_type(&oper->children[1], SLANG_OPER_BREAK)
&& !haveElseClause) {
/* Special case: generate a conditional break */
+ if (!A->CurLoop && A->UnrollLoop) /* trying to unroll */
+ return NULL;
ifBody = new_break_if_true(A->CurLoop, cond);
return ifBody;
}
else if (is_operation_type(&oper->children[1], SLANG_OPER_CONTINUE)
&& !haveElseClause) {
- /* Special case: generate a conditional break */
+ /* Special case: generate a conditional continue */
+ if (!A->CurLoop && A->UnrollLoop) /* trying to unroll */
+ return NULL;
ifBody = new_cont_if_true(A->CurLoop, cond);
return ifBody;
}
else {
/* general case */
ifBody = _slang_gen_operation(A, &oper->children[1]);
+ if (!ifBody)
+ return NULL;
if (haveElseClause)
elseBody = _slang_gen_operation(A, &oper->children[2]);
else
const GLenum datatype = _slang_gltype_from_specifier(&var->type.specifier);
slang_ir_node *varDecl, *n;
slang_ir_storage *store;
- GLint size, totalSize; /* if array then totalSize > size */
- enum register_file file;
+ GLint arrayLen, size, totalSize; /* if array then totalSize > size */
+ gl_register_file file;
/*assert(!var->declared);*/
var->declared = GL_TRUE;
return NULL;
}
- totalSize = size;
- if (var->type.array_len > 0) {
- /* the type is an array, ex: float[4] x; */
- GLint sz = (totalSize + 3) & ~3;
- /* total size = element size * array length */
- sz *= var->type.array_len;
- totalSize = sz;
- }
-
- if (var->array_len > 0) {
- /* this is an array, ex: float x[4]; */
- /* round up the element size to a multiple of 4 */
- GLint sz = (totalSize + 3) & ~3;
- /* total size = element size * array length */
- sz *= var->array_len;
- totalSize = sz;
- }
+ arrayLen = _slang_array_length(var);
+ totalSize = _slang_array_size(size, arrayLen);
/* Allocate IR node for the declaration */
varDecl = new_node0(IR_VAR_DECL);
if (!varDecl)
return NULL;
- _slang_attach_storage(varDecl, var); /* undefined storage at first */
- assert(var->store);
- assert(varDecl->Store == var->store);
- assert(varDecl->Store);
- assert(varDecl->Store->Index < 0);
- store = var->store;
+ /* Allocate slang_ir_storage for this variable if needed.
+ * Note that we may not actually allocate a constant or temporary register
+ * until later.
+ */
+ if (!var->store) {
+ GLint index = -7; /* TBD / unknown */
+ var->store = _slang_new_ir_storage(file, index, totalSize);
+ if (!var->store)
+ return NULL; /* out of memory */
+ }
- assert(store == varDecl->Store);
+ /* set the IR node's Var and Store pointers */
+ varDecl->Var = var;
+ varDecl->Store = var->store;
- /* Fill in storage fields which we now know. store->Index/Swizzle may be
- * set for some cases below. Otherwise, store->Index/Swizzle will be set
- * during code emit.
- */
- store->File = file;
- store->Size = totalSize;
+ store = var->store;
/* if there's an initializer, generate IR for the expression */
if (initializer) {
}
+#if 0
/**
* Determine if the given operation/expression is const-valued.
*/
return GL_TRUE;
}
}
+#endif
/**
}
+/**
+ * Walk up an IR storage path to compute the final swizzle.
+ * This is used when we find an expression such as "foo.xz.yx".
+ */
+static GLuint
+root_swizzle(const slang_ir_storage *st)
+{
+ GLuint swizzle = st->Swizzle;
+ while (st->Parent) {
+ st = st->Parent;
+ swizzle = _slang_swizzle_swizzle(st->Swizzle, swizzle);
+ }
+ return swizzle;
+}
+
+
/**
* Generate IR tree for an assignment (=).
*/
rhs = _slang_gen_operation(A, &oper->children[1]);
if (lhs && rhs) {
/* convert lhs swizzle into writemask */
- GLuint writemask, newSwizzle;
- if (!swizzle_to_writemask(A, lhs->Store->Swizzle,
- &writemask, &newSwizzle)) {
+ const GLuint swizzle = root_swizzle(lhs->Store);
+ GLuint writemask, newSwizzle = 0x0;
+ if (!swizzle_to_writemask(A, swizzle, &writemask, &newSwizzle)) {
/* Non-simple writemask, need to swizzle right hand side in
* order to put components into the right place.
*/
index = (GLint) oper->children[1].literal[0];
if (oper->children[1].type != SLANG_OPER_LITERAL_INT ||
index >= (GLint) max) {
+#if 0
slang_info_log_error(A->log, "Invalid array index for vector type");
+ printf("type = %d\n", oper->children[1].type);
+ printf("index = %d, max = %d\n", index, max);
+ printf("array = %s\n", (char*)oper->children[0].a_id);
+ printf("index = %s\n", (char*)oper->children[1].a_id);
return NULL;
+#else
+ index = 0;
+#endif
}
n = _slang_gen_operation(A, &oper->children[0]);
elem->Store = _slang_new_ir_storage(array->Store->File,
array->Store->Index,
elemSize);
-
+ elem->Store->Swizzle = _slang_var_swizzle(elemSize, 0);
return elem;
}
else {
return _slang_gen_while(A, oper);
case SLANG_OPER_BREAK:
if (!A->CurLoop) {
- slang_info_log_error(A->log, "'break' not in loop");
+ if (!A->UnrollLoop)
+ slang_info_log_error(A->log, "'break' not in loop");
return NULL;
}
return new_break(A->CurLoop);
case SLANG_OPER_CONTINUE:
if (!A->CurLoop) {
- slang_info_log_error(A->log, "'continue' not in loop");
+ if (!A->UnrollLoop)
+ slang_info_log_error(A->log, "'continue' not in loop");
return NULL;
}
return _slang_gen_continue(A, oper);
/**
- * Compute total size of array give size of element, number of elements.
+ * Check if the given type specifier is a rectangular texture sampler.
*/
-static GLint
-array_size(GLint baseSize, GLint arrayLen)
+static GLboolean
+is_rect_sampler_spec(const slang_type_specifier *spec)
{
- GLint total;
- if (arrayLen > 1) {
- /* round up base type to multiple of 4 */
- total = ((baseSize + 3) & ~0x3) * MAX2(arrayLen, 1);
- }
- else {
- total = baseSize;
+ while (spec->_array) {
+ spec = spec->_array;
}
- return total;
+ return spec->type == SLANG_SPEC_SAMPLER2DRECT ||
+ spec->type == SLANG_SPEC_SAMPLER2DRECTSHADOW;
}
+
/**
* Called by compiler when a global variable has been parsed/compiled.
* Here we examine the variable's type to determine what kind of register
slang_ir_storage *store = NULL;
int dbg = 0;
const GLenum datatype = _slang_gltype_from_specifier(&var->type.specifier);
- const GLint texIndex = sampler_to_texture_index(var->type.specifier.type);
const GLint size = _slang_sizeof_type_specifier(&var->type.specifier);
+ const GLint arrayLen = _slang_array_length(var);
+ const GLint totalSize = _slang_array_size(size, arrayLen);
+ GLint texIndex = sampler_to_texture_index(var->type.specifier.type);
+
+ /* check for sampler2D arrays */
+ if (texIndex == -1 && var->type.specifier._array)
+ texIndex = sampler_to_texture_index(var->type.specifier._array->type);
if (texIndex != -1) {
/* This is a texture sampler variable...
}
#if FEATURE_es2_glsl /* XXX should use FEATURE_texture_rect */
/* disallow rect samplers */
- if (var->type.specifier.type == SLANG_SPEC_SAMPLER2DRECT ||
- var->type.specifier.type == SLANG_SPEC_SAMPLER2DRECTSHADOW) {
+ if (is_rect_sampler_spec(&var->type.specifier)) {
slang_info_log_error(A->log, "invalid sampler type for '%s'", varName);
return GL_FALSE;
}
+#else
+ (void) is_rect_sampler_spec; /* silence warning */
#endif
{
GLint sampNum = _mesa_add_sampler(prog->Parameters, varName, datatype);
- store = _slang_new_ir_storage(PROGRAM_SAMPLER, sampNum, texIndex);
+ store = _slang_new_ir_storage_sampler(sampNum, texIndex, totalSize);
+
+ /* If we have a sampler array, then we need to allocate the
+ * additional samplers to ensure we don't allocate them elsewhere.
+ * We can't directly use _mesa_add_sampler() as that checks the
+ * varName and gets a match, so we call _mesa_add_parameter()
+ * directly and use the last sampler number from the call above.
+ */
+ if (arrayLen > 0) {
+ GLint a = arrayLen - 1;
+ GLint i;
+ for (i = 0; i < a; i++) {
+ GLfloat value = (GLfloat)(i + sampNum + 1);
+ (void) _mesa_add_parameter(prog->Parameters, PROGRAM_SAMPLER,
+ varName, 1, datatype, &value, NULL, 0x0);
+ }
+ }
}
if (dbg) printf("SAMPLER ");
}
else if (var->type.qualifier == SLANG_QUAL_UNIFORM) {
/* Uniform variable */
- const GLint totalSize = array_size(size, var->array_len);
const GLuint swizzle = _slang_var_swizzle(totalSize, 0);
if (prog) {
/* user-defined uniform */
if (datatype == GL_NONE) {
- if (var->type.specifier.type == SLANG_SPEC_STRUCT) {
+ if ((var->type.specifier.type == SLANG_SPEC_ARRAY &&
+ var->type.specifier._array->type == SLANG_SPEC_STRUCT) ||
+ (var->type.specifier.type == SLANG_SPEC_STRUCT)) {
/* temporary work-around */
GLenum datatype = GL_FLOAT;
GLint uniformLoc = _mesa_add_uniform(prog->Parameters, varName,
totalSize, datatype, NULL);
store = _slang_new_ir_storage_swz(PROGRAM_UNIFORM, uniformLoc,
totalSize, swizzle);
+
+ if (arrayLen > 0) {
+ GLint a = arrayLen - 1;
+ GLint i;
+ for (i = 0; i < a; i++) {
+ GLfloat value = (GLfloat)(i + uniformLoc + 1);
+ (void) _mesa_add_parameter(prog->Parameters, PROGRAM_UNIFORM,
+ varName, 1, datatype, &value, NULL, 0x0);
+ }
+ }
/* XXX what we need to do is unroll the struct into its
* basic types, creating a uniform variable for each.
if (dbg) printf("UNIFORM (sz %d) ", totalSize);
}
else if (var->type.qualifier == SLANG_QUAL_VARYING) {
- const GLint totalSize = array_size(size, var->array_len);
-
/* varyings must be float, vec or mat */
if (!_slang_type_is_float_vec_mat(var->type.specifier.type) &&
var->type.specifier.type != SLANG_SPEC_ARRAY) {
n = _slang_gen_var_decl(A, var, var->initializer);
/* emit GPU instructions */
- success = _slang_emit_code(n, A->vartable, A->program, GL_FALSE, A->log);
+ success = _slang_emit_code(n, A->vartable, A->program, A->pragmas, GL_FALSE, A->log);
_slang_free_ir_tree(n);
}
#endif
/* Emit program instructions */
- success = _slang_emit_code(n, A->vartable, A->program, GL_TRUE, A->log);
+ success = _slang_emit_code(n, A->vartable, A->program, A->pragmas, GL_TRUE, A->log);
_slang_free_ir_tree(n);
/* free codegen context */