/*
* 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"
}
+/**
+ * Return the size (in floats) of the given type specifier.
+ * If the size is greater than 4, the size should be a multiple of 4
+ * so that the correct number of 4-float registers are allocated.
+ * For example, a mat3x2 is size 12 because we want to store the
+ * 3 columns in 3 float[4] registers.
+ */
GLuint
_slang_sizeof_type_specifier(const slang_type_specifier *spec)
{
+ GLuint sz;
switch (spec->type) {
case SLANG_SPEC_VOID:
- return 0;
+ sz = 0;
+ break;
case SLANG_SPEC_BOOL:
- return 1;
+ sz = 1;
+ break;
case SLANG_SPEC_BVEC2:
- return 2;
+ sz = 2;
+ break;
case SLANG_SPEC_BVEC3:
- return 3;
+ sz = 3;
+ break;
case SLANG_SPEC_BVEC4:
- return 4;
+ sz = 4;
+ break;
case SLANG_SPEC_INT:
- return 1;
+ sz = 1;
+ break;
case SLANG_SPEC_IVEC2:
- return 2;
+ sz = 2;
+ break;
case SLANG_SPEC_IVEC3:
- return 3;
+ sz = 3;
+ break;
case SLANG_SPEC_IVEC4:
- return 4;
+ sz = 4;
+ break;
case SLANG_SPEC_FLOAT:
- return 1;
+ sz = 1;
+ break;
case SLANG_SPEC_VEC2:
- return 2;
+ sz = 2;
+ break;
case SLANG_SPEC_VEC3:
- return 3;
+ sz = 3;
+ break;
case SLANG_SPEC_VEC4:
- return 4;
+ sz = 4;
+ break;
case SLANG_SPEC_MAT2:
- return 2 * 2;
+ sz = 2 * 4; /* 2 columns (regs) */
+ break;
case SLANG_SPEC_MAT3:
- return 3 * 3;
+ sz = 3 * 4;
+ break;
case SLANG_SPEC_MAT4:
- return 4 * 4;
+ sz = 4 * 4;
+ break;
+ case SLANG_SPEC_MAT23:
+ sz = 2 * 4; /* 2 columns (regs) */
+ break;
+ case SLANG_SPEC_MAT32:
+ sz = 3 * 4; /* 3 columns (regs) */
+ break;
+ case SLANG_SPEC_MAT24:
+ sz = 2 * 4;
+ break;
+ case SLANG_SPEC_MAT42:
+ sz = 4 * 4; /* 4 columns (regs) */
+ break;
+ case SLANG_SPEC_MAT34:
+ sz = 3 * 4;
+ break;
+ case SLANG_SPEC_MAT43:
+ sz = 4 * 4; /* 4 columns (regs) */
+ break;
case SLANG_SPEC_SAMPLER1D:
case SLANG_SPEC_SAMPLER2D:
case SLANG_SPEC_SAMPLER3D:
case SLANG_SPEC_SAMPLER2DSHADOW:
case SLANG_SPEC_SAMPLER2DRECT:
case SLANG_SPEC_SAMPLER2DRECTSHADOW:
- return 1; /* a sampler is basically just an integer index */
+ sz = 1; /* a sampler is basically just an integer index */
+ break;
case SLANG_SPEC_STRUCT:
- return _slang_field_offset(spec, 0); /* special use */
+ sz = _slang_field_offset(spec, 0); /* special use */
+ if (sz > 4) {
+ sz = (sz + 3) & ~0x3; /* round up to multiple of four */
+ }
+ break;
case SLANG_SPEC_ARRAY:
- return _slang_sizeof_type_specifier(spec->_array);
+ sz = _slang_sizeof_type_specifier(spec->_array);
+ break;
default:
_mesa_problem(NULL, "Unexpected type in _slang_sizeof_type_specifier()");
- return 0;
+ sz = 0;
}
- return 0;
+
+ if (sz > 4) {
+ /* if size is > 4, it should be a multiple of four */
+ assert((sz & 0x3) == 0);
+ }
+ return sz;
}
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;
}
-/**
- * Produce inline code for a call to an assembly instruction.
- * XXX Note: children are passed as asm args in-order, not by name!
- */
-static slang_operation *
-slang_inline_asm_function(slang_assemble_ctx *A,
- slang_function *fun, slang_operation *oper)
-{
- const GLuint numArgs = oper->num_children;
- const slang_operation *args = oper->children;
- GLuint i;
- slang_operation *inlined = slang_operation_new(1);
-
- /*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);
- }
-
- return inlined;
-}
-
-
static void
slang_resolve_variable(slang_operation *oper)
{
+/**
+ * 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",
}
}
- _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",
/* Replace the function call with the inlined block */
slang_operation_destruct(oper);
*oper = *inlined;
- /* XXX slang_operation_destruct(inlined) ??? */
+ _slang_free(inlined);
#if 0
assert(inlined->locals);
/*_slang_label_delete(A->curFuncEndLabel);*/
A->curFuncEndLabel = prevFuncEndLabel;
- assert(A->curFuncEndLabel);
return n;
}
while (*field) {
switch (*field) {
case 'x':
+ case 's':
+ case 'r':
mask |= WRITEMASK_X;
break;
case 'y':
+ case 't':
+ case 'g':
mask |= WRITEMASK_Y;
break;
case 'z':
+ case 'p':
+ case 'b':
mask |= WRITEMASK_Z;
break;
case 'w':
+ case 'q':
+ case 'a':
mask |= WRITEMASK_W;
break;
default:
n->Store = n0->Store;
n->Writemask = writemask;
- free(n0);
+ _slang_free(n0);
}
return n;
* Try adapting the parameters.
*/
fun = _slang_first_function(A->space.funcs, name);
- if (!_slang_adapt_call(oper, fun, &A->space, A->atoms, A->log)) {
+ if (!fun || !_slang_adapt_call(oper, fun, &A->space, A->atoms, A->log)) {
slang_info_log_error(A->log, "Function '%s' not found (check argument types)", name);
return NULL;
}
* 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;
_slang_gen_temporary(GLint size)
{
slang_ir_storage *store;
- slang_ir_node *n;
+ slang_ir_node *n = NULL;
store = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, size);
if (store) {
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);
+ 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;
}
static slang_ir_node *
_slang_gen_assignment(slang_assemble_ctx * A, slang_operation *oper)
{
+ if (oper->children[0].type == SLANG_OPER_IDENTIFIER) {
+ /* Check that var is writeable */
+ slang_variable *var
+ = _slang_locate_variable(oper->children[0].locals,
+ oper->children[0].a_id, GL_TRUE);
+ if (!var) {
+ slang_info_log_error(A->log, "undefined variable '%s'",
+ (char *) oper->children[0].a_id);
+ return NULL;
+ }
+ if (var->type.qualifier == SLANG_QUAL_CONST ||
+ var->type.qualifier == SLANG_QUAL_ATTRIBUTE ||
+ var->type.qualifier == SLANG_QUAL_UNIFORM) {
+ slang_info_log_error(A->log,
+ "illegal assignment to read-only variable '%s'",
+ (char *) oper->children[0].a_id);
+ return NULL;
+ }
+ }
+
if (oper->children[0].type == SLANG_OPER_IDENTIFIER &&
oper->children[1].type == SLANG_OPER_CALL) {
/* Special case of: x = f(a, b)
lhs->Store->File != PROGRAM_TEMPORARY &&
lhs->Store->File != PROGRAM_VARYING &&
lhs->Store->File != PROGRAM_UNDEFINED) {
- slang_info_log_error(A->log, "Assignment to read-only variable");
+ 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) {
const GLuint rows = 1;
slang_swizzle swz;
slang_ir_node *n;
/* oper->a_id is the field name */
slang_ir_node *base, *n;
slang_typeinfo field_ti;
- GLint fieldSize, fieldOffset;
+ GLint fieldSize, fieldOffset = -1;
/* type of field */
slang_typeinfo_construct(&field_ti);
_slang_typeof_operation(A, oper, &field_ti);
fieldSize = _slang_sizeof_type_specifier(&field_ti.spec);
- fieldOffset = _slang_field_offset(&ti.spec, oper->a_id);
+ if (fieldSize > 0)
+ fieldOffset = _slang_field_offset(&ti.spec, oper->a_id);
- if (fieldOffset < 0) {
+ if (fieldSize == 0 || fieldOffset < 0) {
slang_info_log_error(A->log,
"\"%s\" is not a member of struct \"%s\"",
(char *) oper->a_id,
struct gl_program *prog = A->program;
const char *varName = (char *) var->a_name;
GLboolean success = GL_TRUE;
- GLint texIndex;
slang_ir_storage *store = NULL;
int dbg = 0;
-
- texIndex = sampler_to_texture_index(var->type.specifier.type);
+ const GLenum datatype = _slang_gltype_from_specifier(&var->type.specifier);
+ const GLint texIndex = sampler_to_texture_index(var->type.specifier.type);
if (texIndex != -1) {
/* Texture sampler:
* store->Index = sampler uniform location
* store->Size = texture type index (1D, 2D, 3D, cube, etc)
*/
- GLint samplerUniform = _mesa_add_sampler(prog->Parameters, varName);
+ GLint samplerUniform
+ = _mesa_add_sampler(prog->Parameters, varName, datatype);
store = _slang_new_ir_storage(PROGRAM_SAMPLER, samplerUniform, texIndex);
if (dbg) printf("SAMPLER ");
}
* MAX2(var->array_len, 1);
if (prog) {
/* user-defined uniform */
- GLint uniformLoc = _mesa_add_uniform(prog->Parameters, varName, size);
- 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 */
if (dbg) printf("ATTRIB ");
}
else if (var->type.qualifier == SLANG_QUAL_FIXEDINPUT) {
- GLuint swizzle;
+ GLuint swizzle = SWIZZLE_XYZW; /* silence compiler warning */
GLint index = _slang_input_index(varName, GL_FRAGMENT_PROGRAM_ARB,
&swizzle);
GLint size = 4; /* XXX? */
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 ");