mirror of
https://gitlab.freedesktop.org/mesa/mesa.git
synced 2026-01-08 23:40:12 +01:00
mesa: rework GLSL array code generation
We now express arrays in terms of indirect addressing. For example:
dst = a[i];
becomes:
MOV dst, TEMP[1 + TEMP[2].y];
At instruction-emit time indirect addressing is converted into ARL/
ADDR-relative form:
ARL ADDR.x, TEMP[2].y;
MOV dst, TEMP[1 + ADDR.x];
This fixes a number of array-related issues. Arrays of arrays and complex
array/struct nesting works now.
There may be some regressions, but more work is coming.
(cherry picked from commit ae0ff8097b)
This commit is contained in:
parent
ef4bd18a50
commit
e779e33261
5 changed files with 374 additions and 163 deletions
|
|
@ -3113,7 +3113,7 @@ _slang_gen_struct_field(slang_assemble_ctx * A, slang_operation *oper)
|
|||
/* oper->a_id is the field name */
|
||||
slang_ir_node *base, *n;
|
||||
slang_typeinfo field_ti;
|
||||
GLint fieldSize, fieldOffset = -1, swz;
|
||||
GLint fieldSize, fieldOffset = -1;
|
||||
|
||||
/* type of field */
|
||||
slang_typeinfo_construct(&field_ti);
|
||||
|
|
@ -3146,22 +3146,12 @@ _slang_gen_struct_field(slang_assemble_ctx * A, slang_operation *oper)
|
|||
if (!n)
|
||||
return NULL;
|
||||
|
||||
|
||||
/* setup the storage info for this node */
|
||||
swz = fieldOffset % 4;
|
||||
|
||||
n->Field = (char *) oper->a_id;
|
||||
n->Store = _slang_new_ir_storage_relative(fieldOffset / 4,
|
||||
fieldSize,
|
||||
base->Store);
|
||||
if (fieldSize == 1)
|
||||
n->Store->Swizzle = MAKE_SWIZZLE4(swz, swz, swz, swz);
|
||||
else if (fieldSize == 2)
|
||||
n->Store->Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y,
|
||||
SWIZZLE_NIL, SWIZZLE_NIL);
|
||||
else if (fieldSize == 3)
|
||||
n->Store->Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y,
|
||||
SWIZZLE_Z, SWIZZLE_NIL);
|
||||
|
||||
/* Store the field's offset in storage->Index */
|
||||
n->Store = _slang_new_ir_storage(base->Store->File,
|
||||
fieldOffset,
|
||||
fieldSize);
|
||||
|
||||
return n;
|
||||
}
|
||||
|
|
@ -3254,12 +3244,12 @@ _slang_gen_array_element(slang_assemble_ctx * A, slang_operation *oper)
|
|||
}
|
||||
|
||||
elem = new_node2(IR_ELEMENT, array, index);
|
||||
elem->Store = _slang_new_ir_storage_relative(constIndex,
|
||||
elemSize,
|
||||
array->Store);
|
||||
|
||||
assert(elem->Store->Parent);
|
||||
/* XXX try to do some array bounds checking here */
|
||||
/* The storage info here will be updated during code emit */
|
||||
elem->Store = _slang_new_ir_storage(array->Store->File,
|
||||
array->Store->Index,
|
||||
elemSize);
|
||||
|
||||
return elem;
|
||||
}
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -261,13 +261,16 @@ fix_swizzle(GLuint swizzle)
|
|||
static void
|
||||
storage_to_dst_reg(struct prog_dst_register *dst, const slang_ir_storage *st)
|
||||
{
|
||||
const GLboolean relAddr = st->RelAddr;
|
||||
const GLint size = st->Size;
|
||||
GLint index = st->Index;
|
||||
GLuint swizzle = st->Swizzle;
|
||||
|
||||
assert(index >= 0);
|
||||
/* if this is storage relative to some parent storage, walk up the tree */
|
||||
while (st->Parent) {
|
||||
st = st->Parent;
|
||||
assert(st->Index >= 0);
|
||||
index += st->Index;
|
||||
swizzle = _slang_swizzle_swizzle(st->Swizzle, swizzle);
|
||||
}
|
||||
|
|
@ -304,6 +307,8 @@ storage_to_dst_reg(struct prog_dst_register *dst, const slang_ir_storage *st)
|
|||
}
|
||||
dst->WriteMask = writemask;
|
||||
}
|
||||
|
||||
dst->RelAddr = relAddr;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -318,8 +323,10 @@ storage_to_src_reg(struct prog_src_register *src, const slang_ir_storage *st)
|
|||
GLuint swizzle = st->Swizzle;
|
||||
|
||||
/* if this is storage relative to some parent storage, walk up the tree */
|
||||
assert(index >= 0);
|
||||
while (st->Parent) {
|
||||
st = st->Parent;
|
||||
assert(st->Index >= 0);
|
||||
index += st->Index;
|
||||
swizzle = _slang_swizzle_swizzle(fix_swizzle(st->Swizzle), swizzle);
|
||||
}
|
||||
|
|
@ -413,19 +420,131 @@ new_instruction(slang_emit_info *emitInfo, gl_inst_opcode opcode)
|
|||
}
|
||||
|
||||
|
||||
static struct prog_instruction *
|
||||
emit_arl_load(slang_emit_info *emitInfo,
|
||||
enum 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->DstReg.File = PROGRAM_ADDRESS;
|
||||
inst->DstReg.Index = 0;
|
||||
inst->DstReg.WriteMask = WRITEMASK_X;
|
||||
return inst;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Emit a new instruction with given opcode, operands.
|
||||
* At this point the instruction may have multiple indirect register
|
||||
* loads/stores. We convert those into ARL loads and address-relative
|
||||
* operands. See comments inside.
|
||||
* At some point in the future we could directly emit indirectly addressed
|
||||
* registers in Mesa GPU instructions.
|
||||
*/
|
||||
static struct prog_instruction *
|
||||
emit_instruction(slang_emit_info *emitInfo,
|
||||
gl_inst_opcode opcode,
|
||||
const slang_ir_storage *dst,
|
||||
const slang_ir_storage *src0,
|
||||
const slang_ir_storage *src1,
|
||||
const slang_ir_storage *src2,
|
||||
const slang_ir_storage *src3)
|
||||
const slang_ir_storage *src2)
|
||||
{
|
||||
struct prog_instruction *inst;
|
||||
GLuint numIndirect = 0;
|
||||
const slang_ir_storage *src[3];
|
||||
slang_ir_storage newSrc[3], newDst;
|
||||
GLuint i;
|
||||
GLboolean isTemp[3];
|
||||
|
||||
isTemp[0] = isTemp[1] = isTemp[2] = GL_FALSE;
|
||||
|
||||
src[0] = src0;
|
||||
src[1] = src1;
|
||||
src[2] = src2;
|
||||
|
||||
/* count up how many operands are indirect loads */
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (src[i] && src[i]->IsIndirect)
|
||||
numIndirect++;
|
||||
}
|
||||
if (dst && dst->IsIndirect)
|
||||
numIndirect++;
|
||||
|
||||
/* Take special steps for indirect register loads.
|
||||
* If we had multiple address registers this would be simpler.
|
||||
* For example, this GLSL code:
|
||||
* x[i] = y[j] + z[k];
|
||||
* would translate into something like:
|
||||
* ARL ADDR.x, i;
|
||||
* ARL ADDR.y, j;
|
||||
* ARL ADDR.z, k;
|
||||
* ADD TEMP[ADDR.x+5], TEMP[ADDR.y+9], TEMP[ADDR.z+4];
|
||||
* But since we currently only have one address register we have to do this:
|
||||
* ARL ADDR.x, i;
|
||||
* MOV t1, TEMP[ADDR.x+9];
|
||||
* ARL ADDR.x, j;
|
||||
* MOV t2, TEMP[ADDR.x+4];
|
||||
* ARL ADDR.x, k;
|
||||
* ADD TEMP[ADDR.x+5], t1, t2;
|
||||
* The code here figures this out...
|
||||
*/
|
||||
if (numIndirect > 0) {
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (src[i] && src[i]->IsIndirect) {
|
||||
/* load the ARL register with the indirect register */
|
||||
emit_arl_load(emitInfo,
|
||||
src[i]->IndirectFile,
|
||||
src[i]->IndirectIndex,
|
||||
src[i]->IndirectSwizzle);
|
||||
|
||||
if (numIndirect > 1) {
|
||||
/* Need to load src[i] into a temporary register */
|
||||
slang_ir_storage srcRelAddr;
|
||||
alloc_local_temp(emitInfo, &newSrc[i], src[i]->Size);
|
||||
isTemp[i] = GL_TRUE;
|
||||
|
||||
/* set RelAddr flag on src register */
|
||||
srcRelAddr = *src[i];
|
||||
srcRelAddr.RelAddr = GL_TRUE;
|
||||
srcRelAddr.IsIndirect = GL_FALSE; /* not really needed */
|
||||
|
||||
/* MOV newSrc, srcRelAddr; */
|
||||
inst = emit_instruction(emitInfo,
|
||||
OPCODE_MOV,
|
||||
&newSrc[i],
|
||||
&srcRelAddr,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
src[i] = &newSrc[i];
|
||||
}
|
||||
else {
|
||||
/* just rewrite the src[i] storage to be ARL-relative */
|
||||
newSrc[i] = *src[i];
|
||||
newSrc[i].RelAddr = GL_TRUE;
|
||||
newSrc[i].IsIndirect = GL_FALSE; /* not really needed */
|
||||
src[i] = &newSrc[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Take special steps for indirect dest register write */
|
||||
if (dst && dst->IsIndirect) {
|
||||
/* load the ARL register with the indirect register */
|
||||
emit_arl_load(emitInfo,
|
||||
dst->IndirectFile,
|
||||
dst->IndirectIndex,
|
||||
dst->IndirectSwizzle);
|
||||
newDst = *dst;
|
||||
newDst.RelAddr = GL_TRUE;
|
||||
newDst.IsIndirect = GL_FALSE;
|
||||
dst = &newDst;
|
||||
}
|
||||
|
||||
/* OK, emit the instruction and its dst, src regs */
|
||||
inst = new_instruction(emitInfo, opcode);
|
||||
if (!inst)
|
||||
return NULL;
|
||||
|
|
@ -433,33 +552,17 @@ emit_instruction(slang_emit_info *emitInfo,
|
|||
if (dst)
|
||||
storage_to_dst_reg(&inst->DstReg, dst);
|
||||
|
||||
if (src1)
|
||||
storage_to_src_reg(&inst->SrcReg[0], src1);
|
||||
if (src2)
|
||||
storage_to_src_reg(&inst->SrcReg[1], src2);
|
||||
if (src3)
|
||||
storage_to_src_reg(&inst->SrcReg[2], src3);
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (src[i])
|
||||
storage_to_src_reg(&inst->SrcReg[i], src[i]);
|
||||
}
|
||||
|
||||
return inst;
|
||||
}
|
||||
/* Free any temp registers that we allocated above */
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (isTemp[i])
|
||||
_slang_free_temp(emitInfo->vt, &newSrc[i]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Emit an ARL instruction.
|
||||
*/
|
||||
static struct prog_instruction *
|
||||
emit_arl_instruction(slang_emit_info *emitInfo,
|
||||
GLint addrReg,
|
||||
const slang_ir_storage *src)
|
||||
{
|
||||
struct prog_instruction *inst;
|
||||
|
||||
assert(addrReg == 0); /* only one addr reg at this time */
|
||||
inst = new_instruction(emitInfo, OPCODE_ARL);
|
||||
storage_to_src_reg(&inst->SrcReg[0], src);
|
||||
inst->DstReg.File = PROGRAM_ADDRESS;
|
||||
inst->DstReg.Index = addrReg;
|
||||
inst->DstReg.WriteMask = WRITEMASK_X;
|
||||
return inst;
|
||||
}
|
||||
|
||||
|
|
@ -1217,7 +1320,8 @@ emit_copy(slang_emit_info *emitInfo, slang_ir_node *n)
|
|||
if (inst &&
|
||||
_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)) {
|
||||
(inst->DstReg.Index == n->Children[1]->Store->Index) &&
|
||||
!n->Children[0]->Store->IsIndirect) {
|
||||
/* Peephole optimization:
|
||||
* The Right-Hand-Side has its results in a temporary place.
|
||||
* Modify the RHS (and the prev instruction) to store its results
|
||||
|
|
@ -1675,80 +1779,38 @@ emit_swizzle(slang_emit_info *emitInfo, slang_ir_node *n)
|
|||
|
||||
inst = emit(emitInfo, n->Children[0]);
|
||||
|
||||
/* setup storage info, if needed */
|
||||
if (!n->Store->Parent)
|
||||
n->Store->Parent = n->Children[0]->Store;
|
||||
|
||||
#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);
|
||||
assert(!n->Store->Parent);
|
||||
#endif
|
||||
return inst;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Move a block registers from src to dst (or move a single register).
|
||||
* \param size size of block, in floats (<=4 means one register)
|
||||
*/
|
||||
static struct prog_instruction *
|
||||
move_block(slang_emit_info *emitInfo,
|
||||
GLuint size, GLboolean relAddr,
|
||||
const slang_ir_storage *dst,
|
||||
const slang_ir_storage *src)
|
||||
{
|
||||
struct prog_instruction *inst;
|
||||
|
||||
if (size > 4) {
|
||||
/* move matrix/struct etc (block of registers) */
|
||||
slang_ir_storage dstStore = *dst;
|
||||
slang_ir_storage srcStore = *src;
|
||||
|
||||
dstStore.Size = 4;
|
||||
srcStore.Size = 4;
|
||||
while (size >= 4) {
|
||||
inst = emit_instruction(emitInfo, OPCODE_MOV,
|
||||
&dstStore,
|
||||
&srcStore,
|
||||
NULL,
|
||||
NULL);
|
||||
inst->SrcReg[0].RelAddr = relAddr;
|
||||
inst_comment(inst, "IR_COPY block");
|
||||
srcStore.Index++;
|
||||
dstStore.Index++;
|
||||
size -= 4;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* single register move */
|
||||
inst = emit_instruction(emitInfo,
|
||||
OPCODE_MOV,
|
||||
dst,
|
||||
src,
|
||||
NULL,
|
||||
NULL);
|
||||
inst->SrcReg[0].RelAddr = relAddr;
|
||||
}
|
||||
return inst;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Dereference array element. Just resolve storage for the array
|
||||
* element represented by this node.
|
||||
* This is typically where Indirect addressing comes into play.
|
||||
* See comments on struct slang_ir_storage.
|
||||
* Dereference array element: element == array[index]
|
||||
* This basically involves emitting code for computing the array index
|
||||
* and updating the node/element's storage info.
|
||||
*/
|
||||
static struct prog_instruction *
|
||||
emit_array_element(slang_emit_info *emitInfo, slang_ir_node *n)
|
||||
{
|
||||
assert(n->Opcode == IR_ELEMENT);
|
||||
assert(n->Store);
|
||||
assert(n->Store->File == PROGRAM_UNDEFINED);
|
||||
assert(n->Store->Parent);
|
||||
assert(n->Store->Size > 0);
|
||||
slang_ir_storage *arrayStore, *indexStore;
|
||||
const int elemSize = n->Store->Size; /* number of floats */
|
||||
const GLint elemSizeVec = (elemSize + 3) / 4; /* number of vec4 */
|
||||
struct prog_instruction *inst;
|
||||
|
||||
assert(n->Opcode == IR_ELEMENT);
|
||||
assert(elemSize > 0);
|
||||
|
||||
/* special case for built-in state variables, like light state */
|
||||
{
|
||||
slang_ir_storage *root = n->Store;
|
||||
assert(!root->Parent);
|
||||
while (root->Parent)
|
||||
root = root->Parent;
|
||||
|
||||
|
|
@ -1759,69 +1821,98 @@ emit_array_element(slang_emit_info *emitInfo, slang_ir_node *n)
|
|||
}
|
||||
}
|
||||
|
||||
/* do codegen for array */
|
||||
/* do codegen for array itself */
|
||||
emit(emitInfo, n->Children[0]);
|
||||
arrayStore = n->Children[0]->Store;
|
||||
|
||||
/* The initial array element storage is the array's storage,
|
||||
* then modified below.
|
||||
*/
|
||||
_slang_copy_ir_storage(n->Store, arrayStore);
|
||||
|
||||
|
||||
if (n->Children[1]->Opcode == IR_FLOAT) {
|
||||
/* Constant array index.
|
||||
* Set Store's index to be the offset of the array element in
|
||||
* the register file.
|
||||
*/
|
||||
/* Constant array index */
|
||||
const GLint element = (GLint) n->Children[1]->Value[0];
|
||||
const GLint sz = (n->Store->Size + 3) / 4; /* size in slots/registers */
|
||||
|
||||
n->Store->Index = sz * element;
|
||||
assert(n->Store->Parent);
|
||||
/* this element's storage is the array's storage, plus constant offset */
|
||||
n->Store->Index += elemSizeVec * element;
|
||||
}
|
||||
else {
|
||||
/* Variable array index */
|
||||
struct prog_instruction *inst;
|
||||
|
||||
/* do codegen for array index expression */
|
||||
emit(emitInfo, n->Children[1]);
|
||||
indexStore = n->Children[1]->Store;
|
||||
|
||||
/* allocate temp storage for the array element */
|
||||
assert(n->Store->Index < 0);
|
||||
n->Store->File = PROGRAM_TEMPORARY;
|
||||
n->Store->Parent = NULL;
|
||||
alloc_node_storage(emitInfo, n, -1);
|
||||
if (indexStore->IsIndirect) {
|
||||
/* need to put the array index into a temporary since we can't
|
||||
* directly support a[b[i]] constructs.
|
||||
*/
|
||||
|
||||
if (n->Store->Size > 4) {
|
||||
/* need to multiply the index by the element size */
|
||||
const GLint elemSize = (n->Store->Size + 3) / 4;
|
||||
slang_ir_storage indexTemp, elemSizeStore;
|
||||
|
||||
/* constant containing the element size */
|
||||
constant_to_storage(emitInfo, (float) elemSize, &elemSizeStore);
|
||||
/*indexStore = tempstore();*/
|
||||
}
|
||||
|
||||
|
||||
if (elemSize > 4) {
|
||||
/* need to multiply array index by array element size */
|
||||
struct prog_instruction *inst;
|
||||
slang_ir_storage *indexTemp;
|
||||
slang_ir_storage elemSizeStore;
|
||||
|
||||
/* allocate 1 float indexTemp */
|
||||
alloc_local_temp(emitInfo, &indexTemp, 1);
|
||||
indexTemp = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, 1);
|
||||
_slang_alloc_temp(emitInfo->vt, indexTemp);
|
||||
|
||||
/* MUL temp, index, elemSize */
|
||||
inst = emit_instruction(emitInfo, OPCODE_MUL,
|
||||
&indexTemp, /* dest */
|
||||
n->Children[1]->Store, /* the index */
|
||||
/* allocate a constant containing the element size */
|
||||
constant_to_storage(emitInfo, (float) elemSizeVec, &elemSizeStore);
|
||||
|
||||
/* multiply array index by element size */
|
||||
inst = emit_instruction(emitInfo,
|
||||
OPCODE_MUL,
|
||||
indexTemp, /* dest */
|
||||
indexStore, /* the index */
|
||||
&elemSizeStore,
|
||||
NULL);
|
||||
|
||||
/* load ADDR[0].X = temp */
|
||||
inst = emit_arl_instruction(emitInfo, 0, &indexTemp);
|
||||
|
||||
_slang_free_temp(emitInfo->vt, &indexTemp);
|
||||
}
|
||||
else {
|
||||
/* simply load address reg w/ array index */
|
||||
inst = emit_arl_instruction(emitInfo, 0, n->Children[1]->Store);
|
||||
indexStore = indexTemp;
|
||||
}
|
||||
|
||||
/* copy from array element to temp storage */
|
||||
move_block(emitInfo, n->Store->Size, GL_TRUE,
|
||||
n->Store, n->Children[0]->Store);
|
||||
if (arrayStore->IsIndirect) {
|
||||
/* ex: in a[i][j], a[i] (the arrayStore) is indirect */
|
||||
/* Need to add indexStore to arrayStore->Indirect store */
|
||||
slang_ir_storage indirectArray;
|
||||
slang_ir_storage *indexTemp;
|
||||
|
||||
_slang_init_ir_storage(&indirectArray,
|
||||
arrayStore->IndirectFile,
|
||||
arrayStore->IndirectIndex,
|
||||
1,
|
||||
arrayStore->IndirectSwizzle);
|
||||
|
||||
/* allocate 1 float indexTemp */
|
||||
indexTemp = _slang_new_ir_storage(PROGRAM_TEMPORARY, -1, 1);
|
||||
_slang_alloc_temp(emitInfo->vt, indexTemp);
|
||||
|
||||
inst = emit_instruction(emitInfo,
|
||||
OPCODE_ADD,
|
||||
indexTemp, /* dest */
|
||||
indexStore, /* the index */
|
||||
&indirectArray, /* indirect array base */
|
||||
NULL);
|
||||
|
||||
indexStore = indexTemp;
|
||||
}
|
||||
|
||||
/* update the array element storage info */
|
||||
n->Store->IsIndirect = GL_TRUE;
|
||||
n->Store->IndirectFile = indexStore->File;
|
||||
n->Store->IndirectIndex = indexStore->Index;
|
||||
n->Store->IndirectSwizzle = indexStore->Swizzle;
|
||||
}
|
||||
|
||||
/* if array element size is one, make sure we only access X */
|
||||
if (n->Store->Size == 1)
|
||||
n->Store->Swizzle = SWIZZLE_XXXX;
|
||||
n->Store->Size = elemSize;
|
||||
|
||||
return NULL; /* no instruction */
|
||||
}
|
||||
|
|
@ -1834,9 +1925,11 @@ static struct prog_instruction *
|
|||
emit_struct_field(slang_emit_info *emitInfo, slang_ir_node *n)
|
||||
{
|
||||
slang_ir_storage *root = n->Store;
|
||||
GLint fieldOffset, fieldSize;
|
||||
|
||||
assert(n->Opcode == IR_FIELD);
|
||||
|
||||
assert(!root->Parent);
|
||||
while (root->Parent)
|
||||
root = root->Parent;
|
||||
|
||||
|
|
@ -1852,12 +1945,45 @@ emit_struct_field(slang_emit_info *emitInfo, slang_ir_node *n)
|
|||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
*/
|
||||
|
||||
switch (fieldSize) {
|
||||
case 1:
|
||||
{
|
||||
GLint swz = fieldOffset % 4;
|
||||
n->Store->Swizzle = MAKE_SWIZZLE4(swz, swz, swz, swz);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
n->Store->Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y,
|
||||
SWIZZLE_NIL, SWIZZLE_NIL);
|
||||
break;
|
||||
case 3:
|
||||
n->Store->Swizzle = MAKE_SWIZZLE4(SWIZZLE_X, SWIZZLE_Y,
|
||||
SWIZZLE_Z, SWIZZLE_NIL);
|
||||
break;
|
||||
default:
|
||||
n->Store->Swizzle = SWIZZLE_XYZW;
|
||||
}
|
||||
|
||||
assert(n->Store->Index >= 0);
|
||||
|
||||
return NULL; /* no instruction */
|
||||
}
|
||||
|
||||
|
|
@ -1914,7 +2040,7 @@ emit_var_decl(slang_emit_info *emitInfo, slang_ir_node *n)
|
|||
|
||||
/**
|
||||
* Emit code for a reference to a variable.
|
||||
* Actually, no code is generated but we may do some memory alloation.
|
||||
* Actually, no code is generated but we may do some memory allocation.
|
||||
* In particular, state vars (uniforms) are allocated on an as-needed basis.
|
||||
*/
|
||||
static struct prog_instruction *
|
||||
|
|
@ -2132,7 +2258,7 @@ _slang_resolve_subroutines(slang_emit_info *emitInfo)
|
|||
total += emitInfo->Subroutines[i]->NumInstructions;
|
||||
}
|
||||
|
||||
/* adjust BrancTargets within the functions */
|
||||
/* adjust BranchTargets within the functions */
|
||||
for (i = 0; i < emitInfo->NumSubroutines; i++) {
|
||||
struct gl_program *sub = emitInfo->Subroutines[i];
|
||||
GLuint j;
|
||||
|
|
@ -2201,7 +2327,7 @@ _slang_emit_code(slang_ir_node *n, slang_var_table *vt,
|
|||
emitInfo.prog = prog;
|
||||
emitInfo.Subroutines = NULL;
|
||||
emitInfo.NumSubroutines = 0;
|
||||
emitInfo.MaxInstructions = 0;
|
||||
emitInfo.MaxInstructions = prog->NumInstructions;
|
||||
|
||||
emitInfo.EmitHighLevelInstructions = ctx->Shader.EmitHighLevelInstructions;
|
||||
emitInfo.EmitCondCodes = ctx->Shader.EmitCondCodes;
|
||||
|
|
|
|||
|
|
@ -112,6 +112,20 @@ _slang_ir_info(slang_ir_opcode opcode)
|
|||
}
|
||||
|
||||
|
||||
void
|
||||
_slang_init_ir_storage(slang_ir_storage *st,
|
||||
enum register_file file, GLint index, GLint size,
|
||||
GLuint swizzle)
|
||||
{
|
||||
st->File = file;
|
||||
st->Index = index;
|
||||
st->Size = size;
|
||||
st->Swizzle = swizzle;
|
||||
st->Parent = NULL;
|
||||
st->IsIndirect = GL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a new slang_ir_storage object.
|
||||
*/
|
||||
|
|
@ -126,6 +140,7 @@ _slang_new_ir_storage(enum register_file file, GLint index, GLint size)
|
|||
st->Size = size;
|
||||
st->Swizzle = SWIZZLE_NOOP;
|
||||
st->Parent = NULL;
|
||||
st->IsIndirect = GL_FALSE;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
|
@ -146,6 +161,7 @@ _slang_new_ir_storage_swz(enum register_file file, GLint index, GLint size,
|
|||
st->Size = size;
|
||||
st->Swizzle = swizzle;
|
||||
st->Parent = NULL;
|
||||
st->IsIndirect = GL_FALSE;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
|
@ -166,11 +182,45 @@ _slang_new_ir_storage_relative(GLint index, GLint size,
|
|||
st->Size = size;
|
||||
st->Swizzle = SWIZZLE_NOOP;
|
||||
st->Parent = parent;
|
||||
st->IsIndirect = GL_FALSE;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
|
||||
slang_ir_storage *
|
||||
_slang_new_ir_storage_indirect(enum register_file file,
|
||||
GLint index,
|
||||
GLint size,
|
||||
enum register_file indirectFile,
|
||||
GLint indirectIndex,
|
||||
GLuint indirectSwizzle)
|
||||
{
|
||||
slang_ir_storage *st;
|
||||
st = (slang_ir_storage *) _slang_alloc(sizeof(slang_ir_storage));
|
||||
if (st) {
|
||||
st->File = file;
|
||||
st->Index = index;
|
||||
st->Size = size;
|
||||
st->Swizzle = SWIZZLE_NOOP;
|
||||
st->IsIndirect = GL_TRUE;
|
||||
st->IndirectFile = indirectFile;
|
||||
st->IndirectIndex = indirectIndex;
|
||||
st->IndirectSwizzle = indirectSwizzle;
|
||||
}
|
||||
return st;
|
||||
}
|
||||
|
||||
|
||||
/* XXX temporary function */
|
||||
void
|
||||
_slang_copy_ir_storage(slang_ir_storage *dst, const slang_ir_storage *src)
|
||||
{
|
||||
*dst = *src;
|
||||
dst->Parent = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const char *
|
||||
_slang_ir_name(slang_ir_opcode opcode)
|
||||
|
|
|
|||
|
|
@ -137,24 +137,53 @@ typedef enum
|
|||
|
||||
|
||||
/**
|
||||
* Describes where data storage is allocated.
|
||||
* Describes where data/variables are stored in the various register files.
|
||||
*
|
||||
* In the simple case, the File, Index and Size fields indicate where
|
||||
* a variable is stored. For example, a vec3 variable may be stored
|
||||
* as (File=PROGRAM_TEMPORARY, Index=6, Size=3). Or, File[Index].
|
||||
* Or, a program input like color may be stored as
|
||||
* (File=PROGRAM_INPUT,Index=3,Size=4);
|
||||
*
|
||||
* For single-float values, the Swizzle field indicates which component
|
||||
* of the vector contains the float.
|
||||
*
|
||||
* If IsIndirect is set, the storage is accessed through an indirect
|
||||
* register lookup. The value in question will be located at:
|
||||
* File[Index + IndirectFile[IndirectIndex]]
|
||||
*
|
||||
* This is primary used for indexing arrays. For example, consider this
|
||||
* GLSL code:
|
||||
* uniform int i;
|
||||
* float a[10];
|
||||
* float x = a[i];
|
||||
*
|
||||
* here, storage for a[i] would be described by (File=PROGRAM_TEMPORAY,
|
||||
* Index=aPos, IndirectFile=PROGRAM_UNIFORM, IndirectIndex=iPos), which
|
||||
* would mean TEMP[aPos + UNIFORM[iPos]]
|
||||
*/
|
||||
struct _slang_ir_storage
|
||||
struct slang_ir_storage_
|
||||
{
|
||||
enum register_file File; /**< PROGRAM_TEMPORARY, PROGRAM_INPUT, etc */
|
||||
GLint Index; /**< -1 means unallocated */
|
||||
GLint Size; /**< number of floats */
|
||||
GLuint Swizzle;
|
||||
GLuint Swizzle; /**< Swizzle AND writemask info */
|
||||
GLint RefCount; /**< Used during IR tree delete */
|
||||
GLboolean RelAddr;
|
||||
|
||||
GLboolean RelAddr; /* we'll remove this eventually */
|
||||
|
||||
GLboolean IsIndirect;
|
||||
enum register_file IndirectFile;
|
||||
GLint IndirectIndex;
|
||||
GLuint IndirectSwizzle;
|
||||
|
||||
/** If Parent is non-null, Index is relative to parent.
|
||||
* The other fields are ignored.
|
||||
*/
|
||||
struct _slang_ir_storage *Parent;
|
||||
struct slang_ir_storage_ *Parent;
|
||||
};
|
||||
|
||||
typedef struct _slang_ir_storage slang_ir_storage;
|
||||
typedef struct slang_ir_storage_ slang_ir_storage;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -196,6 +225,11 @@ extern const slang_ir_info *
|
|||
_slang_ir_info(slang_ir_opcode opcode);
|
||||
|
||||
|
||||
extern void
|
||||
_slang_init_ir_storage(slang_ir_storage *st,
|
||||
enum register_file file, GLint index, GLint size,
|
||||
GLuint swizzle);
|
||||
|
||||
extern slang_ir_storage *
|
||||
_slang_new_ir_storage(enum register_file file, GLint index, GLint size);
|
||||
|
||||
|
|
@ -209,6 +243,17 @@ _slang_new_ir_storage_relative(GLint index, GLint size,
|
|||
slang_ir_storage *parent);
|
||||
|
||||
|
||||
extern slang_ir_storage *
|
||||
_slang_new_ir_storage_indirect(enum register_file file,
|
||||
GLint index,
|
||||
GLint size,
|
||||
enum register_file indirectFile,
|
||||
GLint indirectIndex,
|
||||
GLuint indirectSwizzle);
|
||||
|
||||
extern void
|
||||
_slang_copy_ir_storage(slang_ir_storage *dst, const slang_ir_storage *src);
|
||||
|
||||
|
||||
extern void
|
||||
_slang_free_ir_tree(slang_ir_node *n);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
#ifndef SLANG_VARTABLE_H
|
||||
#define SLANG_VARTABLE_H
|
||||
|
||||
struct _slang_ir_storage;
|
||||
struct slang_ir_storage_;
|
||||
|
||||
typedef struct slang_var_table_ slang_var_table;
|
||||
|
||||
|
|
@ -27,16 +27,16 @@ extern struct slang_variable_ *
|
|||
_slang_find_variable(const slang_var_table *t, slang_atom name);
|
||||
|
||||
extern GLboolean
|
||||
_slang_alloc_var(slang_var_table *t, struct _slang_ir_storage *store);
|
||||
_slang_alloc_var(slang_var_table *t, struct slang_ir_storage_ *store);
|
||||
|
||||
extern GLboolean
|
||||
_slang_alloc_temp(slang_var_table *t, struct _slang_ir_storage *store);
|
||||
_slang_alloc_temp(slang_var_table *t, struct slang_ir_storage_ *store);
|
||||
|
||||
extern void
|
||||
_slang_free_temp(slang_var_table *t, struct _slang_ir_storage *store);
|
||||
_slang_free_temp(slang_var_table *t, struct slang_ir_storage_ *store);
|
||||
|
||||
extern GLboolean
|
||||
_slang_is_temp(const slang_var_table *t, const struct _slang_ir_storage *store);
|
||||
_slang_is_temp(const slang_var_table *t, const struct slang_ir_storage_ *store);
|
||||
|
||||
|
||||
#endif /* SLANG_VARTABLE_H */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue