/*
* Mesa 3-D graphics library
- * Version: 6.5.3
+ * Version: 7.1
*
* Copyright (C) 2005-2007 Brian Paul All Rights Reserved.
*
-#include "imports.h"
-#include "macros.h"
-#include "mtypes.h"
-#include "program.h"
-#include "prog_instruction.h"
-#include "prog_parameter.h"
-#include "prog_statevars.h"
+#include "main/imports.h"
+#include "main/macros.h"
+#include "main/mtypes.h"
+#include "shader/program.h"
+#include "shader/prog_instruction.h"
+#include "shader/prog_parameter.h"
+#include "shader/prog_statevars.h"
#include "slang_typeinfo.h"
#include "slang_codegen.h"
#include "slang_compile.h"
#include "slang_label.h"
+#include "slang_mem.h"
#include "slang_simplify.h"
#include "slang_emit.h"
#include "slang_vartable.h"
}
+#define SWIZZLE_ZWWW MAKE_SWIZZLE4(SWIZZLE_Z, SWIZZLE_W, SWIZZLE_W, SWIZZLE_W)
+
/**
* Return the VERT_ATTRIB_* or FRAG_ATTRIB_* value that corresponds to
* a vertex or fragment program input variable. Return -1 if the input
{ "gl_FragCoord", FRAG_ATTRIB_WPOS, SWIZZLE_NOOP },
{ "gl_Color", FRAG_ATTRIB_COL0, SWIZZLE_NOOP },
{ "gl_SecondaryColor", FRAG_ATTRIB_COL1, SWIZZLE_NOOP },
- { "gl_FogFragCoord", FRAG_ATTRIB_FOGC, SWIZZLE_XXXX },
{ "gl_TexCoord", FRAG_ATTRIB_TEX0, SWIZZLE_NOOP },
+ /* note: we're packing several quantities into the fogcoord vector */
+ { "gl_FogFragCoord", FRAG_ATTRIB_FOGC, SWIZZLE_XXXX },
{ "gl_FrontFacing", FRAG_ATTRIB_FOGC, SWIZZLE_YYYY }, /*XXX*/
+ { "gl_PointCoord", FRAG_ATTRIB_FOGC, SWIZZLE_ZWWW },
{ NULL, 0, SWIZZLE_NOOP }
};
GLuint i;
new_node3(slang_ir_opcode op,
slang_ir_node *c0, slang_ir_node *c1, slang_ir_node *c2)
{
- slang_ir_node *n = (slang_ir_node *) calloc(1, sizeof(slang_ir_node));
+ slang_ir_node *n = (slang_ir_node *) _slang_alloc(sizeof(slang_ir_node));
if (n) {
n->Opcode = op;
n->Children[0] = c0;
}
+/**
+ * Create sequence of two nodes.
+ */
static slang_ir_node *
new_seq(slang_ir_node *left, slang_ir_node *right)
{
/**
- * Inlined subroutine.
+ * Non-inlined function call.
*/
static slang_ir_node *
-new_inlined_function_call(slang_ir_node *code, slang_label *name)
+new_function_call(slang_ir_node *code, slang_label *name)
{
- slang_ir_node *n = new_node1(IR_FUNC, code);
+ slang_ir_node *n = new_node1(IR_CALL, code);
assert(name);
if (n)
n->Label = name;
/**
- * Produce inline code for a call to an assembly instruction.
- * XXX Note: children are passed as asm args in-order, not by name!
+ * Count the number of operations of the given time rooted at 'oper'.
*/
-static slang_operation *
-slang_inline_asm_function(slang_assemble_ctx *A,
- slang_function *fun, slang_operation *oper)
+static GLuint
+_slang_count_node_type(slang_operation *oper, slang_operation_type type)
{
- const GLuint numArgs = oper->num_children;
- const slang_operation *args = oper->children;
- GLuint i;
- slang_operation *inlined = slang_operation_new(1);
+ GLuint i, count = 0;
+ if (oper->type == type) {
+ return 1;
+ }
+ for (i = 0; i < oper->num_children; i++) {
+ count += _slang_count_node_type(&oper->children[i], type);
+ }
+ return count;
+}
- /*assert(oper->type == SLANG_OPER_CALL); or vec4_add, etc */
- /*
- printf("Inline asm %s\n", (char*) fun->header.a_name);
- */
- inlined->type = fun->body->children[0].type;
- inlined->a_id = fun->body->children[0].a_id;
- inlined->num_children = numArgs;
- inlined->children = slang_operation_new(numArgs);
- inlined->locals->outer_scope = oper->locals->outer_scope;
- for (i = 0; i < numArgs; i++) {
- slang_operation_copy(inlined->children + i, args + i);
+/**
+ * Check if the 'return' statement found under 'oper' is a "tail return"
+ * that can be no-op'd. For example:
+ *
+ * void func(void)
+ * {
+ * .. do something ..
+ * return; // this is a no-op
+ * }
+ *
+ * This is used when determining if a function can be inlined. If the
+ * 'return' is not the last statement, we can't inline the function since
+ * we still need the semantic behaviour of the 'return' but we don't want
+ * to accidentally return from the _calling_ function. We'd need to use an
+ * unconditional branch, but we don't have such a GPU instruction (not
+ * always, at least).
+ */
+static GLboolean
+_slang_is_tail_return(const slang_operation *oper)
+{
+ GLuint k = oper->num_children;
+
+ while (k > 0) {
+ const slang_operation *last = &oper->children[k - 1];
+ if (last->type == SLANG_OPER_RETURN)
+ return GL_TRUE;
+ else if (last->type == SLANG_OPER_IDENTIFIER ||
+ last->type == SLANG_OPER_LABEL)
+ k--; /* try prev child */
+ else if (last->type == SLANG_OPER_BLOCK_NO_NEW_SCOPE ||
+ last->type == SLANG_OPER_BLOCK_NEW_SCOPE)
+ /* try sub-children */
+ return _slang_is_tail_return(last);
+ else
+ break;
}
- return inlined;
+ return GL_FALSE;
}
+/**
+ * Produce inline code for a call to an assembly instruction.
+ * This is typically used to compile a call to a built-in function like this:
+ *
+ * vec4 mix(const vec4 x, const vec4 y, const vec4 a)
+ * {
+ * __asm vec4_lrp __retVal, a, y, x;
+ * }
+ *
+ * We basically translate a SLANG_OPER_CALL into a SLANG_OPER_ASM.
+ */
+static slang_operation *
+slang_inline_asm_function(slang_assemble_ctx *A,
+ slang_function *fun, slang_operation *oper)
+{
+ const GLuint numArgs = oper->num_children;
+ GLuint i;
+ slang_operation *inlined;
+ const GLboolean haveRetValue = _slang_function_has_return_value(fun);
+ slang_variable **substOld;
+ slang_operation **substNew;
+
+ ASSERT(slang_is_asm_function(fun));
+ ASSERT(fun->param_count == numArgs + haveRetValue);
+
+ /*
+ printf("Inline %s as %s\n",
+ (char*) fun->header.a_name,
+ (char*) fun->body->children[0].a_id);
+ */
+
+ /*
+ * We'll substitute formal params with actual args in the asm call.
+ */
+ substOld = (slang_variable **)
+ _slang_alloc(numArgs * sizeof(slang_variable *));
+ substNew = (slang_operation **)
+ _slang_alloc(numArgs * sizeof(slang_operation *));
+ for (i = 0; i < numArgs; i++) {
+ substOld[i] = fun->parameters->variables[i];
+ substNew[i] = oper->children + i;
+ }
+
+ /* make a copy of the code to inline */
+ inlined = slang_operation_new(1);
+ slang_operation_copy(inlined, &fun->body->children[0]);
+ if (haveRetValue) {
+ /* get rid of the __retVal child */
+ for (i = 0; i < numArgs; i++) {
+ inlined->children[i] = inlined->children[i + 1];
+ }
+ inlined->num_children--;
+ }
+
+ /* now do formal->actual substitutions */
+ slang_substitute(A, inlined, numArgs, substOld, substNew, GL_FALSE);
+
+ _slang_free(substOld);
+ _slang_free(substNew);
+
+ return inlined;
+}
+
+
/**
* Inline the given function call operation.
* Return a new slang_operation that corresponds to the inlined code.
/* allocate temporary arrays */
paramMode = (ParamMode *)
- _mesa_calloc(totalArgs * sizeof(ParamMode));
+ _slang_alloc(totalArgs * sizeof(ParamMode));
substOld = (slang_variable **)
- _mesa_calloc(totalArgs * sizeof(slang_variable *));
+ _slang_alloc(totalArgs * sizeof(slang_variable *));
substNew = (slang_operation **)
- _mesa_calloc(totalArgs * sizeof(slang_operation *));
+ _slang_alloc(totalArgs * sizeof(slang_operation *));
#if 0
printf("Inline call to %s (total vars=%d nparams=%d)\n",
slang_operation_copy(inlined, fun->body);
/*** XXX review this */
- assert(inlined->type = SLANG_OPER_BLOCK_NO_NEW_SCOPE);
+ assert(inlined->type == SLANG_OPER_BLOCK_NO_NEW_SCOPE);
inlined->type = SLANG_OPER_BLOCK_NEW_SCOPE;
#if 0
}
}
- _mesa_free(paramMode);
- _mesa_free(substOld);
- _mesa_free(substNew);
+ _slang_free(paramMode);
+ _slang_free(substOld);
+ _slang_free(substNew);
#if 0
printf("Done Inline call to %s (total vars=%d nparams=%d)\n",
}
else {
/* non-assembly function */
+ /* We always generate an "inline-able" block of code here.
+ * We may either:
+ * 1. insert the inline code
+ * 2. Generate a call to the "inline" code as a subroutine
+ */
+
+
+ slang_operation *ret = NULL;
+
inlined = slang_inline_function_call(A, fun, oper, dest);
- if (inlined && _slang_find_node_type(inlined, SLANG_OPER_RETURN)) {
- /* This inlined function has one or more 'return' statements.
- * So, we can't truly inline this function because we need to
- * implement 'return' with RET (and CAL).
- * XXX check if there's one 'return' and if it's the very last
- * statement in the function - we can optimize that case.
- */
- assert(inlined->type == SLANG_OPER_BLOCK_NEW_SCOPE ||
- inlined->type == SLANG_OPER_SEQUENCE);
- inlined->type = SLANG_OPER_INLINED_CALL;
- inlined->fun = fun;
- inlined->label = _slang_label_new_unique((char*) fun->header.a_name);
+ if (!inlined)
+ return NULL;
+
+ ret = _slang_find_node_type(inlined, SLANG_OPER_RETURN);
+ if (ret) {
+ /* check if this is a "tail" return */
+ if (_slang_count_node_type(inlined, SLANG_OPER_RETURN) == 1 &&
+ _slang_is_tail_return(inlined)) {
+ /* The only RETURN is the last stmt in the function, no-op it
+ * and inline the function body.
+ */
+ ret->type = SLANG_OPER_NONE;
+ }
+ else {
+ slang_operation *callOper;
+ /* The function we're calling has one or more 'return' statements.
+ * So, we can't truly inline this function because we need to
+ * implement 'return' with RET (and CAL).
+ * Nevertheless, we performed "inlining" to make a new instance
+ * of the function body to deal with static register allocation.
+ *
+ * XXX check if there's one 'return' and if it's the very last
+ * statement in the function - we can optimize that case.
+ */
+ assert(inlined->type == SLANG_OPER_BLOCK_NEW_SCOPE ||
+ inlined->type == SLANG_OPER_SEQUENCE);
+
+ if (_slang_function_has_return_value(fun) && !dest) {
+ assert(inlined->children[0].type == SLANG_OPER_VARIABLE_DECL);
+ assert(inlined->children[2].type == SLANG_OPER_IDENTIFIER);
+ callOper = &inlined->children[1];
+ }
+ else {
+ callOper = inlined;
+ }
+ callOper->type = SLANG_OPER_NON_INLINED_CALL;
+ callOper->fun = fun;
+ callOper->label = _slang_label_new_unique((char*) fun->header.a_name);
+ }
}
}
if (!inlined)
return NULL;
- /* Replace the function call with the inlined block */
+ /* Replace the function call with the inlined block (or new CALL stmt) */
slang_operation_destruct(oper);
*oper = *inlined;
- /* XXX slang_operation_destruct(inlined) ??? */
+ _slang_free(inlined);
#if 0
assert(inlined->locals);
}
+/**
+ * Some write-masked assignments are simple, but others are hard.
+ * Simple example:
+ * vec3 v;
+ * v.xy = vec2(a, b);
+ * Hard example:
+ * vec3 v;
+ * v.zy = vec2(a, b);
+ * this gets transformed/swizzled into:
+ * v.zy = vec2(a, b).*yx* (* = don't care)
+ * This function helps to determine simple vs. non-simple.
+ */
+static GLboolean
+_slang_simple_writemask(GLuint writemask, GLuint swizzle)
+{
+ switch (writemask) {
+ case WRITEMASK_X:
+ return GET_SWZ(swizzle, 0) == SWIZZLE_X;
+ case WRITEMASK_Y:
+ return GET_SWZ(swizzle, 1) == SWIZZLE_Y;
+ case WRITEMASK_Z:
+ return GET_SWZ(swizzle, 2) == SWIZZLE_Z;
+ case WRITEMASK_W:
+ return GET_SWZ(swizzle, 3) == SWIZZLE_W;
+ case WRITEMASK_XY:
+ return (GET_SWZ(swizzle, 0) == SWIZZLE_X)
+ && (GET_SWZ(swizzle, 1) == SWIZZLE_Y);
+ case WRITEMASK_XYZ:
+ return (GET_SWZ(swizzle, 0) == SWIZZLE_X)
+ && (GET_SWZ(swizzle, 1) == SWIZZLE_Y)
+ && (GET_SWZ(swizzle, 2) == SWIZZLE_Z);
+ case WRITEMASK_XYZW:
+ return swizzle == SWIZZLE_NOOP;
+ default:
+ return GL_FALSE;
+ }
+}
+
+
+/**
+ * Convert the given swizzle into a writemask. In some cases this
+ * is trivial, in other cases, we'll need to also swizzle the right
+ * hand side to put components in the right places.
+ * \param swizzle the incoming swizzle
+ * \param writemaskOut returns the writemask
+ * \param swizzleOut swizzle to apply to the right-hand-side
+ * \return GL_FALSE for simple writemasks, GL_TRUE for non-simple
+ */
+static GLboolean
+swizzle_to_writemask(GLuint swizzle,
+ GLuint *writemaskOut, GLuint *swizzleOut)
+{
+ GLuint mask = 0x0, newSwizzle[4];
+ GLint i, size;
+
+ /* make new dst writemask, compute size */
+ for (i = 0; i < 4; i++) {
+ const GLuint swz = GET_SWZ(swizzle, i);
+ if (swz == SWIZZLE_NIL) {
+ /* end */
+ break;
+ }
+ assert(swz >= 0 && swz <= 3);
+ mask |= (1 << swz);
+ }
+ assert(mask <= 0xf);
+ size = i; /* number of components in mask/swizzle */
+
+ *writemaskOut = mask;
+
+ /* make new src swizzle, by inversion */
+ for (i = 0; i < 4; i++) {
+ newSwizzle[i] = i; /*identity*/
+ }
+ for (i = 0; i < size; i++) {
+ const GLuint swz = GET_SWZ(swizzle, i);
+ newSwizzle[swz] = i;
+ }
+ *swizzleOut = MAKE_SWIZZLE4(newSwizzle[0],
+ newSwizzle[1],
+ newSwizzle[2],
+ newSwizzle[3]);
+
+ if (_slang_simple_writemask(mask, *swizzleOut)) {
+ if (size >= 1)
+ assert(GET_SWZ(*swizzleOut, 0) == SWIZZLE_X);
+ if (size >= 2)
+ assert(GET_SWZ(*swizzleOut, 1) == SWIZZLE_Y);
+ if (size >= 3)
+ assert(GET_SWZ(*swizzleOut, 2) == SWIZZLE_Z);
+ if (size >= 4)
+ assert(GET_SWZ(*swizzleOut, 3) == SWIZZLE_W);
+ return GL_TRUE;
+ }
+ else
+ return GL_FALSE;
+}
+
+
+/**
+ * Recursively traverse 'oper' to produce a swizzle mask in the event
+ * of any vector subscripts and swizzle suffixes.
+ * Ex: for "vec4 v", "v[2].x" resolves to v.z
+ */
static GLuint
-make_writemask(const char *field)
+resolve_swizzle(const slang_operation *oper)
{
- GLuint mask = 0x0;
- while (*field) {
- switch (*field) {
- case 'x':
- mask |= WRITEMASK_X;
+ if (oper->type == SLANG_OPER_FIELD) {
+ /* writemask from .xyzw suffix */
+ slang_swizzle swz;
+ if (_slang_is_swizzle((char*) oper->a_id, 4, &swz)) {
+ GLuint swizzle = MAKE_SWIZZLE4(swz.swizzle[0],
+ swz.swizzle[1],
+ swz.swizzle[2],
+ swz.swizzle[3]);
+ GLuint child_swizzle = resolve_swizzle(&oper->children[0]);
+ GLuint s = _slang_swizzle_swizzle(child_swizzle, swizzle);
+ return s;
+ }
+ else
+ return SWIZZLE_XYZW;
+ }
+ else if (oper->type == SLANG_OPER_SUBSCRIPT &&
+ oper->children[1].type == SLANG_OPER_LITERAL_INT) {
+ /* writemask from [index] */
+ GLuint child_swizzle = resolve_swizzle(&oper->children[0]);
+ GLuint i = (GLuint) oper->children[1].literal[0];
+ GLuint swizzle;
+ GLuint s;
+ switch (i) {
+ case 0:
+ swizzle = SWIZZLE_XXXX;
break;
- case 'y':
- mask |= WRITEMASK_Y;
+ case 1:
+ swizzle = SWIZZLE_YYYY;
break;
- case 'z':
- mask |= WRITEMASK_Z;
+ case 2:
+ swizzle = SWIZZLE_ZZZZ;
break;
- case 'w':
- mask |= WRITEMASK_W;
+ case 3:
+ swizzle = SWIZZLE_WWWW;
break;
default:
- _mesa_problem(NULL, "invalid writemask in make_writemask()");
- return 0;
+ swizzle = SWIZZLE_XYZW;
}
- field++;
+ s = _slang_swizzle_swizzle(child_swizzle, swizzle);
+ return s;
}
- if (mask == 0x0)
- return WRITEMASK_XYZW;
- else
- return mask;
+ else {
+ return SWIZZLE_XYZW;
+ }
+}
+
+
+/**
+ * As above, but produce a writemask.
+ */
+static GLuint
+resolve_writemask(const slang_operation *oper)
+{
+ GLuint swizzle = resolve_swizzle(oper);
+ GLuint writemask, swizzleOut;
+ swizzle_to_writemask(swizzle, &writemask, &swizzleOut);
+ return writemask;
}
+/**
+ * Recursively descend through swizzle nodes to find the node's storage info.
+ */
+static slang_ir_storage *
+get_store(const slang_ir_node *n)
+{
+ if (n->Opcode == IR_SWIZZLE) {
+ return get_store(n->Children[0]);
+ }
+ return n->Store;
+}
+
+
+
/**
* Generate IR tree for an asm instruction/operation such as:
* __asm vec4_dot __retVal.x, v1, v2;
slang_ir_node *n0;
dest_oper = &oper->children[0];
- while (dest_oper->type == SLANG_OPER_FIELD) {
- /* writemask */
- writemask &= make_writemask((char*) dest_oper->a_id);
- dest_oper = &dest_oper->children[0];
- }
+
+ writemask = resolve_writemask(dest_oper);
n0 = _slang_gen_operation(A, dest_oper);
- assert(n0->Var);
- assert(n0->Store);
+ if (!n0)
+ return NULL;
+
assert(!n->Store);
- n->Store = n0->Store;
+ n->Store = get_store(n0);
n->Writemask = writemask;
- free(n0);
+ assert(n->Store->File != PROGRAM_UNDEFINED);
+
+ _slang_free(n0);
}
return n;
* Determine if the given operation is of a specific type.
*/
static GLboolean
-is_operation_type(const const slang_operation *oper, slang_operation_type type)
+is_operation_type(const slang_operation *oper, slang_operation_type type)
{
if (oper->type == type)
return GL_TRUE;
n->Store = store;
}
else {
- free(store);
+ _slang_free(store);
}
}
return n;
n->Store->File = PROGRAM_TEMPORARY;
n->Store->Size = _slang_sizeof_type_specifier(&n->Var->type.specifier);
+ if (var->array_len > 0) {
+ /* this is an array */
+ /* round up element size to mult of 4 */
+ GLint sz = (n->Store->Size + 3) & ~3;
+ /* mult by array size */
+ sz *= var->array_len;
+ n->Store->Size = sz;
+ }
+ A->program->NumTemporaries++;
assert(n->Store->Size > 0);
}
return n;
select->children[2].literal_size = 1;
n = _slang_gen_select(A, select);
-
- /* xxx wrong */
- free(select->children);
- free(select);
-
return n;
}
slang_operation_copy(&select->children[2], &oper->children[1]);
n = _slang_gen_select(A, select);
-
- /* xxx wrong */
- free(select->children);
- free(select);
-
return n;
}
_slang_gen_return(slang_assemble_ctx * A, slang_operation *oper)
{
const GLboolean haveReturnValue
- = (oper->num_children == 1 &&
- oper->children[0].type != SLANG_OPER_VOID);
+ = (oper->num_children == 1 && oper->children[0].type != SLANG_OPER_VOID);
/* error checking */
assert(A->CurFunction);
return NULL;
}
else if (!haveReturnValue &&
- A->CurFunction->header.type.specifier.type != SLANG_SPEC_VOID) {
+ A->CurFunction->header.type.specifier.type != SLANG_SPEC_VOID) {
slang_info_log_error(A->log, "return statement requires an expression");
return NULL;
}
}
/* XXX make copy of this initializer? */
rhs = _slang_gen_operation(A, &oper->children[0]);
- assert(rhs);
+ if (!rhs)
+ return NULL; /* must have found an error */
init = new_node2(IR_MOVE, var, rhs);
/*assert(rhs->Opcode != IR_SEQ);*/
n = new_seq(varDecl, init);
}
-/**
- * Some write-masked assignments are simple, but others are hard.
- * Simple example:
- * vec3 v;
- * v.xy = vec2(a, b);
- * Hard example:
- * vec3 v;
- * v.zy = vec2(a, b);
- * this gets transformed/swizzled into:
- * v.zy = vec2(a, b).*yx* (* = don't care)
- * This function helps to determine simple vs. non-simple.
- */
-static GLboolean
-_slang_simple_writemask(GLuint writemask, GLuint swizzle)
-{
- switch (writemask) {
- case WRITEMASK_X:
- return GET_SWZ(swizzle, 0) == SWIZZLE_X;
- case WRITEMASK_Y:
- return GET_SWZ(swizzle, 1) == SWIZZLE_Y;
- case WRITEMASK_Z:
- return GET_SWZ(swizzle, 2) == SWIZZLE_Z;
- case WRITEMASK_W:
- return GET_SWZ(swizzle, 3) == SWIZZLE_W;
- case WRITEMASK_XY:
- return (GET_SWZ(swizzle, 0) == SWIZZLE_X)
- && (GET_SWZ(swizzle, 1) == SWIZZLE_Y);
- case WRITEMASK_XYZ:
- return (GET_SWZ(swizzle, 0) == SWIZZLE_X)
- && (GET_SWZ(swizzle, 1) == SWIZZLE_Y)
- && (GET_SWZ(swizzle, 2) == SWIZZLE_Z);
- case WRITEMASK_XYZW:
- return swizzle == SWIZZLE_NOOP;
- default:
- return GL_FALSE;
- }
-}
-
-
-/**
- * Convert the given swizzle into a writemask. In some cases this
- * is trivial, in other cases, we'll need to also swizzle the right
- * hand side to put components in the right places.
- * \param swizzle the incoming swizzle
- * \param writemaskOut returns the writemask
- * \param swizzleOut swizzle to apply to the right-hand-side
- * \return GL_FALSE for simple writemasks, GL_TRUE for non-simple
- */
-static GLboolean
-swizzle_to_writemask(GLuint swizzle,
- GLuint *writemaskOut, GLuint *swizzleOut)
-{
- GLuint mask = 0x0, newSwizzle[4];
- GLint i, size;
-
- /* make new dst writemask, compute size */
- for (i = 0; i < 4; i++) {
- const GLuint swz = GET_SWZ(swizzle, i);
- if (swz == SWIZZLE_NIL) {
- /* end */
- break;
- }
- assert(swz >= 0 && swz <= 3);
- mask |= (1 << swz);
- }
- assert(mask <= 0xf);
- size = i; /* number of components in mask/swizzle */
-
- *writemaskOut = mask;
-
- /* make new src swizzle, by inversion */
- for (i = 0; i < 4; i++) {
- newSwizzle[i] = i; /*identity*/
- }
- for (i = 0; i < size; i++) {
- const GLuint swz = GET_SWZ(swizzle, i);
- newSwizzle[swz] = i;
- }
- *swizzleOut = MAKE_SWIZZLE4(newSwizzle[0],
- newSwizzle[1],
- newSwizzle[2],
- newSwizzle[3]);
-
- if (_slang_simple_writemask(mask, *swizzleOut)) {
- if (size >= 1)
- assert(GET_SWZ(*swizzleOut, 0) == SWIZZLE_X);
- if (size >= 2)
- assert(GET_SWZ(*swizzleOut, 1) == SWIZZLE_Y);
- if (size >= 3)
- assert(GET_SWZ(*swizzleOut, 2) == SWIZZLE_Z);
- if (size >= 4)
- assert(GET_SWZ(*swizzleOut, 3) == SWIZZLE_W);
- return GL_TRUE;
- }
- else
- return GL_FALSE;
-}
-
-
static slang_ir_node *
_slang_gen_swizzle(slang_ir_node *child, GLuint swizzle)
{
}
if (var->type.qualifier == SLANG_QUAL_CONST ||
var->type.qualifier == SLANG_QUAL_ATTRIBUTE ||
- var->type.qualifier == SLANG_QUAL_UNIFORM) {
+ var->type.qualifier == SLANG_QUAL_UNIFORM ||
+ (var->type.qualifier == SLANG_QUAL_VARYING &&
+ A->program->Target == GL_FRAGMENT_PROGRAM_ARB)) {
slang_info_log_error(A->log,
"illegal assignment to read-only variable '%s'",
(char *) oper->children[0].a_id);
lhs = _slang_gen_operation(A, &oper->children[0]);
if (lhs) {
- if (lhs->Store->File != PROGRAM_OUTPUT &&
- lhs->Store->File != PROGRAM_TEMPORARY &&
- lhs->Store->File != PROGRAM_VARYING &&
- lhs->Store->File != PROGRAM_UNDEFINED) {
+ if (!(lhs->Store->File == PROGRAM_OUTPUT ||
+ lhs->Store->File == PROGRAM_TEMPORARY ||
+ (lhs->Store->File == PROGRAM_VARYING &&
+ A->program->Target == GL_VERTEX_PROGRAM_ARB) ||
+ lhs->Store->File == PROGRAM_UNDEFINED)) {
slang_info_log_error(A->log,
"illegal assignment to read-only l-value");
return NULL;
n = _slang_gen_swizzle(n, swizzle);
return n;
}
- else if (ti.spec.type == SLANG_SPEC_FLOAT) {
+ else if ( ti.spec.type == SLANG_SPEC_FLOAT
+ || ti.spec.type == SLANG_SPEC_INT
+ || ti.spec.type == SLANG_SPEC_BOOL) {
const GLuint rows = 1;
slang_swizzle swz;
slang_ir_node *n;
}
-/**
- * Look for expressions such as: gl_ModelviewMatrix * gl_Vertex
- * and replace with this: gl_Vertex * gl_ModelviewMatrixTranpose
- * Since matrices are stored in column-major order, the second form of
- * multiplication is much more efficient (just 4 dot products).
- */
-static void
-_slang_check_matmul_optimization(slang_assemble_ctx *A, slang_operation *oper)
-{
- static const struct {
- const char *orig;
- const char *tranpose;
- } matrices[] = {
- {"gl_ModelViewMatrix", "gl_ModelViewMatrixTranspose"},
- {"gl_ProjectionMatrix", "gl_ProjectionMatrixTranspose"},
- {"gl_ModelViewProjectionMatrix", "gl_ModelViewProjectionMatrixTranspose"},
- {"gl_TextureMatrix", "gl_TextureMatrixTranspose"},
- {"gl_NormalMatrix", "__NormalMatrixTranspose"},
- { NULL, NULL }
- };
-
- assert(oper->type == SLANG_OPER_MULTIPLY);
- if (oper->children[0].type == SLANG_OPER_IDENTIFIER) {
- GLuint i;
- for (i = 0; matrices[i].orig; i++) {
- if (oper->children[0].a_id
- == slang_atom_pool_atom(A->atoms, matrices[i].orig)) {
- /*
- _mesa_printf("Replace %s with %s\n",
- matrices[i].orig, matrices[i].tranpose);
- */
- assert(oper->children[0].type == SLANG_OPER_IDENTIFIER);
- oper->children[0].a_id
- = slang_atom_pool_atom(A->atoms, matrices[i].tranpose);
- /* finally, swap the operands */
- _slang_operation_swap(&oper->children[0], &oper->children[1]);
- return;
- }
- }
- }
-}
-
-
/**
* Generate IR tree for a slang_operation (AST node)
*/
_slang_free_ir_tree(tree);
return NULL; /* error must have occured */
}
- tree = tree ? new_seq(tree, n) : n;
+ tree = new_seq(tree, n);
}
#if 00
{
slang_ir_node *n;
assert(oper->num_children == 2);
- _slang_check_matmul_optimization(A, oper);
n = _slang_gen_function_call_name(A, "*", oper, NULL);
return n;
}
return n;
}
- case SLANG_OPER_INLINED_CALL:
+ case SLANG_OPER_NON_INLINED_CALL:
case SLANG_OPER_SEQUENCE:
{
slang_ir_node *tree = NULL;
GLuint i;
for (i = 0; i < oper->num_children; i++) {
slang_ir_node *n = _slang_gen_operation(A, &oper->children[i]);
- tree = tree ? new_seq(tree, n) : n;
+ tree = new_seq(tree, n);
}
- if (oper->type == SLANG_OPER_INLINED_CALL) {
- tree = new_inlined_function_call(tree, oper->label);
+ if (oper->type == SLANG_OPER_NON_INLINED_CALL) {
+ tree = new_function_call(tree, oper->label);
}
return tree;
}
const GLint texIndex = sampler_to_texture_index(var->type.specifier.type);
if (texIndex != -1) {
- /* Texture sampler:
+ /* This is a texture sampler variable...
* store->File = PROGRAM_SAMPLER
- * store->Index = sampler uniform location
+ * store->Index = sampler number (0..7, typically)
* store->Size = texture type index (1D, 2D, 3D, cube, etc)
*/
- GLint samplerUniform
- = _mesa_add_sampler(prog->Parameters, varName, datatype);
- store = _slang_new_ir_storage(PROGRAM_SAMPLER, samplerUniform, texIndex);
+ GLint sampNum = _mesa_add_sampler(prog->Parameters, varName, datatype);
+ store = _slang_new_ir_storage(PROGRAM_SAMPLER, sampNum, texIndex);
if (dbg) printf("SAMPLER ");
}
else if (var->type.qualifier == SLANG_QUAL_UNIFORM) {
* MAX2(var->array_len, 1);
if (prog) {
/* user-defined uniform */
- GLint uniformLoc = _mesa_add_uniform(prog->Parameters, varName,
- size, datatype);
- store = _slang_new_ir_storage(PROGRAM_UNIFORM, uniformLoc, size);
+ if (datatype == GL_NONE) {
+ if (var->type.specifier.type == SLANG_SPEC_STRUCT) {
+ _mesa_problem(NULL, "user-declared uniform structs not supported yet");
+ /* XXX what we need to do is unroll the struct into its
+ * basic types, creating a uniform variable for each.
+ * For example:
+ * struct foo {
+ * vec3 a;
+ * vec4 b;
+ * };
+ * uniform foo f;
+ *
+ * Should produce uniforms:
+ * "f.a" (GL_FLOAT_VEC3)
+ * "f.b" (GL_FLOAT_VEC4)
+ */
+ }
+ else {
+ slang_info_log_error(A->log,
+ "invalid datatype for uniform variable %s",
+ (char *) var->a_name);
+ }
+ return GL_FALSE;
+ }
+ else {
+ GLint uniformLoc = _mesa_add_uniform(prog->Parameters, varName,
+ size, datatype);
+ store = _slang_new_ir_storage(PROGRAM_UNIFORM, uniformLoc, size);
+ }
}
else {
/* pre-defined uniform, like gl_ModelviewMatrix */
store = _slang_new_ir_storage(PROGRAM_OUTPUT, index, size);
}
else {
- assert(type == SLANG_UNIT_FRAGMENT_BUILTIN);
GLint index = _slang_output_index(varName, GL_FRAGMENT_PROGRAM_ARB);
GLint size = 4; /* XXX? */
+ assert(type == SLANG_UNIT_FRAGMENT_BUILTIN);
store = _slang_new_ir_storage(PROGRAM_OUTPUT, index, size);
}
if (dbg) printf("OUTPUT ");
if (_mesa_strcmp((char *) fun->header.a_name, "main") != 0) {
/* we only really generate code for main, all other functions get
- * inlined.
+ * inlined or codegen'd upon an actual call.
*/
#if 0
/* do some basic error checking though */