/*
* Mesa 3-D graphics library
- * Version: 7.1
*
* Copyright (C) 2005-2008 Brian Paul All Rights Reserved.
+ * Copyright (C) 2008 VMware, Inc. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
GLuint MaxInstructions; /**< size of prog->Instructions[] buffer */
+ GLboolean UnresolvedFunctions;
+
/* code-gen options */
GLboolean EmitHighLevelInstructions;
GLboolean EmitCondCodes;
}
+/**
+ * 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.
+ */
+GLuint
+_slang_var_swizzle(GLint size, GLint comp)
+{
+ switch (size) {
+ case 1:
+ return MAKE_SWIZZLE4(comp, SWIZZLE_NIL, SWIZZLE_NIL, SWIZZLE_NIL);
+ 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;
+ }
+}
+
+
+
/**
* Allocate storage for the given node (if it hasn't already been allocated).
*
dst->WriteMask = swizzle_to_writemask(swizzle);
}
else {
- GLuint writemask;
switch (size) {
case 1:
- writemask = WRITEMASK_X << GET_SWZ(st->Swizzle, 0);
+ dst->WriteMask = WRITEMASK_X << GET_SWZ(st->Swizzle, 0);
break;
case 2:
- writemask = WRITEMASK_XY;
+ dst->WriteMask = WRITEMASK_XY;
break;
case 3:
- writemask = WRITEMASK_XYZ;
+ dst->WriteMask = WRITEMASK_XYZ;
break;
case 4:
- writemask = WRITEMASK_XYZW;
+ dst->WriteMask = WRITEMASK_XYZW;
break;
default:
; /* error would have been caught above */
}
- dst->WriteMask = writemask;
}
dst->RelAddr = relAddr;
assert(index >= 0);
while (st->Parent) {
st = st->Parent;
+ if (st->Index < 0) {
+ /* an error should have been reported already */
+ return;
+ }
assert(st->Index >= 0);
index += st->Index;
swizzle = _slang_swizzle_swizzle(fix_swizzle(st->Swizzle), swizzle);
static struct prog_instruction *
emit_arl_load(slang_emit_info *emitInfo,
- enum register_file file, GLint index, GLuint swizzle)
+ gl_register_file file, GLint index, GLuint swizzle)
{
struct prog_instruction *inst = new_instruction(emitInfo, OPCODE_ARL);
inst->SrcReg[0].File = file;
inst->SrcReg[0].Index = index;
- inst->SrcReg[0].Swizzle = swizzle;
+ inst->SrcReg[0].Swizzle = fix_swizzle(swizzle);
inst->DstReg.File = PROGRAM_ADDRESS;
inst->DstReg.Index = 0;
inst->DstReg.WriteMask = WRITEMASK_X;
emit(emitInfo, n->Children[1]);
if (n->Children[0]->Store->Size != n->Children[1]->Store->Size) {
+ /* XXX this error should have been caught in slang_codegen.c */
slang_info_log_error(emitInfo->log, "invalid operands to == or !=");
+ n->Store = NULL;
return NULL;
}
slang_ir_storage tempStore;
if (!alloc_local_temp(emitInfo, &tempStore, 4)) {
+ n->Store = NULL;
return NULL;
/* out of temps */
}
n->Children[0]->Store,
NULL,
NULL);
- inst->SrcReg[0].NegateBase = NEGATE_XYZW;
+ inst->SrcReg[0].Negate = NEGATE_XYZW;
return inst;
}
{
struct prog_instruction *inst;
gl_inst_opcode opcode;
+ GLboolean shadow = GL_FALSE;
- if (n->Opcode == IR_TEX) {
+ switch (n->Opcode) {
+ case IR_TEX:
opcode = OPCODE_TEX;
- }
- else if (n->Opcode == IR_TEXB) {
+ break;
+ case IR_TEX_SH:
+ opcode = OPCODE_TEX;
+ shadow = GL_TRUE;
+ break;
+ case IR_TEXB:
opcode = OPCODE_TXB;
- }
- else {
- assert(n->Opcode == IR_TEXP);
+ break;
+ case IR_TEXB_SH:
+ opcode = OPCODE_TXB;
+ shadow = GL_TRUE;
+ break;
+ case IR_TEXP:
+ opcode = OPCODE_TXP;
+ break;
+ case IR_TEXP_SH:
opcode = OPCODE_TXP;
+ shadow = GL_TRUE;
+ break;
+ default:
+ _mesa_problem(NULL, "Bad IR TEX code");
+ return NULL;
+ }
+
+ if (n->Children[0]->Opcode == IR_ELEMENT) {
+ /* array is the sampler (a uniform which'll indicate the texture unit) */
+ assert(n->Children[0]->Children[0]->Store);
+ assert(n->Children[0]->Children[0]->Store->File == PROGRAM_SAMPLER);
+
+ emit(emitInfo, n->Children[0]);
+
+ n->Children[0]->Var = n->Children[0]->Children[0]->Var;
+ } else {
+ /* this is the sampler (a uniform which'll indicate the texture unit) */
+ assert(n->Children[0]->Store);
+ assert(n->Children[0]->Store->File == PROGRAM_SAMPLER);
}
/* emit code for the texcoord operand */
NULL,
NULL);
- /* Child[0] is the sampler (a uniform which'll indicate the texture unit) */
- assert(n->Children[0]->Store);
- /* Store->Index is the sampler index */
+ inst->TexShadow = shadow;
+
+ /* Store->Index is the uniform/sampler index */
assert(n->Children[0]->Store->Index >= 0);
- /* Store->Size is the texture target */
- assert(n->Children[0]->Store->Size >= TEXTURE_1D_INDEX);
- assert(n->Children[0]->Store->Size <= TEXTURE_RECT_INDEX);
+ inst->TexSrcUnit = n->Children[0]->Store->Index;
+ inst->TexSrcTarget = n->Children[0]->Store->TexTarget;
- inst->TexSrcTarget = n->Children[0]->Store->Size;
- inst->TexSrcUnit = n->Children[0]->Store->Index; /* i.e. uniform's index */
+ /* mark the sampler as being used */
+ _mesa_use_uniform(emitInfo->prog->Parameters,
+ (char *) n->Children[0]->Var->a_name);
return inst;
}
inst = emit(emitInfo, n->Children[1]);
if (!n->Children[1]->Store || n->Children[1]->Store->Index < 0) {
- if (!emitInfo->log->text) {
+ if (!emitInfo->log->text && !emitInfo->UnresolvedFunctions) {
+ /* XXX this error should have been caught in slang_codegen.c */
slang_info_log_error(emitInfo->log, "invalid assignment");
}
return NULL;
if (n->Store->File == PROGRAM_SAMPLER) {
/* no code generated for sampler assignments,
- * just copy the sampler index at compile time.
+ * just copy the sampler index/target at compile time.
*/
n->Store->Index = n->Children[1]->Store->Index;
+ n->Store->TexTarget = n->Children[1]->Store->TexTarget;
return NULL;
}
#if PEEPHOLE_OPTIMIZATIONS
if (inst &&
+ (n->Children[1]->Opcode != IR_SWIZZLE) &&
_slang_is_temp(emitInfo->vt, n->Children[1]->Store) &&
(inst->DstReg.File == n->Children[1]->Store->File) &&
(inst->DstReg.Index == n->Children[1]->Store->Index) &&
* becomes:
* MUL a, x, y;
*/
- if (n->Children[1]->Opcode != IR_SWIZZLE)
- _slang_free_temp(emitInfo->vt, n->Children[1]->Store);
- *n->Children[1]->Store = *n->Children[0]->Store;
/* fixup the previous instruction (which stored the RHS result) */
assert(n->Children[0]->Store->Index >= 0);
-
storage_to_dst_reg(&inst->DstReg, n->Children[0]->Store);
return inst;
}
}
+/**
+ * Return the size of a swizzle mask given that some swizzle components
+ * may be NIL/undefined. For example:
+ * swizzle_size(".zzxx") = 4
+ * swizzle_size(".xy??") = 2
+ * swizzle_size(".w???") = 1
+ */
+static GLuint
+swizzle_size(GLuint swizzle)
+{
+ GLuint i;
+ for (i = 0; i < 4; i++) {
+ if (GET_SWZ(swizzle, i) == SWIZZLE_NIL)
+ return i;
+ }
+ return 4;
+}
+
+
static struct prog_instruction *
emit_swizzle(slang_emit_info *emitInfo, slang_ir_node *n)
{
inst = emit(emitInfo, n->Children[0]);
-#if 0
- assert(n->Store->Parent);
- /* Apply this node's swizzle to parent's storage */
- GLuint swizzle = n->Store->Swizzle;
- _slang_copy_ir_storage(n->Store, n->Store->Parent);
- n->Store->Swizzle = _slang_swizzle_swizzle(n->Store->Swizzle, swizzle);
+ if (!n->Store->Parent) {
+ /* this covers a case such as "(b ? p : q).x" */
+ n->Store->Parent = n->Children[0]->Store;
+ assert(n->Store->Parent);
+ }
+
+ {
+ const GLuint swizzle = n->Store->Swizzle;
+ /* new storage is parent storage with updated Swizzle + Size fields */
+ _slang_copy_ir_storage(n->Store, n->Store->Parent);
+ /* Apply this node's swizzle to parent's storage */
+ n->Store->Swizzle = _slang_swizzle_swizzle(n->Store->Swizzle, swizzle);
+ /* Update size */
+ n->Store->Size = swizzle_size(n->Store->Swizzle);
+ }
+
assert(!n->Store->Parent);
-#endif
+ assert(n->Store->Index >= 0);
+
return inst;
}
root = root->Parent;
if (root->File == PROGRAM_STATE_VAR) {
- GLint index = _slang_alloc_statevar(n, emitInfo->prog->Parameters);
- assert(n->Store->Index == index);
- return NULL;
+ GLboolean direct;
+ GLint index =
+ _slang_alloc_statevar(n, emitInfo->prog->Parameters, &direct);
+ if (index < 0) {
+ /* error */
+ return NULL;
+ }
+ if (direct) {
+ n->Store->Index = index;
+ return NULL; /* all done */
+ }
}
}
}
n->Store->Size = elemSize;
+ n->Store->Swizzle = _slang_var_swizzle(elemSize, 0);
return NULL; /* no instruction */
}
* space for the ones that we actually use!
*/
if (root->File == PROGRAM_STATE_VAR) {
- root->Index = _slang_alloc_statevar(n, emitInfo->prog->Parameters);
- if (root->Index < 0) {
+ GLboolean direct;
+ GLint index = _slang_alloc_statevar(n, emitInfo->prog->Parameters, &direct);
+ if (index < 0) {
slang_info_log_error(emitInfo->log, "Error parsing state variable");
return NULL;
}
- return NULL;
- }
- else {
- /* do codegen for struct */
- emit(emitInfo, n->Children[0]);
- assert(n->Children[0]->Store->Index >= 0);
+ if (direct) {
+ root->Index = index;
+ return NULL; /* all done */
+ }
}
+ /* do codegen for struct */
+ emit(emitInfo, n->Children[0]);
+ assert(n->Children[0]->Store->Index >= 0);
+
+
fieldOffset = n->Store->Index;
fieldSize = n->Store->Size;
_slang_copy_ir_storage(n->Store, n->Children[0]->Store);
n->Store->Index = n->Children[0]->Store->Index + fieldOffset / 4;
- /* XXX test this:
- n->Store->Index += fieldOffset / 4;
- */
+ n->Store->Size = fieldSize;
switch (fieldSize) {
case 1:
assert(n->Store->File != PROGRAM_UNDEFINED);
if (n->Store->File == PROGRAM_STATE_VAR && n->Store->Index < 0) {
- n->Store->Index = _slang_alloc_statevar(n, emitInfo->prog->Parameters);
+ GLboolean direct;
+ GLint index = _slang_alloc_statevar(n, emitInfo->prog->Parameters, &direct);
+ if (index < 0) {
+ /* error */
+ char s[100];
+ /* XXX isn't this really an out of memory/resources error? */
+ _mesa_snprintf(s, sizeof(s), "Undefined variable '%s'",
+ (char *) n->Var->a_name);
+ slang_info_log_error(emitInfo->log, s);
+ return NULL;
+ }
+
+ n->Store->Index = index;
}
- else if (n->Store->File == PROGRAM_UNIFORM) {
+ else if (n->Store->File == PROGRAM_UNIFORM ||
+ n->Store->File == PROGRAM_SAMPLER) {
/* mark var as used */
_mesa_use_uniform(emitInfo->prog->Parameters, (char *) n->Var->a_name);
}
+ else if (n->Store->File == PROGRAM_INPUT) {
+ assert(n->Store->Index >= 0);
+ emitInfo->prog->InputsRead |= (1 << n->Store->Index);
+ }
if (n->Store->Index < 0) {
/* probably ran out of registers */
return NULL;
}
+ if (n->Comment) {
+ inst = new_instruction(emitInfo, OPCODE_NOP);
+ inst->Comment = _mesa_strdup(n->Comment);
+ inst = NULL;
+ }
+
switch (n->Opcode) {
case IR_SEQ:
/* sequence of two sub-trees */
case IR_POW:
/* trinary operators */
case IR_LRP:
+ case IR_CMP:
return emit_arith(emitInfo, n);
case IR_EQUAL:
case IR_TEX:
case IR_TEXB:
case IR_TEXP:
+ case IR_TEX_SH:
+ case IR_TEXB_SH:
+ case IR_TEXP_SH:
return emit_tex(emitInfo, n);
case IR_NEG:
return emit_negation(emitInfo, n);
-
+/**
+ * Convert the IR tree into GPU instructions.
+ * \param n root of IR tree
+ * \param vt variable table
+ * \param prog program to put GPU instructions into
+ * \param pragmas controls codegen options
+ * \param withEnd if true, emit END opcode at end
+ * \param log log for emitting errors/warnings/info
+ */
GLboolean
_slang_emit_code(slang_ir_node *n, slang_var_table *vt,
- struct gl_program *prog, GLboolean withEnd,
+ struct gl_program *prog,
+ const struct gl_sl_pragmas *pragmas,
+ GLboolean withEnd,
slang_info_log *log)
{
GET_CURRENT_CONTEXT(ctx);
emitInfo.EmitHighLevelInstructions = ctx->Shader.EmitHighLevelInstructions;
emitInfo.EmitCondCodes = ctx->Shader.EmitCondCodes;
- emitInfo.EmitComments = ctx->Shader.EmitComments;
+ emitInfo.EmitComments = ctx->Shader.EmitComments || pragmas->Debug;
emitInfo.EmitBeginEndSub = GL_TRUE;
if (!emitInfo.EmitCondCodes) {
maxUniforms = ctx->Const.VertexProgram.MaxUniformComponents / 4;
}
if (prog->Parameters->NumParameters > maxUniforms) {
- slang_info_log_error(log, "Constant/uniform register limit exceeded");
+ slang_info_log_error(log, "Constant/uniform register limit exceeded "
+ "(max=%u vec4)", maxUniforms);
+
return GL_FALSE;
}